Просмотр исходного кода

Merge branch 'master' into Optimizer

Iñigo Valentin 5 лет назад
Родитель
Сommit
6a82ed20fa
100 измененных файлов с 8086 добавлено и 1246 удалено
  1. 1 1
      application/API/v1/API_Controller.php
  2. 4 0
      application/API/v2/API_Controller.php
  3. 156 0
      application/API/v2/bin/update_collection.py
  4. 2 1
      application/API/v2/bin/upload_run_dungeon.py
  5. 3 1
      application/API/v2/help/api.php
  6. 2 1
      application/API/v2/help/index.php
  7. 1 3
      application/API/v2/units.php
  8. 87 0
      application/API/v2/update_collection.php
  9. 3 3
      application/API/v2/update_logbook.php
  10. 0 1
      application/API/v2/upload_run_dimension.php
  11. 0 1
      application/API/v2/upload_run_dungeon.php
  12. 0 1
      application/API/v2/upload_run_rift.php
  13. 0 1
      application/API/v2/upload_run_scenario.php
  14. 0 1
      application/API/v2/upload_run_toa.php
  15. 98 0
      application/API/v3/API_Controller.php
  16. 425 0
      application/API/v3/help/api.php
  17. 488 0
      application/API/v3/help/index.php
  18. 17 0
      application/API/v3/main.php
  19. 77 0
      application/API/v3/profile/DELETE.php
  20. 67 0
      application/API/v3/profile/GET.php
  21. 211 0
      application/API/v3/profile/POST.php
  22. 1659 0
      application/API/v3/profile/PUT.php
  23. 1469 0
      application/API/v3/run/POST.php
  24. 455 0
      application/API/v3/units/GET.php
  25. 1357 2
      application/Constant.php
  26. 7 3
      application/Controller.php
  27. 6 7
      application/action/delete_team.php
  28. 10 10
      application/action/edit_profile.php
  29. 24 14
      application/action/login.php
  30. 1 2
      application/action/logout.php
  31. 17 10
      application/action/new_team.php
  32. 1 4
      application/action/optimize_get_options.php
  33. 14 25
      application/action/optimize_get_rune_list.php
  34. 14 8
      application/action/rate_team.php
  35. 34 14
      application/action/save_run_team.php
  36. 45 51
      application/entity/Artifact.php
  37. 15 13
      application/entity/Building.php
  38. 15 13
      application/entity/Decoration.php
  39. 47 32
      application/entity/Enchantment.php
  40. 43 38
      application/entity/Fusion.php
  41. 29 25
      application/entity/Guild.php
  42. 18 17
      application/entity/Guild_Member.php
  43. 21 17
      application/entity/Inventory.php
  44. 28 11
      application/entity/K_Area.php
  45. 10 9
      application/entity/K_Building.php
  46. 10 9
      application/entity/K_Decoration.php
  47. 11 10
      application/entity/K_Effect.php
  48. 11 10
      application/entity/K_Guild_Skill.php
  49. 20 17
      application/entity/K_Guild_Skill_Group.php
  50. 22 18
      application/entity/K_Inventory.php
  51. 20 17
      application/entity/K_Leader_Skill.php
  52. 11 10
      application/entity/K_Rune_Set.php
  53. 51 44
      application/entity/K_Skill.php
  54. 13 11
      application/entity/K_Skill_Level.php
  55. 11 10
      application/entity/K_Source.php
  56. 67 60
      application/entity/K_Unit.php
  57. 6 6
      application/entity/K_Unit_Transformation.php
  58. 58 46
      application/entity/Player.php
  59. 49 43
      application/entity/Record.php
  60. 267 205
      application/entity/Run.php
  61. 47 46
      application/entity/Rune.php
  62. 36 33
      application/entity/Team.php
  63. 105 81
      application/entity/Unit.php
  64. 1 1
      application/helper/APPLICATION_Helper.php
  65. 24 90
      application/helper/HTML_Helper.php
  66. 0 1
      application/page/Artifacts_Page.php
  67. 17 0
      application/page/Catalog_Page.php
  68. 6 8
      application/page/Enchantments_Page.php
  69. 59 0
      application/page/Error_Page.php
  70. 1 1
      application/page/Fusion_Page.php
  71. 9 3
      application/page/Landing_Page.php
  72. 0 2
      application/page/Monster_Info_Page.php
  73. 0 2
      application/page/Monster_Page.php
  74. 0 2
      application/page/Monsters_Page.php
  75. 1 1
      application/page/Optimizer_Page.php
  76. 49 50
      application/page/Report_Rune_Enchantment_Page.php
  77. 0 1
      application/page/Report_Skillup_Page.php
  78. 0 7
      application/page/Stats_Page.php
  79. 6 6
      application/page/Teams_Page.php
  80. BIN
      application/sw.sqlite
  81. 3 2
      application/view/artifacts.php
  82. 9 3
      application/view/catalog.php
  83. 3 4
      application/view/enchantments.php
  84. 45 0
      application/view/error.php
  85. 2 2
      application/view/fusion.php
  86. 1 1
      application/view/guild.php
  87. 1 1
      application/view/help.php
  88. 3 2
      application/view/home.php
  89. 2 0
      application/view/inc/header.php
  90. 12 1
      application/view/landing.php
  91. 3 3
      application/view/monster.php
  92. 3 2
      application/view/monster_info.php
  93. 3 3
      application/view/monsters.php
  94. 2 2
      application/view/optimizer.php
  95. 3 11
      application/view/optimizer_unit.php
  96. 3 3
      application/view/profile.php
  97. 3 2
      application/view/report.php
  98. 10 9
      application/view/report_rune_enchantment.php
  99. 3 3
      application/view/report_skillup.php
  100. 3 1
      application/view/runes.php

+ 1 - 1
application/API/v1/API_Controller.php

@@ -32,7 +32,7 @@
                 require_once(__DIR__ . "main.php");
                 require_once(__DIR__ . "main.php");
             }
             }
             else{
             else{
-                $command = strtoupper$pars[1];
+                $command = strtoupper($params[1]);
                 switch ($command){
                 switch ($command){
                     case "log-profile":
                     case "log-profile":
                         require_once(__DIR__ . "log-profile/index.php");
                         require_once(__DIR__ . "log-profile/index.php");

+ 4 - 0
application/API/v2/API_Controller.php

@@ -38,6 +38,7 @@
                 switch ($command){
                 switch ($command){
                     case "help":
                     case "help":
                         require_once(__DIR__ . "/help/index.php");
                         require_once(__DIR__ . "/help/index.php");
+                        break;
                     case "upload_profile":
                     case "upload_profile":
                         require_once(__DIR__ . "/upload_profile.php");
                         require_once(__DIR__ . "/upload_profile.php");
                         break;
                         break;
@@ -59,6 +60,9 @@
                     case "update_logbook":
                     case "update_logbook":
                         require_once(__DIR__ . "/update_logbook.php");
                         require_once(__DIR__ . "/update_logbook.php");
                         break;
                         break;
+                    case "update_collection":
+                        require_once(__DIR__ . "/update_collection.php");
+                        break;
                     case "units":
                     case "units":
                         require_once(__DIR__ . "/units.php");
                         require_once(__DIR__ . "/units.php");
                         break;
                         break;

+ 156 - 0
application/API/v2/bin/update_collection.py

@@ -0,0 +1,156 @@
+#!/usr/bin/python3
+
+import sqlite3
+import json
+import sys
+import os
+
+
+"""
+Reads the API KEY, that must be passed as first command line argument.
+
+:returns: Recovered API KEY.
+:raises Exception: Th KEY couldn't be red.
+"""
+def readKey():
+    try:
+        #print(sys.argv[0])
+        key = sys.argv[1]
+        return key
+    except Exception as e:
+        print("Error parsing API KEY: " + str(e))
+        raise
+
+"""
+Reads the JSON data, that must be passed as second command line argument.
+
+:param: index 2 for request data, 3 for response data
+:returns: Recovered data, in JSON format.
+:raises Exception: The data couldn't be red or converted to JSON.
+"""
+def readData(index):
+    try:
+        data = json.loads(sys.argv[index])
+        return data
+    except Exception as e:
+        print("Error parsing data: " + str(e))
+        raise
+
+"""
+Verifies that the API key matches the player data and that it exists in th DB.
+
+:param db: Connection to the database.
+:returns: Connection to the database.
+:param data: Data in json format.
+:param key: API KEY.
+:returns: True if key and player match, False otherwise.
+:raises IntegrityError: The queryes couldn't bre executed.
+"""
+def verifyKey(db, data, key):
+    print('Verifying KEY...')
+    status = False
+    try:
+        uid = data["wizard_id"]
+        cursor = db.cursor()
+        cursor.execute('SELECT count(uid) AS c FROM player WHERE uid = ? AND api_key = ?;', (uid, key))
+        if cursor.fetchone()[0] == 1:
+            status = True
+        cursor.close()
+    except sqlite3.IntegrityError as e:
+        print("Error executing statement: " + str(e))
+        raise
+    return status
+
+"""
+Opens the database file and deletes from the user tables
+
+:param name: The path to the sqlite database.
+:returns: Connection to the database.
+:raises IntegrityError: The queryes couldn't bre executed.
+:raises IOError: The sqlite file couldn't be created.
+"""
+def openDatabase():
+    kdb = os.path.dirname(os.path.realpath(sys.argv[0])) + '/../../../sw.sqlite'
+    udb = os.path.dirname(os.path.realpath(sys.argv[0])) + '/../../../../data/sw.sqlite'
+    print('Configuring database...')
+    try:
+        db = sqlite3.connect(kdb)
+        cursor = db.cursor()
+        cursor.execute('attach "' + udb + '" as data;')
+        cursor.close()
+        return db
+    except sqlite3.IntegrityError as e:
+        print("Error executing statement: " + str(e))
+        raise
+    except IOError as e:
+        print("I/O Error creating database " + name + ": " + str(e))
+        raise
+
+"""
+Inserts a row into the database.
+
+:param db: Connection to the database.
+:param table: Name of the table to insert into.
+:param values: List of values to insert.
+:raises IntegrityError: The insert query was unsuccesfull.
+"""
+def insert(db, table, values):
+    cursor = db.cursor()
+    placeholders = ''
+    for x in range(0, len(values)):
+        placeholders = placeholders + '?, '
+    placeholders = placeholders[:len(placeholders) - 2]
+    query = 'INSERT INTO ' + table + ' VALUES (' + placeholders + ')'
+    try:
+        cursor.execute(query, values)
+    except sqlite3.IntegrityError as e:
+        print('Error Inserting into ' + table + ' with values (' + str(values) + '): ' + str(e))
+        raise
+    cursor.close;
+
+"""
+Parses run data (tables run, run_party, run_drop_rune, run_drop_runecraft,
+run_drop_item, run_drop_unit, run_drop_sd, run_drop_unit_pieces,
+run_drop_shapeshifting).
+
+:param db: Sqlite database connection.
+:param data: JSON data.
+"""
+def parseData(db, data_request, data_response):
+
+    cursor = db.cursor()
+
+    # Page 1: Cairos non-elemental, rift raid, rift dungeon.
+    print("Parsing collection data...")
+    
+    uid = data_request["wizard_id"]
+    collection = data_response["collection"]
+    cursor.execute("""
+            DELETE FROM collection
+            WHERE uid = ?;
+        """,
+        [uid]
+    )
+
+    # Loop Cairos records
+    for u in collection:
+        unit = u["unit_master_id"]
+        open = u["open"]
+        insert(db, "collection", (uid, unit, open))
+    db.commit()
+
+"""
+Begin script
+"""
+data_request = readData(2)
+data_response = readData(3)
+key = readKey()
+db = openDatabase()
+if verifyKey(db, data_request, key) == False:
+    print("Invalid API KEY...")
+    sys.exit(-1)
+else:
+    parseData(db, data_request, data_response)
+sys.exit(0)
+
+

+ 2 - 1
application/API/v2/bin/upload_run_dungeon.py

@@ -150,6 +150,7 @@ def parseRun(db, data_request, data_response):
         crystal = mana = data_response["reward"]["crystal"]
         crystal = mana = data_response["reward"]["crystal"]
     else:
     else:
         crystal = 0
         crystal = 0
+    guild_points = 0
     # TODO Read helper. Do a test with SWBD-debug
     # TODO Read helper. Do a test with SWBD-debug
     helper = 0
     helper = 0
 
 
@@ -161,7 +162,7 @@ def parseRun(db, data_request, data_response):
 
 
     score = None
     score = None
     rank = None
     rank = None
-    insert(db, "run", (uid, id, dtime, area_type, area, stage, difficulty, win, time, mana, energy, crystal, helper, score, rank))
+    insert(db, "run", (uid, id, dtime, area_type, area, stage, difficulty, win, time, mana, energy, crystal, guild_points, helper, score, rank))
 
 
     # Parse various types of reward
     # Parse various types of reward
     crate = data_response["reward"]["crate"]
     crate = data_response["reward"]["crate"]

+ 3 - 1
application/API/v2/help/api.php

@@ -1,5 +1,7 @@
 <?php
 <?php
-
+    /**
+     * @var mixed[] $API API help structure.
+     */
     $API = [
     $API = [
         "version" => 2,
         "version" => 2,
         "category" => [
         "category" => [

+ 2 - 1
application/API/v2/help/index.php

@@ -5,6 +5,7 @@
      * Shows API documentation.
      * Shows API documentation.
      *
      *
      * @category View
      * @category View
+     * @var mixed[] $API API help structure.
      */
      */
 ?>
 ?>
 <?php
 <?php
@@ -320,7 +321,7 @@
                     foreach ($category["command"] as $command){
                     foreach ($category["command"] as $command){
 ?>
 ?>
                         <li>
                         <li>
-                            <a href='#command_<?=$command["name"]?>' alt='<?=$command["description"]?>'>
+                            <a href='#command_<?=$command["name"]?>' title='<?=$command["description"]?>'>
                                 <?=$command["name"]?>
                                 <?=$command["name"]?>
                             </a>
                             </a>
                         </li>
                         </li>

+ 1 - 3
application/API/v2/units.php

@@ -7,9 +7,7 @@
      *  - key: User API key. If not, only public user's unit can be seen.
      *  - key: User API key. If not, only public user's unit can be seen.
      *
      *
      * @category API
      * @category API
-     * @magic $params URL parameters:
-     *  1: User ID
-     *  2: Unit ID (optional)
+     * @var mixed[] $params URL parameters.
      */
      */
 
 
     global $db;
     global $db;

+ 87 - 0
application/API/v2/update_collection.php

@@ -0,0 +1,87 @@
+<?php
+    /**
+     * Logbook logger script.
+     *
+     * Exposes an API to update the logbook for player data and records.
+     * Reads post data and calls the update_logbook.py script.
+     * Mandatory POST parameters are:
+     *  - data: Received JSON file after a run.
+     *  - key: User API key.
+     *
+     * @category API
+     */
+
+    global $db;
+
+    try{
+        // Check data
+        $request = filter_input(INPUT_POST, 'request');
+        if ($request == null || $request == false){
+            http_response_code(400);
+            return 400;
+        }
+        $response = filter_input(INPUT_POST, 'response');
+        if ($response == null || $response == false){
+            http_response_code(400);
+            return 400;
+        }
+        // Check API key.
+        $key = filter_input(INPUT_POST, 'key');
+        if ($key == null || $key == false){
+            http_response_code(401);
+            return 401;
+        }
+        // Check data format.
+        $json_request = json_decode($request);
+        if ($json_request === null){
+            http_response_code(400);
+            return 400;
+        }
+        $json_response = json_decode($response);
+        if ($json_response === null){
+            http_response_code(400);
+            return 400;
+        }
+        // Authenticate
+        $uid = $json_request->{"wizard_id"};
+        $s = "SELECT COUNT(uid) AS c FROM player WHERE uid = $uid AND api_key = '$key';";
+        if (1 != $db->query($s)->fetchArray(SQLITE3_ASSOC)["c"]){
+            http_response_code(401);
+            return 401;
+        }
+
+        // Run scenario run parser script
+        $cmd = __DIR__ . "/bin/update_collection.py " . $key . " " . escapeshellarg($request). " " . escapeshellarg($response);
+        $out = [];
+        $ret = 0;
+        try{
+            exec($cmd, $out, $ret);
+        }
+        catch(Exception $e) {
+            error_log("Error running collection update script '$cmd': " . $e->getMessage());
+            http_response_code(500);
+            return 500;
+        }
+
+        if ($ret != 200){
+            try{
+                http_response_code($ret);
+                return $ret;
+            }
+            catch(Exception $e) {
+                error_log("Collection update script '$cmd' returned an unexpected value $ret: " . $e->getMessage());
+                http_response_code(500);
+                return 500;
+            }
+        }
+
+        // At this point, status code should be 200
+        http_response_code($ret);
+        return $ret;
+    }
+    catch(Exception $e) {
+        error_log("Unknown error updating collection: " . $e->getMessage());
+        http_response_code(500);
+        return 500;
+    }
+?>

+ 3 - 3
application/API/v2/update_logbook.php

@@ -48,7 +48,7 @@
             exec($cmd, $out, $ret);
             exec($cmd, $out, $ret);
         }
         }
         catch(Exception $e) {
         catch(Exception $e) {
-            error_log("Error running scenario run script '$cmd': " . $e->getMessage());
+            error_log("Error running logbook update script '$cmd': " . $e->getMessage());
             http_response_code(500);
             http_response_code(500);
             return 500;
             return 500;
         }
         }
@@ -59,7 +59,7 @@
                 return $ret;
                 return $ret;
             }
             }
             catch(Exception $e) {
             catch(Exception $e) {
-                error_log("Dungeon run script '$cmd' returned an unexpected value $ret: " . $e->getMessage());
+                error_log("Logbook update script '$cmd' returned an unexpected value $ret: " . $e->getMessage());
                 http_response_code(500);
                 http_response_code(500);
                 return 500;
                 return 500;
             }
             }
@@ -70,7 +70,7 @@
         return $ret;
         return $ret;
     }
     }
     catch(Exception $e) {
     catch(Exception $e) {
-        error_log("Unknown error parsing scenario run: " . $e->getMessage());
+        error_log("Unknown error parsing logbook update: " . $e->getMessage());
         http_response_code(500);
         http_response_code(500);
         return 500;
         return 500;
     }
     }

+ 0 - 1
application/API/v2/upload_run_dimension.php

@@ -40,7 +40,6 @@
 
 
         // Authenticate
         // Authenticate
         $uid = $json_request->{"wizard_id"};
         $uid = $json_request->{"wizard_id"};
-        $uname = $json_response->{"wizard_info"}->{"wizard_name"};
         $s = "SELECT COUNT(uid) AS c FROM player WHERE uid = $uid AND api_key = '$key';";
         $s = "SELECT COUNT(uid) AS c FROM player WHERE uid = $uid AND api_key = '$key';";
         if (1 != $db->query($s)->fetchArray(SQLITE3_ASSOC)["c"]){
         if (1 != $db->query($s)->fetchArray(SQLITE3_ASSOC)["c"]){
             http_response_code(401);
             http_response_code(401);

+ 0 - 1
application/API/v2/upload_run_dungeon.php

@@ -40,7 +40,6 @@
 
 
         // Authenticate
         // Authenticate
         $uid = $json_request->{"wizard_id"};
         $uid = $json_request->{"wizard_id"};
-        $uname = $json_response->{"wizard_info"}->{"wizard_name"};
         $s = "SELECT COUNT(uid) AS c FROM player WHERE uid = $uid AND api_key = '$key';";
         $s = "SELECT COUNT(uid) AS c FROM player WHERE uid = $uid AND api_key = '$key';";
         if (1 != $db->query($s)->fetchArray(SQLITE3_ASSOC)["c"]){
         if (1 != $db->query($s)->fetchArray(SQLITE3_ASSOC)["c"]){
             http_response_code(401);
             http_response_code(401);

+ 0 - 1
application/API/v2/upload_run_rift.php

@@ -51,7 +51,6 @@
 
 
         // Authenticate
         // Authenticate
         $uid = $json_request->{"wizard_id"};
         $uid = $json_request->{"wizard_id"};
-        $uname = $json_response->{"wizard_info"}->{"wizard_name"};
         $s = "SELECT COUNT(uid) AS c FROM player WHERE uid = $uid AND api_key = '$key';";
         $s = "SELECT COUNT(uid) AS c FROM player WHERE uid = $uid AND api_key = '$key';";
         if (1 != $db->query($s)->fetchArray(SQLITE3_ASSOC)["c"]){
         if (1 != $db->query($s)->fetchArray(SQLITE3_ASSOC)["c"]){
             http_response_code(401);
             http_response_code(401);

+ 0 - 1
application/API/v2/upload_run_scenario.php

@@ -37,7 +37,6 @@
 
 
         // Authenticate
         // Authenticate
         $uid = $json->{"wizard_id"};
         $uid = $json->{"wizard_id"};
-        $uname = $json->{"wizard_info"}->{"wizard_name"};
         $s = "SELECT COUNT(uid) AS c FROM player WHERE uid = $uid AND api_key = '$key';";
         $s = "SELECT COUNT(uid) AS c FROM player WHERE uid = $uid AND api_key = '$key';";
         if (1 != $db->query($s)->fetchArray(SQLITE3_ASSOC)["c"]){
         if (1 != $db->query($s)->fetchArray(SQLITE3_ASSOC)["c"]){
             http_response_code(401);
             http_response_code(401);

+ 0 - 1
application/API/v2/upload_run_toa.php

@@ -40,7 +40,6 @@
 
 
         // Authenticate
         // Authenticate
         $uid = $json_request->{"wizard_id"};
         $uid = $json_request->{"wizard_id"};
-        $uname = $json_response->{"wizard_info"}->{"wizard_name"};
         $s = "SELECT COUNT(uid) AS c FROM player WHERE uid = $uid AND api_key = '$key';";
         $s = "SELECT COUNT(uid) AS c FROM player WHERE uid = $uid AND api_key = '$key';";
         if (1 != $db->query($s)->fetchArray(SQLITE3_ASSOC)["c"]){
         if (1 != $db->query($s)->fetchArray(SQLITE3_ASSOC)["c"]){
             http_response_code(401);
             http_response_code(401);

+ 98 - 0
application/API/v3/API_Controller.php

@@ -0,0 +1,98 @@
+<?php
+
+    /**
+     * v3 API Controller file.
+     *
+     * Provides a class to handle all posible API requests.
+     *
+     * @category Constroller
+     */
+
+    /**
+     * v3 API controller.
+     *
+     * Handles every API request.
+     *
+     * @category Controller
+     */
+    class API_Controller {
+
+        /**
+         * Constructor.
+         *
+         * Handles every request, creating the required models and selecting the
+         * view.
+         *
+         * @param mixed[] $query GET parameters of the request.
+         */
+        public function __construct($query){
+
+            // Remove host
+            array_shift($query);
+            // Remove /API/
+            array_shift($query);
+            // Remove /v3/
+            array_shift($query);
+            // API call: Use API controller
+            $method = $_SERVER["REQUEST_METHOD"];
+            if (!in_array($method, ["GET", "POST", "PUT", "DELETE"])){
+                $method = "GET";
+            }
+            if (count($query) == 0 || $query[0] == null || $query[0] == ""){
+                require_once(__DIR__ . "/main.php");
+            }
+            else{
+                $command = strtolower($query[0]);
+                // Remove /<command>/
+                array_shift($query);
+                switch ($command){
+                    case "help":
+                        require_once(__DIR__ . "/help/index.php");
+                        break;
+                    case "profile":
+                    case "run":
+                    case "logbook":
+                    case "collection":
+                    case "run":
+                    case "units":
+                        if (file_exists(__DIR__ . "/$command/$method.php")){
+                            require_once(__DIR__ . "/$command/$method.php");
+                        }
+                        else{
+                            header("HTTP/1.1 404");
+                        }
+                        break;
+                    /*case "update_profile":
+                        require_once(__DIR__ . "/update_profile.php");
+                        break;
+                    case "update_logbook":
+                        require_once(__DIR__ . "/update_logbook.php");
+                        break;
+                    case "update_collection":
+                        require_once(__DIR__ . "/update_collection.php");
+                        break;
+                    case "log_run_dungeon":
+                        require_once(__DIR__ . "/log_run_dungeon.php");
+                        break;
+                    case "log_run_dh":
+                        require_once(__DIR__ . "/log_run_dh.php");
+                        break;
+                    case "log_run_scenario":
+                        require_once(__DIR__ . "/log_run_scenario.php");
+                        break;
+                    case "log_run_toa":
+                        require_once(__DIR__ . "/log_run_toa.php");
+                        break;
+                    case "log_run_rift_dungeon":
+                        require_once(__DIR__ . "/log_run_rift_dungeon.php");
+                        break;
+                    case "units":
+                        require_once(__DIR__ . "/units.php");
+                        break;*/
+                    default:
+                        header("HTTP/1.1 404");
+                }
+            }
+        }
+    }
+?>

+ 425 - 0
application/API/v3/help/api.php

@@ -0,0 +1,425 @@
+<?php
+
+    /**
+     * @var mixed[] $API API help structure.
+     */
+    $API = [
+        "version" => 2,
+        "category" => [
+            [ // BEGIN CATEGORY Units
+                "name" => "Units",
+                "command" => [
+                    [ // BEGIN COMMAND Units
+                        "name" => "units",
+                        "method" => [
+                            [
+                                "id" => "GET",
+                                "url" => "/units/",
+                                "description" => "Retrieves units.",
+                                "parameters" => [
+                                    [
+                                        "key" => "page",
+                                        "via" => "request",
+                                        "type" => "int",
+                                        "description" => "Page to fetch. Deaults to 1.",
+                                        "optional" => true
+                                    ],
+                                    [
+                                        "key" => "per_page",
+                                        "via" => "request",
+                                        "type" => "int",
+                                        "description" => "number of results per page. Defaults to 30, maximum is 100.",
+                                        "optional" => true
+                                    ],
+                                    [
+                                        "key" => "name",
+                                        "via" => "request",
+                                        "type" => "string",
+                                        "description" => "Filter units with this in their name. Case insensitive.",
+                                        "optional" => true
+                                    ]
+                                ],
+                                "responses" => [
+                                    [
+                                        "status" => "200",
+                                        "message" => "Success.",
+                                        "description" => null,
+                                        "example" => null,
+                                    ],
+                                ]
+                            ],
+                            [
+                                "id" => "GET",
+                                "url" => "/units/{id}/",
+                                "description" => "Retrieves a unit info.",
+                                "parameters" => [
+                                    [
+                                        "key" => "{id}",
+                                        "via" => "query",
+                                        "type" => "string",
+                                        "description" => "Unit ID.",
+                                        "optional" => false
+                                    ],
+                                ],
+                                "responses" => [
+                                    [
+                                        "status" => "200",
+                                        "message" => "Success.",
+                                        "description" => null,
+                                        "example" => null,
+                                    ],
+                                    [
+                                        "status" => "404",
+                                        "message" => "Unit not found.",
+                                        "description" => "The requested unit does not exist.",
+                                        "example" => null
+                                    ]
+                                ]
+                            ],
+                        ],
+                    ] // END COMMAND profile
+                ]
+            ], // END CATEGORY Units
+            [ // BEGIN CATEGORY Profile
+                "name" => "Profile",
+                "command" => [
+                    [ // BEGIN COMMAND UploadProfile
+                        "name" => "profile",
+                        "method" => [
+                            [
+                                "id" => "GET",
+                                "url" => "/profile/{id}/",
+                                "description" => "Retrieves player profile.",
+                                "parameters" => [
+                                    [
+                                        "key" => "{id}",
+                                        "via" => "query",
+                                        "type" => "string",
+                                        "description" => "Player ID or name.",
+                                        "optional" => false
+                                    ],
+                                    [
+                                        "key" => "key",
+                                        "via" => "body",
+                                        "type" => "string",
+                                        "description" => "API key. Required for private profiles.",
+                                        "optional" => true
+                                    ]
+                                ],
+                                "responses" => [
+                                    [
+                                        "status" => "200",
+                                        "message" => "Success.",
+                                        "description" => null,
+                                        "example" => json_encode('{"username":"IValentin","level":50,"public":"1"}', JSON_PRETTY_PRINT),
+                                    ],
+                                    [
+                                        "status" => "403",
+                                        "message" => "A list of profiles cant be retrieved. Please specify a profile ID or player name.",
+                                        "description" => "No player ID or name has been supplied. A full list of profiles is not available.",
+                                        "example" => null
+                                    ],
+                                    [
+                                        "status" => "403",
+                                        "message" => "The profile is not public.",
+                                        "description" => "The requestd player profile is private, and the API key has not been sent or it's invalid.",
+                                        "example" => null
+                                    ],
+                                    [
+                                        "status" => "404",
+                                        "message" => "Player not found.",
+                                        "description" => "The requestd player is not registered in SWDB.",
+                                        "example" => null
+                                    ]
+                                ]
+                            ],
+                            [
+                                "id" => "POST",
+                                "url" => "/profile/{id}/",
+                                "description" => "Creates a new player profile.",
+                                "parameters" => [
+                                    [
+                                        "key" => "{id}",
+                                        "via" => "query",
+                                        "type" => "string",
+                                        "description" => "Player ID.",
+                                        "optional" => false
+                                    ],
+                                    [
+                                        "key" => "email",
+                                        "via" => "body",
+                                        "type" => "string",
+                                        "description" => "User email. Must be a valid address.",
+                                        "optional" => false
+                                    ],
+                                    [
+                                        "key" => "password",
+                                        "via" => "body",
+                                        "type" => "string",
+                                        "description" => "New user password.",
+                                        "optional" => false
+                                    ],
+                                    [
+                                        "key" => "name",
+                                        "via" => "body",
+                                        "type" => "string",
+                                        "description" => "New username. If not supplied, it will default to 'player_[id]'. Will be overriden on the next PUT request.",
+                                        "optional" => true
+                                    ],
+                                    [
+                                        "key" => "public",
+                                        "via" => "body",
+                                        "type" => "int",
+                                        "description" => "1 to make the profile public, 0 to keep it private. Default to 0.",
+                                        "optional" => true
+                                    ],
+                                ],
+                                "responses" => [
+                                    [
+                                        "status" => "201",
+                                        "message" => "Created.",
+                                        "description" => null,
+                                        "example" => json_encode('{"username":"IValentin","email":example@example.com,"api_key":"0123456789012345","public":"0"}', JSON_PRETTY_PRINT),
+                                    ],
+                                    [
+                                        "status" => "400",
+                                        "message" => "User ID not received.",
+                                        "description" => "The ID of the player to create is not in the query.",
+                                        "example" => null
+                                    ],
+                                    [
+                                        "status" => "400",
+                                        "message" => "User email not received.",
+                                        "description" => "The email of the player to create has not ben passed in the request.",
+                                        "example" => null
+                                    ],
+                                    [
+                                        "status" => "400",
+                                        "message" => "Invalid email.",
+                                        "description" => "The 'mail' parameter must be a valid email address.",
+                                        "example" => null
+                                    ],
+                                    [
+                                        "status" => "400",
+                                        "message" => "User password not received.",
+                                        "description" => "The password of the player to create has not ben passed in the request.",
+                                        "example" => null
+                                    ],
+                                    [
+                                        "status" => "400",
+                                        "message" => "Existing user.",
+                                        "description" => "A player with the same ID is already registered in SWDB.",
+                                        "example" => null
+                                    ]
+                                ]
+                            ],
+                            [
+                                "id" => "PUT",
+                                "url" => "/profile/{id}/",
+                                "description" => "Updates a player profile with data received from the game.",
+                                "parameters" => [
+                                    [
+                                        "key" => "{id}",
+                                        "via" => "query",
+                                        "type" => "string",
+                                        "description" => "Player ID.",
+                                        "optional" => false
+                                    ],
+                                    [
+                                        "key" => "key",
+                                        "via" => "body",
+                                        "type" => "string",
+                                        "description" => "API key.",
+                                        "optional" => false
+                                    ],
+                                    [
+                                        "key" => "response",
+                                        "via" => "body",
+                                        "type" => "string",
+                                        "description" => "JSON received from game server on HubUserLogin command.",
+                                        "optional" => false
+                                    ]
+                                ],
+                                "responses" => [
+                                    [
+                                        "status" => "204",
+                                        "message" => "Profile imported.",
+                                        "description" => null,
+                                        "example" => null,
+                                    ],
+                                    [
+                                        "status" => "400",
+                                        "message" => "API key not received.",
+                                        "description" => "No API key was suplied in the request.",
+                                        "example" => null
+                                    ],
+                                    [
+                                        "status" => "400",
+                                        "message" => "No data received.",
+                                        "description" => "Game JSON response not received from request",
+                                        "example" => null
+                                    ],
+                                    [
+                                        "status" => "400",
+                                        "message" => "Data is no valid JSON.",
+                                        "description" => "The parameter 'response' contains information, but it's not valid JSON data.",
+                                        "example" => null
+                                    ],
+                                    [
+                                        "status" => "401",
+                                        "message" => "Invalid credentials",
+                                        "description" => "The API key is not valid for the profile being updated.",
+                                        "example" => null
+                                    ]
+                                ]
+                            ],
+                            [
+                                "id" => "DELETE",
+                                "url" => "/profile/{id}/",
+                                "description" => "Deletes a player profile.",
+                                "parameters" => [
+                                    [
+                                        "key" => "{id}",
+                                        "via" => "query",
+                                        "type" => "string",
+                                        "description" => "Player ID.",
+                                        "optional" => false
+                                    ],
+                                    [
+                                        "key" => "key",
+                                        "via" => "body",
+                                        "type" => "string",
+                                        "description" => "API key.",
+                                        "optional" => false
+                                    ]
+                                ],
+                                "responses" => [
+                                    [
+                                        "status" => "204",
+                                        "message" => "Profile deleted.",
+                                        "description" => null,
+                                        "example" => null,
+                                    ],
+                                    [
+                                        "status" => "400",
+                                        "message" => "User ID not received.",
+                                        "description" => "The ID of the player to create is not in the query.",
+                                        "example" => null
+                                    ],
+                                    [
+                                        "status" => "400",
+                                        "message" => "API key not received.",
+                                        "description" => "No API key was suplied in the request.",
+                                        "example" => null
+                                    ],
+                                    [
+                                        "status" => "401",
+                                        "message" => "Invalid credentials",
+                                        "description" => "The API key is not valid for the profile being updated.",
+                                        "example" => null
+                                    ]
+                                ]
+                            ],
+                        ],
+                    ] // END COMMAND profile
+                ]
+            ], // END CATEGORY Profile
+            [ // BEGIN CATEGORY Run
+                "name" => "Run",
+                "command" => [
+                    [ // BEGIN COMMAND run
+                        "name" => "run",
+                        "method" => [
+                            [
+                                "id" => "POST",
+                                "url" => "/run/",
+                                "description" => "Logs a game run using JSON files intercepted from the game.",
+                                "parameters" => [
+                                    [
+                                        "key" => "key",
+                                        "via" => "body",
+                                        "type" => "string",
+                                        "description" => "API key.",
+                                        "optional" => false
+                                    ],
+                                    [
+                                        "key" => "result_response",
+                                        "via" => "body",
+                                        "type" => "string",
+                                        "description" => "JSON received from game server on run result.",
+                                        "optional" => false
+                                    ],
+                                    [
+                                        "key" => "result_request",
+                                        "via" => "body",
+                                        "type" => "string",
+                                        "description" => "JSON sent to game server on run result. Required for commands: BattleDungeonResult_V2, BattleDimensionHoleDungeonResult_v2",
+                                        "optional" => true
+                                    ],
+                                    [
+                                        "key" => "start_response",
+                                        "via" => "body",
+                                        "type" => "string",
+                                        "description" => "JSON received from game server on run start. Required for commands: BattleRiftOfWorldsRaidResult, BattleScenarioResult",
+                                        "optional" => true
+                                    ],
+                                    [
+                                        "key" => "start_request",
+                                        "via" => "body",
+                                        "type" => "string",
+                                        "description" => "JSON sent to game server on run start. Required for commands: ",
+                                        "optional" => true
+                                    ],
+                                ],
+                                "responses" => [
+                                    [
+                                        "status" => "201",
+                                        "message" => "Created.",
+                                        "description" => null,
+                                        "example" => null,
+                                    ],
+                                    [
+                                        "status" => "400",
+                                        "message" => "API key not received.",
+                                        "description" => "No API key was suplied in the request.",
+                                        "example" => null
+                                    ],
+                                    [
+                                        "status" => "400",
+                                        "message" => "No result response data received.",
+                                        "description" => "JSON received from game server on run result wast receiven on the request.",
+                                        "example" => null
+                                    ],
+                                    [
+                                        "status" => "400",
+                                        "message" => "Result response data is no valid JSON.",
+                                        "description" => "The parameter 'result_response' contains information, but it's not valid JSON data.",
+                                        "example" => null
+                                    ],
+                                    [
+                                        "status" => "401",
+                                        "message" => "Invalid credentials",
+                                        "description" => "The API key is not valid for the profile being updated.",
+                                        "example" => null
+                                    ],
+                                    [
+                                        "status" => "405",
+                                        "message" => "Command not implemented.",
+                                        "description" => "The command referenced in the JSON file is not implemented.",
+                                        "example" => null
+                                    ],
+                                    [
+                                        "status" => "409",
+                                        "message" => "Run already in database.",
+                                        "description" => "The run is already in the database for the user.",
+                                        "example" => null
+                                    ]
+                                ]
+                            ],
+                        ],
+                    ] // END COMMAND Run
+                ]
+            ], // END CATEGORY Run
+        ],
+    ];
+?>

+ 488 - 0
application/API/v3/help/index.php

@@ -0,0 +1,488 @@
+<?php
+    /**
+     * API Help view.
+     *
+     * Shows API documentation.
+     *
+     * @category View
+     * @var mixed[] $API API help structure.
+     */
+?>
+<?php
+    include __DIR__ . "/api.php";
+?>
+<!DOCTYPE html>
+<html lang='en'>
+    <head>
+        <meta content='text/html; charset=utf-8' http-equiv='content-type'/>
+        <meta name='viewport' content='width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1'/>
+        <title>SWDB APIv3</title>
+        <link rel='shortcut icon' href='<?=URL::IMG["LOGO"]?>sw.png'/>
+        <!-- CSS -->
+        <link rel='stylesheet' type='text/css' href='<?=URL::CSS?>ui.css'/>
+        <style>
+
+            aside hr{
+                height: 0em;
+                padding: 0;
+                margin: 0 1em;
+                border: 0.01em solid #db490054;
+                border-radius: 1em;
+            }
+
+            aside h3 {
+                margin: 0.4em 0 0.2em 1em;
+                border-left: 0.5em solid #db490054;
+                border-radius: 0.2em;
+                padding-left: 0.3em;
+                background-color: #00000000;
+                transition: all .3s ease-in-out;
+            }
+
+            aside h3:hover{
+                background-color: #db490054;
+            }
+
+            aside h3 a{
+                color: #cccccc
+            }
+
+            aside h3:hover a{
+                color: #ffffff
+            }
+
+            aside ul {
+                margin: 0.2em 0;
+                list-style: none;
+            }
+
+            aside ul li{
+                border-left: 0.5em solid #db490054;
+                border-radius: 0.2em;
+                padding-left: 0.3em;
+                margin-bottom: 0.2em;
+                background-color: #00000000;
+                transition: all .3s ease-in-out;
+            }
+
+            aside ul li:hover{
+                background-color: #db490054;
+            }
+
+            aside ul li a{
+                color: #cccccc
+            }
+
+            aside ul li:hover a{
+                color: #ffffff
+            }
+
+            aside div#copyright{
+                text-align: center;
+                font-size: 70%;
+                position: absolute;
+                bottom: 1em;
+            }
+
+            section.category article{
+                margin: 1.5em;
+                padding-left: 1em;
+                padding-right: 1em;
+                text-align: left;
+            }
+
+            section.category article h3{
+                vertical-align: bottom;
+            }
+
+            section.category article h3 span.description{
+                font-style: italic;
+                font-size: 90%;
+            }
+
+            section.category article:not(:last-child){
+                padding-bottom: 1em;
+                margin-bottom: 1em;
+                border-bottom: 0.1em solid #ffffff66;
+            }
+
+            section.category article div.command span{
+                display: inline-block;
+                border-radius: 0.6em;
+                padding: 0.3em 0.5em;
+                border-width: 0.15em;
+                border-style: solid;
+                color: #ffffff;
+                font-family: monospace, monospace;
+                font-weight: bold;
+            }
+
+            section.category article div.command span.url{
+                background-color: #292b36;
+                border-color: #4b4d57;
+            }
+
+            section.category article div.command span.type{
+                text-transform: uppercase;
+            }
+
+            section.category article div.command span.type_GET {
+                background-color: #008000;
+                border-color: #22a222;
+            }
+
+            section.category article div.command span.type_PUT {
+                background-color: #e5c500;
+                border-color: #f7e722;
+            }
+
+            section.category article div.command span.type_POST {
+                background-color: #4070ec;
+                border-color: #6292fe;
+            }
+
+            section.category article div.command span.type_DELETE {
+                background-color: #ed0039;
+                border-color: #ff225b;
+            }
+
+            section.category article table{
+                border-collapse: collapse;
+                width: 80%;
+                border-radius: 0.5em;
+                margin: 0.5em auto 1em auto;
+            }
+
+            section.category article table th {
+                background-color: #331100;
+                text-align: left;
+                font-weight: bold;
+                padding: 0.5em 1em;
+                border: 0.1px solid #e0e0e0;
+            }
+
+            section.category article table td {
+                background-color: #352413;
+                vertical-align: top;
+                padding: 0.2em 0.4em;
+                border: #e0e0e0 1px solid;
+            }
+
+            section.category article table td.name {
+                font-family: monospace, monospace;
+                font-weight: bold;
+            }
+
+            section.category article table td.name span.location{
+                padding-left: 1em;
+                font-size: 80%;
+                font-style: italic;
+                color: #ffffff77;
+            }
+
+            section.category article table td.type {
+                font-family: monospace, monospace;
+                font-weight: bold;
+            }
+
+            section.category article table td.status span{
+                display: inline-block;
+                border-radius: 0.6em;
+                padding: 0.3em 0.5em;
+                border-width: 0.15em;
+                border-style: solid;
+                color: #ffffff;
+                font-family: monospace, monospace;
+                font-weight: bold;
+            }
+
+            section.category article table td.status_1 span{
+                border-color: #999999;
+                background-color: #777777;
+            }
+            section.category article table td.status_2 span{
+                background-color: #008000;
+                border-color: #22a222;
+            }
+            section.category article table td.status_3 span{
+                background-color: #4070ec;
+                border-color: #6292fe;
+            }
+            section.category article table td.status_4 span{
+                background-color: #e5c500;
+                border-color: #f7e722;
+            }
+            section.category article table td.status_5 span{
+                background-color: #ed0039;
+                border-color: #ff225b;
+            }
+
+            section.category article table td.message{
+                font-family: monospace, monospace;
+            }
+
+            section.category article table td.description span.optional {
+                font-size: 90%;
+                color: #bbbbbb;
+                font-style: italic;
+            }
+
+            section#example{
+                position: fixed;
+                display: none;
+                top: 15%;
+                left: 20%;
+                width: 60%;
+                max-width: 90em;
+                height: 70%;
+                max-height: 30em;
+                text-align: right;
+            }
+
+            section#example article{
+                text-align: right;
+            }
+
+            section#example article pre#example_content{
+                text-align: left;
+                background-color: #292b36;
+                border: 0.3em solid #4b4d57;
+                border-radius: 0.8em;
+                padding: 1em;
+                max-height: 20em;
+                overflow: scroll;
+            }
+
+        </style>
+        <!-- Javascript -->
+        <script>
+            function showExample(command, status, example){
+                document.getElementById('example_title').innerHTML = command + " HTTP status " + status + " response example";
+                document.getElementById('example_content').innerHTML = JSON.stringify(JSON.parse(example), null, 4);
+                document.getElementById('example').style.display = 'block';
+            }
+            function closeExample(command, status, example){
+                document.getElementById('example').style.display = 'none';
+            }
+        </script>
+        <!-- Meta tags -->
+        <link rel='canonical' href='<?=URL::BASE?>API/v3/help/'/>
+        <link rel='author' href='SWDB'/>
+        <link rel='publisher' href='SWDB'/>
+        <meta name='description' content='SWDB API v3 Documentation'/>
+        <meta property='og:title' content='SWDB APIv3'/>
+        <meta property='og:url' content='<?=URL::BASE?>API/v3/help/'/>
+        <meta property='og:description' content='SWDB API v3 Documentation'/>
+        <meta property='og:image' content='<?=URL::IMG["LOGO"]?>sw.png'/>
+        <meta property='og:site_name' content='SWDB'/>
+        <meta property='og:type' content='website'/>
+        <meta property='og:locale' content='en'/>
+        <meta name='twitter:card' content='summary'/>
+        <meta name='twitter:title' content='SWDB APIv3'/>
+        <meta name='twitter:description' content='SWDB API v3 Documentation'/>
+        <meta name='twitter:image' content='<?=URL::IMG["LOGO"]?>sw.png'/>
+        <meta name='twitter:url' content='<?=URL::BASE?>API/v3/help/'/>
+        <meta name='robots' content='index follow'/>
+    </head>
+    <body>
+        <header>
+            <div id='logo'>
+                <img id='logo_img' src='<?=URL::IMG["LOGO"]?>sw.png' alt=''/>
+                <h1 id='logo_text'>
+                    <span class='large'>D</span>
+                    <span class='small'>ata</span>
+                    <span class='large'>B</span>
+                    <span class='small'>ase</span>
+                </h1>
+            </div>
+        </header>
+        <aside>
+            <h2>
+                API v3 endopoints:
+            </h2>
+<?php
+            foreach ($API["category"] as $category){
+?>
+                <h3>
+                    <a href='#category_<?=$category["name"]?>'>
+                        <?=$category["name"]?>
+                    </a>
+                </h3>
+                <ul>
+<?php
+                    foreach ($category["command"] as $command){
+                        foreach ($command["method"] as $method){
+?>
+                            <li>
+                                <a href='#command_<?=$command["name"]?>-<?=$method["id"]?>-<?=htmlspecialchars($method["url"])?>' title='<?=$command["description"]?>'>
+                                    <?=$method["id"]?> <?=htmlspecialchars($method["url"])?>
+                                </a>
+                            </li>
+<?php
+                        }
+                    }
+?>
+                </ul>
+                <hr/>
+<?php
+            }
+?>
+        </aside>
+        <main>
+<?php
+            foreach ($API["category"] as $category){
+                foreach ($category["command"] as $command){
+?>
+                    <section id='category_<?=$category["name"]?>' class='category content'>
+                    <h2>
+                        <?=$category["name"]?>
+                    </h2>
+                        <article id='command_<?=$command["name"]?>'>
+                            <h3>
+                                <?=$command["name"]?>
+                            </h3>
+<?php
+                            foreach ($command["method"] as $method){
+?>
+                                <div class='command' id='command_<?=$command["name"]?>-<?=$method["id"]?>-<?=htmlspecialchars($method["url"])?>'>
+                                    <span class='type type_<?=$method["id"]?>'>
+                                        <?=$method["id"]?>
+                                    </span>
+                                    <span class='url'>
+                                        <?=htmlspecialchars($method["url"])?>
+                                    </span>
+                                    <span class='description'>
+                                        <?=$method["description"]?>
+                                    </span>
+                                </div>
+                                <table class='params'>
+                                    <thead>
+                                        <tr>
+                                            <th class='header' colspan='3'>
+                                                Parameters
+                                            </th>
+                                        </tr>
+                                        <tr>
+                                            <th class='name'>
+                                                Parameter
+                                            </th>
+                                            <th class='type'>
+                                                Type
+                                            </th>
+                                            <th class='description'>
+                                                Description
+                                            </th>
+                                        </tr>
+                                    </thead>
+                                    <tbody>
+    <?php
+                                        foreach ($method["parameters"] as $param){
+    ?>
+                                            <tr>
+                                                <td class='name'>
+                                                    <?=$param["key"]?>
+                                                    <span class='location'>
+                                                        (<?=$param["via"]?>)
+                                                    </span>
+                                                </td>
+                                                <td class='type'>
+                                                    <?=$param["type"]?>
+                                                </td>
+                                                <td class='description'>
+                                                    <?=($param["optional"] ? "<span class='optional'>[Optional] </span>" : "")?>
+                                                    <?=$param["description"]?>
+                                                </td>
+                                            </tr>
+    <?php
+                                        }
+    ?>
+                                    </tbody>
+                                </table>
+                                <table class='responses'>
+                                    <thead>
+                                        <tr>
+                                            <th class='header' colspan='3'>
+                                                Responses
+                                            </th>
+                                        </tr>
+                                        <tr>
+                                            <th class='status'>
+                                                Status
+                                            </th>
+                                            <th class='status'>
+                                                Message
+                                            </th>
+                                            <th class='description'>
+                                                Description
+                                            </th>
+                                        </tr>
+                                    </thead>
+                                    <tbody>
+    <?php
+                                        foreach ($method["responses"] as $response){
+    ?>
+                                            <tr>
+                                                <td class='status status_<?=substr($response["status"], 0, 1)?>'>
+                                                    <span>
+                                                        <?=$response["status"]?>
+                                                    </span>
+                                                </td>
+                                                <td class='message'>
+                                                    <?=$response["message"]?>
+                                                </td>
+                                                <td class='description'>
+                                                    <?=$response["description"]?>
+    <?php
+                                                    if ($response["example"] != null){
+    ?>
+                                                        <span class='fake_a' onclick="showExample('<?=$command["name"]?>', <?=$response["status"]?>, '<?=htmlspecialchars(json_decode($response["example"]), ENT_QUOTES)?>')">
+                                                            View example.
+                                                        </span>
+    <?php
+                                                    }
+    ?>
+                                                </td>
+                                            </tr>
+    <?php
+                                        }
+    ?>
+                                    </tbody>
+                                </table>
+<?php
+                            }
+?>
+                        </article>
+                    </section>
+<?php
+                }
+?>
+                <section id='example' class='content'>
+                    <h2 id='example_title'>
+                    </h2>
+                    <article>
+                        <pre id='example_content'>
+                        </pre>
+                        <input type='button' value='Close' onClick='closeExample();'>
+                    </article>
+                </section>
+<?php
+            }
+?>
+        </main>
+        <footer>
+            <table id='footer_table'>
+                <tr>
+                    <td id='footer_left'>
+                        Version <?=APP::VERSION?>. Developed by <a href='https://inigovalentin.com'>I&ntilde;igo Valentin</a>.
+                        <br/>
+                        <br/>
+                        Source code available on <a href='https://github.com'>Github</a> under the GPLv3.
+                    </td>
+                    <td id='footer_right'>
+                        Neither I nor this tool are affiliated with or endorsed by <a href='http://com2us.com/'>Com2uS</a> in any way. The Summoners >
+                    </td>
+                </tr>
+            </table>
+        </footer>
+    </body>
+</html>

+ 17 - 0
application/API/v3/main.php

@@ -0,0 +1,17 @@
+<?php
+    header("Content-Type:application/json");
+    $links = [
+        "Archetypes" => URL::BASE . "/API/v2/archetypes",
+        "Area types" => URL::BASE . "/API/v2/area_types",
+        "Areas types" => URL::BASE . "/API/v2/areas",
+        "Buildings" => URL::BASE . "/API/v2/buildings",
+        "Decorations" => URL::BASE . "/API/v2/decorations",
+        "Areas types" => URL::BASE . "/API/v2/areas",
+        "Units" => URL::BASE . "/API/v2/units",
+        "Skills" => URL::BASE . "/API/v2/skills",
+        "Skill effects" => URL::BASE . "/API/v2/skill_efects",
+    ];
+    header("HTTP/1.1 200");
+    $json_response = json_encode($links);
+    echo $json_response;
+?>

+ 77 - 0
application/API/v3/profile/DELETE.php

@@ -0,0 +1,77 @@
+<?php
+    /**
+     * Profile deleter script.
+     *
+     * Exposes an API to update an existing profile.
+     *
+     * It also saves the data to a JSON file in the data directory.
+     *
+     * Mandatory query parameters are:
+     *  - id: Player ID.
+     *
+     * Mandatory DELETE parameters are:
+     *  - key: User API key.
+     *
+     * @category API
+     */
+
+    global $db;
+
+    try{
+
+        header("Content-type: application/json; charset=utf-8");
+
+        // Get put data
+        $_DELETE = [];
+        parse_str(file_get_contents("php://input"), $_DELETE);
+
+        // Get profile ID
+        /** @var mixed $query Request parameters, from API_CONTROLLER*/
+        if (count($query) > 0){
+            $id = $query[0];
+        }
+        else{
+            // ID is mandatory
+            header("HTTP/1.1 400 User ID not received.");
+            syslog(LOG_INFO, "[APIv3] HTTP/1.1 400 User ID not received.");
+            return 400;
+        }
+
+        // Check API key.
+        $api_key = $_DELETE["key"];
+        if ($api_key == null || $api_key == false){
+            header("HTTP/1.1 400 API key not received.");
+            syslog(LOG_INFO, "[APIv3] HTTP/1.1 400 API key not received.");
+            return 400;
+        }
+
+        // Authenticate
+        $statement = $db->prepare("SELECT COUNT(uid) AS c FROM player WHERE uid = :uid AND api_key = :api_key;");
+        $statement->bindValue(":uid", $id, SQLITE3_INTEGER);
+        $statement->bindValue(":api_key", $api_key, SQLITE3_TEXT);
+        if (1 != $statement->execute()->fetchArray(SQLITE3_ASSOC)["c"]){
+            header("HTTP/1.1 401 Invalid credentials.");
+            syslog(LOG_INFO, "[APIv3] HTTP/1.1 401 Invalid credentials.");
+            return 401;
+        }
+
+        $statement = $db->prepare("
+          DELETE FROM player
+          WHERE
+            uid = :uid AND
+            api_key, = :api_key;
+        ");
+        $statement->bindValue(":uid", $id, SQLITE3_INTEGER);
+        $statement->bindValue(":api_key", $api_key, SQLITE3_TEXT);
+        $statement->execute();
+
+        header("HTTP/1.1 204 Profile deleted.");
+        syslog(LOG_INFO, "[APIv3] HTTP/1.1 204 Profile deleted.");
+        return 204;
+    }
+    catch(Exception $e) {
+        header("HTTP/1.1 500 Unexpeced error: " . $e->getMessage());
+        syslog(LOG_ERR, "[APIv3] HTTP/1.1 500 Unexpected error: " . $e->getMessage());
+        return 500;
+    }
+?>

+ 67 - 0
application/API/v3/profile/GET.php

@@ -0,0 +1,67 @@
+<?php
+    /**
+     * Profile getter script.
+     *
+     * Exposes an API to rerieve a user profile.
+     *
+     * A lst of profiles can't be retrieved.
+     *
+     * Mandatory query parameters are:
+     *  - id: Player ID.
+     *
+     * Optional GET parameters are.
+     *  - key: User API key to retrieve a private profile.
+     *
+     * @category API
+     */
+
+    global $db;
+
+    try{
+        header("Content-type: application/json; charset=utf-8");
+
+        // Get profile ID
+        /** @var mixed $query Request parameters, from API_CONTROLLER*/
+        if (count($query) > 1){
+            $id = $query[0];
+        }
+        else{
+            // Id is mandatory, a list can be retrieved
+            header("HTTP/1.1 403 A list of profiles cant be retrieved. Please specify a profile ID or player name.");
+            syslog(LOG_INFO, "[APIv3] HTTP/1.1 403 A list of profiles cant be retrieved. Please specify a profile ID or player name.");
+            return 403;
+        }
+
+        // Get player
+        $statement = $db->prepare("SELECT * FROM player WHERE uid = :uid OR upper(name) = upper(:uid);");
+        $statement->bindValue(":uid", $id, SQLITE3_INTEGER);
+        $r = $statement->execute()->fetchArray(SQLITE3_ASSOC);
+        if ($r == null){
+            // No player found
+            header("HTTP/1.1 404 Player not found.");
+            syslog(LOG_INFO, "[APIv3] HTTP/1.1 404 Player not found.");
+            return 403;
+        }
+        if ($r["public"] != 1 && $r["key"] != filter_input(INPUT_GET, "key")){
+            header("HTTP/1.1 403 The profile is not public.");
+            syslog(LOG_INFO, "[APIv3] HTTP/1.1 403 The profile is not public.");
+            return 403;
+        }
+
+        // Build array
+        $player = [
+            "username" => $r["name"],
+            "level" => $r["level"],
+            "public" => "1"
+        ];
+        echo(json_encode($player));
+        header("HTTP/1.1 200 Success.");
+        syslog(LOG_INFO, "[APIv3] HTTP/1.1 200 Success.");
+        return 200;
+    }
+    catch(Exception $e) {
+        header("HTTP/1.1 500 Unexpeced error: " . $e->getMessage());
+        syslog(LOG_ERR, "[APIv3] HTTP/1.1 500 Unexpected error: " . $e->getMessage());
+        return 500;
+    }
+?>

+ 211 - 0
application/API/v3/profile/POST.php

@@ -0,0 +1,211 @@
+<?php
+    /**
+     * Profile creator script.
+     *
+     * Exposes an API to create a new profile.
+     *
+     * Mandatory query parameters are:
+     *  - id: Player ID.
+     *
+     * Mandatory POST parameters are:
+     *  - email: User email.
+     *  - password: User password.
+     *
+     * Optional POST parameters are:
+     *  - name: User name.
+     *  - public: 1 To make the profile public, 0 for private.
+     *
+     * @category API
+     */
+
+    global $db;
+
+    try{
+
+        header("Content-type: application/json; charset=utf-8");
+
+        // Get put data
+        parse_str(file_get_contents("php://input"), $_POST);
+
+        // Get profile ID
+        /** @var mixed $query Request parameters, from API_CONTROLLER*/
+        if (count($query) > 0){
+            $id = $query[0];
+        }
+        else{
+            // ID is mandatory
+            header("HTTP/1.1 400 User ID not received.");
+            syslog(LOG_INFO, "[APIv3] HTTP/1.1 400 User ID not received.");
+            return 400;
+        }
+
+        // Check user mail.
+        $mail = $_POST["email"];
+        if ($mail == null || $mail == false){
+            header("HTTP/1.1 400 User email not received.");
+            syslog(LOG_INFO, "[APIv3] HTTP/1.1 400 User email not received.");
+            return 400;
+        }
+        if (!filter_var($mail, FILTER_VALIDATE_EMAIL)) {
+            header("HTTP/1.1 400 Invalid email.");
+            syslog(LOG_INFO, "[APIv3] HTTP/1.1 400 Invalid email.");
+            return 400;
+        }
+        // Check user password.
+        $password = $_POST["password"];
+        if ($password == null || $password == false){
+            header("HTTP/1.1 400 User password not received.");
+            syslog(LOG_INFO, "[APIv3] HTTP/1.1 400 User password not received.");
+            return 400;
+        }
+        // Check user name.
+        $name = $_POST["name"];
+        if ($name == null || $name == false){
+            $name = "player_" . $id;
+        }
+        // Check user name.
+        $public = intval($_POST["public"]);
+        if ($public != 1){
+            $public = 0;
+        }
+
+        // Check if player exists
+        $statement = $db->prepare("SELECT COUNT(uid) AS c FROM player WHERE uid = :uid;");
+        $statement->bindValue(":uid", $id, SQLITE3_INTEGER);
+        if (1 != $statement->execute()->fetchArray(SQLITE3_ASSOC)["c"]){
+            header("HTTP/1.1 400 Existing user.");
+            syslog(LOG_INFO, "[APIv3] HTTP/1.1 400 Existing user.");
+            return 400;
+        }
+
+        // Prepare inputs
+        $password = hash("sha256", $password);
+        $characters = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+        $charactersLength = 16;
+        $api_key = "";
+        for ($i = 0; $i < $charactersLength; $i++) {
+            $api_key .= $characters[rand(0, $charactersLength - 1)];
+        }
+
+        // Insert
+        $statement = $db->prepare("
+          INSERT INTO player (
+            uid,
+            name,
+            mail,
+            password,
+            api_key,
+            mana,
+            crystal,
+            country,
+            lang,
+            level,
+            experience,
+            energy,
+            energy_max,
+            energy_per_min,
+            arena_energy,
+            arena_energy_max,
+            rep,
+            social_point,
+            honor_point,
+            guild_point,
+            darkportal_energy,
+            darkportal_energy_max,
+            dimension_energy,
+            dimension_energy_max,
+            costume_point,
+            costume_point_max,
+            honor_medal,
+            honor_mark,
+            event_coin,
+            storage_slots,
+            island,
+            public
+          ) VALUES (
+            :uid,
+            :name,
+            :mail,
+            :password,
+            :api_key,
+            :mana,
+            :crystal,
+            :country,
+            :lang,
+            :level,
+            :experience,
+            :energy,
+            :energy_max,
+            :energy_per_min,
+            :arena_energy,
+            :arena_energy_max,
+            :rep,
+            :social_point,
+            :honor_point,
+            :guild_point,
+            :darkportal_energy,
+            :darkportal_energy_max,
+            :dimension_energy,
+            :dimension_energy_max,
+            :costume_point,
+            :costume_point_max,
+            :honor_medal,
+            :honor_mark,
+            :event_coin,
+            :storage_slots,
+            :island,
+            :public
+          );
+        ");
+        $statement->bindValue(":uid", $id, SQLITE3_INTEGER);
+        $statement->bindValue(":name", $name, SQLITE3_TEXT);
+        $statement->bindValue(":mail", $mail, SQLITE3_TEXT);
+        $statement->bindValue(":password", $password, SQLITE3_TEXT);
+        $statement->bindValue(":api_key", $api_key, SQLITE3_TEXT);
+        $statement->bindValue(":mana", 0, SQLITE3_INTEGER);
+        $statement->bindValue(":crystal", 0, SQLITE3_INTEGER);
+        $statement->bindValue(":country", null, SQLITE3_TEXT);
+        $statement->bindValue(":lang", null, SQLITE3_TEXT);
+        $statement->bindValue(":level", 1, SQLITE3_INTEGER);
+        $statement->bindValue(":experience", 0, SQLITE3_INTEGER);
+        $statement->bindValue(":energy", 0, SQLITE3_INTEGER);
+        $statement->bindValue(":energy_max", 0, SQLITE3_INTEGER);
+        $statement->bindValue(":energy_per_min", 0, SQLITE3_INTEGER);
+        $statement->bindValue(":arena_energy", 0, SQLITE3_INTEGER);
+        $statement->bindValue(":arena_energy_max", 10, SQLITE3_INTEGER);
+        $statement->bindValue(":rep", null, SQLITE3_INTEGER);
+        $statement->bindValue(":social_point", 0, SQLITE3_INTEGER);
+        $statement->bindValue(":honor_point", 0, SQLITE3_INTEGER);
+        $statement->bindValue(":guild_point", 0, SQLITE3_INTEGER);
+        $statement->bindValue(":darkportal_energy", 0, SQLITE3_INTEGER);
+        $statement->bindValue(":darkportal_energy_max", 10, SQLITE3_INTEGER);
+        $statement->bindValue(":dimension_energy", 0, SQLITE3_INTEGER);
+        $statement->bindValue(":dimension_energy_max", 100, SQLITE3_INTEGER);
+        $statement->bindValue(":costume_point", 0, SQLITE3_INTEGER);
+        $statement->bindValue(":costume_point_max", 0, SQLITE3_INTEGER);
+        $statement->bindValue(":honor_medal", 0, SQLITE3_INTEGER);
+        $statement->bindValue(":honor_mark", 0, SQLITE3_INTEGER);
+        $statement->bindValue(":event_coin", 0, SQLITE3_INTEGER);
+        $statement->bindValue(":storage_slots", 0, SQLITE3_INTEGER);
+        $statement->bindValue(":island_upgrade", 0, SQLITE3_INTEGER);
+        $statement->bindValue(":public", $public, SQLITE3_INTEGER);
+        $statement->execute();
+
+        // Build array
+        $player = [
+            "username" => $name,
+            "email" => $mail,
+            "api_key" => $api_key,
+            "public" => "1"
+        ];
+        echo(json_encode($player));
+        header("HTTP/1.1 201 Created.");
+        syslog(LOG_INFO, "[APIv3] HTTP/1.1 201 Created.");
+        return 201;
+    }
+    catch(Exception $e) {
+        header("HTTP/1.1 500 Unexpeced error: " . $e->getMessage());
+        syslog(LOG_ERR, "[APIv3] HTTP/1.1 500 Unexpected error: " . $e->getMessage());
+        return 500;
+    }
+?>

+ 1659 - 0
application/API/v3/profile/PUT.php

@@ -0,0 +1,1659 @@
+<?php
+    /**
+     * Profile uploader script.
+     *
+     * Exposes an API to update an existing profile.
+     *
+     * It also saves the data to a JSON file in the data directory.
+     *
+     * Mandatory PUT parameters are:
+     *  - response: JSON received from game server on HubUserLogin command.
+     *  - key: User API key.
+     *
+     * @category API
+     */
+
+    global $db;
+
+    /**
+     * Calculates the currrent efficiency of a rune.
+     *
+     * @param mixed[] $rune JSON fragment of the rune.
+     * @return int Efficiency (0-100)
+     */
+    function calculate_efficiency($rune){
+        $efficiency = 0.0;
+        $level = $rune->{"upgrade_curr"};
+        $stars = $rune->{"class"};
+        // Ancient stars are + 10
+        if ($stars > 10){
+            $stars -= 10;
+        }
+        $list = null;
+        // Main stat
+        $main_stat = $rune->{"pri_eff"}[0];
+        switch ($main_stat){
+            case RUNE_STAT_ID::HP:
+                $list = RUNE_STAT_VALUES::HP;
+                break;
+            case RUNE_STAT_ID::HP_P:
+                $list = RUNE_STAT_VALUES::HP_P;
+                break;
+            case RUNE_STAT_ID::ATK:
+                $list = RUNE_STAT_VALUES::ATK;
+                break;
+            case RUNE_STAT_ID::ATK_P:
+                $list = RUNE_STAT_VALUES::ATK_P;
+                break;
+            case RUNE_STAT_ID::DEF:
+                $list = RUNE_STAT_VALUES::DEF;
+                break;
+            case RUNE_STAT_ID::DEF_P:
+                $list = RUNE_STAT_VALUES::DEF_P;
+                break;
+            case RUNE_STAT_ID::SPD:
+                $list = RUNE_STAT_VALUES::SPD;
+                break;
+            case RUNE_STAT_ID::CRR:
+                $list = RUNE_STAT_VALUES::CRR;
+                break;
+            case RUNE_STAT_ID::CRD:
+                $list = RUNE_STAT_VALUES::CRD;
+                break;
+            case RUNE_STAT_ID::ACC:
+                $list = RUNE_STAT_VALUES::ACC;
+                break;
+            case RUNE_STAT_ID::RES:
+                $list = RUNE_STAT_VALUES::RES;
+                break;
+        }
+        $efficiency += floatval($list[$stars][$level]) / floatval($list[6][15]);
+        // Innate stat
+        if ($rune->{"prefix_eff"}[0] > 0){
+            $innate_stat = $rune->{"pri_eff"}[0];
+            $innate_stat_value = $rune->{"pri_eff"}[1];
+            $efficiency += floatval($innate_stat_value) / (5 * floatval(RUNE_SUBSTAT_MAX_VALUES::SUBSTAT[$innate_stat][6]));
+        }
+        // Substats
+        for ($i = 0; $i <= 3; $i ++){
+            if (sizeof($rune->{"sec_eff"}) > $i){
+                $substat = $rune->{"sec_eff"}[$i][0];
+                $substat_value = $rune->{"sec_eff"}[$i][1];
+                $efficiency += floatval($substat_value) / (5 * floatval(RUNE_SUBSTAT_MAX_VALUES::SUBSTAT[$substat][6]));
+            }
+        }
+        $efficiency = $efficiency / 2.8 * 100;
+        if ($efficiency > 100){
+            $efficiency = 100;
+        }
+        return $efficiency;
+    }
+
+    /**
+     * Calculates the maximum efficiency of a rune.
+     *
+     * @param mixed[] $rune JSON fragment of the rune.
+     * @return int Maximum efficiency (0-100)
+     */
+    function calculate_maximum_efficiency($rune){
+        $efficiency = 0.0;
+        $stars = $rune->{"class"};
+        // Ancient stars are + 10
+        if ($stars > 10){
+            $stars -= 10;
+        }
+        $list = null;
+        // Main stat
+        $main_stat = $rune->{"pri_eff"}[0];
+        switch ($main_stat){
+            case RUNE_STAT_ID::HP:
+                $list = RUNE_STAT_VALUES::HP;
+                break;
+            case RUNE_STAT_ID::HP_P:
+                $list = RUNE_STAT_VALUES::HP_P;
+                break;
+            case RUNE_STAT_ID::ATK:
+                $list = RUNE_STAT_VALUES::ATK;
+                break;
+            case RUNE_STAT_ID::ATK_P:
+                $list = RUNE_STAT_VALUES::ATK_P;
+                break;
+            case RUNE_STAT_ID::DEF:
+                $list = RUNE_STAT_VALUES::DEF;
+                break;
+            case RUNE_STAT_ID::DEF_P:
+                $list = RUNE_STAT_VALUES::DEF_P;
+                break;
+            case RUNE_STAT_ID::SPD:
+                $list = RUNE_STAT_VALUES::SPD;
+                break;
+            case RUNE_STAT_ID::CRR:
+                $list = RUNE_STAT_VALUES::CRR;
+                break;
+            case RUNE_STAT_ID::CRD:
+                $list = RUNE_STAT_VALUES::CRD;
+                break;
+            case RUNE_STAT_ID::ACC:
+                $list = RUNE_STAT_VALUES::ACC;
+                break;
+            case RUNE_STAT_ID::RES:
+                $list = RUNE_STAT_VALUES::RES;
+                break;
+        }
+        $efficiency += floatval($list[$stars][15]) / floatval($list[6][15]);
+        // Innate stat
+        if ($rune->{"prefix_eff"}[0] > 0){
+            $innate_stat = $rune->{"pri_eff"}[0];
+            $innate_stat_value = $rune->{"pri_eff"}[1];
+            $efficiency += floatval($innate_stat_value) / (5 * floatval(RUNE_SUBSTAT_MAX_VALUES::SUBSTAT[$innate_stat][6]));
+        }
+        // Substats
+        for ($i = 0; $i <= 3; $i ++){
+            if (sizeof($rune->{"sec_eff"}) > $i){
+                $substat = $rune->{"sec_eff"}[$i][0];
+                $efficiency += floatval(RUNE_SUBSTAT_MAX_VALUES::SUBSTAT[$substat][$stars]) / (5 * floatval(RUNE_SUBSTAT_MAX_VALUES::SUBSTAT[$substat][6]));
+            }
+        }
+        $efficiency = $efficiency / 2.8 * 100;
+        if ($efficiency > 100){
+            $efficiency = 100;
+        }
+        return $efficiency;
+    }
+    
+    /**
+     * Parses an artifact and saves it to the database.
+     *
+     * @param string $uid Owner ID.
+     * @param JSON artifact JSON fragment of the artifact.
+     */
+    function parse_artifact($uid, $artifact){
+        global $db;
+        $statement = $db->prepare("
+          INSERT INTO artifact (
+            uid,
+            id,
+            assigned_to,
+            type,
+            attribute,
+            archetype,
+            level,
+            quality,
+            original_quality,
+            value,
+            efficiency,
+            max_efficiency,
+            main_stat,
+            main_stat_value,
+            effect_1,
+            effect_1_value,
+            effect_1_enchant,
+            effect_1_grind,
+            effect_2,
+            effect_2_value,
+            effect_2_enchant,
+            effect_2_grind,
+            effect_3,
+            effect_3_value,
+            effect_3_enchant,
+            effect_3_grind,
+            effect_4,
+            effect_4_value,
+            effect_4_enchant,
+            effect_4_grind,
+            locked
+          ) VALUES (
+            :uid,
+            :id,
+            :assigned_to,
+            :type,
+            :attribute,
+            :archetype,
+            :level,
+            :quality,
+            :original_quality,
+            :value,
+            :efficiency,
+            :max_efficiency,
+            :main_stat,
+            :main_stat_value,
+            :effect_1,
+            :effect_1_value,
+            :effect_1_enchant,
+            :effect_1_grind,
+            :effect_2,
+            :effect_2_value,
+            :effect_2_enchant,
+            :effect_2_grind,
+            :effect_3,
+            :effect_3_value,
+            :effect_3_enchant,
+            :effect_3_grind,
+            :effect_4,
+            :effect_4_value,
+            :effect_4_enchant,
+            :effect_4_grind,
+            :locked
+          );
+        ");
+        $statement->bindValue(":uid", $uid, SQLITE3_INTEGER);
+        $statement->bindValue(":id", $artifact->{"rid"}, SQLITE3_INTEGER);
+        if (intval($artifact->{"occupied_id"}) == 0){
+            $statement->bindValue(":assigned_to", null, SQLITE3_INTEGER);
+        }
+        else{
+            $statement->bindValue(":assigned_to", $artifact->{"occupied_id"}, SQLITE3_INTEGER);
+        }
+        if (intval($artifact->{"attribute"}) == 0){
+            $statement->bindValue(":attribute", null, SQLITE3_INTEGER);
+        }
+        else{
+            $statement->bindValue(":attribute", $artifact->{"attribute"}, SQLITE3_INTEGER);
+        }
+        if (intval($artifact->{"type"}) == 0){
+            $statement->bindValue(":type", null, SQLITE3_INTEGER);
+        }
+        else{
+            $statement->bindValue(":type", $artifact->{"type"}, SQLITE3_INTEGER);
+        }
+        if (intval($artifact->{"unit_style"}) == 0){
+            $statement->bindValue(":archetype", null, SQLITE3_INTEGER);
+        }
+        else{
+            $statement->bindValue(":archetype", $artifact->{"unit_style"}, SQLITE3_INTEGER);
+        }
+        $statement->bindValue(":level", $artifact->{"level"}, SQLITE3_INTEGER);
+        $statement->bindValue(":quality", $artifact->{"rank"}, SQLITE3_INTEGER);
+        $statement->bindValue(":original_quality", $artifact->{"natural_rank"}, SQLITE3_INTEGER);
+        $statement->bindValue(":value", 0, SQLITE3_INTEGER); // Not in JSON file
+        $statement->bindValue(":locked", $artifact->{"locked"}, SQLITE3_INTEGER);
+        $efficiency = 0; // Not standard formula yet
+        $max_efficiency = 0; // Not standard formula yet
+        $statement->bindValue(":efficiency", $efficiency, SQLITE3_FLOAT);
+        $statement->bindValue(":max_efficiency", $max_efficiency, SQLITE3_FLOAT);
+        $statement->bindValue(":main_stat", $artifact->{"pri_effect"}[0], SQLITE3_INTEGER);
+        $statement->bindValue(":main_stat_value", $artifact->{"pri_effect"}[1], SQLITE3_INTEGER);
+        if (sizeof($artifact->{"sec_effects"}) > 0){
+            $statement->bindValue(":effect_1", $artifact->{"sec_effects"}[0][0], SQLITE3_INTEGER);
+            $statement->bindValue(":effect_1_value", $artifact->{"sec_effects"}[0][1], SQLITE3_INTEGER);
+            $statement->bindValue(":effect_1_enchant", $artifact->{"sec_effects"}[0][2], SQLITE3_INTEGER);
+            $statement->bindValue(":effect_1_grind", $artifact->{"sec_effects"}[0][3], SQLITE3_INTEGER);
+        }
+        else{
+            $statement->bindValue(":effect_1", null, SQLITE3_INTEGER);
+            $statement->bindValue(":effect_1_value", 0, SQLITE3_INTEGER);
+            $statement->bindValue(":effect_1_enchant", 0, SQLITE3_INTEGER);
+            $statement->bindValue(":effect_1_grind", 0, SQLITE3_INTEGER);
+        }
+        if (sizeof($artifact->{"sec_effects"}) > 1){
+            $statement->bindValue(":effect_2", $artifact->{"sec_effects"}[1][0], SQLITE3_INTEGER);
+            $statement->bindValue(":effect_2_value", $artifact->{"sec_effects"}[1][1], SQLITE3_INTEGER);
+            $statement->bindValue(":effect_2_enchant", $artifact->{"sec_effects"}[1][2], SQLITE3_INTEGER);
+            $statement->bindValue(":effect_2_grind", $artifact->{"sec_effects"}[1][3], SQLITE3_INTEGER);
+        }
+        else{
+            $statement->bindValue(":effect_2", null, SQLITE3_INTEGER);
+            $statement->bindValue(":effect_2_value", 0, SQLITE3_INTEGER);
+            $statement->bindValue(":effect_2_enchant", 0, SQLITE3_INTEGER);
+            $statement->bindValue(":effect_2_grind", 0, SQLITE3_INTEGER);
+        }
+        if (sizeof($artifact->{"sec_effects"}) > 2){
+            $statement->bindValue(":effect_3", $artifact->{"sec_effects"}[2][0], SQLITE3_INTEGER);
+            $statement->bindValue(":effect_3_value", $artifact->{"sec_effects"}[2][1], SQLITE3_INTEGER);
+            $statement->bindValue(":effect_3_enchant", $artifact->{"sec_effects"}[2][2], SQLITE3_INTEGER);
+            $statement->bindValue(":effect_3_grind", $artifact->{"sec_effects"}[2][3], SQLITE3_INTEGER);
+        }
+        else{
+            $statement->bindValue(":effect_3", null, SQLITE3_INTEGER);
+            $statement->bindValue(":effect_3_value", 0, SQLITE3_INTEGER);
+            $statement->bindValue(":effect_3_enchant", 0, SQLITE3_INTEGER);
+            $statement->bindValue(":effect_3_grind", 0, SQLITE3_INTEGER);
+        }
+        if (sizeof($artifact->{"sec_effects"}) > 3){
+            $statement->bindValue(":effect_4", $artifact->{"sec_effects"}[3][0], SQLITE3_INTEGER);
+            $statement->bindValue(":effect_4_value", $artifact->{"sec_effects"}[3][1], SQLITE3_INTEGER);
+            $statement->bindValue(":effect_4_enchant", $artifact->{"sec_effects"}[3][2], SQLITE3_INTEGER);
+            $statement->bindValue(":effect_4_grind", $artifact->{"sec_effects"}[3][3], SQLITE3_INTEGER);
+        }
+        else{
+            $statement->bindValue(":effect_4", null, SQLITE3_INTEGER);
+            $statement->bindValue(":effect_4_value", 0, SQLITE3_INTEGER);
+            $statement->bindValue(":effect_4_enchant", 0, SQLITE3_INTEGER);
+            $statement->bindValue(":effect_4_grind", 0, SQLITE3_INTEGER);
+        }
+        $statement->execute();
+    }
+
+    /**
+     * Parses a rune and saves it to the database.
+     *
+     * @param string $uid Owner ID.
+     * @param JSON rune JSON fragment of the rune.
+     */
+    function parse_rune($uid, $rune, $lock_list){
+        global $db;
+        $statement = $db->prepare("
+          INSERT INTO rune (
+            uid,
+            id,
+            assigned_to,
+            type,
+            slot,
+            stars,
+            ancient,
+            level,
+            quality,
+            original_quality,
+            value,
+            efficiency,
+            max_efficiency,
+            main_stat,
+            main_stat_value,
+            innate_stat,
+            innate_stat_value,
+            substat_1,
+            substat_1_value,
+            substat_1_enchant,
+            substat_1_grind,
+            substat_2,
+            substat_2_value,
+            substat_2_enchant,
+            substat_2_grind,
+            substat_3,
+            substat_3_value,
+            substat_3_enchant,
+            substat_3_grind,
+            substat_4,
+            substat_4_value,
+            substat_4_enchant,
+            substat_4_grind,
+            locked
+          ) VALUES (
+            :uid,
+            :id,
+            :assigned_to,
+            :type,
+            :slot,
+            :stars,
+            :ancient,
+            :level,
+            :quality,
+            :original_quality,
+            :value,
+            :efficiency,
+            :max_efficiency,
+            :main_stat,
+            :main_stat_value,
+            :innate_stat,
+            :innate_stat_value,
+            :substat_1,
+            :substat_1_value,
+            :substat_1_enchant,
+            :substat_1_grind,
+            :substat_2,
+            :substat_2_value,
+            :substat_2_enchant,
+            :substat_2_grind,
+            :substat_3,
+            :substat_3_value,
+            :substat_3_enchant,
+            :substat_3_grind,
+            :substat_4,
+            :substat_4_value,
+            :substat_4_enchant,
+            :substat_4_grind,
+            :locked
+          );
+        ");
+        $statement->bindValue(":uid", $uid, SQLITE3_INTEGER);
+        $statement->bindValue(":id", $rune->{"rune_id"}, SQLITE3_INTEGER);
+        if (intval($rune->{"occupied_id"}) == 0){
+            $statement->bindValue(":assigned_to", null, SQLITE3_INTEGER);
+        }
+        else{
+            $statement->bindValue(":assigned_to", $rune->{"occupied_id"}, SQLITE3_INTEGER);
+        }
+        $statement->bindValue(":type", $rune->{"set_id"}, SQLITE3_INTEGER);
+        $statement->bindValue(":slot", $rune->{"slot_no"}, SQLITE3_INTEGER);
+        $statement->bindValue(":value", $rune->{"sell_value"}, SQLITE3_INTEGER);
+        if ($rune->{"class"} > 10){
+            // Ancient rune
+            $statement->bindValue(":ancient", 1, SQLITE3_INTEGER);
+            $statement->bindValue(":stars", intval($rune->{"class"}) - 10, SQLITE3_INTEGER);
+            $statement->bindValue(":original_quality", intval($rune->{"extra"}) - 10, SQLITE3_INTEGER);
+        }
+        else{
+            // Non Ancient rune
+            $statement->bindValue(":ancient", 0, SQLITE3_INTEGER);
+            $statement->bindValue(":stars", $rune->{"class"}, SQLITE3_INTEGER);
+            $statement->bindValue(":original_quality", $rune->{"extra"}, SQLITE3_INTEGER);
+        }
+        $level = $rune->{"upgrade_curr"};
+        $statement->bindValue(":level", $level, SQLITE3_INTEGER);
+        $quality = QUALITY_ID::NORMAL;
+        if ($level >= 12){
+            $quality = QUALITY_ID::LEGEND;
+        }
+        elseif ($level >= 9){
+            $quality = QUALITY_ID::HERO;
+        }
+        elseif ($level >= 6){
+            $quality = QUALITY_ID::RARE;
+        }
+        elseif ($level >= 3){
+            $quality = QUALITY_ID::MAGIC;
+        }
+        if ($rune->{"extra"} > $quality){
+            $quality = $rune->{"extra"};
+        }
+        $statement->bindValue(":quality", $quality, SQLITE3_INTEGER);
+        $lock = 0;
+        if (in_array($rune->{"rune_id"}, $lock_list)){
+            $lock = 1;
+        }
+        $statement->bindValue(":locked", $lock, SQLITE3_INTEGER);
+        $efficiency = calculate_efficiency($rune);
+        $max_efficiency = calculate_maximum_efficiency($rune);
+        $statement->bindValue(":efficiency", $efficiency, SQLITE3_FLOAT);
+        $statement->bindValue(":max_efficiency", $max_efficiency, SQLITE3_FLOAT);
+        $statement->bindValue(":main_stat", $rune->{"pri_eff"}[0], SQLITE3_INTEGER);
+        $statement->bindValue(":main_stat_value", $rune->{"pri_eff"}[1], SQLITE3_INTEGER);
+        if ($rune->{"prefix_eff"}[0] > 0){
+            $statement->bindValue(":innate_stat", $rune->{"prefix_eff"}[0], SQLITE3_INTEGER);
+            $statement->bindValue(":innate_stat_value", $rune->{"prefix_eff"}[1], SQLITE3_INTEGER);
+        }
+        else{
+            $statement->bindValue(":innate_stat", null, SQLITE3_INTEGER);
+            $statement->bindValue(":innate_stat_value", 0, SQLITE3_INTEGER);
+        }
+        if (sizeof($rune->{"sec_eff"}) > 0){
+            $statement->bindValue(":substat_1", $rune->{"sec_eff"}[0][0], SQLITE3_INTEGER);
+            $statement->bindValue(":substat_1_value", $rune->{"sec_eff"}[0][1], SQLITE3_INTEGER);
+            $statement->bindValue(":substat_1_enchant", $rune->{"sec_eff"}[0][2], SQLITE3_INTEGER);
+            $statement->bindValue(":substat_1_grind", $rune->{"sec_eff"}[0][3], SQLITE3_INTEGER);
+        }
+        else{
+            $statement->bindValue(":substat_1", null, SQLITE3_INTEGER);
+            $statement->bindValue(":substat_1_value", 0, SQLITE3_INTEGER);
+            $statement->bindValue(":substat_1_enchant", 0, SQLITE3_INTEGER);
+            $statement->bindValue(":substat_1_grind", 0, SQLITE3_INTEGER);
+        }
+        if (sizeof($rune->{"sec_eff"}) > 1){
+            $statement->bindValue(":substat_2", $rune->{"sec_eff"}[1][0], SQLITE3_INTEGER);
+            $statement->bindValue(":substat_2_value", $rune->{"sec_eff"}[1][1], SQLITE3_INTEGER);
+            $statement->bindValue(":substat_2_enchant", $rune->{"sec_eff"}[1][2], SQLITE3_INTEGER);
+            $statement->bindValue(":substat_2_grind", $rune->{"sec_eff"}[1][3], SQLITE3_INTEGER);
+        }
+        else{
+            $statement->bindValue(":substat_2", null, SQLITE3_INTEGER);
+            $statement->bindValue(":substat_2_value", 0, SQLITE3_INTEGER);
+            $statement->bindValue(":substat_2_enchant", 0, SQLITE3_INTEGER);
+            $statement->bindValue(":substat_2_grind", 0, SQLITE3_INTEGER);
+        }
+        if (sizeof($rune->{"sec_eff"}) > 2){
+            $statement->bindValue(":substat_3", $rune->{"sec_eff"}[2][0], SQLITE3_INTEGER);
+            $statement->bindValue(":substat_3_value", $rune->{"sec_eff"}[2][1], SQLITE3_INTEGER);
+            $statement->bindValue(":substat_3_enchant", $rune->{"sec_eff"}[2][2], SQLITE3_INTEGER);
+            $statement->bindValue(":substat_3_grind", $rune->{"sec_eff"}[2][3], SQLITE3_INTEGER);
+        }
+        else{
+            $statement->bindValue(":substat_3", null, SQLITE3_INTEGER);
+            $statement->bindValue(":substat_3_value", 0, SQLITE3_INTEGER);
+            $statement->bindValue(":substat_3_enchant", 0, SQLITE3_INTEGER);
+            $statement->bindValue(":substat_3_grind", 0, SQLITE3_INTEGER);
+        }
+        if (sizeof($rune->{"sec_eff"}) > 3){
+            $statement->bindValue(":substat_4", $rune->{"sec_eff"}[3][0], SQLITE3_INTEGER);
+            $statement->bindValue(":substat_4_value", $rune->{"sec_eff"}[3][1], SQLITE3_INTEGER);
+            $statement->bindValue(":substat_4_enchant", $rune->{"sec_eff"}[3][2], SQLITE3_INTEGER);
+            $statement->bindValue(":substat_4_grind", $rune->{"sec_eff"}[3][3], SQLITE3_INTEGER);
+        }
+        else{
+            $statement->bindValue(":substat_4", null, SQLITE3_INTEGER);
+            $statement->bindValue(":substat_4_value", 0, SQLITE3_INTEGER);
+            $statement->bindValue(":substat_4_enchant", 0, SQLITE3_INTEGER);
+            $statement->bindValue(":substat_4_grind", 0, SQLITE3_INTEGER);
+        }
+        $statement->execute();
+    }
+
+    /**
+     * Parses the response to the HubUserLogin command and updates profile.
+     *
+     * @param resource $db Database connection.
+     * @param int $uid Player UID.
+     * @param mixed[] $json Response.
+     */
+    function parse_profile($db, $uid, $json){
+        // Save data file
+        $uname = $json->{"wizard_info"}->{"wizard_name"};
+        $dtime = (new DateTime())->format("Y-m-dTH:i:s");
+        $fname = ($_SERVER["DOCUMENT_ROOT"] . "/../data/profile_" . $uid . "_" . $uname . "_" . $dtime . ".json");
+        try{
+            file_put_contents($fname, json_encode($json));
+        }
+        catch(Exception $e) {
+            header("HTTP/1.1 500 Unable to save profile file: " . $e->getMessage());
+            syslog(LOG_INFO, "[APIv3] HTTP/1.1 500 Unable to save profile file: " . $e->getMessage());
+            return 500;
+        }
+
+        // Clear previous profile data
+        $db->query("PRAGMA foreign_keys = OFF;");
+        $statement = $db->prepare("DELETE FROM unit_skill WHERE unit IN (SELECT id FROM unit WHERE uid = :uid);");
+        $statement->bindValue(":uid", $uid, SQLITE3_INTEGER);
+        $statement->execute();
+        $tables_to_clear = [
+            "scenario",
+            "defense",
+            "gw_defense",
+            "unit",
+            "rune",
+            "artifact",
+            "building",
+            "decoration",
+            "inventory",
+            "enchantment"
+        ];
+        foreach ($tables_to_clear as $table){
+            $statement = $db->prepare("DELETE FROM $table WHERE uid = :uid;");
+            $statement->bindValue(":uid", $uid, SQLITE3_INTEGER);
+            $statement->execute();
+        }
+        $db->query("DELETE FROM summon_special"); # For every player, will be reloaded.
+
+        // Get rune lock list
+        $rune_lock_list = $json->{"rune_lock_list"};
+
+        // Update player data
+        $statement = $db->prepare("
+          UPDATE player
+          SET
+            name = :name,
+            mana = :mana,
+            crystal = :crystal,
+            country = :country,
+            lang = :lang,
+            level = :level,
+            experience = :experience,
+            energy = :energy,
+            energy_max = :energy_max,
+            energy_per_min = :energy_per_min,
+            arena_energy = :arena_energy,
+            arena_energy_max = :arena_energy_max,
+            rep = :rep,
+            social_point = :social_point,
+            honor_point = :honor_point,
+            guild_point = :guild_point,
+            darkportal_energy = :darkportal_energy,
+            darkportal_energy_max = :darkportal_energy_max,
+            dimension_energy = :dimension_energy,
+            dimension_energy_max = :dimension_energy_max,
+            costume_point = :costume_point,
+            costume_point_max = :costume_point_max,
+            honor_medal = :honor_medal,
+            honor_mark = :honor_mark,
+            event_coin = :event_coin,
+            storage_slots = :storage_slots,
+            island = :island_upgrade
+          WHERE uid = :uid;
+        ");
+        $statement->bindValue(":name", $json->{"wizard_info"}->{"wizard_name"}, SQLITE3_TEXT);
+        $statement->bindValue(":mana", $json->{"wizard_info"}->{"wizard_mana"}, SQLITE3_INTEGER);
+        $statement->bindValue(":crystal", $json->{"wizard_info"}->{"wizard_crystal"}, SQLITE3_INTEGER);
+        $statement->bindValue(":country", $json->{"wizard_info"}->{"wizard_last_country"}, SQLITE3_TEXT);
+        $statement->bindValue(":lang", $json->{"wizard_info"}->{"wizard_last_lang"}, SQLITE3_TEXT);
+        $statement->bindValue(":level", $json->{"wizard_info"}->{"wizard_level"}, SQLITE3_INTEGER);
+        $statement->bindValue(":experience", $json->{"wizard_info"}->{"experience"}, SQLITE3_INTEGER);
+        $statement->bindValue(":energy", $json->{"wizard_info"}->{"wizard_energy"}, SQLITE3_INTEGER);
+        $statement->bindValue(":energy_max", $json->{"wizard_info"}->{"energy_max"}, SQLITE3_INTEGER);
+        $statement->bindValue(":energy_per_min", $json->{"wizard_info"}->{"energy_per_min"}, SQLITE3_INTEGER);
+        $statement->bindValue(":arena_energy", $json->{"wizard_info"}->{"arena_energy"}, SQLITE3_INTEGER);
+        $statement->bindValue(":arena_energy_max", $json->{"wizard_info"}->{"arena_energy_max"}, SQLITE3_INTEGER);
+        $statement->bindValue(":rep", $json->{"wizard_info"}->{"rep_unit_id"}, SQLITE3_INTEGER);
+        $statement->bindValue(":social_point", $json->{"wizard_info"}->{"social_point_current"}, SQLITE3_INTEGER);
+        $statement->bindValue(":honor_point", $json->{"wizard_info"}->{"honor_point"}, SQLITE3_INTEGER);
+        $statement->bindValue(":guild_point", $json->{"wizard_info"}->{"guild_point"}, SQLITE3_INTEGER);
+        $statement->bindValue(":darkportal_energy", $json->{"wizard_info"}->{"darkportal_energy"}, SQLITE3_INTEGER);
+        $statement->bindValue(":darkportal_energy_max", $json->{"wizard_info"}->{"darkportal_energy_max"}, SQLITE3_INTEGER);
+        $statement->bindValue(":dimension_energy", $json->{"dimension_hole_info"}->{"energy"}, SQLITE3_INTEGER);
+        $statement->bindValue(":dimension_energy_max", $json->{"dimension_hole_info"}->{"energy_max"}, SQLITE3_INTEGER);
+        $statement->bindValue(":costume_point", $json->{"wizard_info"}->{"costume_point"}, SQLITE3_INTEGER);
+        $statement->bindValue(":costume_point_max", $json->{"wizard_info"}->{"costume_point_max"}, SQLITE3_INTEGER);
+        $statement->bindValue(":honor_medal", $json->{"wizard_info"}->{"honor_medal"}, SQLITE3_INTEGER);
+        $statement->bindValue(":honor_mark", $json->{"wizard_info"}->{"honor_mark"}, SQLITE3_INTEGER);
+        $statement->bindValue(":event_coin", $json->{"wizard_info"}->{"event_coin"}, SQLITE3_INTEGER);
+        $statement->bindValue(":storage_slots", $json->{"unit_depository_slots"}->{"number"}, SQLITE3_INTEGER);
+        $island_upgrade = 0;
+        foreach ($json->{"island_info"} as $island){
+            if (intval($island->{"id"}) > 100 && intval($island->{"open"}) == 1){
+                $island_upgrade = intval($island->{"id"});
+            }
+        }
+        $statement->bindValue(":island_upgrade", $island_upgrade, SQLITE3_INTEGER);
+        $statement->bindValue(":uid", $uid, SQLITE3_INTEGER);
+        $statement->execute();
+
+        // Update scenarion completion
+        foreach ($json->{"scenario_list"} as $sce){
+            $statement = $db->prepare("
+              INSERT INTO scenario (
+                uid,
+                region,
+                difficulty,
+                cleared,
+                max_cleared
+              ) VALUES (
+                :uid,
+                :region,
+                :difficulty,
+                :cleared,
+                :max_cleared
+              );
+            ");
+            $statement->bindValue(":uid", $uid, SQLITE3_INTEGER);
+            $statement->bindValue(":region", $sce->{"region_id"}, SQLITE3_INTEGER);
+            $statement->bindValue(":difficulty", $sce->{"difficulty"}, SQLITE3_INTEGER);
+            $statement->bindValue(":cleared", $sce->{"cleared"}, SQLITE3_INTEGER);
+            $max_cleared = 0;
+            foreach ($sce->{"stage_list"} as $stage){
+                if (intval($stage->{"cleared"}) == 1){
+                    $max_cleared = intval($stage->{"stage_no"});
+                }
+            }
+            $statement->bindValue(":max_cleared", $max_cleared, SQLITE3_INTEGER);
+            $statement->execute();
+        }
+
+        // Parse Arena defense
+        foreach ($json->{"defense_unit_list"} as $defense){
+            $statement = $db->prepare("
+              INSERT INTO defense (
+                uid,
+                unit,
+                position
+              ) VALUES (
+                :uid,
+                :unit,
+                :position
+              );
+            ");
+            $statement->bindValue(":uid", $uid, SQLITE3_INTEGER);
+            $statement->bindValue(":unit", $defense->{"unit_id"}, SQLITE3_INTEGER);
+            $statement->bindValue(":position", $defense->{"pos_id"}, SQLITE3_INTEGER);
+            $statement->execute();
+        }
+
+        // Parse GW defense
+        if ($json->{"guildwar_defense_unit_list"}[0]){
+            $position = 1;
+            foreach ($json->{"guildwar_defense_unit_list"}[0] as $defense){
+                $statement = $db->prepare("
+                  INSERT INTO gw_defense (
+                    uid,
+                    unit,
+                    position
+                  ) VALUES (
+                    :uid,
+                    :unit,
+                    :position
+                  );
+                ");
+                $statement->bindValue(":uid", $uid, SQLITE3_INTEGER);
+                $statement->bindValue(":unit", $defense->{"unit_id"}, SQLITE3_INTEGER);
+                $statement->bindValue(":position", $position, SQLITE3_INTEGER);
+                $statement->execute();
+                $position ++;
+            }
+        }
+        if ($json->{"guildwar_defense_unit_list"}[1]){
+            $position = 4;
+            foreach ($json->{"guildwar_defense_unit_list"}[1] as $defense){
+                $statement = $db->prepare("
+                  INSERT INTO gw_defense (
+                    uid,
+                    unit,
+                    position
+                  ) VALUES (
+                    :uid,
+                    :unit,
+                    :position
+                  );
+                ");
+                $statement->bindValue(":uid", $uid, SQLITE3_INTEGER);
+                $statement->bindValue(":unit", $defense->{"unit_id"}, SQLITE3_INTEGER);
+                $statement->bindValue(":position", $position, SQLITE3_INTEGER);
+                $statement->execute();
+                $position ++;
+            }
+        }
+
+        // Parse buildings
+        foreach($json->{"building_list"} as $building){
+            $statement = $db->prepare("
+              INSERT INTO building (
+                uid,
+                id,
+                building,
+                gain
+              ) VALUES (
+                :uid,
+                :id,
+                :building,
+                :gain
+              );
+            ");
+            $statement->bindValue(":uid", $uid, SQLITE3_INTEGER);
+            $statement->bindValue(":id", $building->{"building_id"}, SQLITE3_INTEGER);
+            $statement->bindValue(":building", $building->{"building_master_id"}, SQLITE3_INTEGER);
+            $statement->bindValue(":gain", $building->{"gain_per_hour"}, SQLITE3_INTEGER);
+            $statement->execute();
+        }
+
+        // Parse decorarion
+        foreach($json->{"deco_list"} as $building){
+            $statement = $db->prepare("
+              INSERT INTO decoration (
+                uid,
+                id,
+                decoration,
+                level
+              ) VALUES (
+                :uid,
+                :id,
+                :decoration,
+                :level
+              );
+            ");
+            $statement->bindValue(":uid", $uid, SQLITE3_INTEGER);
+            $statement->bindValue(":id", $building->{"deco_id"}, SQLITE3_INTEGER);
+            $statement->bindValue(":decoration", $building->{"master_id"}, SQLITE3_INTEGER);
+            $statement->bindValue(":level", $building->{"level"}, SQLITE3_INTEGER);
+            $statement->execute();
+        }
+
+        // Parse units
+        $lock_list = $json->{"unit_lock_list"};
+        foreach ($json->{"unit_list"} as $unit){
+            $statement = $db->prepare("
+              INSERT INTO unit (
+                uid,
+                id,
+                building,
+                unit,
+                level,
+                stars,
+                hp,
+                attack,
+                defense,
+                speed,
+                crit_rate,
+                crit_damage,
+                resistance,
+                accuracy,
+                experience,
+                exp_gained,
+                exp_gain_rate,
+                costume,
+                attribute,
+                source,
+                create_time,
+                homunculus,
+                homunculus_name,
+                lock
+              ) VALUES (
+                :uid,
+                :id,
+                :building,
+                :unit,
+                :level,
+                :stars,
+                :hp,
+                :attack,
+                :defense,
+                :speed,
+                :crit_rate,
+                :crit_damage,
+                :resistance,
+                :accuracy,
+                :experience,
+                :exp_gained,
+                :exp_gain_rate,
+                :costume,
+                :attribute,
+                :source,
+                :create_time,
+                :homunculus,
+                :homunculus_name,
+                :lock
+              );
+            ");
+            $statement->bindValue(":uid", $uid, SQLITE3_INTEGER);
+            $statement->bindValue(":id", $unit->{"unit_id"}, SQLITE3_INTEGER);
+            $statement->bindValue(":building", $unit->{"building_id"}, SQLITE3_INTEGER);
+            $statement->bindValue(":unit", $unit->{"unit_master_id"}, SQLITE3_INTEGER);
+            $statement->bindValue(":level", $unit->{"unit_level"}, SQLITE3_INTEGER);
+            $statement->bindValue(":stars", $unit->{"class"}, SQLITE3_INTEGER);
+            $statement->bindValue(":hp", intval($unit->{"con"}) * 15, SQLITE3_INTEGER); # Always x15
+            $statement->bindValue(":attack", $unit->{"atk"}, SQLITE3_INTEGER);
+            $statement->bindValue(":defense", $unit->{"def"}, SQLITE3_INTEGER);
+            $statement->bindValue(":speed", $unit->{"spd"}, SQLITE3_INTEGER);
+            $statement->bindValue(":crit_rate", $unit->{"critical_rate"}, SQLITE3_INTEGER);
+            $statement->bindValue(":crit_damage", $unit->{"critical_damage"}, SQLITE3_INTEGER);
+            $statement->bindValue(":resistance", $unit->{"resist"}, SQLITE3_INTEGER);
+            $statement->bindValue(":accuracy", $unit->{"accuracy"}, SQLITE3_INTEGER);
+            $statement->bindValue(":experience", $unit->{"experience"}, SQLITE3_INTEGER);
+            $statement->bindValue(":exp_gained", $unit->{"exp_gained"}, SQLITE3_INTEGER);
+            $statement->bindValue(":exp_gain_rate", $unit->{"exp_gain_rate"}, SQLITE3_INTEGER);
+            $statement->bindValue(":costume", $unit->{"costume_master_id"}, SQLITE3_INTEGER);
+            $statement->bindValue(":attribute", $unit->{"attribute"}, SQLITE3_INTEGER);
+            $statement->bindValue(":source", $unit->{"source"}, SQLITE3_INTEGER);
+            $statement->bindValue(":create_time", $unit->{"create_time"}, SQLITE3_INTEGER);
+            $statement->bindValue(":homunculus", $unit->{"homunculus"}, SQLITE3_INTEGER);
+            $statement->bindValue(":homunculus_name", $unit->{"homunculus_name"}, SQLITE3_TEXT);
+            $lock = 0;
+            if (in_array($unit->{"unit_id"}, $lock_list)){
+                $lock = 1;
+            }
+            $statement->bindValue(":lock", $lock, SQLITE3_INTEGER);
+            $statement->execute();
+            foreach ($unit->{"skills"} as $skill){
+                $statement = $db->prepare("
+                  INSERT INTO unit_skill (
+                    unit,
+                    skill,
+                    level
+                  ) VALUES (
+                    :unit,
+                    :skill,
+                    :level
+                  );
+                ");
+                $statement->bindValue(":unit", $unit->{"unit_id"}, SQLITE3_INTEGER);
+                $statement->bindValue(":skill", $skill[0], SQLITE3_INTEGER);
+                $statement->bindValue(":level", $skill[1], SQLITE3_INTEGER);
+                $statement->execute();
+            }
+        }
+
+        // Parse invetory
+        foreach ($json->{"inventory_info"} as $item){
+            $statement = $db->prepare("
+              INSERT INTO inventory (
+                uid,
+                id,
+                type,
+                amount
+              ) VALUES (
+                :uid,
+                :id,
+                :type,
+                :amount
+              );
+            ");
+            $statement->bindValue(":uid", $uid, SQLITE3_INTEGER);
+            $statement->bindValue(":id", $item->{"item_master_id"}, SQLITE3_INTEGER);
+            $statement->bindValue(":type", $item->{"item_master_type"}, SQLITE3_INTEGER);
+            $statement->bindValue(":amount", $item->{"item_quantity"}, SQLITE3_INTEGER);
+            $statement->execute();
+        }
+        // Fix rune craft item type.
+        $db->query("UPDATE inventory SET type = 27 WHERE type = 29 AND id IN (2001, 4001, 4002, 4003, 9001, 9002, 9003, 8001);");
+
+        // Parse Summon Stone summoning list
+        // TODO: Set propper dates
+        foreach ($json->{"summon_special_info"}->{"this"} as $unit){
+            $statement = $db->prepare("
+              INSERT INTO summon_special (
+                week,
+                unit
+              ) VALUES (
+                :week,
+                :unit
+              );
+            ");
+            $statement->bindValue(":week", 0, SQLITE3_INTEGER);
+            $statement->bindValue(":unit", $unit, SQLITE3_INTEGER);
+            $statement->execute();
+        }
+        foreach ($json->{"summon_special_info"}->{"next"} as $unit){
+            $statement = $db->prepare("
+              INSERT INTO summon_special (
+                week,
+                unit
+              ) VALUES (
+                :week,
+                :unit
+              );
+            ");
+            $statement->bindValue(":week", 1, SQLITE3_INTEGER);
+            $statement->bindValue(":unit", $unit, SQLITE3_INTEGER);
+            $statement->execute();
+        }
+        foreach ($json->{"summon_special_info"}->{"third"} as $unit){
+            $statement = $db->prepare("
+              INSERT INTO summon_special (
+                week,
+                unit
+              ) VALUES (
+                :week,
+                :unit
+              );
+            ");
+            $statement->bindValue(":week", 2, SQLITE3_INTEGER);
+            $statement->bindValue(":unit", $unit, SQLITE3_INTEGER);
+            $statement->execute();
+        }
+        foreach ($json->{"summon_special_info"}->{"fourth"} as $unit){
+            $statement = $db->prepare("
+              INSERT INTO summon_special (
+                week,
+                unit
+              ) VALUES (
+                :week,
+                :unit
+              );
+            ");
+            $statement->bindValue(":week", 3, SQLITE3_INTEGER);
+            $statement->bindValue(":unit", $unit, SQLITE3_INTEGER);
+            $statement->execute();
+        }
+
+        // Parse runes
+        foreach ($json->{"runes"} as $rune){
+            parse_rune($uid, $rune, $rune_lock_list);
+        }
+        foreach ($json->{"unit_list"} as $unit){
+            foreach ($unit->{"runes"} as $rune){
+                parse_rune($uid, $rune, $rune_lock_list);
+            }
+        }
+
+        // Parse artifacts
+        foreach ($json->{"artifacts"} as $artifact){
+            parse_artifact($uid, $artifact);
+        }
+        foreach ($json->{"unit_list"} as $unit){
+            foreach ($unit->{"artifacts"} as $artifact){
+                parse_artifact($uid, $artifact);
+            }
+        }
+
+        // Parse enchantments
+        foreach ($json->{"rune_craft_item_list"} as $item){
+            $statement = $db->prepare("
+              INSERT INTO enchantment (
+                uid,
+                id,
+                type,
+                quality,
+                rune,
+                stat,
+                value,
+                amount
+              ) VALUES (
+                :uid,
+                :id,
+                :type,
+                :quality,
+                :rune,
+                :stat,
+                :value,
+                :amount
+              );
+            ");
+            $statement->bindValue(":uid", $uid, SQLITE3_INTEGER);
+            $statement->bindValue(":id", $item->{"craft_item_id"}, SQLITE3_INTEGER);
+            $statement->bindValue(":type", $item->{"craft_type"}, SQLITE3_INTEGER);
+            $statement->bindValue(":value", $item->{"sell_value"}, SQLITE3_INTEGER);
+            $statement->bindValue(":amount", $item->{"amount"}, SQLITE3_INTEGER);
+            $info = str_pad(intval($item->{"craft_type_id"}), 6, "0", STR_PAD_LEFT);
+            /*
+            info : 5 or 6 digit number: RRSSQQ
+             RR: Rune (may not be padded)
+             SS: Stat
+             QQ:  Quality
+            */
+            $statement->bindValue(":quality", intval(substr($info, 4, 2)), SQLITE3_INTEGER);
+            $statement->bindValue(":stat", intval(substr($info, 2, 2)), SQLITE3_INTEGER);
+            $statement->bindValue(":rune", intval(substr($info, 0, 2)), SQLITE3_INTEGER);
+            $statement->execute();
+        }
+
+        // Parse guild
+        if ($json->{"guild"}->{"guild_info"} != null){
+            $guild = $json->{"guild"}->{"guild_info"};
+            $statement = $db->prepare("DELETE FROM guild WHERE id = :id;");
+            $statement->bindValue(":id", $guild->{"guild_id"}, SQLITE3_INTEGER);
+            $statement->execute();
+            $statement = $db->prepare("DELETE FROM guild_member WHERE guild = :guild;");
+            $statement->bindValue(":guild", $guild->{"guild_id"}, SQLITE3_INTEGER);
+            $statement->execute();
+            $statement = $db->prepare("
+              INSERT INTO guild (
+                id,
+                name,
+                level,
+                experience,
+                recruiting,
+                members,
+                leader,
+                comment,
+                notice
+              ) VALUES (
+                :id,
+                :name,
+                :level,
+                :experience,
+                :recruiting,
+                :members,
+                :leader,
+                :comment,
+                :notice
+              );
+            ");
+            $statement->bindValue(":id",$guild->{"guild_id"}, SQLITE3_INTEGER);
+            $statement->bindValue(":name",$guild->{"name"}, SQLITE3_TEXT);
+            $statement->bindValue(":level",$guild->{"level"}, SQLITE3_INTEGER);
+            $statement->bindValue(":experience",$guild->{"experience"}, SQLITE3_INTEGER);
+            $statement->bindValue(":recruiting",$guild->{"recruit_status"}, SQLITE3_INTEGER);
+            $statement->bindValue(":members",$guild->{"member_now"}, SQLITE3_INTEGER);
+            $statement->bindValue(":leader",$guild->{"master_wizard_id"}, SQLITE3_INTEGER);
+            $statement->bindValue(":comment",$guild->{"comment"}, SQLITE3_TEXT);
+            $statement->bindValue(":notice",$guild->{"notice"}, SQLITE3_TEXT);
+            $statement->execute();
+            foreach ($json->{"guild"}->{"guild_members"} as $member){
+                $statement = $db->prepare("
+                  INSERT INTO guild_member (
+                    id,
+                    guild,
+                    grade,
+                    name,
+                    level,
+                    rating,
+                    arena_score,
+                    joined,
+                    last_login,
+                    in_war,
+                    has_defense
+                  ) VALUES (
+                    :id,
+                    :guild,
+                    :grade,
+                    :name,
+                    :level,
+                    :rating,
+                    :arena_score,
+                    :joined,
+                    :last_login,
+                    :in_war,
+                    :has_defense
+                  );
+                ");
+                $statement->bindValue(":id", $member->{"wizard_id"}, SQLITE3_INTEGER);
+                $statement->bindValue(":guild", $member->{"guild_id"}, SQLITE3_INTEGER);
+                $statement->bindValue(":grade", $member->{"grade"}, SQLITE3_INTEGER);
+                $statement->bindValue(":name", $member->{"wizard_name"}, SQLITE3_TEXT);
+                $statement->bindValue(":level", $member->{"wizard_level"}, SQLITE3_INTEGER);
+                $statement->bindValue(":rating", $member->{"rating_id"}, SQLITE3_INTEGER);
+                $statement->bindValue(":arena_score", $member->{"arena_score"}, SQLITE3_INTEGER);
+                $statement->bindValue(":joined", $member->{"join_timestamp"}, SQLITE3_TEXT);
+                $statement->bindValue(":last_login", $member->{"last_login_timestamp"}, SQLITE3_TEXT);
+                $in_war = 0;
+                foreach ($json->{"guildwar_member_list"} as $war){
+                    if ($war->{"wizard_id"} == $member->{"wizard_id"}){
+                        $in_war = 1;
+                        break;
+                    }
+                }
+                $has_defense = 0;
+                foreach ($json->{"guild_member_defense_list"} as $defense){
+                    if ($defense->{"wizard_id"} == $member->{"wizard_id"}){
+                        $has_defense = 1;
+                        break;
+                    }
+                }
+                $statement->bindValue(":in_war", $in_war, SQLITE3_INTEGER);
+                $statement->bindValue(":has_defense", $has_defense, SQLITE3_INTEGER);
+                $statement->execute();
+            }
+        }
+
+        // Update invalid teams
+        $statement = $db->prepare("
+          DELETE FROM team 
+          WHERE 
+            id IN (
+              SELECT DISTINCT team 
+              FROM team_unit 
+              WHERE unit NOT IN (
+                SELECT DISTINCT id FROM unit WHERE uid = :uid
+              )
+            ) AND
+            uid = :uid
+          ");
+        $statement->bindValue(":uid", $uid, SQLITE3_INTEGER);
+        $statement->execute();
+        $db->query("
+          DELETE FROM team_unit
+          WHERE 
+            unit NOT IN (
+              SELECT DISTINCT id FROM unit
+            ) OR 
+            team NOT IN (
+              SELECT DISTINCT id FROM team
+            );"
+        );
+        // Return success
+        return "201 Created.";
+    }
+
+    /**
+     * Parses the response to the GetUnitCollection command and updates the
+     * user monster collection status.
+     *
+     * @param resource $db Database connection.
+     * @param int $uid Player UID.
+     * @param mixed[] $json Response.
+     */
+    function parse_collection($db, $uid, $json){
+        // Clear previous collection data
+        $db->query("PRAGMA foreign_keys = OFF;");
+        $statement = $db->prepare("DELETE FROM collection WHERE uid = :uid;");
+        $statement->bindValue(":uid", $uid, SQLITE3_INTEGER);
+        $statement->execute();
+        foreach ($json->{"collection"} as $unit){
+            $statement = $db->prepare("
+              INSERT INTO collection (uid, unit, open)
+              VALUES (:uid, :unit, :open);
+            ");
+            $statement->bindValue(":uid", $uid, SQLITE3_INTEGER);
+            $statement->bindValue(":unit", $unit->{"unit_master_id"}, SQLITE3_INTEGER);
+            $statement->bindValue(":open", $unit->{"open"}, SQLITE3_INTEGER);
+            $statement->execute();
+        }
+        // Return success
+        return "201 Created.";
+    }
+
+    /**
+     * Parses the response to the GetLobbyWizardLog command and updates the
+     * user records.
+     *
+     * @param resource $db Database connection.
+     * @param int $uid Player UID.
+     * @param mixed[] $json Response.
+     */
+    function parse_records($db, $uid, $json){
+
+        # Page 1: Cairos non-elemental, rift raid, rift dungeon.
+        if (intval($json->{"lobby_wizard_log"}->{"page_no"}) == 1){
+
+            // Update data in player table
+            $db->query("PRAGMA foreign_keys = OFF;");
+            $statement = $db->prepare("
+              UPDATE player SET 
+                joined = :joined,
+                top_rank_arena = :top_rank_arena,
+                top_rank_world_arena = :top_rank_world_arena,
+                top_rank_special_league = :top_rank_special_league,
+                top_rank_gw = :top_rank_gw,
+                top_rank_siege = :top_rank_siege,
+                top_rank_wboss = :top_rank_wboss,
+                top_rank_toan = :top_rank_toan,
+                top_rank_toah = :top_rank_toah
+              WHERE uid = :uid;
+            ");
+            $statement->bindValue(":joined", $json->{"lobby_wizard_log"}->{"account_create_timestamp"}, SQLITE3_TEXT);
+            $statement->bindValue(":top_rank_arena", $json->{"lobby_wizard_log"}->{"pvp_best_rating_id"}, SQLITE3_INTEGER);
+            $statement->bindValue(":top_rank_world_arena", $json->{"lobby_wizard_log"}->{"rtpvp_rank_best_rating_id"}, SQLITE3_INTEGER);
+            $statement->bindValue(":top_rank_special_league", $json->{"lobby_wizard_log"}->{"rtpvp_contest_best_rating_id"}, SQLITE3_INTEGER);
+            $statement->bindValue(":top_rank_gw", $json->{"lobby_wizard_log"}->{"guildwar_best_rating_id"}, SQLITE3_INTEGER);
+            $statement->bindValue(":top_rank_siege", $json->{"lobby_wizard_log"}->{"guildsiege_best_rating_id"}, SQLITE3_INTEGER);
+            $statement->bindValue(":top_rank_wboss", $json->{"lobby_wizard_log"}->{"world_boss_best_rank_id"}, SQLITE3_INTEGER);
+            $statement->bindValue(":top_rank_toan", $json->{"lobby_wizard_log"}->{"trial_tower_normal_best_floor"}, SQLITE3_INTEGER);
+            $statement->bindValue(":top_rank_toah", $json->{"lobby_wizard_log"}->{"trial_tower_hard_best_floor"}, SQLITE3_INTEGER);
+            $statement->bindValue(":uid", $uid, SQLITE3_INTEGER);
+            $statement->execute();
+
+            // Loop Cairos records
+            foreach ($json->{"lobby_wizard_log"}->{"dungeon_best_clear_info_list"} as $record){
+                // Delete prevous data
+                $statement = $db->prepare("
+                  DELETE FROM record_party
+                  WHERE 
+                    uid = :uid AND
+                    area_type = :area_type AND
+                    area = :area;
+                ");
+                $statement->bindValue(":uid", $uid, SQLITE3_INTEGER);
+                $statement->bindValue(":area_type", AREA_TYPE_ID::CAIROS_DUNGEON, SQLITE3_INTEGER);
+                $statement->bindValue(":area", $record->{"dungeon_id"}, SQLITE3_INTEGER);
+                $statement->execute();
+                $statement = $db->prepare("
+                  DELETE FROM record
+                  WHERE 
+                    uid = :uid AND
+                    area_type = :area_type AND
+                    area = :area;
+                ");
+                $statement->bindValue(":uid", $uid, SQLITE3_INTEGER);
+                $statement->bindValue(":area_type", AREA_TYPE_ID::CAIROS_DUNGEON, SQLITE3_INTEGER);
+                $statement->bindValue(":area", $record->{"dungeon_id"}, SQLITE3_INTEGER);
+                $statement->execute();
+
+                // Insert new data
+                $statement = $db->prepare("
+                  INSERT INTO record
+                    (uid, area_type, area, stage, time, score, rank)
+                  VALUES
+                    (:uid, :area_type, :area, :stage, :time, :score, :rank);
+                ");
+                $statement->bindValue(":uid", $uid, SQLITE3_INTEGER);
+                $statement->bindValue(":area_type", AREA_TYPE_ID::CAIROS_DUNGEON, SQLITE3_INTEGER);
+                $statement->bindValue(":area", $record->{"dungeon_id"}, SQLITE3_INTEGER);
+                $statement->bindValue(":area", $record->{"dungeon_id"}, SQLITE3_INTEGER);
+                $statement->bindValue(":stage", $record->{"stage_id"}, SQLITE3_INTEGER);
+                $statement->bindValue(":time", $record->{"clear_time"}, SQLITE3_INTEGER);
+                $statement->bindValue(":score", 0, SQLITE3_INTEGER);
+                $statement->bindValue(":rank", null, SQLITE3_TEXT);
+                $statement->execute();
+
+                // Loop party
+                foreach ($record->{"my_unit_deck_list"} as $party){
+                    $statement = $db->prepare("
+                      INSERT INTO record_party
+                        (uid, area_type, area, unit, k_unit, leader, front)
+                      VALUES
+                        (:uid, :area_type, :area, :unit, :k_unit, :leader, :front);
+                    ");
+                    $statement->bindValue(":uid", $uid, SQLITE3_INTEGER);
+                    $statement->bindValue(":area_type", AREA_TYPE_ID::CAIROS_DUNGEON, SQLITE3_INTEGER);
+                    $statement->bindValue(":area", $record->{"dungeon_id"}, SQLITE3_INTEGER);
+                    $statement->bindValue(":unit", $party->{"unit_id"}, SQLITE3_INTEGER);
+                    $statement->bindValue(":k_unit", $party->{"unit_master_id"}, SQLITE3_INTEGER);
+                    $statement->bindValue(":leader", $party->{"leader"}, SQLITE3_INTEGER);
+                    $statement->bindValue(":front", 0, SQLITE3_INTEGER);
+                    $statement->execute();
+                }
+            }
+
+            // Rift Raid record
+            if (sizeof($json->{"lobby_wizard_log"}->{"raid_best_clear_info_list"}) > 0){
+                $record = $json->{"lobby_wizard_log"}->{"raid_best_clear_info_list"}[0];
+
+                // Delete prevous data
+                $statement = $db->prepare("
+                  DELETE FROM record_party 
+                  WHERE 
+                    uid = :uid AND
+                    area_type = :area_type AND
+                    area = :area;
+                ");
+                $statement->bindValue(":uid", $uid, SQLITE3_INTEGER);
+                $statement->bindValue(":area_type", AREA_TYPE_ID::RIFT_RAID, SQLITE3_INTEGER);
+                $statement->bindValue(":area", $record->{"stage_id"}, SQLITE3_INTEGER);
+                $statement->execute();
+                $statement = $db->prepare("
+                  DELETE FROM record
+                  WHERE 
+                    uid = :uid AND
+                    area_type = :area_type AND
+                    area = :area;
+                ");
+                $statement->bindValue(":uid", $uid, SQLITE3_INTEGER);
+                $statement->bindValue(":area_type", AREA_TYPE_ID::RIFT_RAID, SQLITE3_INTEGER);
+                $statement->bindValue(":area", $record->{"stage_id"}, SQLITE3_INTEGER);
+                $statement->execute();
+
+                // Insert new data
+                $statement = $db->prepare("
+                  INSERT INTO record
+                    (uid, area_type, area, stage, time, score, rank)
+                  VALUES
+                    (:uid, :area_type, :area, :stage, :time, :score, :rank);
+                ");
+                $statement->bindValue(":uid", $uid, SQLITE3_INTEGER);
+                $statement->bindValue(":area_type", AREA_TYPE_ID::RIFT_RAID, SQLITE3_INTEGER);
+                $statement->bindValue(":area", $record->{"stage_id"}, SQLITE3_INTEGER);
+                $statement->bindValue(":stage", $record->{"stage_id"}, SQLITE3_INTEGER);
+                $statement->bindValue(":time", $record->{"clear_time"}, SQLITE3_TEXT);
+                $statement->bindValue(":score", 0, SQLITE3_INTEGER);
+                $statement->bindValue(":rank", null, SQLITE3_TEXT);
+                $statement->execute();
+
+                // Loop party
+                foreach ($record->{"my_unit_deck_list"} as $party){
+                    $statement = $db->prepare("
+                      INSERT INTO record_party
+                        (uid, area_type, area, unit, k_unit, leader, front)
+                      VALUES
+                        (:uid, :area_type, :area, :unit, :k_unit, :leader, :front);
+                    ");
+                    $statement->bindValue(":uid", $uid, SQLITE3_INTEGER);
+                    $statement->bindValue(":area_type", AREA_TYPE_ID::RIFT_RAID, SQLITE3_INTEGER);
+                    $statement->bindValue(":area", $record->{"stage_id"}, SQLITE3_INTEGER);
+                    $statement->bindValue(":unit", $party->{"unit_id"}, SQLITE3_INTEGER);
+                    $statement->bindValue(":k_unit", $party->{"unit_master_id"}, SQLITE3_INTEGER);
+                    $statement->bindValue(":leader", $party->{"leader"}, SQLITE3_INTEGER);
+                    if ($party->{"slot_index"} <= 4){
+                        $statement->bindValue(":front", 1, SQLITE3_INTEGER);
+                    }
+                    else{
+                        $statement->bindValue(":front", 0, SQLITE3_INTEGER);
+                    }
+                    $statement->execute();
+                }
+            }
+
+            // Loop Rift Dungeon records
+            foreach ( $json->{"lobby_wizard_log"}->{"rift_dungeon_best_clear_info_list"} as $record){
+
+                // Delete prevous data
+                $statement = $db->prepare("
+                  DELETE FROM record_party 
+                  WHERE 
+                    uid = :uid AND
+                    area_type = :area_type AND
+                    area = :area;
+                ");
+                $statement->bindValue(":uid", $uid, SQLITE3_INTEGER);
+                $statement->bindValue(":area_type", AREA_TYPE_ID::RIFT_DUNGEON, SQLITE3_INTEGER);
+                $statement->bindValue(":area", $record->{"rift_dungeon_id"}, SQLITE3_INTEGER);
+                $statement->execute();
+                $statement = $db->prepare("
+                  DELETE FROM record
+                  WHERE 
+                    uid = :uid AND
+                    area_type = :area_type AND
+                    area = :area;
+                ");
+                $statement->bindValue(":uid", $uid, SQLITE3_INTEGER);
+                $statement->bindValue(":area_type", AREA_TYPE_ID::RIFT_DUNGEON, SQLITE3_INTEGER);
+                $statement->bindValue(":area", $record->{"rift_dungeon_id"}, SQLITE3_INTEGER);
+                $statement->execute();
+
+                // Insert new data
+                $statement = $db->prepare("
+                  INSERT INTO record
+                    (uid, area_type, area, stage, time, score, rank)
+                  VALUES
+                    (:uid, :area_type, :area, :stage, :time, :score, :rank);
+                ");
+                $statement->bindValue(":uid", $uid, SQLITE3_INTEGER);
+                $statement->bindValue(":area_type", AREA_TYPE_ID::RIFT_DUNGEON, SQLITE3_INTEGER);
+                $statement->bindValue(":area", $record->{"rift_dungeon_id"}, SQLITE3_INTEGER);
+                $statement->bindValue(":stage", 0, SQLITE3_INTEGER);
+                $statement->bindValue(":time", 0, SQLITE3_INTEGER);
+                $statement->bindValue(":score", $record->{"clear_damage"}, SQLITE3_INTEGER);
+                switch (intval($record->{"clear_rating"})){
+                    case 2:
+                        $statement->bindValue(":rank", "D", SQLITE3_TEXT);
+                        break;
+                    case 3:
+                        $statement->bindValue(":rank", "C", SQLITE3_TEXT);
+                        break;
+                    case 4:
+                        $statement->bindValue(":rank", "B-", SQLITE3_TEXT);
+                        break;
+                    case 5:
+                        $statement->bindValue(":rank", "B", SQLITE3_TEXT);
+                        break;
+                    case 6:
+                        $statement->bindValue(":rank", "B+", SQLITE3_TEXT);
+                        break;
+                    case 7:
+                        $statement->bindValue(":rank", "A-", SQLITE3_TEXT);
+                        break;
+                    case 8:
+                        $statement->bindValue(":rank", "A", SQLITE3_TEXT);
+                        break;
+                    case 9:
+                        $statement->bindValue(":rank", "A+", SQLITE3_TEXT);
+                        break;
+                    case 10:
+                        $statement->bindValue(":rank", "S", SQLITE3_TEXT);
+                        break;
+                    case 11:
+                        $statement->bindValue(":rank", "SS", SQLITE3_TEXT);
+                        break;
+                    case 12:
+                        $statement->bindValue(":rank", "SS", SQLITE3_TEXT);
+                        break;
+                    default:
+                        $statement->bindValue(":rank", "F", SQLITE3_TEXT);
+                }
+                $statement->execute();
+
+                // Loop party
+                foreach ($record->{"my_unit_deck_list"} as $party){
+                    $statement = $db->prepare("
+                      INSERT INTO record_party
+                        (uid, area_type, area, unit, k_unit, leader, front)
+                      VALUES
+                        (:uid, :area_type, :area, :unit, :k_unit, :leader, :front);
+                    ");
+                    $statement->bindValue(":uid", $uid, SQLITE3_INTEGER);
+                    $statement->bindValue(":area_type", AREA_TYPE_ID::RIFT_DUNGEON, SQLITE3_INTEGER);
+                    $statement->bindValue(":area", $record->{"rift_dungeon_id"}, SQLITE3_INTEGER);
+                    $statement->bindValue(":unit", $party->{"unit_id"}, SQLITE3_INTEGER);
+                    $statement->bindValue(":k_unit", $party->{"unit_master_id"}, SQLITE3_INTEGER);
+                    $statement->bindValue(":leader", $party->{"leader"}, SQLITE3_INTEGER);
+                    if ($party->{"slot_index"} <= 4){
+                        $statement->bindValue(":front", 1, SQLITE3_INTEGER);
+                    }
+                    else{
+                        $statement->bindValue(":front", 0, SQLITE3_INTEGER);
+                    }
+                    $statement->execute();
+                }
+            }
+        }
+
+        # Page 2: Cairos non-elemental, rift raid, rift dungeon.
+        elseif (intval($json->{"lobby_wizard_log"}->{"page_no"} == 2)){
+            // Loop Cairos records
+            foreach ($json->{"lobby_wizard_log"}->{"dungeon_best_clear_info_list"} as $record){
+                // Delete prevous data
+                $statement = $db->prepare("
+                  DELETE FROM record_party
+                  WHERE 
+                    uid = :uid AND
+                    area_type = :area_type AND
+                    area = :area;
+                ");
+                $statement->bindValue(":uid", $uid, SQLITE3_INTEGER);
+                $statement->bindValue(":area_type", AREA_TYPE_ID::CAIROS_DUNGEON, SQLITE3_INTEGER);
+                $statement->bindValue(":area", $record->{"dungeon_id"}, SQLITE3_INTEGER);
+                $statement->execute();
+                $statement = $db->prepare("
+                  DELETE FROM record
+                  WHERE 
+                    uid = :uid AND
+                    area_type = :area_type AND
+                    area = :area;
+                ");
+                $statement->bindValue(":uid", $uid, SQLITE3_INTEGER);
+                $statement->bindValue(":area_type", AREA_TYPE_ID::CAIROS_DUNGEON, SQLITE3_INTEGER);
+                $statement->bindValue(":area", $record->{"dungeon_id"}, SQLITE3_INTEGER);
+                $statement->execute();
+
+                // Insert new data
+                $statement = $db->prepare("
+                  INSERT INTO record
+                    (uid, area_type, area, stage, time, score, rank)
+                  VALUES
+                    (:uid, :area_type, :area, :stage, :time, :score, :rank);
+                ");
+                $statement->bindValue(":uid", $uid, SQLITE3_INTEGER);
+                $statement->bindValue(":area_type", AREA_TYPE_ID::CAIROS_DUNGEON, SQLITE3_INTEGER);
+                $statement->bindValue(":area", $record->{"dungeon_id"}, SQLITE3_INTEGER);
+                $statement->bindValue(":area", $record->{"dungeon_id"}, SQLITE3_INTEGER);
+                $statement->bindValue(":stage", $record->{"stage_id"}, SQLITE3_INTEGER);
+                $statement->bindValue(":time", $record->{"clear_time"}, SQLITE3_INTEGER);
+                $statement->bindValue(":score", 0, SQLITE3_INTEGER);
+                $statement->bindValue(":rank", null, SQLITE3_TEXT);
+                $statement->execute();
+
+                // Loop party
+                foreach ($record->{"my_unit_deck_list"} as $party){
+                    $statement = $db->prepare("
+                      INSERT INTO record_party
+                        (uid, area_type, area, unit, k_unit, leader, front)
+                      VALUES
+                        (:uid, :area_type, :area, :unit, :k_unit, :leader, :front);
+                    ");
+                    $statement->bindValue(":uid", $uid, SQLITE3_INTEGER);
+                    $statement->bindValue(":area_type", AREA_TYPE_ID::CAIROS_DUNGEON, SQLITE3_INTEGER);
+                    $statement->bindValue(":area", $record->{"dungeon_id"}, SQLITE3_INTEGER);
+                    $statement->bindValue(":unit", $party->{"unit_id"}, SQLITE3_INTEGER);
+                    $statement->bindValue(":k_unit", $party->{"unit_master_id"}, SQLITE3_INTEGER);
+                    $statement->bindValue(":leader", $party->{"leader"}, SQLITE3_INTEGER);
+                    $statement->bindValue(":front", 0, SQLITE3_INTEGER);
+                    $statement->execute();
+                }
+            }
+        }
+        elseif (intval($json->{"lobby_wizard_log"}->{"page_no"}) == 3){
+            return "204 Page not logged (only pages 1 and 2 are needed).";
+        }
+        elseif (intval($json->{"lobby_wizard_log"}->{"page_no"}) == 4){
+            return "204 Page not logged (only pages 1 and 2 are needed).";
+        }
+        else{
+            return "400 Unknown page.";
+        }
+
+        // Return success
+        return "201 Created.";
+    }
+
+    try{
+
+        header("Content-type: application/json; charset=utf-8");
+
+        // Get put data
+        $_PUT = [];
+        parse_str(file_get_contents("php://input"), $_PUT);
+
+        // Check API key.
+        $key = $_PUT["key"];
+        if ($key == null || $key == false){
+            header("HTTP/1.1 400 API key not received.");
+            syslog(LOG_INFO, "[APIv3] HTTP/1.1 400 API key not received.");
+            return 400;
+        }
+
+        // Check data
+        $data = $_PUT["response"];
+        if ($data == null || $data == false){
+            header("HTTP/1.1 400 No data received.");
+            syslog(LOG_INFO, "[APIv3] HTTP/1.1 400 No data received.");
+            return 400;
+        }
+
+        // Check data format.
+        $json = json_decode($data);
+        if ($json === null){
+            header("HTTP/1.1 400 Data is no valid JSON.");
+            syslog(LOG_INFO, "[APIv3] HTTP/1.1 400 Data is no valid JSON.");
+            return 400;
+        }
+
+        // Get and validate command
+        $command = $json->{"command"};
+        $accepted_commands = [
+            "HubUserLogin", // Login, full profile
+            "GetUnitCollection", // Unit collection
+            "GetLobbyWizardLog" // Records
+        ];
+        if (!in_array($command, $accepted_commands)){
+            header("HTTP/1.1 405 Command not implemented.");
+            syslog(LOG_INFO, "[APIv3] HTTP/1.1 405 Command not implemented.");
+            return 405;
+        }
+
+        // Get user info and Authenticate
+        switch ($command){
+            case "HubUserLogin":
+                $uid = $json->{"wizard_id"};
+                $statement = $db->prepare("SELECT COUNT(uid) AS c FROM player WHERE uid = :uid AND api_key = :api_key;");
+                $statement->bindValue(":uid", $uid, SQLITE3_INTEGER);
+                $statement->bindValue(":api_key", $key, SQLITE3_TEXT);
+                if (1 != $statement->execute()->fetchArray(SQLITE3_ASSOC)["c"]){
+                    header("HTTP/1.1 401 Invalid credentials.");
+                    syslog(LOG_INFO, "[APIv3] HTTP/1.1 401 Invalid credentials.");
+                    return 401;
+                }
+                break;
+            case "GetUnitCollection":
+                // No identification in this JSON, get uid from databases
+                $statement = $db->prepare("SELECT uid FROM player WHERE api_key = :api_key;");
+                $statement->bindValue(":api_key", $key, SQLITE3_TEXT);
+                $r = $statement->execute()->fetchArray(SQLITE3_ASSOC);
+                if ($r){
+                    $uid = $r["uid"];
+                }
+                else{
+                    header("HTTP/1.1 401 Invalid credentials.");
+                    syslog(LOG_INFO, "[APIv3] HTTP/1.1 401 Invalid credentials.");
+                    return 401;
+                }
+                break;
+            case "GetLobbyWizardLog":
+                $uid = $json->{"lobby_wizard_log"}->{"wizard_id"};
+                $statement = $db->prepare("SELECT COUNT(uid) AS c FROM player WHERE uid = :uid AND api_key = :api_key;");
+                $statement->bindValue(":uid", $uid, SQLITE3_INTEGER);
+                $statement->bindValue(":api_key", $key, SQLITE3_TEXT);
+                if (1 != $statement->execute()->fetchArray(SQLITE3_ASSOC)["c"]){
+                    header("HTTP/1.1 401 Invalid credentials.");
+                    syslog(LOG_INFO, "[APIv3] HTTP/1.1 401 Invalid credentials.");
+                    return 401;
+                }
+                break;
+        }
+        if ($command == "GetUnitCollection"){ // This command doesnt provide wizard_id
+            $statement = $db->prepare("SELECT COUNT(uid) AS c FROM player WHERE uid = :uid AND api_key = :api_key;");
+            $statement->bindValue(":uid", $uid, SQLITE3_INTEGER);
+            $statement->bindValue(":api_key", $key, SQLITE3_TEXT);
+            if (1 != $statement->execute()->fetchArray(SQLITE3_ASSOC)["c"]){
+                header("HTTP/1.1 401 Invalid credentials.");
+                syslog(LOG_INFO, "[APIv3] HTTP/1.1 401 Invalid credentials.");
+                return 401;
+            }
+        }
+
+        // Run parser
+        $result = "500 Unknown Error";
+        switch($command){
+            case "HubUserLogin":
+                $result = parse_profile($db, $uid, $json);
+                break;
+            case "GetUnitCollection":
+                $result = parse_collection($db, $uid, $json);
+                break;
+            case "GetLobbyWizardLog":
+                $result = parse_records($db, $uid, $json);
+                break;
+        }
+
+        // Process result
+        $status_code = intval(substr($result, 0, 3));
+        $status_message = substr($result, 4);
+        if ($status_code == 0 || $status_code < 100 || $status_code > 599){
+            header("HTTP/1.1 500 Unknown error.");
+            syslog(LOG_ERR, "[APIv3] HTTP/1.1 500 Unknown error.");
+            return 500;
+        }
+        else{
+            header("HTTP/1.1 $status_code $status_message");
+            syslog(LOG_INFO, "[APIv3] HTTP/1.1 $status_code $status_message");
+            return $status_code;
+        }
+    }
+    catch(Exception $e) {
+        header("HTTP/1.1 500 Unexpeced error: " . $e->getMessage());
+        syslog(LOG_INFO, "[APIv3] HTTP/1.1 500 Unexpected error: " . $e->getMessage());
+        return 500;
+    }
+?>

+ 1469 - 0
application/API/v3/run/POST.php

@@ -0,0 +1,1469 @@
+<?php
+    /**
+     * Run logger script.
+     *
+     * Exposes an API to log a run.
+     *
+     * Mandatory PUT parameters are:
+     *  - result_response: JSON received from game server on run end.
+     *  - key: User API key.
+     *
+     * Optional POST parameters are:
+     *  - result_request: JSON sent to game server on run end.
+     *  - start_response: JSON received from game server on run start.
+     *  - start_request: JSON sent to game server on run start.
+     *
+     * @category API
+     */
+
+    /**
+     * Calculates the currrent efficiency of a rune.
+     *
+     * @param mixed[] $rune JSON fragment of the rune.
+     * @return int Efficiency (0-100)
+     */
+    function calculate_efficiency($rune){
+        $efficiency = 0.0;
+        $level = $rune->{"upgrade_curr"};
+        $stars = $rune->{"class"};
+        // Ancient stars are + 10
+        if ($stars > 10){
+            $stars -= 10;
+        }
+        $list = null;
+        // Main stat
+        $main_stat = $rune->{"pri_eff"}[0];
+        switch ($main_stat){
+            case RUNE_STAT_ID::HP:
+                $list = RUNE_STAT_VALUES::HP;
+                break;
+            case RUNE_STAT_ID::HP_P:
+                $list = RUNE_STAT_VALUES::HP_P;
+                break;
+            case RUNE_STAT_ID::ATK:
+                $list = RUNE_STAT_VALUES::ATK;
+                break;
+            case RUNE_STAT_ID::ATK_P:
+                $list = RUNE_STAT_VALUES::ATK_P;
+                break;
+            case RUNE_STAT_ID::DEF:
+                $list = RUNE_STAT_VALUES::DEF;
+                break;
+            case RUNE_STAT_ID::DEF_P:
+                $list = RUNE_STAT_VALUES::DEF_P;
+                break;
+            case RUNE_STAT_ID::SPD:
+                $list = RUNE_STAT_VALUES::SPD;
+                break;
+            case RUNE_STAT_ID::CRR:
+                $list = RUNE_STAT_VALUES::CRR;
+                break;
+            case RUNE_STAT_ID::CRD:
+                $list = RUNE_STAT_VALUES::CRD;
+                break;
+            case RUNE_STAT_ID::ACC:
+                $list = RUNE_STAT_VALUES::ACC;
+                break;
+            case RUNE_STAT_ID::RES:
+                $list = RUNE_STAT_VALUES::RES;
+                break;
+        }
+        $efficiency += floatval($list[$stars][$level]) / floatval($list[6][15]);
+        // Innate stat
+        if ($rune->{"prefix_eff"}[0] > 0){
+            $innate_stat = $rune->{"pri_eff"}[0];
+            $innate_stat_value = $rune->{"pri_eff"}[1];
+            $efficiency += floatval($innate_stat_value) / (5 * floatval(RUNE_SUBSTAT_MAX_VALUES::SUBSTAT[$innate_stat][6]));
+        }
+        // Substats
+        for ($i = 0; $i <= 3; $i ++){
+            if (sizeof($rune->{"sec_eff"}) > $i){
+                $substat = $rune->{"sec_eff"}[$i][0];
+                $substat_value = $rune->{"sec_eff"}[$i][1];
+                $efficiency += floatval($substat_value) / (5 * floatval(RUNE_SUBSTAT_MAX_VALUES::SUBSTAT[$substat][6]));
+            }
+        }
+        $efficiency = $efficiency / 2.8 * 100;
+        if ($efficiency > 100){
+            $efficiency = 100;
+        }
+        return $efficiency;
+    }
+
+    /**
+     * Calculates the maximum efficiency of a rune.
+     *
+     * @param mixed[] $rune JSON fragment of the rune.
+     * @return int Maximum efficiency (0-100)
+     */
+    function calculate_maximum_efficiency($rune){
+        $efficiency = 0.0;
+        $stars = $rune->{"class"};
+        // Ancient stars are + 10
+        if ($stars > 10){
+            $stars -= 10;
+        }
+        $list = null;
+        // Main stat
+        $main_stat = $rune->{"pri_eff"}[0];
+        switch ($main_stat){
+            case RUNE_STAT_ID::HP:
+                $list = RUNE_STAT_VALUES::HP;
+                break;
+            case RUNE_STAT_ID::HP_P:
+                $list = RUNE_STAT_VALUES::HP_P;
+                break;
+            case RUNE_STAT_ID::ATK:
+                $list = RUNE_STAT_VALUES::ATK;
+                break;
+            case RUNE_STAT_ID::ATK_P:
+                $list = RUNE_STAT_VALUES::ATK_P;
+                break;
+            case RUNE_STAT_ID::DEF:
+                $list = RUNE_STAT_VALUES::DEF;
+                break;
+            case RUNE_STAT_ID::DEF_P:
+                $list = RUNE_STAT_VALUES::DEF_P;
+                break;
+            case RUNE_STAT_ID::SPD:
+                $list = RUNE_STAT_VALUES::SPD;
+                break;
+            case RUNE_STAT_ID::CRR:
+                $list = RUNE_STAT_VALUES::CRR;
+                break;
+            case RUNE_STAT_ID::CRD:
+                $list = RUNE_STAT_VALUES::CRD;
+                break;
+            case RUNE_STAT_ID::ACC:
+                $list = RUNE_STAT_VALUES::ACC;
+                break;
+            case RUNE_STAT_ID::RES:
+                $list = RUNE_STAT_VALUES::RES;
+                break;
+        }
+        $efficiency += floatval($list[$stars][15]) / floatval($list[6][15]);
+        // Innate stat
+        if ($rune->{"prefix_eff"}[0] > 0){
+            $innate_stat = $rune->{"pri_eff"}[0];
+            $innate_stat_value = $rune->{"pri_eff"}[1];
+            $efficiency += floatval($innate_stat_value) / (5 * floatval(RUNE_SUBSTAT_MAX_VALUES::SUBSTAT[$innate_stat][6]));
+        }
+        // Substats
+        for ($i = 0; $i <= 3; $i ++){
+            if (sizeof($rune->{"sec_eff"}) > $i){
+                $substat = $rune->{"sec_eff"}[$i][0];
+                $efficiency += floatval(RUNE_SUBSTAT_MAX_VALUES::SUBSTAT[$substat][$stars]) / (5 * floatval(RUNE_SUBSTAT_MAX_VALUES::SUBSTAT[$substat][6]));
+            }
+        }
+        $efficiency = $efficiency / 2.8 * 100;
+        if ($efficiency > 100){
+            $efficiency = 100;
+        }
+        return $efficiency;
+    }
+
+    /**
+     * Parses the JSONs relateds to an Arena run and saves the data.
+     *
+     * @param resource $db Database connection.
+     * @param int $uid Player UID.
+     * @param int $id Run ID.
+     * @param mixed[] $json List of received JSONs.
+     */
+    function log_arena_run($db, $id, $uid, $json){
+        // Only the result request and response JSONs are needed:
+        $response = $json["result_res"];
+
+        // Prepare the "run" insert.
+        $statement = $db->prepare("
+          INSERT INTO run (
+            uid,
+            id,
+            dtime,
+            area_type,
+            area,
+            stage,
+            difficulty,
+            win,
+            time,
+            mana,
+            energy,
+            crystal,
+            guild_points,
+            honor_points,
+            helper,
+            score,
+            rank
+          ) VALUES (
+            :uid,
+            :id,
+            :dtime,
+            :area_type,
+            :area,
+            :stage,
+            :difficulty,
+            :win,
+            :time,
+            :mana,
+            :energy,
+            :crystal,
+            :guild_points,
+            :honor_points,
+            :helper,
+            :score,
+            :rank
+          );
+        ");
+
+        // Bind data and insert
+        $statement->bindValue(":uid", $uid, SQLITE3_INTEGER);
+        $statement->bindValue(":id", $id, SQLITE3_INTEGER);
+        $statement->bindValue(":dtime", $response->{"tvaluelocal"}, SQLITE3_TEXT);
+        $statement->bindValue(":area_type", AREA_TYPE_ID::ARENA, SQLITE3_INTEGER);
+        $statement->bindValue(":area", AREA_TYPE_ID::ARENA, SQLITE3_INTEGER);
+        $statement->bindValue(":stage", null, SQLITE3_INTEGER);
+        $statement->bindValue(":difficulty", null, SQLITE3_INTEGER);
+        $statement->bindValue(":win", $response->{"win_lose"}, SQLITE3_INTEGER);
+        $statement->bindValue(":time", 1, SQLITE3_INTEGER);
+        if (array_key_exists("mana", $response->{"reward"})){
+            $statement->bindValue(":mana", $response->{"reward"}->{"mana"}, SQLITE3_INTEGER);
+        }
+        else{
+            $statement->bindValue(":mana", 0, SQLITE3_INTEGER);
+        }
+        if (array_key_exists("energy", $response->{"reward"})){
+            $statement->bindValue(":energy", $response->{"reward"}->{"energy"}, SQLITE3_INTEGER);
+        }
+        else{
+            $statement->bindValue(":energy", 0, SQLITE3_INTEGER);
+        }
+        if (array_key_exists("crystal", $response->{"reward"})){
+            $statement->bindValue(":crystal", $response->{"reward"}->{"crystal"}, SQLITE3_INTEGER);
+        }
+        else{
+            $statement->bindValue(":crystal", 0, SQLITE3_INTEGER);
+        }
+        $statement->bindValue(":guild_points", 0, SQLITE3_INTEGER);
+        if (array_key_exists("honor_point", $response->{"reward"})){
+            $statement->bindValue(":honor_points", $response->{"reward"}->{"honor_point"}, SQLITE3_INTEGER);
+        }
+        else{
+            $statement->bindValue(":honor_points", 0, SQLITE3_INTEGER);
+        }
+        $statement->bindValue(":helper", 0, SQLITE3_INTEGER);
+        $statement->bindValue(":score", null, SQLITE3_INTEGER);
+        $statement->bindValue(":rank", null, SQLITE3_TEXT);
+        $statement->execute();
+
+        // Parse party
+        $leader = 1;
+        foreach ($response->{"unit_list"} as $unit){
+            $statement = $db->prepare("
+              INSERT INTO run_party 
+                (run, unit, k_unit, leader, front)
+              VALUES
+                (:run, :unit, :k_unit, :leader, :front);"
+            );
+            $statement->bindValue(":run", $id, SQLITE3_INTEGER);
+            $statement->bindValue(":unit", $unit->{"unit_id"}, SQLITE3_INTEGER);
+            $statement->bindValue(":k_unit", $unit->{"unit_master_id"}, SQLITE3_INTEGER);
+            $statement->bindValue(":leader", $leader, SQLITE3_INTEGER);
+            $leader = 0;
+            $statement->bindValue(":front", 0, SQLITE3_INTEGER);
+            $statement->execute();
+        }
+
+        // Return success
+        return "201 Created.";
+    }
+
+    /**
+     * Parses the JSONs relateds to a Dimensional Rift run and saves the data.
+     *
+     * @param resource $db Database connection.
+     * @param int $uid Player UID.
+     * @param int $id Run ID.
+     * @param mixed[] $json List of received JSONs.
+     */
+    function log_dark_portal_run($db, $id, $uid, $json){
+        // Only the result request and response JSONs are needed:
+        $response = $json["result_res"];
+
+        // Prepare the "run" insert.
+        $statement = $db->prepare("
+          INSERT INTO run (
+            uid,
+            id,
+            dtime,
+            area_type,
+            area,
+            stage,
+            difficulty,
+            win,
+            time,
+            mana,
+            energy,
+            crystal,
+            guild_points,
+            honor_points,
+            helper,
+            score,
+            rank
+          ) VALUES (
+            :uid,
+            :id,
+            :dtime,
+            :area_type,
+            :area,
+            :stage,
+            :difficulty,
+            :win,
+            :time,
+            :mana,
+            :energy,
+            :crystal,
+            :guild_points,
+            :honor_points,
+            :helper,
+            :score,
+            :rank
+          );
+        ");
+
+        // Bind data and insert
+        $statement->bindValue(":uid", $uid, SQLITE3_INTEGER);
+        $statement->bindValue(":id", $id, SQLITE3_INTEGER);
+        $statement->bindValue(":dtime", $response->{"tvaluelocal"}, SQLITE3_INTEGER);
+        $statement->bindValue(":area_type", AREA_TYPE_ID::DIMENSIONAL_RIFT, SQLITE3_INTEGER);
+        // The area is the region the portal is open in.
+        $statement->bindValue(":area", $response->{"region_id"}, SQLITE3_INTEGER);
+        $statement->bindValue(":stage", null, SQLITE3_INTEGER);
+        $statement->bindValue(":difficulty", $response->{"difficulty"}, SQLITE3_INTEGER);
+        $statement->bindValue(":win", $response->{"win_lose"}, SQLITE3_INTEGER);
+        $statement->bindValue(":time", 1, SQLITE3_INTEGER);
+        if (array_key_exists("mana", $response->{"reward"})){
+            $statement->bindValue(":mana", $response->{"reward"}->{"mana"}, SQLITE3_INTEGER);
+        }
+        else{
+            $statement->bindValue(":mana", 0, SQLITE3_INTEGER);
+        }
+        if (array_key_exists("energy", $response->{"reward"})){
+            $statement->bindValue(":energy", $response->{"reward"}->{"energy"});
+        }
+        else{
+            $statement->bindValue(":energy", 0);
+        }
+        if (array_key_exists("crystal", $response->{"reward"})){
+            $statement->bindValue(":crystal", $response->{"reward"}->{"crystal"}, SQLITE3_INTEGER);
+        }
+        else{
+            $statement->bindValue(":crystal", 0, SQLITE3_INTEGER);
+        }
+        $statement->bindValue(":guild_points", 0, SQLITE3_INTEGER);
+        $statement->bindValue(":honor_points", 0, SQLITE3_INTEGER);
+        $statement->bindValue(":helper", 0, SQLITE3_INTEGER);
+        $statement->bindValue(":score", null, SQLITE3_INTEGER);
+        $statement->bindValue(":rank", null, SQLITE3_TEXT);
+        $statement->execute();
+
+        // Parse party
+        $leader = 1;
+        foreach ($response->{"unit_list"} as $unit){
+            $statement = $db->prepare("
+              INSERT INTO run_party 
+                (run, unit, k_unit, leader, front)
+              VALUES
+                (:run, :unit, :k_unit, :leader, :front);"
+            );
+            $statement->bindValue(":run", $id, SQLITE3_INTEGER);
+            $statement->bindValue(":unit", $unit->{"unit_id"}, SQLITE3_INTEGER);
+            $statement->bindValue(":k_unit", $unit->{"unit_master_id"}, SQLITE3_INTEGER);
+            $statement->bindValue(":leader", $leader, SQLITE3_INTEGER);
+            $leader = 0;
+            $statement->bindValue(":front", 0, SQLITE3_INTEGER);
+            $statement->execute();
+        }
+
+        // Return success
+        return "201 Created.";
+    }
+
+    /**
+     * Parses the JSONs relateds to a scenario run and saves the data.
+     *
+     * @param resource $db Database connection.
+     * @param int $uid Player UID.
+     * @param int $id Run ID.
+     * @param mixed[] $json List of received JSONs.
+     */
+    function log_scenario_run($db, $id, $uid, $json){
+        // Only the result request and response JSONs are needed:
+        $response = $json["result_res"];
+
+        if ($json["start_res"] === null){
+            return ("400 Start response is required to parse scenario runs.");
+        }
+        $request = $json["start_res"];
+
+        // Prepare the "run" insert.
+        $statement = $db->prepare("
+          INSERT INTO run (
+            uid,
+            id,
+            dtime,
+            area_type,
+            area,
+            stage,
+            difficulty,
+            win,
+            time,
+            mana,
+            energy,
+            crystal,
+            guild_points,
+            honor_points,
+            helper,
+            score,
+            rank
+          ) VALUES (
+            :uid,
+            :id,
+            :dtime,
+            :area_type,
+            :area,
+            :stage,
+            :difficulty,
+            :win,
+            :time,
+            :mana,
+            :energy,
+            :crystal,
+            :guild_points,
+            :honor_points,
+            :helper,
+            :score,
+            :rank
+          );
+        ");
+
+        // Bind data and insert
+        $statement->bindValue(":uid", $uid, SQLITE3_INTEGER);
+        $statement->bindValue(":id", $id, SQLITE3_INTEGER);
+        $statement->bindValue(":dtime", $response->{"tvaluelocal"}, SQLITE3_TEXT);
+        $statement->bindValue(":area_type", AREA_TYPE_ID::SCENARIO, SQLITE3_INTEGER);
+        $statement->bindValue(":area", $response->{"scenario_info"}->{"region_id"}, SQLITE3_INTEGER);
+        $statement->bindValue(":stage", $response->{"scenario_info"}->{"stage_no"}, SQLITE3_INTEGER);
+        $statement->bindValue(":difficulty", $response->{"scenario_info"}->{"difficulty"}, SQLITE3_INTEGER);
+        $statement->bindValue(":win", $response->{"win_lose"}, SQLITE3_INTEGER);
+        $statement->bindValue(":time", $response->{"clear_time"}->{"current_time"}, SQLITE3_INTEGER);
+        if (array_key_exists("mana", $response->{"reward"})){
+            $statement->bindValue(":mana", $response->{"reward"}->{"mana"}, SQLITE3_INTEGER);
+        }
+        else{
+            $statement->bindValue(":mana", 0, SQLITE3_INTEGER);
+        }
+        if (array_key_exists("energy", $response->{"reward"})){
+            $statement->bindValue(":energy", $response->{"reward"}->{"energy"}, SQLITE3_INTEGER);
+        }
+        else{
+            $statement->bindValue(":energy", 0, SQLITE3_INTEGER);
+        }
+        if (array_key_exists("crystal", $response->{"reward"})){
+            $statement->bindValue(":crystal", $response->{"reward"}->{"crystal"}, SQLITE3_INTEGER);
+        }
+        else{
+            $statement->bindValue(":crystal", 0, SQLITE3_INTEGER);
+        }
+        $statement->bindValue(":guild_points", 0, SQLITE3_INTEGER);
+        $statement->bindValue(":honor_points", 0, SQLITE3_INTEGER);
+        if (array_key_exists("helper_unit_list", $request) && sizeof($request->{"helper_unit_list"}) > 0){
+            $statement->bindValue(":helper", 1, SQLITE3_INTEGER);
+        }
+        else{
+            $statement->bindValue(":helper", 0, SQLITE3_INTEGER);
+        }
+        $statement->bindValue(":score", null, SQLITE3_INTEGER);
+        $statement->bindValue(":rank", null, SQLITE3_TEXT);
+        $statement->execute();
+
+        // Parse various types of reward
+        if (array_key_exists("crate", $response->{"reward"})){
+            $crate = $response->{"reward"}->{"crate"};
+            if (array_key_exists("unit_info", $crate)){
+                $unit = $crate->{"unit_info"};
+                $statement = $db->prepare("INSERT INTO run_drop_unit (run, unit) VALUES (:run, :unit);");
+                $statement->bindValue(":run", $id, SQLITE3_INTEGER);
+                $statement->bindValue(":unit", $unit->{"unit_master_id"}, SQLITE3_INTEGER);
+                $statement->execute();
+            }
+            if (array_key_exists("craft_stuff", $crate)){
+                $item = $crate->{"craft_stuff"};
+                $statement = $db->prepare("INSERT INTO run_drop_item (run, item, amount) VALUES (:run, :item, :amount);");
+                $statement->bindValue(":run", $id, SQLITE3_INTEGER);
+                $statement->bindValue(":item", $item->{"item_master_id"}, SQLITE3_INTEGER);
+                $statement->bindValue(":amount", $item->{"item_quantity"}, SQLITE3_INTEGER);
+                $statement->execute();
+            }
+            if (array_key_exists("random_scroll", $crate)){
+                $item = $crate->{"random_scroll"};
+                $statement = $db->prepare("INSERT INTO run_drop_item (run, item, amount) VALUES (:run, :item, :amount);");
+                $statement->bindValue(":run", $id, SQLITE3_INTEGER);
+                $statement->bindValue(":item", $item->{"item_master_id"}, SQLITE3_INTEGER);
+                $statement->bindValue(":amount", $item->{"item_quantity"}, SQLITE3_INTEGER);
+                $statement->execute();
+            }
+            if (array_key_exists("rune", $crate)){
+                $rune = $crate->{"rune"};
+                $statement = $db->prepare("
+                    INSERT INTO run_drop_rune (
+                    run,
+                    id,
+                    type,
+                    slot,
+                    stars,
+                    ancient,
+                    quality,
+                    value,
+                    efficiency,
+                    max_efficiency,
+                    main_stat,
+                    main_stat_value,
+                    innate_stat,
+                    innate_stat_value,
+                    substat_1,
+                    substat_1_value,
+                    substat_2,
+                    substat_2_value,
+                    substat_3,
+                    substat_3_value,
+                    substat_4,
+                    substat_4_value
+                    ) VALUES (
+                    :run,
+                    :id,
+                    :type,
+                    :slot,
+                    :stars,
+                    :ancient,
+                    :quality,
+                    :value,
+                    :efficiency,
+                    :max_efficiency,
+                    :main_stat,
+                    :main_stat_value,
+                    :innate_stat,
+                    :innate_stat_value,
+                    :substat_1,
+                    :substat_1_value,
+                    :substat_2,
+                    :substat_2_value,
+                    :substat_3,
+                    :substat_3_value,
+                    :substat_4,
+                    :substat_4_value
+                    );
+                ");
+                $statement->bindValue(":run", $id);
+                $statement->bindValue(":id", $rune->{"rune_id"});
+                $statement->bindValue(":type", $rune->{"set_id"});
+                $statement->bindValue(":slot", $rune->{"slot_no"});
+                $statement->bindValue(":value", $rune->{"sell_value"});
+                if ($rune->{"class"} > 10){
+                    // Ancient rune
+                    $statement->bindValue(":ancient", 1, SQLITE3_INTEGER);
+                    $statement->bindValue(":stars", intval($rune->{"class"}) - 10, SQLITE3_INTEGER);
+                    $statement->bindValue(":quality", intval($rune->{"rank"}) - 10, SQLITE3_INTEGER);
+                }
+                else{
+                    // Non Ancient rune
+                    $statement->bindValue(":ancient", 0, SQLITE3_INTEGER);
+                    $statement->bindValue(":stars", $rune->{"class"}, SQLITE3_INTEGER);
+                    $statement->bindValue(":quality", $rune->{"rank"}, SQLITE3_INTEGER);
+                }
+                $efficiency = calculate_efficiency($rune);
+                $max_efficiency = calculate_maximum_efficiency($rune);
+                $statement->bindValue(":efficiency", $efficiency, SQLITE3_FLOAT);
+                $statement->bindValue(":max_efficiency", $max_efficiency, SQLITE3_FLOAT);
+                $statement->bindValue(":main_stat", $rune->{"pri_eff"}[0], SQLITE3_INTEGER);
+                $statement->bindValue(":main_stat_value", $rune->{"pri_eff"}[1], SQLITE3_INTEGER);
+                if ($rune->{"prefix_eff"}[0] > 0){
+                    $statement->bindValue(":innate_stat", $rune->{"prefix_eff"}[0], SQLITE3_INTEGER);
+                    $statement->bindValue(":innate_stat_value", $rune->{"prefix_eff"}[1], SQLITE3_INTEGER);
+                }
+                else{
+                    $statement->bindValue(":innate_stat", null, SQLITE3_INTEGER);
+                    $statement->bindValue(":innate_stat_value", 0, SQLITE3_INTEGER);
+                }
+                if (sizeof($rune->{"sec_eff"}) > 0){
+                    $statement->bindValue(":substat_1", $rune->{"sec_eff"}[0][0], SQLITE3_INTEGER);
+                    $statement->bindValue(":substat_1_value", $rune->{"sec_eff"}[0][1], SQLITE3_INTEGER);
+                }
+                else{
+                    $statement->bindValue(":substat_1", null, SQLITE3_INTEGER);
+                    $statement->bindValue(":substat_1_value", 0, SQLITE3_INTEGER);
+                }
+                if (sizeof($rune->{"sec_eff"}) > 1){
+                    $statement->bindValue(":substat_2", $rune->{"sec_eff"}[1][0], SQLITE3_INTEGER);
+                    $statement->bindValue(":substat_2_value", $rune->{"sec_eff"}[1][1], SQLITE3_INTEGER);
+                }
+                else{
+                    $statement->bindValue(":substat_2", null, SQLITE3_INTEGER);
+                    $statement->bindValue(":substat_2_value", 0, SQLITE3_INTEGER);
+                }
+                if (sizeof($rune->{"sec_eff"}) > 2){
+                    $statement->bindValue(":substat_3", $rune->{"sec_eff"}[2][0], SQLITE3_INTEGER);
+                    $statement->bindValue(":substat_3_value", $rune->{"sec_eff"}[2][1], SQLITE3_INTEGER);
+                }
+                else{
+                    $statement->bindValue(":substat_3", null, SQLITE3_INTEGER);
+                    $statement->bindValue(":substat_3_value", 0, SQLITE3_INTEGER);
+                }
+                if (sizeof($rune->{"sec_eff"}) > 3){
+                    $statement->bindValue(":substat_4", $rune->{"sec_eff"}[3][0], SQLITE3_INTEGER);
+                    $statement->bindValue(":substat_4_value", $rune->{"sec_eff"}[3][1], SQLITE3_INTEGER);
+                }
+                else{
+                    $statement->bindValue(":substat_4", null, SQLITE3_INTEGER);
+                    $statement->bindValue(":substat_4_value", 0, SQLITE3_INTEGER);
+                }
+                $statement->execute();
+            }
+        }
+
+        // Parse party
+        $leader = 1;
+        foreach ($response->{"unit_list"} as $unit){
+            $statement = $db->prepare("
+              INSERT INTO run_party 
+                (run, unit, k_unit, leader, front)
+              VALUES
+                (:run, :unit, :k_unit, :leader, :front);"
+            );
+            $statement->bindValue(":run", $id, SQLITE3_INTEGER);
+            $statement->bindValue(":unit", $unit->{"unit_id"}, SQLITE3_INTEGER);
+            $statement->bindValue(":k_unit", $unit->{"unit_master_id"}, SQLITE3_INTEGER);
+            $statement->bindValue(":leader", $leader, SQLITE3_INTEGER);
+            $leader = 0;
+            $statement->bindValue(":front", 0, SQLITE3_INTEGER);
+            $statement->execute();
+        }
+
+        // Return success
+        return "201 Created.";
+    }
+
+    /**
+     * Parses the JSONs relateds to a cairos run and saves the data.
+     *
+     * @param resource $db Database connection.
+     * @param int $uid Player UID.
+     * @param int $id Run ID.
+     * @param mixed[] $json List of received JSONs.
+     */
+    function log_rift_raid_run($db, $id, $uid, $json){
+        // Only the start and result requests JSONs are needed:
+        $result = $json["result_res"];
+        if ($json["start_res"] === null){
+            return ("400 Start response is required to parse Rift Raid runs.");
+        }
+        $start = $json["start_res"];
+
+        // Prepare the "run" insert.
+        $statement = $db->prepare("
+          INSERT INTO run (
+            uid,
+            id,
+            dtime,
+            area_type,
+            area,
+            stage,
+            difficulty,
+            win,
+            time,
+            mana,
+            energy,
+            crystal,
+            guild_points,
+            honor_points,
+            helper,
+            score,
+            rank
+          ) VALUES (
+            :uid,
+            :id,
+            :dtime,
+            :area_type,
+            :area,
+            :stage,
+            :difficulty,
+            :win,
+            :time,
+            :mana,
+            :energy,
+            :crystal,
+            :guild_points,
+            :honor_points,
+            :helper,
+            :score,
+            :rank
+          );
+        ");
+
+        // Bind data and insert
+        $statement->bindValue(":uid", $uid, SQLITE3_INTEGER);
+        $statement->bindValue(":id", $id, SQLITE3_INTEGER);
+        $statement->bindValue(":dtime", $result->{"tvaluelocal"}, SQLITE3_TEXT);
+        $statement->bindValue(":area_type", AREA_TYPE_ID::RIFT_RAID, SQLITE3_INTEGER);
+        $statement->bindValue(":area", AREA_TYPE_ID::RIFT_RAID, SQLITE3_INTEGER);
+        $statement->bindValue(":stage", $start->{"battle_info"}->{"stage_id"}, SQLITE3_INTEGER);
+        $statement->bindValue(":difficulty", null, SQLITE3_INTEGER);
+        $statement->bindValue(":win", $result->{"win_lose"}, SQLITE3_INTEGER);
+        if ($result->{"win_lose"} == 1){
+            $statement->bindValue(":time", $result->{"clear_time"}->{"current_time"}, SQLITE3_TEXT);
+        }
+        else{
+            $statement->bindValue(":time", 1, SQLITE3_INTEGER);
+        }
+        $statement->bindValue(":mana", 0, SQLITE3_INTEGER); // If reward is mana, i will be updated later
+        $statement->bindValue(":energy", 0, SQLITE3_INTEGER);
+        $statement->bindValue(":crystal", 0, SQLITE3_INTEGER);
+        $statement->bindValue(":guild_points", 0, SQLITE3_INTEGER);
+        $statement->bindValue(":honor_points", 0, SQLITE3_INTEGER);
+        $statement->bindValue(":helper", 0, SQLITE3_INTEGER);
+        $statement->bindValue(":score", null, SQLITE3_INTEGER);
+        $statement->bindValue(":rank", null, SQLITE3_TEXT);
+        $statement->execute();
+
+        // Parse various types of reward
+        if ($result->{"win_lose"} == 1 && array_key_exists("battle_reward_list", $result)){
+            foreach ($result->{"battle_reward_list"} as $reward_list){
+                if ($reward_list->{"wizard_id"} == $uid){
+                    $reward = $reward_list->{"reward_list"}[0];
+                    $reward_type = $reward->{"item_master_type"};
+                    switch ($reward_type){
+                        case INVENTORY_TYPE_ID::MONSTER: // Unit
+                            $statement = $db->prepare("INSERT INTO run_drop_unit (run, unit) VALUES (:run, :unit);");
+                            $statement->bindValue(":run", $id, SQLITE3_INTEGER);
+                            $statement->bindValue(":unit", $reward->{"item_master_id"}, SQLITE3_INTEGER);
+                            $statement->execute();
+                            break;
+                        case INVENTORY_TYPE_ID::SCROLL:
+                        case INVENTORY_TYPE_ID::ESSENCES:
+                            $statement = $db->prepare("INSERT INTO run_drop_item (run, item, amount) VALUES (:run, :item, :amount);");
+                            $statement->bindValue(":run", $id, SQLITE3_INTEGER);
+                            $statement->bindValue(":item", $reward->{"item_master_id"}, SQLITE3_INTEGER);
+                            $statement->bindValue(":amount", $reward->{"item_quantity"}, SQLITE3_INTEGER);
+                            $statement->execute();
+                            break;
+                        case INVENTORY_TYPE_ID::ENCHANTMENT:
+                            $statement = $db->prepare("
+                              INSERT INTO run_drop_enchantment (run, id, type, quality, rune, stat, value) 
+                              VALUES (:run, :id, :type, :quality, :rune, :stat, :value);
+                            ");
+                            $statement->bindValue(":run", $id, SQLITE3_INTEGER);
+                            $statement->bindValue(":id", $reward->{"runecraft_item_id"}, SQLITE3_INTEGER);
+                            $statement->bindValue(":type", $reward->{"runecraft_type"}, SQLITE3_INTEGER);
+                            $statement->bindValue(":quality", $reward->{"runecraft_rank"}, SQLITE3_INTEGER);
+                            $statement->bindValue(":rune", $reward->{"runecraft_set_id"}, SQLITE3_INTEGER);
+                            $statement->bindValue(":stat", $reward->{"runecraft_effect_id"}, SQLITE3_INTEGER);
+                            $statement->bindValue(":value", 0, SQLITE3_INTEGER);
+                            $statement->execute();
+                            break;
+                        case 102: //: Mana
+                            $statement = $db->prepare("UPDATE run SET mana = :mana WHERE run = :run;");
+                            $statement->bindValue(":run", $id, SQLITE3_INTEGER);
+                            $statement->bindValue(":id", $reward->{"runecraft_item_id"}, SQLITE3_INTEGER);
+                            $statement->execute();
+                            break;
+                    }
+                }
+            }
+        }
+
+        // Parse party
+        foreach ($start->{"battle_info"}->{"user_list"} as $user){
+            if ($user->{"wizard_id"} == $uid){
+                foreach ($user->{"deck_list"} as $unit){
+                    $statement = $db->prepare("
+                      INSERT INTO run_party 
+                        (run, unit, k_unit, leader, front)
+                      VALUES
+                        (:run, :unit, :k_unit, :leader, :front);"
+                    );
+                    $statement->bindValue(":run", $id, SQLITE3_INTEGER);
+                    $statement->bindValue(":unit", $unit->{"unit_info"}->{"unit_id"}, SQLITE3_INTEGER);
+                    $statement->bindValue(":k_unit", $unit->{"unit_info"}->{"unit_master_id"}, SQLITE3_INTEGER);
+                    $statement->bindValue(":leader", $unit->{"leader"}, SQLITE3_INTEGER);
+                    if (intval($unit->{"index"}) <= 4){
+                        $statement->bindValue(":front", 1, SQLITE3_INTEGER);
+                    }
+                    else{
+                        $statement->bindValue(":front", 0, SQLITE3_INTEGER);
+                    }
+                    $statement->execute();
+                }
+            }
+        }
+
+        // Return success
+        return "201 Created.";
+    }
+
+    /**
+     * Parses the JSONs relateds to a cairos run and saves the data.
+     *
+     * @param resource $db Database connection.
+     * @param int $uid Player UID.
+     * @param int $id Run ID.
+     * @param mixed[] $json List of received JSONs.
+     */
+    function log_cairos_run($db, $id, $uid, $json){
+        // Only the result request and response JSONs are needed:
+        $response = $json["result_res"];
+        if ($json["result_req"] === null){
+            return ("400 Result request is required to parse Cairos runs.");
+        }
+        $request = $json["result_req"];
+
+        // Prepare the "run" insert.
+        $statement = $db->prepare("
+          INSERT INTO run (
+            uid,
+            id,
+            dtime,
+            area_type,
+            area,
+            stage,
+            difficulty,
+            win,
+            time,
+            mana,
+            energy,
+            crystal,
+            guild_points,
+            honor_points,
+            helper,
+            score,
+            rank
+          ) VALUES (
+            :uid,
+            :id,
+            :dtime,
+            :area_type,
+            :area,
+            :stage,
+            :difficulty,
+            :win,
+            :time,
+            :mana,
+            :energy,
+            :crystal,
+            :guild_points,
+            :honor_points,
+            :helper,
+            :score,
+            :rank
+          );
+        ");
+
+        // Bind data and insert
+        $statement->bindValue(":uid", $uid, SQLITE3_INTEGER);
+        $statement->bindValue(":id", $id, SQLITE3_INTEGER);
+        $statement->bindValue(":dtime", $response->{"tvaluelocal"}, SQLITE3_TEXT);
+        $statement->bindValue(":area_type", AREA_TYPE_ID::CAIROS_DUNGEON, SQLITE3_INTEGER);
+        $statement->bindValue(":area", $request->{"dungeon_id"}, SQLITE3_INTEGER);
+        $statement->bindValue(":stage", $request->{"stage_id"}, SQLITE3_INTEGER);
+        $statement->bindValue(":difficulty", null, SQLITE3_INTEGER);
+        $statement->bindValue(":win", $response->{"win_lose"}, SQLITE3_INTEGER);
+        $statement->bindValue(":time", $response->{"clear_time"}->{"current_time"}, SQLITE3_INTEGER);
+        if (array_key_exists("mana", $response->{"reward"})){
+            $statement->bindValue(":mana", $response->{"reward"}->{"mana"}, SQLITE3_INTEGER);
+        }
+        else{
+            $statement->bindValue(":mana", 0, SQLITE3_INTEGER);
+        }
+        if (array_key_exists("energy", $response->{"reward"})){
+            $statement->bindValue(":energy", $response->{"reward"}->{"energy"}, SQLITE3_INTEGER);
+        }
+        else{
+            $statement->bindValue(":energy", 0, SQLITE3_INTEGER);
+        }
+        if (array_key_exists("crystal", $response->{"reward"})){
+            $statement->bindValue(":crystal", $response->{"reward"}->{"crystal"}, SQLITE3_INTEGER);
+        }
+        else{
+            $statement->bindValue(":crystal", 0, SQLITE3_INTEGER);
+        }
+        $statement->bindValue(":guild_points", 0, SQLITE3_INTEGER);
+        $statement->bindValue(":honor_points", 0, SQLITE3_INTEGER);
+        $statement->bindValue(":helper", 0, SQLITE3_INTEGER); // TODO Where is this information??
+        $statement->bindValue(":score", null, SQLITE3_INTEGER);
+        $statement->bindValue(":rank", null, SQLITE3_TEXT);
+        $statement->execute();
+
+        // Parse various types of reward
+        if (array_key_exists("changed_item_list", $response)){
+            $reward_type = $response->{"changed_item_list"}[0]->{"type"};
+            switch ($reward_type){
+                case INVENTORY_TYPE_ID::MONSTER: // Unit
+                    $statement = $db->prepare("INSERT INTO run_drop_unit (run, unit) VALUES (:run, :unit);");
+                    $statement->bindValue(":run", $id, SQLITE3_INTEGER);
+                    $statement->bindValue(":unit", $response->{"changed_item_list"}[0]->{"view"}->{"item_master_id"}, SQLITE3_INTEGER);
+                    $statement->execute();
+                    break;
+                case INVENTORY_TYPE_ID::SCROLL:
+                case INVENTORY_TYPE_ID::ESSENCES:
+                    $statement = $db->prepare("INSERT INTO run_drop_item (run, item, amount) VALUES (:run, :item, :amount);");
+                    $statement->bindValue(":run", $id, SQLITE3_INTEGER);
+                    $statement->bindValue(":item", $response->{"changed_item_list"}[0]->{"view"}->{"item_master_id"}, SQLITE3_INTEGER);
+                    $statement->bindValue(":amount", $response->{"changed_item_list"}[0]->{"view"}->{"item_quantity"}, SQLITE3_INTEGER);
+                    $statement->execute();
+                    break;
+                case INVENTORY_TYPE_ID::RUNE:
+                    $rune = $response->{"changed_item_list"}[0]->{"info"};
+                    $statement = $db->prepare("
+                      INSERT INTO run_drop_rune (
+                        run,
+                        id,
+                        type,
+                        slot,
+                        stars,
+                        ancient,
+                        quality,
+                        value,
+                        efficiency,
+                        max_efficiency,
+                        main_stat,
+                        main_stat_value,
+                        innate_stat,
+                        innate_stat_value,
+                        substat_1,
+                        substat_1_value,
+                        substat_2,
+                        substat_2_value,
+                        substat_3,
+                        substat_3_value,
+                        substat_4,
+                        substat_4_value
+                      ) VALUES (
+                        :run,
+                        :id,
+                        :type,
+                        :slot,
+                        :stars,
+                        :ancient,
+                        :quality,
+                        :value,
+                        :efficiency,
+                        :max_efficiency,
+                        :main_stat,
+                        :main_stat_value,
+                        :innate_stat,
+                        :innate_stat_value,
+                        :substat_1,
+                        :substat_1_value,
+                        :substat_2,
+                        :substat_2_value,
+                        :substat_3,
+                        :substat_3_value,
+                        :substat_4,
+                        :substat_4_value
+                      );
+                    ");
+                    $statement->bindValue(":run", $id, SQLITE3_INTEGER);
+                    $statement->bindValue(":id", $rune->{"rune_id"}, SQLITE3_INTEGER);
+                    $statement->bindValue(":type", $rune->{"set_id"}, SQLITE3_INTEGER);
+                    $statement->bindValue(":slot", $rune->{"slot_no"}, SQLITE3_INTEGER);
+                    $statement->bindValue(":value", $rune->{"sell_value"}, SQLITE3_INTEGER);
+                    if ($rune->{"class"} > 10){
+                        // Ancient rune
+                        $statement->bindValue(":ancient", 1, SQLITE3_INTEGER);
+                        $statement->bindValue(":stars", intval($rune->{"class"}) - 10, SQLITE3_INTEGER);
+                        $statement->bindValue(":quality", intval($rune->{"rank"}) - 10, SQLITE3_INTEGER);
+                    }
+                    else{
+                        // Non Ancient rune
+                        $statement->bindValue(":ancient", 0, SQLITE3_INTEGER);
+                        $statement->bindValue(":stars", $rune->{"class"}, SQLITE3_INTEGER);
+                        $statement->bindValue(":quality", $rune->{"rank"}, SQLITE3_INTEGER);
+                    }
+                    $efficiency = calculate_efficiency($rune);
+                    $max_efficiency = calculate_maximum_efficiency($rune);
+                    $statement->bindValue(":efficiency", $efficiency, SQLITE3_FLOAT);
+                    $statement->bindValue(":max_efficiency", $max_efficiency, SQLITE3_FLOAT);
+                    $statement->bindValue(":main_stat", $rune->{"pri_eff"}[0], SQLITE3_INTEGER);
+                    $statement->bindValue(":main_stat_value", $rune->{"pri_eff"}[1], SQLITE3_INTEGER);
+                    if ($rune->{"prefix_eff"}[0] > 0){
+                        $statement->bindValue(":innate_stat", $rune->{"prefix_eff"}[0], SQLITE3_INTEGER);
+                        $statement->bindValue(":innate_stat_value", $rune->{"prefix_eff"}[1], SQLITE3_INTEGER);
+                    }
+                    else{
+                        $statement->bindValue(":innate_stat", null, SQLITE3_INTEGER);
+                        $statement->bindValue(":innate_stat_value", 0, SQLITE3_INTEGER);
+                    }
+                    if (sizeof($rune->{"sec_eff"}) > 0){
+                        $statement->bindValue(":substat_1", $rune->{"sec_eff"}[0][0], SQLITE3_INTEGER);
+                        $statement->bindValue(":substat_1_value", $rune->{"sec_eff"}[0][1], SQLITE3_INTEGER);
+                    }
+                    else{
+                        $statement->bindValue(":substat_1", null, SQLITE3_INTEGER);
+                        $statement->bindValue(":substat_1_value", 0, SQLITE3_INTEGER);
+                    }
+                    if (sizeof($rune->{"sec_eff"}) > 1){
+                        $statement->bindValue(":substat_2", $rune->{"sec_eff"}[1][0]);
+                        $statement->bindValue(":substat_2_value", $rune->{"sec_eff"}[1][1]);
+                    }
+                    else{
+                        $statement->bindValue(":substat_2", null, SQLITE3_INTEGER);
+                        $statement->bindValue(":substat_2_value", 0, SQLITE3_INTEGER);
+                    }
+                    if (sizeof($rune->{"sec_eff"}) > 2){
+                        $statement->bindValue(":substat_3", $rune->{"sec_eff"}[2][0], SQLITE3_INTEGER);
+                        $statement->bindValue(":substat_3_value", $rune->{"sec_eff"}[2][1], SQLITE3_INTEGER);
+                    }
+                    else{
+                        $statement->bindValue(":substat_3", null, SQLITE3_INTEGER);
+                        $statement->bindValue(":substat_3_value", 0, SQLITE3_INTEGER);
+                    }
+                    if (sizeof($rune->{"sec_eff"}) > 3){
+                        $statement->bindValue(":substat_4", $rune->{"sec_eff"}[3][0], SQLITE3_INTEGER);
+                        $statement->bindValue(":substat_4_value", $rune->{"sec_eff"}[3][1], SQLITE3_INTEGER);
+                    }
+                    else{
+                        $statement->bindValue(":substat_4", null, SQLITE3_INTEGER);
+                        $statement->bindValue(":substat_4_value", 0, SQLITE3_INTEGER);
+                    }
+                    $statement->execute();
+                    break;
+            }
+        }
+
+        // Parse party
+        $leader = 1;
+        foreach ($response->{"unit_list"} as $unit){
+            $statement = $db->prepare("
+              INSERT INTO run_party 
+                (run, unit, k_unit, leader, front)
+              VALUES
+                (:run, :unit, :k_unit, :leader, :front);"
+            );
+            $statement->bindValue(":run", $id, SQLITE3_INTEGER);
+            $statement->bindValue(":unit", $unit->{"unit_id"}, SQLITE3_INTEGER);
+            $statement->bindValue(":k_unit", $unit->{"unit_master_id"}, SQLITE3_INTEGER);
+            $statement->bindValue(":leader", $leader, SQLITE3_INTEGER);
+            $leader = 0;
+            $statement->bindValue(":front", 0, SQLITE3_INTEGER);
+            $statement->execute();
+        }
+
+        // Return success
+        return "201 Created.";
+    }
+
+    /**
+     * Parses the JSONs relateds to a Dimension Hole run and saves the data.
+     *
+     * @param resource $db Database connection.
+     * @param int $uid Player UID.
+     * @param int $id Run ID.
+     * @param mixed[] $json List of received JSONs.
+     */
+    function log_dimension_hole_run($db, $id, $uid, $json){
+        // Only the result request and response JSONs are needed:
+        $response = $json["result_res"];
+        if ($json["result_req"] === null){
+            return ("400 Result request is required to parse Dimension Hole runs.");
+        }
+
+        // Prepare the "run" insert.
+        $statement = $db->prepare("
+          INSERT INTO run (
+            uid,
+            id,
+            dtime,
+            area_type,
+            area,
+            stage,
+            difficulty,
+            win,
+            time,
+            mana,
+            energy,
+            crystal,
+            guild_points,
+            honor_points,
+            helper,
+            score,
+            rank
+          ) VALUES (
+            :uid,
+            :id,
+            :dtime,
+            :area_type,
+            :area,
+            :stage,
+            :difficulty,
+            :win,
+            :time,
+            :mana,
+            :energy,
+            :crystal,
+            :guild_points,
+            :honor_points,
+            :helper,
+            :score,
+            :rank
+          );
+        ");
+
+        // Bind data and insert
+        $statement->bindValue(":uid", $uid, SQLITE3_INTEGER);
+        $statement->bindValue(":id", $id, SQLITE3_INTEGER);
+        $statement->bindValue(":dtime", $response->{"tvaluelocal"}, SQLITE3_TEXT);
+        $statement->bindValue(":area_type", AREA_TYPE_ID::DIMENSIONAL_HOLE, SQLITE3_INTEGER);
+        $statement->bindValue(":area", $response->{"dungeon_id"}, SQLITE3_INTEGER);
+        $statement->bindValue(":stage", $response->{"difficulty"}, SQLITE3_INTEGER); // Difficulty is stage
+        $statement->bindValue(":difficulty", null, SQLITE3_INTEGER);
+        $statement->bindValue(":win", $response->{"win_lose"}, SQLITE3_INTEGER);
+        $statement->bindValue(":time", $response->{"clear_time"}->{"current_time"}, SQLITE3_INTEGER);
+        if (array_key_exists("mana", $response->{"reward"})){
+            $statement->bindValue(":mana", $response->{"reward"}->{"mana"}, SQLITE3_INTEGER);
+        }
+        else{
+            $statement->bindValue(":mana", 0, SQLITE3_INTEGER);
+        }
+        if (array_key_exists("energy", $response->{"reward"})){
+            $statement->bindValue(":energy", $response->{"reward"}->{"energy"}, SQLITE3_INTEGER);
+        }
+        $statement->bindValue(":energy", 0, SQLITE3_INTEGER);
+        if (array_key_exists("crystal", $response->{"reward"})){
+            $statement->bindValue(":crystal", $response->{"reward"}->{"crystal"}, SQLITE3_INTEGER);
+        }
+        else{
+            $statement->bindValue(":crystal", 0, SQLITE3_INTEGER);
+        }
+        $statement->bindValue(":guild_points", 0, SQLITE3_INTEGER);
+        $statement->bindValue(":honor_points", 0, SQLITE3_INTEGER);
+        $statement->bindValue(":helper", 0, SQLITE3_INTEGER); // TODO Where is this information??
+        $statement->bindValue(":score", null, SQLITE3_INTEGER);
+        $statement->bindValue(":rank", null, SQLITE3_TEXT);
+        $statement->execute();
+
+        // Parse various types of reward
+        if (array_key_exists("changed_item_list", $response)){
+            foreach ($response->{"changed_item_list"} as $drop){
+                $reward_type = $drop->{"type"};
+                switch ($reward_type){
+                    case INVENTORY_TYPE_ID::CRAFT_STUFF:
+                        $statement = $db->prepare("INSERT INTO run_drop_item (run, item, amount) VALUES (:run, :item, :amount);");
+                        $statement->bindValue(":run", $id, SQLITE3_INTEGER);
+                        $statement->bindValue(":item", $drop->{"view"}->{"item_master_id"}, SQLITE3_INTEGER);
+                        $statement->bindValue(":amount", $drop->{"view"}->{"item_quantity"}, SQLITE3_INTEGER);
+                        $statement->execute();
+                        break;
+                    case INVENTORY_TYPE_ID::RUNE:
+                        // TODO: Investigate with no awaken dungeons
+                        /*$rune = $response->{"changed_item_list"}[0]->{"info"};
+                        $statement = $db->prepare("
+                          INSERT INTO run_drop_rune (
+                            run,
+                            id,
+                            type,
+                            slot,
+                            stars,
+                            ancient,
+                            quality,
+                            value,
+                            efficiency,
+                            max_efficiency,
+                            main_stat,
+                            main_stat_value,
+                            innate_stat,
+                            innate_stat_value,
+                            substat_1,
+                            substat_1_value,
+                            substat_2,
+                            substat_2_value,
+                            substat_3,
+                            substat_3_value,
+                            substat_4,
+                            substat_4_value
+                          ) VALUES (
+                            :run,
+                            :id,
+                            :type,
+                            :slot,
+                            :stars,
+                            :ancient,
+                            :quality,
+                            :value,
+                            :efficiency,
+                            :max_efficiency,
+                            :main_stat,
+                            :main_stat_value,
+                            :innate_stat,
+                            :innate_stat_value,
+                            :substat_1,
+                            :substat_1_value,
+                            :substat_2,
+                            :substat_2_value,
+                            :substat_3,
+                            :substat_3_value,
+                            :substat_4,
+                            :substat_4_value
+                        );
+                        ");
+                        $statement->bindValue(":run", $id, SQLITE3_INTEGER);
+                        $statement->bindValue(":id", $rune->{"rune_id"}, SQLITE3_INTEGER);
+                        $statement->bindValue(":type", $rune->{"set_id"}, SQLITE3_INTEGER);
+                        $statement->bindValue(":slot", $rune->{"slot_no"}, SQLITE3_INTEGER);
+                        $statement->bindValue(":value", $rune->{"sell_value"}, SQLITE3_INTEGER);
+                        if ($rune->{"class"} > 10){
+                            // Ancient rune
+                            $statement->bindValue(":ancient", 1, SQLITE3_INTEGER);
+                            $statement->bindValue(":stars", intval($rune->{"class"}) - 10, SQLITE3_INTEGER);
+                            $statement->bindValue(":quality", intval($rune->{"rank"}) - 10, SQLITE3_INTEGER);
+                        }
+                        else{
+                            // Non Ancient rune
+                            $statement->bindValue(":ancient", 0, SQLITE3_INTEGER);
+                            $statement->bindValue(":stars", $rune->{"class"}, SQLITE3_INTEGER);
+                            $statement->bindValue(":quality", $rune->{"rank"}, SQLITE3_INTEGER);
+                        }
+                        $efficiency = calculate_efficiency($rune);
+                        $max_efficiency = calculate_maximum_efficiency($rune);
+                        $statement->bindValue(":efficiency", $efficiency, SQLITE3_FLOAT);
+                        $statement->bindValue(":max_efficiency", $max_efficiency, SQLITE3_FLOAT);
+                        $statement->bindValue(":main_stat", $rune->{"pri_eff"}[0], SQLITE3_INTEGER);
+                        $statement->bindValue(":main_stat_value", $rune->{"pri_eff"}[1], SQLITE3_INTEGER);
+                        if ($rune->{"prefix_eff"}[0] > 0){
+                            $statement->bindValue(":innate_stat", $rune->{"prefix_eff"}[0], SQLITE3_INTEGER);
+                            $statement->bindValue(":innate_stat_value", $rune->{"prefix_eff"}[1], SQLITE3_INTEGER);
+                        }
+                        else{
+                            $statement->bindValue(":innate_stat", null, SQLITE3_INTEGER);
+                            $statement->bindValue(":innate_stat_value", 0, SQLITE3_INTEGER);
+                        }
+                        if (sizeof($rune->{"sec_eff"}) > 0){
+                            $statement->bindValue(":substat_1", $rune->{"sec_eff"}[0][0], SQLITE3_INTEGER);
+                            $statement->bindValue(":substat_1_value", $rune->{"sec_eff"}[0][1], SQLITE3_INTEGER);
+                        }
+                        else{
+                            $statement->bindValue(":substat_1", null, SQLITE3_INTEGER);
+                            $statement->bindValue(":substat_1_value", 0, SQLITE3_INTEGER);
+                        }
+                        if (sizeof($rune->{"sec_eff"}) > 1){
+                            $statement->bindValue(":substat_2", $rune->{"sec_eff"}[1][0], SQLITE3_INTEGER);
+                            $statement->bindValue(":substat_2_value", $rune->{"sec_eff"}[1][1], SQLITE3_INTEGER);
+                        }
+                        else{
+                            $statement->bindValue(":substat_2", null, SQLITE3_INTEGER);
+                            $statement->bindValue(":substat_2_value", 0, SQLITE3_INTEGER);
+                        }
+                        if (sizeof($rune->{"sec_eff"}) > 2){
+                            $statement->bindValue(":substat_3", $rune->{"sec_eff"}[2][0], SQLITE3_INTEGER);
+                            $statement->bindValue(":substat_3_value", $rune->{"sec_eff"}[2][1], SQLITE3_INTEGER);
+                        }
+                        else{
+                            $statement->bindValue(":substat_3", null, SQLITE3_INTEGER);
+                            $statement->bindValue(":substat_3_value", 0, SQLITE3_INTEGER);
+                        }
+                        if (sizeof($rune->{"sec_eff"}) > 3){
+                            $statement->bindValue(":substat_4", $rune->{"sec_eff"}[3][0], SQLITE3_INTEGER);
+                            $statement->bindValue(":substat_4_value", $rune->{"sec_eff"}[3][1], SQLITE3_INTEGER);
+                        }
+                        else{
+                            $statement->bindValue(":substat_4", null, SQLITE3_INTEGER);
+                            $statement->bindValue(":substat_4_value", 0, SQLITE3_INTEGER);
+                        }
+                        $statement->execute();*/
+                        break;
+                }
+            }
+        }
+
+        // Parse party
+        $leader = 1;
+        foreach ($response->{"unit_list"} as $unit){
+            $statement = $db->prepare("
+              INSERT INTO run_party 
+                (run, unit, k_unit, leader, front)
+              VALUES
+                (:run, :unit, :k_unit, :leader, :front);"
+            );
+            $statement->bindValue(":run", $id, SQLITE3_INTEGER);
+            $statement->bindValue(":unit", $unit->{"unit_id"}, SQLITE3_INTEGER);
+            $statement->bindValue(":k_unit", $unit->{"unit_master_id"}, SQLITE3_INTEGER);
+            $statement->bindValue(":leader", $leader, SQLITE3_INTEGER);
+            $leader = 0;
+            $statement->bindValue(":front", 0, SQLITE3_INTEGER);
+            $statement->execute();
+        }
+
+        // Return success
+        return "201 Created.";
+    }
+
+    global $db;
+
+    try{
+
+        header("Content-type: application/json; charset=utf-8");
+
+        // Get put data
+        parse_str(file_get_contents("php://input"), $_POST);
+
+        // Check API key.
+        if (!array_key_exists("key", $_POST)){
+            header("HTTP/1.1 400 API key not received.");
+            syslog(LOG_INFO, "[APIv3] HTTP/1.1 400 API key not received.");
+            return 400;
+        }
+        $key = $_POST["key"];
+
+        // Get all JSON files
+        $json = [
+            "start_req" => null,
+            "start_res" => null,
+            "result_req" => null,
+            "result_res" => null,
+        ];
+
+        // Result response - mandatory
+        if (!array_key_exists("result_response", $_POST)){
+            header("HTTP/1.1 400 No result response data received.");
+            syslog(LOG_INFO, "[APIv3] HTTP/1.1 400 No result response data received.");
+            return 400;
+        }
+        $data_json = json_decode($_POST["result_response"]);
+        if ($data_json === null){
+            header("HTTP/1.1 400 Result response data is no valid JSON.");
+            syslog(LOG_INFO, "[APIv3] HTTP/1.1 400 Result response data is no valid JSON.");
+            return 400;
+        }
+        $json["result_res"] = $data_json;
+
+        // Result request - optional
+        if (array_key_exists("result_request", $_POST)){
+            $data_raw = $_POST["result_request"];
+            if ($data_raw != null && $data_raw != false){
+                $data_json = json_decode($data_raw);
+                if ($data_json != null){
+                    $json["result_req"] = $data_json;
+                }
+            }
+        }
+        // Start result - optional
+        if (array_key_exists("start_response", $_POST)){
+            $data_raw = $_POST["start_response"];
+            if ($data_raw != null && $data_raw != false){
+                $data_json = json_decode($data_raw);
+                if ($data_json != null){
+                    $json["start_res"] = $data_json;
+                }
+            }
+        }
+        // Start result - optional
+        if (array_key_exists("start_request", $_POST)){
+            $data_raw = $_POST["start_request"];
+            if ($data_raw != null && $data_raw != false){
+                $data_json = json_decode($data_raw);
+                if ($data_json != null){
+                    $json["start_req"] = $data_json;
+                }
+            }
+        }
+
+        // Extract basic data
+        $uid = $json["result_res"]->{"wizard_info"}->{"wizard_id"};
+        $command = $json["result_res"]->{"command"};
+
+        // Authenticate
+        $statement = $db->prepare("SELECT COUNT(uid) AS c FROM player WHERE uid = :uid AND api_key = :api_key;");
+        $statement->bindValue(":uid", $uid, SQLITE3_INTEGER);
+        $statement->bindValue(":api_key", $key, SQLITE3_TEXT);
+        if (1 != $statement->execute()->fetchArray(SQLITE3_ASSOC)["c"]){
+            header("HTTP/1.1 401 Invalid credentials.");
+            syslog(LOG_INFO, "[APIv3] HTTP/1.1 401 Invalid credentials.");
+            return 401;
+        }
+
+        // Check for implemented command
+        $accepted_commands = [
+            "BattleDungeonResult_V2", // Dungeon Run
+            "BattleDimensionHoleDungeonResult_v2", // Dimension Hole Run
+            "BattleRiftOfWorldsRaidResult", // Rift Raid Run
+            "BattleScenarioResult", // Scenario Run
+            "BattleArenaResult", // Arena Run
+            "BattleDarkPortalResult" // Dimensinal Rift Run
+        ];
+        if (!in_array($command, $accepted_commands)){
+            header("HTTP/1.1 405 Command not implemented.");
+            syslog(LOG_INFO, "[APIv3] HTTP/1.1 405 Command not implemented.");
+            return 405;
+        }
+
+        // Check if already in DB
+        $dtime = $json["result_res"]->{"tvaluelocal"};
+        $statement = $db->prepare("SELECT count(id) AS c FROM run WHERE uid = :uid AND dtime = :dtime;");
+        $statement->bindValue(":uid", $uid, SQLITE3_INTEGER);
+        $statement->bindValue(":dtime", $dtime, SQLITE3_TEXT);
+        if (0 != $statement->execute()->fetchArray(SQLITE3_ASSOC)["c"]){
+            header("HTTP/1.1 409 Run already in database.");
+            syslog(LOG_INFO, "[APIv3] HTTP/1.1 409 Run already in database.");
+            return 409;
+        }
+
+        // Get new ID
+        $q = $db->query("SELECT max(id) + 1 AS id FROM run;");
+        $r = $q->fetchArray(SQLITE3_ASSOC);
+        if ($r){
+            $id = $r["id"];
+        }
+        else{
+            $id = 1;
+        }
+
+        // Run parsing function
+        $result = "500 Unknown Error";
+        switch($command){
+            case "BattleDungeonResult_V2":
+                $result = log_cairos_run($db, $id, $uid, $json);
+                break;
+            case "BattleDimensionHoleDungeonResult_v2":
+                $result = log_dimension_hole_run($db, $id, $uid, $json);
+                break;
+            case "BattleRiftOfWorldsRaidResult":
+                $result = log_rift_raid_run($db, $id, $uid, $json);
+                break;
+            case "BattleScenarioResult":
+                $result = log_scenario_run($db, $id, $uid, $json);
+                break;
+            case "BattleArenaResult":
+                $result = log_arena_run($db, $id, $uid, $json);
+                break;
+            case "BattleDarkPortalResult":
+                $result = log_dark_portal_run($db, $id, $uid, $json);
+                break;
+        }
+
+        // Process result
+        $status_code = intval(substr($result, 0, 3));
+        $status_message = substr($result, 4);
+        if ($status_code == 0 || $status_code < 100 || $status_code > 599){
+            header("HTTP/1.1 500 Unknown error.");
+            syslog(LOG_ERR, "[APIv3] HTTP/1.1 500 Unknown error.");
+            return 500;
+        }
+        else{
+            header("HTTP/1.1 $status_code $status_message");
+            syslog(LOG_INFO, "[APIv3] HTTP/1.1 $status_code $status_message");
+            return $status_code;
+        }
+    }
+    catch(Exception $e) {
+        header("HTTP/1.1 500 Unexpeced error: " . $e->getMessage());
+        syslog(LOG_ERR, "[APIv3] HTTP/1.1 500 Unexpected error: " . $e->getMessage());
+        return 500;
+    }
+?>

+ 455 - 0
application/API/v3/units/GET.php

@@ -0,0 +1,455 @@
+<?php
+    /**
+     * Unit getter script.
+     *
+     * Exposes an API to rerieve unit info.
+     *
+     * Optional query parameters are:
+     *  - id: Unit ID.
+     *
+     * @category API
+     */
+
+    global $db;
+
+    /**
+     * Gets info on a unit.
+     *
+     * @param resource $db Database connection.
+     * @param int $id Unit identifier
+     * @return mixed[] Content.
+     */
+    function get_unit($db, $id){
+        $result = [
+            "status" => 404,
+            "message" => "Unit not found",
+            "content" => ""
+        ];
+        $statement = $db->prepare("
+          SELECT
+            k_unit.id AS id,
+            k_unit.name AS name,
+            k_unit.family AS family,
+            k_unit.element AS element,
+            k_element.name AS element_name,
+            k_unit.archetype AS archetype,
+            k_archetype.name AS archetype_name,
+            k_unit.base_stars AS base_stars,
+            k_unit.natural_stars AS natural_stars,
+            k_unit.obtainable AS obtainable,
+            k_unit.awakens_from AS awakens_from,
+            k_unit.awakens_to AS awakens_to,
+            k_unit.homunculus AS homunculus,
+            k_unit.hp AS hp,
+            k_unit.attack AS attack,
+            k_unit.defense AS defense,
+            k_unit.speed AS speed,
+            k_unit.crit_rate AS crit_rate,
+            k_unit.crit_damage AS crit_damage,
+            k_unit.accuracy AS accuracy,
+            k_unit.resistance AS resistance,
+            k_unit.leader_skill AS leader_skill
+          FROM
+            k_unit,
+            k_element,
+            k_archetype
+          WHERE
+            k_unit.element = k_element.id AND
+            k_unit.archetype = k_archetype.id AND
+            k_unit.id = :id ;
+        ");
+        $statement->bindValue(":id", $id, SQLITE3_INTEGER);
+        $q = $statement->execute();
+        $r = $q->fetchArray(SQLITE3_ASSOC);
+        if ($r){
+            $unit = [
+                "id" => $r["id"],
+                "url" => URL::BASE . "API/v3/units/" . $r["id"] . "/",
+                "name" => $r["name"],
+                "family" => $r["family"],
+                "image" => APPLICATION::img("UNIT", $r["id"]),
+                "element" => $r["element"],
+                "element_name" => $r["element_name"],
+                "archetype" => $r["archetype"],
+                "archetype_name" => $r["archetype_name"],
+                "stars" => $r["base_stars"],
+                "natural_stars" => $r["natural_stars"],
+                "obtainable" => (($r["obtainable"] == 1) ? (true) : (false)),
+                "awakens_from" => $r["awakens_from"],
+                "awakens_to" => $r["awakens_to"],
+                "homunculus" => (($r["homunculus"] == 1) ? (true) : (false)),
+                "hp" => $r["hp"],
+                "attack" => $r["attack"],
+                "defense" => $r["defense"],
+                "speed" => $r["speed"],
+                "critical_rate" => $r["crit_rate"],
+                "critical_damage" => $r["crit_damage"],
+                "accuracy" => $r["accuracy"],
+                "resistance" => $r["resistance"],
+                "leader_skill" => null,
+                "skills" => [],
+            ];
+
+            // Leader_skill
+            if ($r["leader_skill"] != null){
+                $statement_leader = $db->prepare("
+                SELECT
+                    k_leader_skill.id AS id,
+                    k_leader_skill.stat AS stat,
+                    k_stat.name AS stat_name,
+                    k_leader_skill.amount AS amount,
+                    k_leader_skill.area AS area,
+                    k_effect_area.name AS area_name,
+                    k_leader_skill.element AS element,
+                    k_element.name AS element_name
+                FROM
+                    k_leader_skill,
+                    k_stat,
+                    k_effect_area,
+                    k_element
+                WHERE
+                    k_leader_skill.id = :id AND
+                    k_leader_skill.stat = k_stat.id AND
+                    k_leader_skill.area = k_effect_area.id AND
+                    k_leader_skill.element = k_element.id;
+                ");
+                $statement_leader->bindValue(":id", $r["leader_skill"], SQLITE3_INTEGER);
+                $q_leader = $statement_leader->execute();
+                $r_leader = $q_leader->fetchArray(SQLITE3_ASSOC);
+                if ($r_leader){
+                    $description = "Increases the ";
+                    switch ($r_leader["stat"]){
+                        case STAT_ID::ATK:
+                            $description .= "attack power";
+                            break;
+                        case STAT_ID::DEF:
+                            $description .= "defense";
+                            break;
+                        case STAT_ID::HP:
+                            $description .= "HP";
+                            break;
+                        case STAT_ID::SPD:
+                            $description .= "attack speed";
+                            break;
+                        case STAT_ID::CRIT_RATE:
+                            $description .= "critical rate";
+                            break;
+                        case STAT_ID::CRIT_DMG:
+                            $description .= "critical damage";
+                            break;
+                        case STAT_ID::ACCURACY:
+                            $description .= "accuracy";
+                            break;
+                        case STAT_ID::RESIST:
+                            $description .= "resistance";
+                            break;
+                    }
+                    $description .= " of ally monsters ";
+                    switch ($r_leader["element"]){
+                        case ELEMENT_ID::WATER:
+                            $description .= " with Water attribute ";
+                            break;
+                        case ELEMENT_ID::FIRE:
+                            $description .= " with Fire attribute ";
+                            break;
+                        case ELEMENT_ID::WIND:
+                            $description .= " with Wind attribute ";
+                            break;
+                        case ELEMENT_ID::LIGHT:
+                            $description .= " with Light attribute ";
+                            break;
+                        case ELEMENT_ID::DARK:
+                            $description .= " with Dark attribute ";
+                            break;
+                    }
+                    $description = $description . "by " . $r_leader["amount"] . "%";
+                    switch ($r_leader["area"]){
+                        case EFFECT_AREA_ID::DUNGEON:
+                            $description .= " in the Dungeons";
+                            break;
+                        case EFFECT_AREA_ID::ARENA:
+                            $description .= " in the Arena";
+                            break;
+                        case EFFECT_AREA_ID::GUILD:
+                            $description .= " in Guild content";
+                            break;
+                    }
+                    $description = str_replace("  ", " ", $description) . ".";
+                    $unit["leader_skill"] = [
+                        "id" => $r_leader["id"],
+                        "stat" => $r_leader["stat"],
+                        "stat_name" => $r_leader["stat_name"],
+                        "increase" => $r_leader["amount"],
+                        "area" => $r_leader["area"],
+                        "area_name" => $r_leader["area_name"],
+                        "element" => $r_leader["element"],
+                        "element_name" => $r_leader["element_name"],
+                        "description" => $description
+                    ];
+                }
+            }
+
+            // Skill
+            $statement_skills = $db->prepare("
+              SELECT
+                k_skill.id AS id,
+                k_skill.slot AS slot,
+                k_skill.name AS name,
+                k_skill.description AS description,
+                k_skill.passive AS passive,
+                k_skill.cooltime AS cooltime,
+                k_skill.hits AS hits,
+                k_skill.aoe AS aoe,
+                k_skill.multiplier_formula AS multiplier_formula,
+                k_skill.max_level AS max_level
+              FROM
+                k_skill,
+                k_unit_skill
+              WHERE
+                k_skill.id = k_unit_skill.skill AND
+                k_unit_skill.unit = :id 
+              ORDER BY slot;
+            ");
+            $statement_skills->bindValue(":id", $id, SQLITE3_INTEGER);
+            $q_skills = $statement_skills->execute();
+            while ($r_skills = $q_skills->fetchArray(SQLITE3_ASSOC)){
+                $skill = [
+                    "id" => $r_skills["id"],
+                    "slot" => $r_skills["slot"],
+                    "name" => $r_skills["name"],
+                    "description" => $r_skills["description"],
+                    "image" => APPLICATION::img("SKILL", $r_skills["id"]),
+                    "passive" => (($r_skills["passive"] == 1) ? (true) : (false)),
+                    "cooltime" => $r_skills["cooltime"],
+                    "hits" => $r_skills["hits"],
+                    "aoe" => (($r_skills["aoe"] == 1) ? (true) : (false)),
+                    "effects" => [],
+                    "max_level" => $r_skills["max_level"],
+                    "upgrades" => [],
+                    "formula" => $r_skills["multiplier_formula"]
+                ];
+                // Skill levels
+                $statement_skill_levels = $db->prepare("
+                  SELECT
+                    level,
+                    description
+                  FROM k_skill_level
+                  WHERE
+                    level > 1 AND
+                    skill = :id
+                  ORDER BY level;
+                ");
+                $statement_skill_levels->bindValue(":id", $r_skills["id"], SQLITE3_INTEGER);
+                $q_skill_levels = $statement_skill_levels->execute();
+                while ($r_skill_levels = $q_skill_levels->fetchArray(SQLITE3_ASSOC)){
+                    $level = [
+                        "level" => $r_skill_levels["level"],
+                        "description" => $r_skill_levels["description"]
+                    ];
+                    array_push($skill["upgrades"], $level);
+                }
+                // Skill efffects
+                $statement_skill_effects = $db->prepare("
+                  SELECT
+                    k_effect.id AS id,
+                    k_effect.is_buff AS is_buff,
+                    k_effect.name AS name,
+                    k_effect.description AS description
+                  FROM
+                    k_effect,
+                    k_skill_effect
+                  WHERE
+                    k_skill_effect.skill = :id AND
+                    k_skill_effect.effect = k_effect.id
+                ");
+                $statement_skill_effects->bindValue(":id", $r_skills["id"], SQLITE3_INTEGER);
+                $q_skill_effects = $statement_skill_effects->execute();
+                while ($r_skill_effects = $q_skill_effects->fetchArray(SQLITE3_ASSOC)){
+                    $effect = [
+                        "id" => $r_skill_effects["id"],
+                        "buff" => (($r_skill_effects["is_buff"] == 1) ? (true) : (false)),
+                        "name" => $r_skill_effects["name"],
+                        "description" => $r_skill_effects["description"],
+                        "image" => APPLICATION::img("EFFECT", $r_skill_effects["id"]),
+                    ];
+                    array_push($skill["effects"], $effect);
+                }
+                array_push($unit["skills"], $skill);
+            }
+
+            // Add to array
+            $result["content"] = $unit;
+            $result["status"] = 200;
+            $result["message"] = "Success.";
+        }
+        return $result;
+    }
+
+    /**
+     * Gets a list of units, paginated.
+     *
+     * @param resource $db Database connection.
+     * @return mixed[] Content.
+     */
+    function get_unit_list($db){
+        $result = [
+            "status" => 200,
+            "message" => "Success.",
+            "content" => ""
+        ];
+
+        // Get filters
+        $parameters = "";
+        $filters = [
+            "page" => 1,
+            "per_page" => 30,
+            "name" => "",
+            "element" => "",
+            "archetype" => "",
+            "stars" => "",
+            "stars_lte" => "",
+            "stars_gte" => "",
+        ];
+
+        foreach (array_keys($filters) as $filter_key){
+            $filter = filter_input(INPUT_GET, $filter_key);
+            if ($filter != null && $filter !== false){
+                $filters[$filter_key] = $filter;
+                // Also, build the new url parameters
+                if ($filter_key != "page"){
+                    $parameters .= ("&" . $filter_key . "=" . $filter);
+                }
+            }
+        }
+
+        // Fix some filters
+        if (intval($filters["page"]) < 1){
+            $filters["page"] = 1;
+        }
+        if (intval($filters["per_page"]) < 1){
+            $filters["per_page"] = 1;
+        }
+        elseif (intval($filters["per_page"]) > 100){
+            $filters["per_page"] = 100;
+        }
+
+        // Build the where clause
+        $where = "
+          k_unit.element = k_element.id AND
+          k_unit.archetype = k_archetype.id
+        ";
+        if (strlen($filters["name"]) > 0){
+            $where .= " AND upper(k_unit.name) LIKE upper(:name) ";
+        }
+        if (strlen($filters["element"]) > 0){
+            $where .= " AND (k_element.id = :element OR upper(k_element.name) = upper(:element)) ";
+        }
+        if (strlen($filters["archetype"]) > 0){
+            $where .= " AND (k_archetype.id = :archetype OR upper(k_archetype.name) = upper(:archetype)) ";
+        }
+        if (strlen($filters["stars"]) > 0){
+            $where .= " AND k_unit.base_stars = :stars ";
+        }
+        if (strlen($filters["stars_lte"]) > 0){
+            $where .= " AND k_unit.base_stars <= :stars_lte ";
+        }
+        if (strlen($filters["stars_gte"]) > 0){
+            $where .= " AND k_unit.base_stars >= :stars_gte ";
+        }
+
+        // Get total
+        $statement = $db->prepare("
+          SELECT count(k_unit.id) AS c
+          FROM
+            k_unit,
+            k_element,
+            k_archetype
+          WHERE $where ;
+        ");
+        $statement->bindValue(":name", "%" . $filters["name"] . "%", SQLITE3_TEXT);
+        $statement->bindValue(":element", $filters["element"], SQLITE3_TEXT);
+        $statement->bindValue(":archetype", $filters["archetype"], SQLITE3_TEXT);
+        $statement->bindValue(":stars", $filters["stars"], SQLITE3_INTEGER);
+        $statement->bindValue(":stars_gte", $filters["stars_gte"], SQLITE3_INTEGER);
+        $statement->bindValue(":stars_lte", $filters["stars_lte"], SQLITE3_INTEGER);
+        $total = $statement->execute()->fetchArray(SQLITE3_ASSOC)["c"];
+
+        // Selet all units
+        $statement = $db->prepare("
+          SELECT k_unit.id AS id
+          FROM
+            k_unit,
+            k_element,
+            k_archetype
+          WHERE $where
+          LIMIT :limit
+          OFFSET :offset ;
+        ");
+        $statement->bindValue(":name", "%" . $filters["name"] . "%", SQLITE3_TEXt);
+        $statement->bindValue(":element", $filters["element"], SQLITE3_TEXT);
+        $statement->bindValue(":archetype", $filters["archetype"], SQLITE3_TEXT);
+        $statement->bindValue(":stars", $filters["stars"], SQLITE3_INTEGER);
+        $statement->bindValue(":stars_gte", $filters["stars_gte"], SQLITE3_INTEGER);
+        $statement->bindValue(":stars_lte", $filters["stars_lte"], SQLITE3_INTEGER);
+        $statement->bindValue(":limit", $filters["per_page"], SQLITE3_INTEGER);
+        $statement->bindValue(":offset", $filters["per_page"] * ($filters["page"] - 1), SQLITE3_INTEGER);
+        $q = $statement->execute();
+        $units = [];
+
+        // Loop and get unit info
+        while ($r = $q->fetchArray(SQLITE3_ASSOC)){
+            $unit = get_unit($db, $r["id"]);
+            if ($unit["status"] == 200){
+                array_push($units, $unit["content"]);
+            }
+        };
+
+        // Calculate previous and next pages
+        if ($filters["page"] == 1){
+            $url_prev = null;
+        }
+        else{
+            $url_prev = URL::BASE . "API/v3/units/?page=" . ($filters["page"] - 1) . $parameters;
+        }
+        if ($filters["page"] < ceil($total / $filters["per_page"])){
+            $url_next = URL::BASE . "API/v3/units/?page=" . ($filters["page"] + 1) . $parameters;
+        }
+        else{
+            $url_next = null;
+        }
+        $content = [
+            "count" => $total,
+            "next" => $url_next,
+            "previous" => $url_prev,
+            "results" => $units
+        ];
+        $result["content"] = $content;
+        return $result;
+    }
+
+    try{
+        header("Content-type: application/json; charset=utf-8");
+        $result = [
+            "status" => 200,
+            "message" => "Success.",
+            "content" => ""
+        ];
+        // Get profile ID
+        /** @var mixed $query Request parameters, from API_CONTROLLER*/
+        if (strlen($query[0]) > 0){
+            $id = $query[0];
+            $result = get_unit($db, $id);
+        }
+        else{
+            $result = get_unit_list($db);
+        }
+        header("HTTP/1.1 " . $result["status"] . " " . $result["message"]);
+        echo(json_encode($result["content"]));
+        syslog(LOG_ERR, "HTTP/1.1 " . $result["status"] . " " . $result["message"]);
+        return $result["status"];
+    }
+    catch(Exception $e) {
+        header("HTTP/1.1 500 Unexpeced error: " . $e->getMessage());
+        syslog(LOG_ERR, "[APIv3] HTTP/1.1 500 Unexpected error: " . $e->getMessage());
+        return 500;
+    }

+ 1357 - 2
application/Constant.php

@@ -1019,9 +1019,9 @@
         const RAINBOWMON = 25;   # Possibly material monsters in general. Appears when wish returns a rainbowmon.
         const RAINBOWMON = 25;   # Possibly material monsters in general. Appears when wish returns a rainbowmon.
 
 
         /**
         /**
-         * Rune Craft.
+         * Enchantment.
          */
          */
-        const RUNE_CRAFT = 27;
+        const ENCHANTMENT = 27;
 
 
         /**
         /**
          * Craft Stuff.
          * Craft Stuff.
@@ -2763,6 +2763,1361 @@
         ];
         ];
     };
     };
 
 
+    /**
+     * Rune main stat values constants.
+     *
+     * Includes the value of the main stats for type, stars, and level.
+     *
+     * @category Data
+     */
+    final class RUNE_SUBSTAT_MAX_VALUES{
+    
+        const SUBSTAT = [
+            RUNE_STAT_ID::HP => [
+                "1" => 300,
+                "2" => 525,
+                "3" => 825,
+                "4" => 1125,
+                "5" => 1500,
+                "6" => 1875
+            ],
+            RUNE_STAT_ID::HP_P => [
+                "1" => 10,
+                "2" => 15,
+                "3" => 25,
+                "4" => 30,
+                "5" => 35,
+                "6" => 40
+            ],
+            RUNE_STAT_ID::ATK => [
+                "1" => 20,
+                "2" => 25,
+                "3" => 40,
+                "4" => 50,
+                "5" => 75,
+                "6" => 100
+            ],
+            RUNE_STAT_ID::ATK_P => [
+                "1" => 10,
+                "2" => 15,
+                "3" => 25,
+                "4" => 30,
+                "5" => 35,
+                "6" => 40
+            ],
+            RUNE_STAT_ID::DEF => [
+                "1" => 20,
+                "2" => 25,
+                "3" => 40,
+                "4" => 50,
+                "5" => 75,
+                "6" => 100
+            ],
+            RUNE_STAT_ID::DEF_P => [
+                "1" => 10,
+                "2" => 15,
+                "3" => 25,
+                "4" => 30,
+                "5" => 35,
+                "6" => 40
+            ],
+            RUNE_STAT_ID::SPD => [
+                "1" => 5,
+                "2" => 10,
+                "3" => 15,
+                "4" => 20,
+                "5" => 25,
+                "6" => 30
+            ],
+            RUNE_STAT_ID::CRR => [
+                "1" => 5,
+                "2" => 10,
+                "3" => 15,
+                "4" => 20,
+                "5" => 25,
+                "6" => 30
+            ],
+            RUNE_STAT_ID::CRD => [
+                "1" => 10,
+                "2" => 15,
+                "3" => 20,
+                "4" => 25,
+                "5" => 30,
+                "6" => 35
+            ],
+            RUNE_STAT_ID::RES => [
+                "1" => 10,
+                "2" => 15,
+                "3" => 25,
+                "4" => 30,
+                "5" => 35,
+                "6" => 40
+            ],
+            RUNE_STAT_ID::ACC => [
+                "1" => 10,
+                "2" => 15,
+                "3" => 25,
+                "4" => 30,
+                "5" => 35,
+                "6" => 40
+            ]
+        ];
+
+        /**
+         * Values of the HP main stat [stars][level]
+         */
+        const HP = [
+            "1" => [
+                "0" => 40,
+                "1" => 85,
+                "2" => 130,
+                "3" => 175,
+                "4" => 220,
+                "5" => 265,
+                "6" => 310,
+                "7" => 355,
+                "8" => 400,
+                "9" => 445,
+                "10" => 490,
+                "11" => 535,
+                "12" => 580,
+                "13" => 625,
+                "14" => 670,
+                "15" => 804
+            ],
+            "2" => [
+                "0" => 70,
+                "1" => 130,
+                "2" => 190,
+                "3" => 250,
+                "4" => 310,
+                "5" => 370,
+                "6" => 430,
+                "7" => 490,
+                "8" => 550,
+                "9" => 610,
+                "10" => 670,
+                "11" => 730,
+                "12" => 790,
+                "13" => 850,
+                "14" => 910,
+                "15" => 1092
+            ],
+            "3" => [
+                "0" => 100,
+                "1" => 175,
+                "2" => 250,
+                "3" => 325,
+                "4" => 400,
+                "5" => 475,
+                "6" => 550,
+                "7" => 625,
+                "8" => 700,
+                "9" => 775,
+                "10" => 850,
+                "11" => 925,
+                "12" => 1000,
+                "13" => 1075,
+                "14" => 1150,
+                "15" => 1380
+            ],
+            "4" => [
+                "0" => 160,
+                "1" => 250,
+                "2" => 340,
+                "3" => 430,
+                "4" => 520,
+                "5" => 610,
+                "6" => 700,
+                "7" => 790,
+                "8" => 880,
+                "9" => 970,
+                "10" => 1060,
+                "11" => 1150,
+                "12" => 1240,
+                "13" => 1330,
+                "14" => 1420,
+                "15" => 1704
+            ],
+            "5" => [
+                "0" => 270,
+                "1" => 375,
+                "2" => 480,
+                "3" => 585,
+                "4" => 690,
+                "5" => 795,
+                "6" => 900,
+                "7" => 1005,
+                "8" => 1110,
+                "9" => 1215,
+                "10" => 1320,
+                "11" => 1425,
+                "12" => 1530,
+                "13" => 1635,
+                "14" => 1740,
+                "15" => 2088
+            ],
+            "6" => [
+                "0" => 360,
+                "1" => 480,
+                "2" => 600,
+                "3" => 720,
+                "4" => 840,
+                "5" => 960,
+                "6" => 1080,
+                "7" => 1200,
+                "8" => 1320,
+                "9" => 1440,
+                "10" => 1560,
+                "11" => 1680,
+                "12" => 1800,
+                "13" => 1920,
+                "14" => 2040,
+                "15" => 2448
+            ]
+        ];
+        
+        /**
+         * Values of the HP_P main stat[stars][level]
+         */
+        const HP_P = [
+            "1" => [
+                "0" => 1,
+                "1" => 2,
+                "2" => 3,
+                "3" => 4,
+                "4" => 5,
+                "5" => 6,
+                "6" => 7,
+                "7" => 8,
+                "8" => 9,
+                "9" => 10,
+                "10" => 11,
+                "11" => 12,
+                "12" => 13,
+                "13" => 14,
+                "14" => 15,
+                "15" => 18
+            ],
+            "2" => [
+                "0" => 2,
+                "1" => 3,
+                "2" => 4,
+                "3" => 5,
+                "4" => 6,
+                "5" => 7,
+                "6" => 8,
+                "7" => 9,
+                "8" => 10,
+                "9" => 11,
+                "10" => 12,
+                "11" => 13,
+                "12" => 14,
+                "13" => 15,
+                "14" => 16,
+                "15" => 19
+            ],
+            "3" => [
+                "0" => 4,
+                "1" => 6,
+                "2" => 8,
+                "3" => 10,
+                "4" => 12,
+                "5" => 14,
+                "6" => 16,
+                "7" => 18,
+                "8" => 20,
+                "9" => 22,
+                "10" => 24,
+                "11" => 26,
+                "12" => 28,
+                "13" => 30,
+                "14" => 32,
+                "15" => 38
+            ],
+            "4" => [
+                "0" => 5,
+                "1" => 7,
+                "2" => 9,
+                "3" => 11,
+                "4" => 13,
+                "5" => 16,
+                "6" => 18,
+                "7" => 20,
+                "8" => 22,
+                "9" => 24,
+                "10" => 27,
+                "11" => 29,
+                "12" => 31,
+                "13" => 33,
+                "14" => 36,
+                "15" => 43
+            ],
+            "5" => [
+                "0" => 8,
+                "1" => 10,
+                "2" => 12,
+                "3" => 15,
+                "4" => 17,
+                "5" => 20,
+                "6" => 22,
+                "7" => 24,
+                "8" => 27,
+                "9" => 29,
+                "10" => 32,
+                "11" => 34,
+                "12" => 37,
+                "13" => 40,
+                "14" => 43,
+                "15" => 51
+            ],
+            "6" => [
+                "0" => 11,
+                "1" => 14,
+                "2" => 17,
+                "3" => 20,
+                "4" => 23,
+                "5" => 26,
+                "6" => 29,
+                "7" => 32,
+                "8" => 35,
+                "9" => 38,
+                "10" => 41,
+                "11" => 44,
+                "12" => 47,
+                "13" => 50,
+                "14" => 53,
+                "15" => 63
+            ]
+        ];
+
+        /**
+         * Values of the ATK main stat[stars][level]
+         */
+        const ATK = [
+            "1" => [
+                "0" => 3,
+                "1" => 6,
+                "2" => 9,
+                "3" => 12,
+                "4" => 15,
+                "5" => 18,
+                "6" => 21,
+                "7" => 24,
+                "8" => 27,
+                "9" => 30,
+                "10" => 33,
+                "11" => 36,
+                "12" => 39,
+                "13" => 42,
+                "14" => 45,
+                "15" => 54
+            ],
+            "2" => [
+                "0" => 5,
+                "1" => 9,
+                "2" => 13,
+                "3" => 17,
+                "4" => 21,
+                "5" => 25,
+                "6" => 29,
+                "7" => 33,
+                "8" => 37,
+                "9" => 41,
+                "10" => 45,
+                "11" => 49,
+                "12" => 53,
+                "13" => 57,
+                "14" => 61,
+                "15" => 73
+            ],
+            "3" => [
+                "0" => 7,
+                "1" => 12,
+                "2" => 17,
+                "3" => 22,
+                "4" => 27,
+                "5" => 32,
+                "6" => 37,
+                "7" => 42,
+                "8" => 47,
+                "9" => 52,
+                "10" => 57,
+                "11" => 62,
+                "12" => 67,
+                "13" => 72,
+                "14" => 77,
+                "15" => 92
+            ],
+            "4" => [
+                "0" => 10,
+                "1" => 16,
+                "2" => 22,
+                "3" => 28,
+                "4" => 34,
+                "5" => 40,
+                "6" => 46,
+                "7" => 52,
+                "8" => 58,
+                "9" => 64,
+                "10" => 70,
+                "11" => 76,
+                "12" => 82,
+                "13" => 88,
+                "14" => 94,
+                "15" => 112
+            ],
+            "5" => [
+                "0" => 15,
+                "1" => 22,
+                "2" => 29,
+                "3" => 36,
+                "4" => 43,
+                "5" => 50,
+                "6" => 57,
+                "7" => 64,
+                "8" => 71,
+                "9" => 78,
+                "10" => 85,
+                "11" => 92,
+                "12" => 99,
+                "13" => 106,
+                "14" => 113,
+                "15" => 135
+            ],
+            "6" => [
+                "0" => 22,
+                "1" => 30,
+                "2" => 38,
+                "3" => 46,
+                "4" => 54,
+                "5" => 62,
+                "6" => 70,
+                "7" => 78,
+                "8" => 86,
+                "9" => 94,
+                "10" => 102,
+                "11" => 110,
+                "12" => 118,
+                "13" => 126,
+                "14" => 134,
+                "15" => 160
+            ]
+        ];
+
+        /**
+         * Values of the ATK_P main stat[stars][level]
+         */
+        const ATK_P = [
+            "1" => [
+                "0" => 1,
+                "1" => 2,
+                "2" => 3,
+                "3" => 4,
+                "4" => 5,
+                "5" => 6,
+                "6" => 7,
+                "7" => 8,
+                "8" => 9,
+                "9" => 10,
+                "10" => 11,
+                "11" => 12,
+                "12" => 13,
+                "13" => 14,
+                "14" => 15,
+                "15" => 18
+            ],
+            "2" => [
+                "0" => 2,
+                "1" => 3,
+                "2" => 4,
+                "3" => 5,
+                "4" => 6,
+                "5" => 7,
+                "6" => 8,
+                "7" => 9,
+                "8" => 10,
+                "9" => 11,
+                "10" => 12,
+                "11" => 13,
+                "12" => 14,
+                "13" => 15,
+                "14" => 16,
+                "15" => 19
+            ],
+            "3" => [
+                "0" => 4,
+                "1" => 6,
+                "2" => 8,
+                "3" => 10,
+                "4" => 12,
+                "5" => 14,
+                "6" => 16,
+                "7" => 18,
+                "8" => 20,
+                "9" => 22,
+                "10" => 24,
+                "11" => 26,
+                "12" => 28,
+                "13" => 30,
+                "14" => 32,
+                "15" => 38
+            ],
+            "4" => [
+                "0" => 5,
+                "1" => 7,
+                "2" => 9,
+                "3" => 11,
+                "4" => 13,
+                "5" => 16,
+                "6" => 18,
+                "7" => 20,
+                "8" => 22,
+                "9" => 24,
+                "10" => 27,
+                "11" => 29,
+                "12" => 31,
+                "13" => 33,
+                "14" => 36,
+                "15" => 43
+            ],
+            "5" => [
+                "0" => 8,
+                "1" => 10,
+                "2" => 12,
+                "3" => 15,
+                "4" => 17,
+                "5" => 20,
+                "6" => 22,
+                "7" => 24,
+                "8" => 27,
+                "9" => 29,
+                "10" => 32,
+                "11" => 34,
+                "12" => 37,
+                "13" => 40,
+                "14" => 43,
+                "15" => 51
+            ],
+            "6" => [
+                "0" => 11,
+                "1" => 14,
+                "2" => 17,
+                "3" => 20,
+                "4" => 23,
+                "5" => 26,
+                "6" => 29,
+                "7" => 32,
+                "8" => 35,
+                "9" => 38,
+                "10" => 41,
+                "11" => 44,
+                "12" => 47,
+                "13" => 50,
+                "14" => 53,
+                "15" => 63
+            ]
+        ];
+        
+        /**
+         * Values of the DEF main stat[stars][level]
+         */
+        const DEF = [
+            "1" => [
+                "0" => 3,
+                "1" => 6,
+                "2" => 9,
+                "3" => 12,
+                "4" => 15,
+                "5" => 18,
+                "6" => 21,
+                "7" => 24,
+                "8" => 27,
+                "9" => 30,
+                "10" => 33,
+                "11" => 36,
+                "12" => 39,
+                "13" => 42,
+                "14" => 45,
+                "15" => 54
+            ],
+            "2" => [
+                "0" => 5,
+                "1" => 9,
+                "2" => 13,
+                "3" => 17,
+                "4" => 21,
+                "5" => 25,
+                "6" => 29,
+                "7" => 33,
+                "8" => 37,
+                "9" => 41,
+                "10" => 45,
+                "11" => 49,
+                "12" => 53,
+                "13" => 57,
+                "14" => 61,
+                "15" => 73
+            ],
+            "3" => [
+                "0" => 7,
+                "1" => 12,
+                "2" => 17,
+                "3" => 22,
+                "4" => 27,
+                "5" => 32,
+                "6" => 37,
+                "7" => 42,
+                "8" => 47,
+                "9" => 52,
+                "10" => 57,
+                "11" => 62,
+                "12" => 67,
+                "13" => 72,
+                "14" => 77,
+                "15" => 92
+            ],
+            "4" => [
+                "0" => 10,
+                "1" => 16,
+                "2" => 22,
+                "3" => 28,
+                "4" => 34,
+                "5" => 40,
+                "6" => 46,
+                "7" => 52,
+                "8" => 58,
+                "9" => 64,
+                "10" => 70,
+                "11" => 76,
+                "12" => 82,
+                "13" => 88,
+                "14" => 94,
+                "15" => 112
+            ],
+            "5" => [
+                "0" => 15,
+                "1" => 22,
+                "2" => 29,
+                "3" => 36,
+                "4" => 43,
+                "5" => 50,
+                "6" => 57,
+                "7" => 64,
+                "8" => 71,
+                "9" => 78,
+                "10" => 85,
+                "11" => 92,
+                "12" => 99,
+                "13" => 106,
+                "14" => 113,
+                "15" => 135
+            ],
+            "6" => [
+                "0" => 22,
+                "1" => 30,
+                "2" => 38,
+                "3" => 46,
+                "4" => 54,
+                "5" => 62,
+                "6" => 70,
+                "7" => 78,
+                "8" => 86,
+                "9" => 94,
+                "10" => 102,
+                "11" => 110,
+                "12" => 118,
+                "13" => 126,
+                "14" => 134,
+                "15" => 160
+            ]
+        ];
+        
+        /**
+         * Values of the DEF_P main stat[stars][level]
+         */
+        const DEF_P = [
+            "1" => [
+                "0" => 1,
+                "1" => 2,
+                "2" => 3,
+                "3" => 4,
+                "4" => 5,
+                "5" => 6,
+                "6" => 7,
+                "7" => 8,
+                "8" => 9,
+                "9" => 10,
+                "10" => 11,
+                "11" => 12,
+                "12" => 13,
+                "13" => 14,
+                "14" => 15,
+                "15" => 18
+            ],
+            "2" => [
+                "0" => 2,
+                "1" => 3,
+                "2" => 4,
+                "3" => 5,
+                "4" => 6,
+                "5" => 7,
+                "6" => 8,
+                "7" => 9,
+                "8" => 10,
+                "9" => 11,
+                "10" => 12,
+                "11" => 13,
+                "12" => 14,
+                "13" => 15,
+                "14" => 16,
+                "15" => 19
+            ],
+            "3" => [
+                "0" => 4,
+                "1" => 6,
+                "2" => 8,
+                "3" => 10,
+                "4" => 12,
+                "5" => 14,
+                "6" => 16,
+                "7" => 18,
+                "8" => 20,
+                "9" => 22,
+                "10" => 24,
+                "11" => 26,
+                "12" => 28,
+                "13" => 30,
+                "14" => 32,
+                "15" => 38
+            ],
+            "4" => [
+                "0" => 5,
+                "1" => 7,
+                "2" => 9,
+                "3" => 11,
+                "4" => 13,
+                "5" => 16,
+                "6" => 18,
+                "7" => 20,
+                "8" => 22,
+                "9" => 24,
+                "10" => 27,
+                "11" => 29,
+                "12" => 31,
+                "13" => 33,
+                "14" => 36,
+                "15" => 43
+            ],
+            "5" => [
+                "0" => 8,
+                "1" => 10,
+                "2" => 12,
+                "3" => 15,
+                "4" => 17,
+                "5" => 20,
+                "6" => 22,
+                "7" => 24,
+                "8" => 27,
+                "9" => 29,
+                "10" => 32,
+                "11" => 34,
+                "12" => 37,
+                "13" => 40,
+                "14" => 43,
+                "15" => 51
+            ],
+            "6" => [
+                "0" => 11,
+                "1" => 14,
+                "2" => 17,
+                "3" => 20,
+                "4" => 23,
+                "5" => 26,
+                "6" => 29,
+                "7" => 32,
+                "8" => 35,
+                "9" => 38,
+                "10" => 41,
+                "11" => 44,
+                "12" => 47,
+                "13" => 50,
+                "14" => 53,
+                "15" => 63
+            ]
+        ];
+
+        /**
+         * Values of the SPD main stat[stars][level]
+         */
+        const SPD = [
+            "1" => [
+                "0" => 1,
+                "1" => 2,
+                "2" => 3,
+                "3" => 4,
+                "4" => 5,
+                "5" => 6,
+                "6" => 7,
+                "7" => 8,
+                "8" => 9,
+                "9" => 10,
+                "10" => 11,
+                "11" => 12,
+                "12" => 13,
+                "13" => 14,
+                "14" => 15,
+                "15" => 18
+            ],
+            "2" => [
+                "0" => 2,
+                "1" => 3,
+                "2" => 4,
+                "3" => 5,
+                "4" => 6,
+                "5" => 7,
+                "6" => 8,
+                "7" => 9,
+                "8" => 10,
+                "9" => 11,
+                "10" => 12,
+                "11" => 13,
+                "12" => 14,
+                "13" => 15,
+                "14" => 16,
+                "15" => 19
+            ],
+            "3" => [
+                "0" => 3,
+                "1" => 4,
+                "2" => 5,
+                "3" => 6,
+                "4" => 8,
+                "5" => 9,
+                "6" => 10,
+                "7" => 12,
+                "8" => 13,
+                "9" => 14,
+                "10" => 16,
+                "11" => 17,
+                "12" => 18,
+                "13" => 19,
+                "14" => 21,
+                "15" => 25
+            ],
+            "4" => [
+                "0" => 4,
+                "1" => 5,
+                "2" => 7,
+                "3" => 8,
+                "4" => 10,
+                "5" => 11,
+                "6" => 13,
+                "7" => 14,
+                "8" => 16,
+                "9" => 17,
+                "10" => 19,
+                "11" => 20,
+                "12" => 22,
+                "13" => 23,
+                "14" => 25,
+                "15" => 30
+            ],
+            "5" => [
+                "0" => 5,
+                "1" => 7,
+                "2" => 9,
+                "3" => 11,
+                "4" => 13,
+                "5" => 15,
+                "6" => 17,
+                "7" => 19,
+                "8" => 21,
+                "9" => 23,
+                "10" => 25,
+                "11" => 27,
+                "12" => 29,
+                "13" => 31,
+                "14" => 33,
+                "15" => 39
+            ],
+            "6" => [
+                "0" => 7,
+                "1" => 9,
+                "2" => 11,
+                "3" => 13,
+                "4" => 15,
+                "5" => 17,
+                "6" => 19,
+                "7" => 21,
+                "8" => 23,
+                "9" => 25,
+                "10" => 27,
+                "11" => 29,
+                "12" => 31,
+                "13" => 33,
+                "14" => 35,
+                "15" => 42
+            ]
+        ];
+
+        /**
+         * Values of the CRR main stat[stars][level]
+         */
+        const CRR = [
+            "1" => [
+                "0" => 1,
+                "1" => 2,
+                "2" => 3,
+                "3" => 4,
+                "4" => 5,
+                "5" => 6,
+                "6" => 7,
+                "7" => 8,
+                "8" => 9,
+                "9" => 10,
+                "10" => 11,
+                "11" => 12,
+                "12" => 13,
+                "13" => 14,
+                "14" => 15,
+                "15" => 18
+            ],
+            "2" => [
+                "0" => 2,
+                "1" => 3,
+                "2" => 4,
+                "3" => 5,
+                "4" => 6,
+                "5" => 7,
+                "6" => 8,
+                "7" => 9,
+                "8" => 10,
+                "9" => 11,
+                "10" => 12,
+                "11" => 13,
+                "12" => 14,
+                "13" => 15,
+                "14" => 16,
+                "15" => 19
+            ],
+            "3" => [
+                "0" => 3,
+                "1" => 5,
+                "2" => 7,
+                "3" => 9,
+                "4" => 11,
+                "5" => 13,
+                "6" => 15,
+                "7" => 17,
+                "8" => 19,
+                "9" => 21,
+                "10" => 23,
+                "11" => 25,
+                "12" => 27,
+                "13" => 29,
+                "14" => 31,
+                "15" => 37
+            ],
+            "4" => [
+                "0" => 4,
+                "1" => 6,
+                "2" => 8,
+                "3" => 11,
+                "4" => 13,
+                "5" => 15,
+                "6" => 17,
+                "7" => 19,
+                "8" => 22,
+                "9" => 24,
+                "10" => 26,
+                "11" => 28,
+                "12" => 30,
+                "13" => 33,
+                "14" => 35,
+                "15" => 41
+            ],
+            "5" => [
+                "0" => 5,
+                "1" => 7,
+                "2" => 10,
+                "3" => 12,
+                "4" => 15,
+                "5" => 17,
+                "6" => 19,
+                "7" => 22,
+                "8" => 24,
+                "9" => 27,
+                "10" => 29,
+                "11" => 31,
+                "12" => 34,
+                "13" => 36,
+                "14" => 39,
+                "15" => 47
+            ],
+            "6" => [
+                "0" => 7,
+                "1" => 10,
+                "2" => 13,
+                "3" => 16,
+                "4" => 19,
+                "5" => 22,
+                "6" => 25,
+                "7" => 28,
+                "8" => 31,
+                "9" => 34,
+                "10" => 37,
+                "11" => 40,
+                "12" => 43,
+                "13" => 46,
+                "14" => 49,
+                "15" => 58
+            ]
+        ];
+
+        /**
+         * Values of the CRD main stat[stars][level]
+         */
+        const CRD = [
+            "1" => [
+                "0" => 2,
+                "1" => 3,
+                "2" => 4,
+                "3" => 5,
+                "4" => 6,
+                "5" => 7,
+                "6" => 8,
+                "7" => 9,
+                "8" => 10,
+                "9" => 11,
+                "10" => 12,
+                "11" => 13,
+                "12" => 14,
+                "13" => 15,
+                "14" => 16,
+                "15" => 19
+            ],
+            "2" => [
+                "0" => 3,
+                "1" => 5,
+                "2" => 7,
+                "3" => 9,
+                "4" => 11,
+                "5" => 13,
+                "6" => 15,
+                "7" => 17,
+                "8" => 19,
+                "9" => 21,
+                "10" => 23,
+                "11" => 25,
+                "12" => 27,
+                "13" => 29,
+                "14" => 31,
+                "15" => 37
+            ],
+            "3" => [
+                "0" => 4,
+                "1" => 6,
+                "2" => 9,
+                "3" => 11,
+                "4" => 13,
+                "5" => 16,
+                "6" => 18,
+                "7" => 20,
+                "8" => 22,
+                "9" => 25,
+                "10" => 27,
+                "11" => 29,
+                "12" => 32,
+                "13" => 34,
+                "14" => 36,
+                "15" => 43
+            ],
+            "4" => [
+                "0" => 6,
+                "1" => 9,
+                "2" => 12,
+                "3" => 15,
+                "4" => 18,
+                "5" => 21,
+                "6" => 24,
+                "7" => 27,
+                "8" => 30,
+                "9" => 33,
+                "10" => 36,
+                "11" => 39,
+                "12" => 42,
+                "13" => 45,
+                "14" => 48,
+                "15" => 57
+            ],
+            "5" => [
+                "0" => 8,
+                "1" => 11,
+                "2" => 15,
+                "3" => 18,
+                "4" => 21,
+                "5" => 25,
+                "6" => 28,
+                "7" => 31,
+                "8" => 34,
+                "9" => 38,
+                "10" => 41,
+                "11" => 44,
+                "12" => 48,
+                "13" => 51,
+                "14" => 54,
+                "15" => 65
+            ],
+            "6" => [
+                "0" => 11,
+                "1" => 15,
+                "2" => 19,
+                "3" => 23,
+                "4" => 27,
+                "5" => 31,
+                "6" => 35,
+                "7" => 39,
+                "8" => 43,
+                "9" => 47,
+                "10" => 51,
+                "11" => 55,
+                "12" => 59,
+                "13" => 63,
+                "14" => 67,
+                "15" => 80
+            ]
+        ];
+
+        /**
+         * Values of the ACC main stat[stars][level]
+         */
+        const ACC = [
+            "1" => [
+                "0" => 1,
+                "1" => 2,
+                "2" => 3,
+                "3" => 4,
+                "4" => 5,
+                "5" => 6,
+                "6" => 7,
+                "7" => 8,
+                "8" => 9,
+                "9" => 10,
+                "10" => 11,
+                "11" => 12,
+                "12" => 13,
+                "13" => 14,
+                "14" => 15,
+                "15" => 18
+            ],
+            "2" => [
+                "0" => 2,
+                "1" => 3,
+                "2" => 4,
+                "3" => 5,
+                "4" => 6,
+                "5" => 7,
+                "6" => 8,
+                "7" => 9,
+                "8" => 10,
+                "9" => 11,
+                "10" => 12,
+                "11" => 13,
+                "12" => 14,
+                "13" => 15,
+                "14" => 16,
+                "15" => 19
+            ],
+            "3" => [
+                "0" => 4,
+                "1" => 6,
+                "2" => 8,
+                "3" => 10,
+                "4" => 12,
+                "5" => 14,
+                "6" => 16,
+                "7" => 18,
+                "8" => 20,
+                "9" => 22,
+                "10" => 24,
+                "11" => 26,
+                "12" => 28,
+                "13" => 30,
+                "14" => 32,
+                "15" => 38
+            ],
+            "4" => [
+                "0" => 6,
+                "1" => 8,
+                "2" => 10,
+                "3" => 13,
+                "4" => 15,
+                "5" => 17,
+                "6" => 19,
+                "7" => 21,
+                "8" => 24,
+                "9" => 26,
+                "10" => 28,
+                "11" => 30,
+                "12" => 32,
+                "13" => 35,
+                "14" => 37,
+                "15" => 44
+            ],
+            "5" => [
+                "0" => 9,
+                "1" => 11,
+                "2" => 14,
+                "3" => 16,
+                "4" => 19,
+                "5" => 21,
+                "6" => 23,
+                "7" => 26,
+                "8" => 28,
+                "9" => 31,
+                "10" => 33,
+                "11" => 35,
+                "12" => 38,
+                "13" => 40,
+                "14" => 43,
+                "15" => 51
+            ],
+            "6" => [
+                "0" => 12,
+                "1" => 15,
+                "2" => 18,
+                "3" => 21,
+                "4" => 24,
+                "5" => 27,
+                "6" => 30,
+                "7" => 33,
+                "8" => 36,
+                "9" => 39,
+                "10" => 42,
+                "11" => 45,
+                "12" => 48,
+                "13" => 51,
+                "14" => 54,
+                "15" => 64
+            ]
+        ];
+
+        /**
+         * Values of the RES main stat[stars][level]
+         */
+        const RES = [
+            "1" => [
+                "0" => 1,
+                "1" => 2,
+                "2" => 3,
+                "3" => 4,
+                "4" => 5,
+                "5" => 6,
+                "6" => 7,
+                "7" => 8,
+                "8" => 9,
+                "9" => 10,
+                "10" => 11,
+                "11" => 12,
+                "12" => 13,
+                "13" => 14,
+                "14" => 15,
+                "15" => 18
+            ],
+            "2" => [
+                "0" => 2,
+                "1" => 3,
+                "2" => 4,
+                "3" => 5,
+                "4" => 6,
+                "5" => 7,
+                "6" => 8,
+                "7" => 9,
+                "8" => 10,
+                "9" => 11,
+                "10" => 12,
+                "11" => 13,
+                "12" => 14,
+                "13" => 15,
+                "14" => 16,
+                "15" => 19
+            ],
+            "3" => [
+                "0" => 4,
+                "1" => 6,
+                "2" => 8,
+                "3" => 10,
+                "4" => 12,
+                "5" => 14,
+                "6" => 16,
+                "7" => 18,
+                "8" => 20,
+                "9" => 22,
+                "10" => 24,
+                "11" => 26,
+                "12" => 28,
+                "13" => 30,
+                "14" => 32,
+                "15" => 38
+            ],
+            "4" => [
+                "0" => 6,
+                "1" => 8,
+                "2" => 10,
+                "3" => 13,
+                "4" => 15,
+                "5" => 17,
+                "6" => 19,
+                "7" => 21,
+                "8" => 24,
+                "9" => 26,
+                "10" => 28,
+                "11" => 30,
+                "12" => 32,
+                "13" => 35,
+                "14" => 37,
+                "15" => 44
+            ],
+            "5" => [
+                "0" => 9,
+                "1" => 11,
+                "2" => 14,
+                "3" => 16,
+                "4" => 19,
+                "5" => 21,
+                "6" => 23,
+                "7" => 26,
+                "8" => 28,
+                "9" => 31,
+                "10" => 33,
+                "11" => 35,
+                "12" => 38,
+                "13" => 40,
+                "14" => 43,
+                "15" => 51
+            ],
+            "6" => [
+                "0" => 12,
+                "1" => 15,
+                "2" => 18,
+                "3" => 21,
+                "4" => 24,
+                "5" => 27,
+                "6" => 30,
+                "7" => 33,
+                "8" => 36,
+                "9" => 39,
+                "10" => 42,
+                "11" => 45,
+                "12" => 48,
+                "13" => 51,
+                "14" => 54,
+                "15" => 64
+            ]
+        ];
+    };
+
     /**
     /**
      * Artifact types.
      * Artifact types.
      *
      *

+ 7 - 3
application/Controller.php

@@ -87,6 +87,10 @@
                             require_once(__DIR__ . "/API/v2/API_Controller.php");
                             require_once(__DIR__ . "/API/v2/API_Controller.php");
                             new API_Controller($params);
                             new API_Controller($params);
                             break;
                             break;
+                        case "v3":
+                            require_once(__DIR__ . "/API/v3/API_Controller.php");
+                            new API_Controller($params);
+                            break;
                     }
                     }
                 }
                 }
                 return;
                 return;
@@ -284,9 +288,9 @@
                         require_once(PATH::PAGE . "Report_Skillup_Page.php");
                         require_once(PATH::PAGE . "Report_Skillup_Page.php");
                         $page = new Report_Skillup_Page($pars[1]);
                         $page = new Report_Skillup_Page($pars[1]);
                     }
                     }
-                    elseif (strtoupper($pars[1]) == "RUNECRAFT"){
-                        require_once(PATH::PAGE . "Report_Runecraft_Page.php");
-                        $page = new Report_Runecraft_Page($pars[1]);
+                    elseif (strtoupper($pars[1]) == "RUNE_ENCHANTMENT"){
+                        require_once(PATH::PAGE . "Report_Rune_Enchantment_Page.php");
+                        $page = new Report_Rune_Enchantment_Page($pars[1]);
                     }
                     }
                 }
                 }
                 elseif (strtoupper($pars[0]) == "OPTIMIZER"){
                 elseif (strtoupper($pars[0]) == "OPTIMIZER"){

+ 6 - 7
application/action/delete_team.php

@@ -22,17 +22,16 @@
     function action(){
     function action(){
 
 
         global $db;
         global $db;
-
         $player = filter_input(INPUT_POST, 'uid');
         $player = filter_input(INPUT_POST, 'uid');
         $id = filter_input(INPUT_POST, 'id');
         $id = filter_input(INPUT_POST, 'id');
         $statement = $db->prepare('DELETE FROM team WHERE uid = :uid AND id = :id;');
         $statement = $db->prepare('DELETE FROM team WHERE uid = :uid AND id = :id;');
-        $statement->bindValue(':uid', $player);
-        $statement->bindValue(':id', $id);
-        $res = $statement->execute();
+        $statement->bindValue(':uid', $player, SQLITE3_INTEGER);
+        $statement->bindValue(':id', $id, SQLITE3_INTEGER);
+        $statement->execute();
         $statement = $db->prepare('DELETE FROM team_unit WHERE team = :id;');
         $statement = $db->prepare('DELETE FROM team_unit WHERE team = :id;');
-        $statement->bindValue(':uid', $player);
-        $statement->bindValue(':id', $id);
-        $res = $statement->execute();
+        $statement->bindValue(':uid', $player, SQLITE3_INTEGER);
+        $statement->bindValue(':id', $id, SQLITE3_INTEGER);
+        $statement->execute();
         return 0;
         return 0;
     }
     }
 ?>
 ?>

+ 10 - 10
application/action/edit_profile.php

@@ -37,8 +37,8 @@
                 return -1;
                 return -1;
             }
             }
             $s = $db->prepare('UPDATE player SET mail = :mail WHERE uid = :uid;');
             $s = $db->prepare('UPDATE player SET mail = :mail WHERE uid = :uid;');
-            $s->bindValue(':uid', $player);
-            $s->bindValue(':mail', $mail);
+            $s->bindValue(':uid', $player, SQLITE3_INTEGER);
+            $s->bindValue(':mail', $mail, SQLITE3_TEXT);
             if(!$s->execute()){
             if(!$s->execute()){
                 return -2;
                 return -2;
             }
             }
@@ -48,17 +48,17 @@
             $pass = sha1(filter_input(INPUT_POST, 'pass'));
             $pass = sha1(filter_input(INPUT_POST, 'pass'));
             $currentPass = sha1(filter_input(INPUT_POST, 'currentPass'));
             $currentPass = sha1(filter_input(INPUT_POST, 'currentPass'));
             $s = $db->prepare('SELECT COUNT(uid) AS count FROM player WHERE uid = :uid AND password = :currentPass;');
             $s = $db->prepare('SELECT COUNT(uid) AS count FROM player WHERE uid = :uid AND password = :currentPass;');
-            $s->bindValue(':uid', $player);
-            $s->bindValue(':currentPass', $currentPass);
+            $s->bindValue(':uid', $player, SQLITE3_INTEGER);
+            $s->bindValue(':currentPass', $currentPass, SQLITE3_TEXT);
             $q = $s->execute();
             $q = $s->execute();
             $r = $q->fetchArray(SQLITE3_ASSOC);
             $r = $q->fetchArray(SQLITE3_ASSOC);
             if ($r["count"] != 1){
             if ($r["count"] != 1){
                 return -3;
                 return -3;
             }
             }
             $s = $db->prepare('UPDATE player SET password = :pass WHERE uid = :uid AND password = :currentPass;');
             $s = $db->prepare('UPDATE player SET password = :pass WHERE uid = :uid AND password = :currentPass;');
-            $s->bindValue(':uid', $player);
-            $s->bindValue(':pass', $mail);
-            $s->bindValue(':currentPass', $currentPass);
+            $s->bindValue(':uid', $player, SQLITE3_INTEGER);
+            $s->bindValue(':pass', $pass, SQLITE3_TEXT);
+            $s->bindValue(':currentPass', $currentPass, SQLITE3_TEXT);
             if(!$s->execute()){
             if(!$s->execute()){
                 return -4;
                 return -4;
             }
             }
@@ -68,12 +68,12 @@
             $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
             $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
             $charactersLength = 16;
             $charactersLength = 16;
             $api = '';
             $api = '';
-            for ($i = 0; $i < $length; $i++) {
+            for ($i = 0; $i < $charactersLength; $i++) {
                 $api .= $characters[rand(0, $charactersLength - 1)];
                 $api .= $characters[rand(0, $charactersLength - 1)];
             }
             }
             $s = $db->prepare('UPDATE player SET api_key = :api WHERE uid = :uid;');
             $s = $db->prepare('UPDATE player SET api_key = :api WHERE uid = :uid;');
-            $s->bindValue(':uid', $player);
-            $s->bindValue(':api', $api);
+            $s->bindValue(':uid', $player, SQLITE3_INTEGER);
+            $s->bindValue(':api', $api, SQLITE3_TEXT);
             if(!$s->execute()){
             if(!$s->execute()){
                 return -5;
                 return -5;
             }
             }

+ 24 - 14
application/action/login.php

@@ -26,27 +26,37 @@
         global $db;
         global $db;
 
 
         if (!isset($_POST['uname'], $_POST['password'])){
         if (!isset($_POST['uname'], $_POST['password'])){
-error_log("-1");
-            return -1;
+            header("Location: " . URL::BASE);
+            exit();
         }
         }
         $uname = SQLite3::escapeString($_POST['uname']);
         $uname = SQLite3::escapeString($_POST['uname']);
         if (strlen($uname) == 0){
         if (strlen($uname) == 0){
-error_log("-2");
-            return -2;
+            header("Location: " . URL::BASE);
+            exit();
         }
         }
         $password = SQLite3::escapeString($_POST['password']);
         $password = SQLite3::escapeString($_POST['password']);
         if (strlen($password) == 0){
         if (strlen($password) == 0){
-error_log("-3");
-            return -3;
+            header("Location: " . URL::BASE);
+            exit();
         }
         }
         $password = hash('sha256', $password);
         $password = hash('sha256', $password);
-error_log("SELECT uid FROM player WHERE upper(name) = upper('$uname') AND password = '$password';");
-        $q = $db->query("SELECT uid FROM player;");
-        $r = $q->fetchArray(SQLITE3_ASSOC);
-error_log("RET ID: " . $r["uid"]);
+        $statement = $db->prepare("
+          SELECT uid 
+          FROM player 
+          WHERE
+            upper(name) = upper(:name) AND 
+            password = :password;
+        ");
+        $statement->bindValue(":name", $uname, SQLITE3_TEXT);
+        $statement->bindValue(":password", $password, SQLITE3_TEXT);
+        $statement->execute();
+        $r = $statement->execute()->fetchArray(SQLITE3_ASSOC);
         if (!$r){
         if (!$r){
-error_log("-4");
-            return -4;
+            error_log("REDIRECT TO:" . URL::BASE);
+            header("Location: " . URL::BASE);
+            exit();
+            die();
+            return 401;
         }
         }
         $uid = $r["uid"];
         $uid = $r["uid"];
         setcookie("uid", $uid, time() + 5 * 24 * 60 * 60); // 5 Days
         setcookie("uid", $uid, time() + 5 * 24 * 60 * 60); // 5 Days
@@ -54,9 +64,9 @@ error_log("-4");
         $_SESSION['session'] = true;
         $_SESSION['session'] = true;
         $_SESSION['name'] = $uname;
         $_SESSION['name'] = $uname;
         $_SESSION['uid'] = $uid;
         $_SESSION['uid'] = $uid;
-        header("Location: /$uid/");
+        header("Location: " . URL::BASE . "/$uid/");
+        exit();
         die();
         die();
-error_log("0");
         return 0;
         return 0;
     }
     }
 ?>
 ?>

+ 1 - 2
application/action/logout.php

@@ -18,8 +18,7 @@
      * @global int The user id.
      * @global int The user id.
      */
      */
     function action(){
     function action(){
-        global $UID;
-        $UID = null;
+        $GLOBALS["UID"] = null;
         setcookie("uid", null, time() - 3600);
         setcookie("uid", null, time() - 3600);
         session_regenerate_id();
         session_regenerate_id();
         $_SESSION['session'] = false;
         $_SESSION['session'] = false;

+ 17 - 10
application/action/new_team.php

@@ -172,15 +172,15 @@
         $r = $q->fetchArray(SQLITE3_ASSOC);
         $r = $q->fetchArray(SQLITE3_ASSOC);
         $team_id = $r["id"];
         $team_id = $r["id"];
         $statement = $db->prepare('INSERT INTO team (uid, id, name, description, area_type, area, stage, difficulty, score) VALUES (:uid, :id, :name, :description, :area_type, :area, :stage, :difficulty, :score);');
         $statement = $db->prepare('INSERT INTO team (uid, id, name, description, area_type, area, stage, difficulty, score) VALUES (:uid, :id, :name, :description, :area_type, :area, :stage, :difficulty, :score);');
-        $statement->bindValue(':uid', $player);
-        $statement->bindValue(':id', $team_id);
-        $statement->bindValue(':name', $name);
-        $statement->bindValue(':description', $description);
-        $statement->bindValue(':area_type', $area_type);
-        $statement->bindValue(':area', $area);
-        $statement->bindValue(':stage', $stage);
-        $statement->bindValue(':difficulty', $difficulty);
-        $statement->bindValue(':score', $score);
+        $statement->bindValue(':uid', $player, SQLITE3_INTEGER);
+        $statement->bindValue(':id', $team_id, SQLITE3_INTEGER);
+        $statement->bindValue(':name', $name, SQLITE3_TEXT);
+        $statement->bindValue(':description', $description, SQLITE3_TEXT);
+        $statement->bindValue(':area_type', $area_type, SQLITE3_INTEGER);
+        $statement->bindValue(':area', $area, SQLITE3_INTEGER);
+        $statement->bindValue(':stage', $stage, SQLITE3_INTEGER);
+        $statement->bindValue(':difficulty', $difficulty, SQLITE3_INTEGER);
+        $statement->bindValue(':score', $score, SQLITE3_INTEGER);
         $res = $statement->execute();
         $res = $statement->execute();
         if (!$res){
         if (!$res){
             return -5;
             return -5;
@@ -196,7 +196,14 @@
             if ($j < $total_front){
             if ($j < $total_front){
                 $front = 1;
                 $front = 1;
             }
             }
-            $s = "INSERT INTO team_unit VALUES ($team_id, $i, $leader, $front);";
+            $statement = $db->prepare("
+              INSERT INTO team_unit (team, unit, leader, front)
+              VALUES (:team, :unit, :leader, :front);
+            ");
+            $statement->bindValue(':team', $team_id, SQLITE3_INTEGER);
+            $statement->bindValue(':unit', $i, SQLITE3_INTEGER);
+            $statement->bindValue(':leader', $leader, SQLITE3_INTEGER);
+            $statement->bindValue(':front', $front, SQLITE3_INTEGER);
             $db->query($s);
             $db->query($s);
             $j ++;
             $j ++;
         }
         }

+ 1 - 4
application/action/optimize_get_options.php

@@ -21,12 +21,9 @@
      * @return int|string 0 on success, negative values on error. If the API
      * @return int|string 0 on success, negative values on error. If the API
      * key has been updated, the new key.
      * key has been updated, the new key.
      * @category Action
      * @category Action
-     * @global resource Database connection.
      */
      */
     function action(){
     function action(){
 
 
-        global $db;
-
         // Increase max execution time.
         // Increase max execution time.
         set_time_limit(60);
         set_time_limit(60);
         
         
@@ -109,7 +106,7 @@
                         break;
                         break;
                 }
                 }
                 $stat_values = [
                 $stat_values = [
-                    $rune->main_stat_value,
+                    $main_value,
                     $rune->innate_stat_value,
                     $rune->innate_stat_value,
                     $rune->substat_1_value + $rune->substat_1_craft,
                     $rune->substat_1_value + $rune->substat_1_craft,
                     $rune->substat_2_value + $rune->substat_2_craft,
                     $rune->substat_2_value + $rune->substat_2_craft,

+ 14 - 25
application/action/optimize_get_rune_list.php

@@ -26,8 +26,6 @@
     function action(){
     function action(){
 
 
         global $db;
         global $db;
-        
-        $HARD_LIMIT = 100;
 
 
         // Increase max execution time.
         // Increase max execution time.
         set_time_limit(60);
         set_time_limit(60);
@@ -40,8 +38,6 @@
             5 => [],
             5 => [],
             6 => []
             6 => []
         ];
         ];
-        
-        $options = [];
 
 
         $response = null;
         $response = null;
 
 
@@ -84,19 +80,6 @@
         if ($tuning == null){
         if ($tuning == null){
             return -6;
             return -6;
         }
         }
-        
-        $min = [
-            "attack" => intval(filter_input(INPUT_POST, 'min_attack')),
-            "defense" => intval(filter_input(INPUT_POST, 'min_defense')),
-            "hp" => intval(filter_input(INPUT_POST, 'min_hp')),
-            "speed" => intval(filter_input(INPUT_POST, 'min_speed')),
-            "crit_rate" => intval(filter_input(INPUT_POST, 'min_crit_rate')),
-            "crit_damage" => intval(filter_input(INPUT_POST, 'min_crit_damage')),
-            "accuracy" => intval(filter_input(INPUT_POST, 'min_accuracy')),
-            "resistance" => intval(filter_input(INPUT_POST, 'min_resistance')),
-            "ehp" => intval(filter_input(INPUT_POST, 'min_ehp')),
-            "dmg" => intval(filter_input(INPUT_POST, 'min_dmg'))
-        ];
 
 
         // Instantiate the unit
         // Instantiate the unit
         $unit = new Unit($unit_id, true, $uid);
         $unit = new Unit($unit_id, true, $uid);
@@ -123,7 +106,7 @@
             substat_4_value + substat_4_grind AS substat_4_value
             substat_4_value + substat_4_grind AS substat_4_value
           FROM rune
           FROM rune
           WHERE
           WHERE
-            uid = $uid AND
+            uid = :uid AND
             type IN (
             type IN (
         ";
         ";
         foreach ($sets as $set){
         foreach ($sets as $set){
@@ -134,14 +117,14 @@
             case 0: // Storage only (or itself)
             case 0: // Storage only (or itself)
                 $base_s .= "
                 $base_s .= "
                   (
                   (
-                    assigned_to = $unit_id OR
+                    assigned_to = :unit_id OR
                     assigned_to IS NULL
                     assigned_to IS NULL
                   )";
                   )";
                 break;
                 break;
             case 1: // Units in no teams (or itself)
             case 1: // Units in no teams (or itself)
                 $base_s .= "
                 $base_s .= "
                   (
                   (
-                    assigned_to = $unit_id OR
+                    assigned_to = :unit_id OR
                     assigned_to IS NULL OR 
                     assigned_to IS NULL OR 
                     assigned_to NOT IN (SELECT DISTINCT unit FROM team_unit)
                     assigned_to NOT IN (SELECT DISTINCT unit FROM team_unit)
                   )
                   )
@@ -150,7 +133,7 @@
             case 2: // Units in teams with 0 score (or itself)
             case 2: // Units in teams with 0 score (or itself)
                 $base_s .= "
                 $base_s .= "
                   (
                   (
-                    assigned_to = $unit_id OR
+                    assigned_to = :unit_id OR
                     assigned_to IS NULL OR 
                     assigned_to IS NULL OR 
                     assigned_to NOT IN (SELECT DISTINCT unit FROM team_unit) OR
                     assigned_to NOT IN (SELECT DISTINCT unit FROM team_unit) OR
                     assigned_to NOT IN (
                     assigned_to NOT IN (
@@ -175,7 +158,7 @@
                 $base_s .= " 1 = 0 ";
                 $base_s .= " 1 = 0 ";
         }
         }
         $s_order = " ORDER BY stars DESC, original_quality DESC, max_efficiency DESC, efficiency DESC, level DESC";
         $s_order = " ORDER BY stars DESC, original_quality DESC, max_efficiency DESC, efficiency DESC, level DESC";
-        $s_in = " main_stat IN (" . $stats[0] . ", " . $stats[1] . ", " . $stats[2] . ") ";
+        $s_in = " main_stat IN (:stat_0, :stat_1, :stat_2) ";
 
 
         $s = ["", "", "", "", "", "", ""];
         $s = ["", "", "", "", "", "", ""];
         $s[1] = $base_s . " AND slot = 1 " . $s_order;
         $s[1] = $base_s . " AND slot = 1 " . $s_order;
@@ -187,7 +170,13 @@
 
 
         $total_candidates = 0;
         $total_candidates = 0;
         for ($i = 1; $i <= 6; $i ++){
         for ($i = 1; $i <= 6; $i ++){
-            $q = $db->query($s[$i]);
+            $statement = $db->prepare($s[$i]);
+            $statement->bindValue(':uid', $uid, SQLITE3_INTEGER);
+            $statement->bindValue(':unit_id', $unit_id, SQLITE3_INTEGER);
+            $statement->bindValue(':stat_0', $stats[0], SQLITE3_INTEGER);
+            $statement->bindValue(':stat_1', $stats[1], SQLITE3_INTEGER);
+            $statement->bindValue(':stat_2', $stats[2], SQLITE3_INTEGER);
+            $q = $statement->execute();
             while ($r = $q->fetchArray(SQLITE3_ASSOC)){
             while ($r = $q->fetchArray(SQLITE3_ASSOC)){
                 $rune = create_rune_array($unit, $r, $tuning);
                 $rune = create_rune_array($unit, $r, $tuning);
                 //array_push($candidates[$i], new Rune($r["id"]));
                 //array_push($candidates[$i], new Rune($r["id"]));
@@ -195,7 +184,7 @@
                 $total_candidates ++;
                 $total_candidates ++;
             }
             }
         }
         }
-        $max_combinations = sizeof($candidates[1]) * sizeof($candidates[2]) * sizeof($candidates[3]) * sizeof($candidates[4]) * sizeof($candidates[5]) * sizeof($candidates[6]);
+        //$max_combinations = sizeof($candidates[1]) * sizeof($candidates[2]) * sizeof($candidates[3]) * sizeof($candidates[4]) * sizeof($candidates[5]) * sizeof($candidates[6]);
         
         
         // TODO: Build response
         // TODO: Build response
         $response = json_encode($candidates);
         $response = json_encode($candidates);
@@ -211,7 +200,7 @@
      * Creates an array with the stats provided by a rune on a unit.
      * Creates an array with the stats provided by a rune on a unit.
      *
      *
      * @param Unit $unit Target unit.
      * @param Unit $unit Target unit.
-     * @param SQLResult $r Rune main stat ID.
+     * @param int $r Rune main stat ID.
      * @param int $stars Rune stars.
      * @param int $stars Rune stars.
      * @return int Value of the main stat at the selected level.
      * @return int Value of the main stat at the selected level.
      */
      */

+ 14 - 8
application/action/rate_team.php

@@ -23,14 +23,20 @@
      */
      */
     function action(){
     function action(){
         global $db;
         global $db;
-        $player = filter_input(INPUT_GET, 'uid');
-        $team = filter_input(INPUT_GET, 'team');
-        $score = intval(filter_input(INPUT_GET, 'score'));
-        $statement = $db->prepare('UPDATE team SET score = :score WHERE uid = :uid AND id = :team;');
-        $statement->bindValue(':score', $score);
-        $statement->bindValue(':uid', $player);
-        $statement->bindValue(':team', $team);
-        $res = $statement->execute();
+        $player = filter_input(INPUT_GET, "uid");
+        $team = filter_input(INPUT_GET, "team");
+        $score = intval(filter_input(INPUT_GET, "score"));
+        $statement = $db->prepare("
+          UPDATE team
+          SET score = :score
+          WHERE
+            uid = :uid AND
+            id = :team;
+        ");
+        $statement->bindValue(":score", $score, SQLITE3_INTEGER);
+        $statement->bindValue(":uid", $player, SQLITE3_INTEGER);
+        $statement->bindValue(":team", $team, SQLITE3_INTEGER);
+        $statement->execute();
         return 0;
         return 0;
     }
     }
 ?>
 ?>

+ 34 - 14
application/action/save_run_team.php

@@ -34,22 +34,37 @@
         $q = $db->query($s);
         $q = $db->query($s);
         $r = $q->fetchArray(SQLITE3_ASSOC);
         $r = $q->fetchArray(SQLITE3_ASSOC);
         $team_id = $r["id"];
         $team_id = $r["id"];
-        $s = "SELECT run.area AS area, run.stage AS stage, run.difficulty AS difficulty, k_area.type AS area_type FROM run, k_area WHERE run.uid = '$player' AND run.id = '$run' AND k_area.id = run.area AND run.helper = 0;";
-        $q = $db->query($s);
-        $r = $q->fetchArray(SQLITE3_ASSOC);
+        $statement = $db->prepare("
+          SELECT
+            run.area AS area,
+            run.stage AS stage,
+            run.difficulty AS difficulty,
+            k_area.type AS area_type
+          FROM
+            run,
+            k_area
+          WHERE
+            run.uid = :uid AND
+            run.id = :run AND
+            k_area.id = run.area AND
+            run.helper = 0;
+        ");
+        $statement->bindValue(':uid', $player, SQLITE3_INTEGER);
+        $statement->bindValue(':run', $run, SQLITE3_INTEGER);
+        $r = $statement->execute()->fetchArray(SQLITE3_ASSOC);
         if (!$r){
         if (!$r){
             return -2;
             return -2;
         }
         }
         $statement = $db->prepare('INSERT INTO team (uid, id, name, description, area_type, area, stage, difficulty, score) VALUES (:uid, :id, :name, :description, :area_type, :area, :stage, :difficulty, :score);');
         $statement = $db->prepare('INSERT INTO team (uid, id, name, description, area_type, area, stage, difficulty, score) VALUES (:uid, :id, :name, :description, :area_type, :area, :stage, :difficulty, :score);');
-        $statement->bindValue(':uid', $player);
-        $statement->bindValue(':id', $team_id);
-        $statement->bindValue(':name', $name);
-        $statement->bindValue(':description', $description);
-        $statement->bindValue(':area_type', $r["area_type"]);
-        $statement->bindValue(':area', $r["area"]);
-        $statement->bindValue(':stage', $r["stage"]);
-        $statement->bindValue(':difficulty', $r["difficulty"]);
-        $statement->bindValue(':score', $score);
+        $statement->bindValue(':uid', $player, SQLITE3_INTEGER);
+        $statement->bindValue(':id', $team_id, SQLITE3_INTEGER);
+        $statement->bindValue(':name', $name, SQLITE3_TEXT);
+        $statement->bindValue(':description', $description, SQLITE3_TEXT);
+        $statement->bindValue(':area_type', $r["area_type"], SQLITE3_INTEGER);
+        $statement->bindValue(':area', $r["area"], SQLITE3_INTEGER);
+        $statement->bindValue(':stage', $r["stage"], SQLITE3_INTEGER);
+        $statement->bindValue(':difficulty', $r["difficulty"], SQLITE3_INTEGER);
+        $statement->bindValue(':score', 0, SQLITE3_INTEGER);
         $res = $statement->execute();
         $res = $statement->execute();
         if (!$res){
         if (!$res){
             return -3;
             return -3;
@@ -57,8 +72,13 @@
         $s = "SELECT unit FROM run_party WHERE run = $run AND unit IS NOT NULL;";
         $s = "SELECT unit FROM run_party WHERE run = $run AND unit IS NOT NULL;";
         $q = $db->query($s);
         $q = $db->query($s);
         while ($r = $q->fetchArray(SQLITE3_ASSOC)){
         while ($r = $q->fetchArray(SQLITE3_ASSOC)){
-            $s = "INSERT INTO team_unit VALUES ('$team_id', '" . $r["unit"] . "');";
-            $db->query($s);
+            $statement = $db->prepare("
+              INSERT INTO team_unit (team, unit)
+              VALUES (:team, :unit)
+            ");
+            $statement->bindValue(':team', $team_id, SQLITE3_INTEGER);
+            $statement->bindValue(':unit', $r["unit"], SQLITE3_INTEGER);
+            $statement->execute();
         }
         }
         return 0;
         return 0;
     }
     }

+ 45 - 51
application/entity/Artifact.php

@@ -65,14 +65,14 @@
         /**
         /**
          * @var int Artifact quality.
          * @var int Artifact quality.
          *
          *
-         * @see QUALITY
+         * @see QUALITY_ID
          */
          */
         public $quality;
         public $quality;
 
 
         /**
         /**
          * @var int Artifact original quality.
          * @var int Artifact original quality.
          *
          *
-         * @see QUALITY
+         * @see QUALITY_ID
          */
          */
         public $original_quality;
         public $original_quality;
 
 
@@ -201,41 +201,42 @@
 
 
             global $db;
             global $db;
 
 
-            $s =
-              "SELECT " .
-              "  id, " .
-              "  assigned_to, " .
-              "  type, " .
-              "  attribute, " .
-              "  archetype, " .
-              "  level, " .
-              "  quality, " .
-              "  original_quality, " .
-              "  value, " .
-              "  efficiency, " .
-              "  max_efficiency, " .
-              "  main_stat, " .
-              "  main_stat_value, " .
-              "  effect_1, " .
-              "  effect_1_value, " .
-              "  effect_1_enchant, " .
-              "  effect_1_grind, " .
-              "  effect_2, " .
-              "  effect_2_value, " .
-              "  effect_2_enchant, " .
-              "  effect_2_grind, " .
-              "  effect_3, " .
-              "  effect_3_value, " .
-              "  effect_3_enchant, " .
-              "  effect_3_grind, " .
-              "  effect_4, " .
-              "  effect_4_value, " .
-              "  effect_4_enchant, " .
-              "  effect_4_grind " .
-              "FROM artifact " .
-              "WHERE id = '$id'; ";
-            $q = $db->query($s);
-            $r = $q->fetchArray(SQLITE3_ASSOC);
+            $statement = $db->prepare("
+              SELECT
+                id,
+                assigned_to,
+                type,
+                attribute,
+                archetype,
+                level,
+                quality,
+                original_quality,
+                value,
+                efficiency,
+                max_efficiency,
+                main_stat,
+                main_stat_value,
+                effect_1,
+                effect_1_value,
+                effect_1_enchant,
+                effect_1_grind,
+                effect_2,
+                effect_2_value,
+                effect_2_enchant,
+                effect_2_grind,
+                effect_3,
+                effect_3_value,
+                effect_3_enchant,
+                effect_3_grind,
+                effect_4,
+                effect_4_value,
+                effect_4_enchant,
+                effect_4_grind
+              FROM artifact
+              WHERE id = :id;
+            ");
+            $statement->bindValue(':id', $id, SQLITE3_INTEGER);
+            $r = $statement->execute()->fetchArray(SQLITE3_ASSOC);
             if ($r){
             if ($r){
                 $this->id = $r["id"];
                 $this->id = $r["id"];
                 $this->assigned_to = $r["assigned_to"];
                 $this->assigned_to = $r["assigned_to"];
@@ -252,20 +253,12 @@
                 $this->main_stat_value = $r["main_stat_value"];
                 $this->main_stat_value = $r["main_stat_value"];
                 $this->effect_1 = $r["effect_1"];
                 $this->effect_1 = $r["effect_1"];
                 $this->effect_1_value = $r["effect_1_value"];
                 $this->effect_1_value = $r["effect_1_value"];
-                //$this->effect_1_enchant = $r["effect_1_enchant"];
-                //$this->effect_1_grind = $r["effect_1_grind"];
                 $this->effect_2 = $r["effect_2"];
                 $this->effect_2 = $r["effect_2"];
                 $this->effect_2_value = $r["effect_2_value"];
                 $this->effect_2_value = $r["effect_2_value"];
-                //$this->effect_2_enchant = $r["effect_2_enchant"];
-                //$this->effect_2_grind = $r["effect_2_grind"];
                 $this->effect_3 = $r["effect_3"];
                 $this->effect_3 = $r["effect_3"];
                 $this->effect_3_value = $r["effect_3_value"];
                 $this->effect_3_value = $r["effect_3_value"];
-                //$this->effect_3_enchant = $r["effect_3_enchant"];
-                //$this->effect_3_grind = $r["effect_3_grind"];
                 $this->effect_4 = $r["effect_4"];
                 $this->effect_4 = $r["effect_4"];
                 $this->effect_4_value = $r["effect_4_value"];
                 $this->effect_4_value = $r["effect_4_value"];
-                //$this->effect_4_enchant = $r["effect_4_enchant"];
-                //$this->effect_4_grind = $r["effect_4_grind"];
                 $this->refresh_names();
                 $this->refresh_names();
             }
             }
         }
         }
@@ -314,12 +307,13 @@
 
 
             global $db;
             global $db;
 
 
-            $s =
-              "SELECT name " .
-              "FROM k_artifact_effect " .
-              "WHERE id = '$effect'; ";
-            $q = $db->query($s);
-            $r = $q->fetchArray(SQLITE3_ASSOC);
+            $statement = $db->prepare("
+              SELECT name
+              FROM k_artifact_effect
+              WHERE id = :id;
+            ");
+            $statement->bindValue(':id', $effect, SQLITE3_INTEGER);
+            $r = $statement->execute()->fetchArray(SQLITE3_ASSOC);
             if ($r){
             if ($r){
                 return str_replace("{}", $value, $r["name"]);
                 return str_replace("{}", $value, $r["name"]);
             }
             }

+ 15 - 13
application/entity/Building.php

@@ -51,19 +51,21 @@
 
 
             global $db;
             global $db;
 
 
-            $s = "
-                SELECT
-                  uid,
-                  building,
-                  gain
-                FROM building
-                WHERE id = $id;
-            ";
-            $q = $db->query($s);
-            $r = $q->fetchArray(SQLITE3_ASSOC);
-            $this->uid = $r["uid"];
-            $this->building = new K_Building($r["building"]);
-            $this->gain = $r["gain"];
+            $statement = $db->prepare("
+              SELECT
+                uid,
+                building,
+                gain
+              FROM building
+              WHERE id = :id;
+            ");
+            $statement->bindValue(':id', $id, SQLITE3_INTEGER);
+            $r = $statement->execute()->fetchArray(SQLITE3_ASSOC);
+            if ($r){
+                $this->uid = $r["uid"];
+                $this->building = new K_Building($r["building"]);
+                $this->gain = $r["gain"];
+            }
         }
         }
     }
     }
 ?>
 ?>

+ 15 - 13
application/entity/Decoration.php

@@ -50,19 +50,21 @@
 
 
             global $db;
             global $db;
 
 
-            $s = "
-                SELECT
-                  uid,
-                  decoration,
-                  level
-                FROM decoration
-                WHERE id = $id;
-            ";
-            $q = $db->query($s);
-            $r = $q->fetchArray(SQLITE3_ASSOC);
-            $this->uid = $r["uid"];
-            $this->decoration = new K_Decoration($r["decoration"]);
-            $this->level = $r["level"];
+            $statement = $db->prepare("
+              SELECT
+                uid,
+                decoration,
+                level
+              FROM decoration
+              WHERE id = :id;
+            ");
+            $statement->bindValue(':id', $id, SQLITE3_INTEGER);
+            $r = $statement->execute()->fetchArray(SQLITE3_ASSOC);
+            if ($r){
+                $this->uid = $r["uid"];
+                $this->decoration = new K_Decoration($r["decoration"]);
+                $this->level = $r["level"];
+            }
         }
         }
     }
     }
 ?>
 ?>

+ 47 - 32
application/entity/Rune_Craft.php → application/entity/Enchantment.php

@@ -1,6 +1,6 @@
 <?php
 <?php
     /**
     /**
-     * Rune craft items entity file.
+     * Enchantments items entity file.
      *
      *
      * Creates the entity and makes it available.
      * Creates the entity and makes it available.
      *
      *
@@ -14,13 +14,13 @@
     require_once(PATH::ENTITY . "K_Rune_Set.php");
     require_once(PATH::ENTITY . "K_Rune_Set.php");
 
 
     /**
     /**
-     * Owned rune craft item.
+     * Owned enchantments.
      *
      *
-     * Represents an object from the table 'rune_craft'.
+     * Represents an object from the table 'enchantment'.
      *
      *
      * @category Entity
      * @category Entity
      */
      */
-    class Rune_Craft extends Entity{
+    class Enchantment extends Entity{
 
 
         /**
         /**
          * @var int Owner identifier.
          * @var int Owner identifier.
@@ -35,7 +35,7 @@
         /**
         /**
          * @var int Item quality.
          * @var int Item quality.
          *
          *
-         * @see QUALITY
+         * @see QUALITY_ID
          */
          */
         public $quality;
         public $quality;
 
 
@@ -52,7 +52,7 @@
         /**
         /**
          * @var int Stat the item modifies.
          * @var int Stat the item modifies.
          *
          *
-         * @see RUNE_STAT
+         * @see RUNE_STAT_ID
          */
          */
         public $stat;
         public $stat;
 
 
@@ -114,35 +114,35 @@
 
 
             global $db;
             global $db;
 
 
-            $s = "
+            $statement = $db->prepare("
               SELECT
               SELECT
-                rune_craft.id AS id,
-                rune_craft.quality As quality,
-                rune_craft.rune AS rune,
-                rune_craft.stat AS stat,
-                rune_craft.value AS value,
-                rune_craft.amount AS amount,
-                k_rune_craft_type.name AS name,
-                k_rune_craft_type.gem AS gem,
-                k_rune_craft_type.inmemorial AS inmemorial,
-                k_rune_craft_type.ancient AS ancient,
-                k_rune_craft_range.min AS min,
-                k_rune_craft_range.max AS max
+                enchantment.id AS id,
+                enchantment.quality As quality,
+                enchantment.rune AS rune,
+                enchantment.stat AS stat,
+                enchantment.value AS value,
+                enchantment.amount AS amount,
+                k_enchantment_type.name AS name,
+                k_enchantment_type.gem AS gem,
+                k_enchantment_type.inmemorial AS inmemorial,
+                k_enchantment_type.ancient AS ancient,
+                k_enchantment_range.min AS min,
+                k_enchantment_range.max AS max
               FROM
               FROM
-                rune_craft,
-                k_rune_craft_type,
-                k_rune_craft_range
+                enchantment,
+                k_enchantment_type,
+                k_enchantment_range
               WHERE
               WHERE
-                rune_craft.id = $id AND
-                rune_craft.type = k_rune_craft_type.id AND
-                k_rune_craft_type.gem = k_rune_craft_range.gem AND
-                k_rune_craft_type.gem = k_rune_craft_range.gem AND
-                k_rune_craft_type.ancient = k_rune_craft_range.ancient AND
-                rune_craft.quality = k_rune_craft_range.quality AND
-                rune_craft.stat = k_rune_craft_range.stat;
-            ";
-            $q = $db->query($s);
-            $r = $q->fetchArray(SQLITE3_ASSOC);
+                enchantment.id = :id AND
+                enchantment.type = k_enchantment_type.id AND
+                k_enchantment_type.gem = k_enchantment_range.gem AND
+                k_enchantment_type.gem = k_enchantment_range.gem AND
+                k_enchantment_type.ancient = k_enchantment_range.ancient AND
+                enchantment.quality = k_enchantment_range.quality AND
+                enchantment.stat = k_enchantment_range.stat;
+            ");
+            $statement->bindValue(':id', $id, SQLITE3_INTEGER);
+            $r = $statement->execute()->fetchArray(SQLITE3_ASSOC);
             if ($r){
             if ($r){
                 $this->id = $r["id"];
                 $this->id = $r["id"];
                 $this->gem = $r["gem"];
                 $this->gem = $r["gem"];
@@ -224,5 +224,20 @@
             }
             }
         }
         }
 
 
+        /**
+         * Calculates name variables.
+         */
+        public function refresh_names(){
+            $this->stat_name = $this->stat_name($this->stat);
+            $this->quality_name = $this->quality_name($this->quality);
+            $this->name = $this->rune->name . " " . $this->stat;
+            if ($this->inmemorial == 0){
+                $this->name = $this->rune->name . " " . $this->stat;
+            }
+            else{
+                $this->name = "Inmemorial " . $this->stat;
+            }
+        }
+
     }
     }
 ?>
 ?>

+ 43 - 38
application/entity/Fusion.php

@@ -40,21 +40,23 @@
         public function __construct($id, $uid){
         public function __construct($id, $uid){
             global $db;
             global $db;
             parent::__construct($id, true);
             parent::__construct($id, true);
-            $s = "
+            $statement = $db->prepare("
               SELECT unit.id AS id
               SELECT unit.id AS id
               FROM
               FROM
                 unit,
                 unit,
                 k_unit
                 k_unit
               WHERE
               WHERE
                 k_unit.id = unit.unit AND
                 k_unit.id = unit.unit AND
-                unit.uid = '$uid' AND
+                unit.uid = :uid AND
                 (
                 (
-                  k_unit.id = $id OR
-                  k_unit.awakens_from = $id OR
-                  k_unit.awakens_to = $id
+                  k_unit.id = :id OR
+                  k_unit.awakens_from = :id OR
+                  k_unit.awakens_to = :id
                 );
                 );
-            ";
-            $q = $db->query($s);
+            ");
+            $statement->bindValue(':uid', $uid, SQLITE3_INTEGER);
+            $statement->bindValue(':id', $id, SQLITE3_INTEGER);
+            $q = $statement->execute();
             while ($r = $q->fetchArray(SQLITE3_ASSOC)){
             while ($r = $q->fetchArray(SQLITE3_ASSOC)){
                 array_push($this->owned, new Unit($r["id"], false));
                 array_push($this->owned, new Unit($r["id"], false));
             }
             }
@@ -125,7 +127,7 @@
 
 
             global $db;
             global $db;
 
 
-            $s = "
+            $statement = $db->prepare("
               SELECT DISTINCT
               SELECT DISTINCT
                 product,
                 product,
                 stars,
                 stars,
@@ -135,18 +137,18 @@
                 product = $id OR
                 product = $id OR
                 product = (SELECT awakens_to FROM k_unit WHERE id = $id) OR
                 product = (SELECT awakens_to FROM k_unit WHERE id = $id) OR
                 product = (SELECT awakens_from FROM k_unit WHERE id = $id);
                 product = (SELECT awakens_from FROM k_unit WHERE id = $id);
-            ";
-            $q = $db->query($s);
-            $r = $q->fetchArray(SQLITE3_ASSOC);
+            ");
+            $statement->bindValue(':id', $id, SQLITE3_INTEGER);
+            $r = $statement->execute()->fetchArray(SQLITE3_ASSOC);
             $this->product = new Monster_Fusion($r["product"], $uid);
             $this->product = new Monster_Fusion($r["product"], $uid);
             $this->product_awaken = new Monster_Fusion($this->product->awakens_to, $uid);
             $this->product_awaken = new Monster_Fusion($this->product->awakens_to, $uid);
             $this->stars = $r["stars"];
             $this->stars = $r["stars"];
             $this->cost = $r["cost"];
             $this->cost = $r["cost"];
-            $s_f = "
+            $statement = $db->prepare("
               SELECT DISTINCT ingredient
               SELECT DISTINCT ingredient
               FROM k_fusion
               FROM k_fusion
               WHERE
               WHERE
-                product = " . $this->product->id . " AND
+                product = :product AND
                 ingredient IN (
                 ingredient IN (
                   SELECT DISTINCT k_unit.id
                   SELECT DISTINCT k_unit.id
                   FROM
                   FROM
@@ -157,34 +159,37 @@
                     k_fusion.product = k_unit.awakens_to OR
                     k_fusion.product = k_unit.awakens_to OR
                     k_fusion.product = k_unit.id
                     k_fusion.product = k_unit.id
                 );
                 );
-            ";
-            $q_f = $db->query($s_f);
+            ");
+            $statement->bindValue(':product', $this->product->id, SQLITE3_INTEGER);
+            $q_f = $statement->execute();
             while ($r_f = $q_f->fetchArray(SQLITE3_ASSOC)){
             while ($r_f = $q_f->fetchArray(SQLITE3_ASSOC)){
                 array_push($this->fusion, new Fusion($r_f["ingredient"], $uid));
                 array_push($this->fusion, new Fusion($r_f["ingredient"], $uid));
             }
             }
-            $s_m =
-              "SELECT  " .
-              "  id, " .
-              "  awakens_from " .
-              "FROM k_unit " .
-              "WHERE id IN ( " .
-              "  SELECT DISTINCT " .
-              "    ingredient " .
-              "  FROM k_fusion " .
-              "  WHERE  " .
-              "    product = " . $this->product->id . " AND " .
-              "    ingredient NOT IN (  " .
-              "      SELECT DISTINCT k_unit.id  " .
-              "      FROM  " .
-              "        k_fusion,  " .
-              "        k_unit  " .
-              "      WHERE " .
-              "        k_fusion.product = k_unit.awakens_from OR " .
-              "        k_fusion.product = k_unit.awakens_to OR " .
-              "        k_fusion.product = k_unit.id " .
-              "    ) " .
-              "  ); ";
-            $q_m = $db->query($s_m);
+            $statement = $db->prepare("
+              SELECT 
+                id,
+                awakens_from
+              FROM k_unit
+              WHERE id IN (
+                SELECT DISTINCT
+                  ingredient
+                FROM k_fusion
+                WHERE 
+                  product = :product AND
+                  ingredient NOT IN ( 
+                    SELECT DISTINCT k_unit.id 
+                    FROM 
+                      k_fusion, 
+                      k_unit 
+                    WHERE
+                      k_fusion.product = k_unit.awakens_from OR
+                      k_fusion.product = k_unit.awakens_to OR
+                      k_fusion.product = k_unit.id
+                  )
+                );
+            ");
+            $statement->bindValue(':product', $this->product->id, SQLITE3_INTEGER);
+            $q_m = $statement->execute();
             while ($r_m = $q_m->fetchArray(SQLITE3_ASSOC)){
             while ($r_m = $q_m->fetchArray(SQLITE3_ASSOC)){
                 $m = new Monster_Fusion($r_m["id"], $uid);
                 $m = new Monster_Fusion($r_m["id"], $uid);
                 array_push($this->ingredient, $m);
                 array_push($this->ingredient, $m);

+ 29 - 25
application/entity/Guild.php

@@ -85,21 +85,23 @@
 
 
             global $db;
             global $db;
 
 
-            $s =
-              "SELECT " .
-              "  id, " .
-              "  name, " .
-              "  name, " .
-              "  level, " .
-              "              experience, " .
-              "  recruiting, " .
-              "  members, " .
-              "  leader, " .
-              "  comment, " .
-              "  notice " .
-              "FROM guild " .
-              "WHERE id = $id; ";
-            $q = $db->query($s);
+            $statement = $db->prepare("
+              SELECT
+                id,
+                name,
+                name,
+                level,
+                experience,
+                recruiting,
+                members,
+                leader,
+                comment,
+                notice
+              FROM guild
+              WHERE id = :id;
+            ");
+            $statement->bindValue(':id', $id, SQLITE3_INTEGER);
+            $q = $statement->execute();
             $r = $q->fetchArray(SQLITE3_ASSOC);
             $r = $q->fetchArray(SQLITE3_ASSOC);
             if ($r){
             if ($r){
                 $this->id = $r["id"];
                 $this->id = $r["id"];
@@ -112,16 +114,18 @@
                 $this->comment = HTML::e($r["comment"]);
                 $this->comment = HTML::e($r["comment"]);
                 $this->notice = HTML::e($r["notice"]);
                 $this->notice = HTML::e($r["notice"]);
             }
             }
-            $s =
-              "SELECT id " .
-              "FROM guild_member " .
-              "WHERE guild = $this->id " .
-              "ORDER BY " .
-              "  grade = 1 DESC, " .
-              "  grade = 3 DESC, " .
-              "  grade = 2 DESC, " .
-              "  arena_score DESC; ";
-            $q = $db->query($s);
+            $statement = $db->prepare("
+              SELECT id
+              FROM guild_member
+              WHERE guild = :guild
+              ORDER BY
+                grade = 1 DESC,
+                grade = 3 DESC,
+                grade = 2 DESC,
+                arena_score DESC;
+            ");
+            $statement->bindValue(':guild', $this->id, SQLITE3_INTEGER);
+            $q = $statement->execute();
             while ($r = $q->fetchArray(SQLITE3_ASSOC)){
             while ($r = $q->fetchArray(SQLITE3_ASSOC)){
                 array_push($this->members, new Guild_Member($r["id"]));
                 array_push($this->members, new Guild_Member($r["id"]));
             }
             }

+ 18 - 17
application/entity/Guild_Member.php

@@ -90,23 +90,24 @@
 
 
             global $db;
             global $db;
 
 
-            $s =
-              "SELECT " .
-              "  id, " .
-              "  guild, " .
-              "  name, " .
-              "  level, " .
-              "  grade, " .
-              "  rating, " .
-              "  arena_score, " .
-              "  joined, " .
-              "  last_login, " .
-              "  in_war, " .
-              "  has_defense " .
-              "FROM guild_member " .
-              "WHERE id = $id; ";
-            $q = $db->query($s);
-            $r = $q->fetchArray(SQLITE3_ASSOC);
+            $statement = $db->prepare("
+              SELECT
+                id,
+                guild,
+                name,
+                level,
+                grade,
+                rating,
+                arena_score,
+                joined,
+                last_login,
+                in_war,
+                has_defense
+              FROM guild_member
+              WHERE id = :id;
+            ");
+            $statement->bindValue(':id', $id, SQLITE3_INTEGER);
+            $r = $statement->execute()->fetchArray(SQLITE3_ASSOC);
             if ($r){
             if ($r){
                 $this->id = $r["id"];
                 $this->id = $r["id"];
                 $this->guild = $r["guild"];
                 $this->guild = $r["guild"];

+ 21 - 17
application/entity/Inventory.php

@@ -82,26 +82,30 @@
                   inventory.type = k_inventory_type.id AND
                   inventory.type = k_inventory_type.id AND
                   inventory.id = k_inventory.id AND
                   inventory.id = k_inventory.id AND
                   inventory.type = k_inventory.type AND
                   inventory.type = k_inventory.type AND
-                  inventory.id = $id
+                  inventory.id = :id
             ";
             ";
             if ($type != null){
             if ($type != null){
-                $s .= "AND inventory.type = $type";
+                $s .= "AND inventory.type = :type";
             }
             }
-            $q = $db->query($s);
-            $r = $q->fetchArray(SQLITE3_ASSOC);
-            $this->type = $r["type"];
-            $this->amount = $r["amount"];
-            if ($r["type"] == INVENTORY_TYPE_ID::GUILD_MONSTER_PIECE || $r["type"] == INVENTORY_TYPE_ID::MONSTER_PIECE){
-                $this->is_monster_pices = true;
-                $this->id = new K_Unit($r["id"]);
-                $this->name = HTML::e($this->id->title) . " Pieces";
-                $this->description = HTML::e($this->id->title) . " Pieces";
-            }
-            else{
-                $this->is_monster_pices = false;
-                $this->id = $r["id"];
-                $this->name = HTML::e($r["name"]);
-                $this->description = HTML::e($r["description"]);
+            $statement = $db->prepare($s);
+            $statement->bindValue(':id', $id, SQLITE3_INTEGER);
+            $statement->bindValue(':type', $type, SQLITE3_INTEGER);
+            $r = $statement->execute()->fetchArray(SQLITE3_ASSOC);
+            if ($r){
+                $this->type = $r["type"];
+                $this->amount = $r["amount"];
+                if ($r["type"] == INVENTORY_TYPE_ID::GUILD_MONSTER_PIECE || $r["type"] == INVENTORY_TYPE_ID::MONSTER_PIECE){
+                    $this->is_monster_pices = true;
+                    $this->id = new K_Unit($r["id"]);
+                    $this->name = HTML::e($this->id->title) . " Pieces";
+                    $this->description = HTML::e($this->id->title) . " Pieces";
+                }
+                else{
+                    $this->is_monster_pices = false;
+                    $this->id = $r["id"];
+                    $this->name = HTML::e($r["name"]);
+                    $this->description = HTML::e($r["description"]);
+                }
             }
             }
         }
         }
 
 

+ 28 - 11
application/entity/K_Area.php

@@ -53,19 +53,20 @@
 
 
             $this->id = $id;
             $this->id = $id;
             $this->type = $type;
             $this->type = $type;
-            $s = "
+            $statement = $db->prepare("
                 SELECT
                 SELECT
                   id,
                   id,
                   type,
                   type,
                   name
                   name
                 FROM k_area
                 FROM k_area
                 WHERE
                 WHERE
-                  id = '$id' AND
-                  type = '$type' 
-                ORDER BY type = '$type' DESC;
-            ";
-            $q = $db->query($s);
-            $r = $q->fetchArray(SQLITE3_ASSOC);
+                  id = :id AND
+                  type = :type
+                ORDER BY type DESC;
+            ");
+            $statement->bindValue(':id', $id, SQLITE3_INTEGER);
+            $statement->bindValue(':type', $type, SQLITE3_INTEGER);
+            $r = $statement->execute()->fetchArray(SQLITE3_ASSOC);
             if ($r){
             if ($r){
                 $this->name = HTML::e($r["name"]);
                 $this->name = HTML::e($r["name"]);
             }
             }
@@ -73,6 +74,17 @@
                 $this->type = AREA_TYPE_ID::CAIROS_DUNGEON;
                 $this->type = AREA_TYPE_ID::CAIROS_DUNGEON;
                 $this->name = "Hall of Heroes";
                 $this->name = "Hall of Heroes";
             }
             }
+            else{
+                $statement = $db->prepare("
+                  SELECT name
+                  FROM k_area_type
+                  WHERE id = :type;
+                ");
+                $statement->bindValue(':type', $type, SQLITE3_INTEGER);
+                if ($r){
+                    $this->name = HTML::e($r["name"]);
+                }
+            }
         }
         }
 
 
         /**
         /**
@@ -88,9 +100,17 @@
                 // Hall of Heroes
                 // Hall of Heroes
                 return APPLICATION::img("AREA", "HOH");
                 return APPLICATION::img("AREA", "HOH");
             }
             }
+            elseif ($this->type == AREA_TYPE_ID::RIFT_RAID){
+                return APPLICATION::img("UNIT", 44007);
+            }
+            elseif ($this->type == AREA_TYPE_ID::ARENA){
+                return APPLICATION::img("AREA", "ARENA");
+            }
+            elseif ($this->type == AREA_TYPE_ID::DIMENSIONAL_RIFT){
+                return APPLICATION::img("CURRENCY", "darkportalenergy");
+            }
             elseif (
             elseif (
                 $this->type == AREA_TYPE_ID::SCENARIO ||
                 $this->type == AREA_TYPE_ID::SCENARIO ||
-                $this->type == AREA_TYPE_ID::ARENA ||
                 $this->type == AREA_TYPE_ID::GUILD_WAR ||
                 $this->type == AREA_TYPE_ID::GUILD_WAR ||
                 $this->type == AREA_TYPE_ID::GUILD_SIEGE ||
                 $this->type == AREA_TYPE_ID::GUILD_SIEGE ||
                 $this->type == AREA_TYPE_ID::WORLD_BOSS ||
                 $this->type == AREA_TYPE_ID::WORLD_BOSS ||
@@ -159,9 +179,6 @@
                         break;
                         break;
                 }
                 }
             }
             }
-            elseif ($this->type == AREA_TYPE_ID::RIFT_RAID){
-                return APPLICATION::img("UNIT", 44007);
-            }
             elseif ($this->type == AREA_TYPE_ID::DIMENSIONAL_HOLE){
             elseif ($this->type == AREA_TYPE_ID::DIMENSIONAL_HOLE){
                 switch ($this->id){
                 switch ($this->id){
                     case DUNGEON_ID::FOREST_OF_ROARING_BEASTS:
                     case DUNGEON_ID::FOREST_OF_ROARING_BEASTS:

+ 10 - 9
application/entity/K_Building.php

@@ -50,15 +50,16 @@
 
 
             global $db;
             global $db;
 
 
-            $s =
-              "SELECT " .
-              "  id, " .
-              "  name, " .
-              "  description " .
-              "FROM k_building " .
-              "WHERE id = '$id'; ";
-            $q = $db->query($s);
-            $r = $q->fetchArray(SQLITE3_ASSOC);
+            $statement = $db->prepare("
+              SELECT
+                id,
+                name,
+                description
+              FROM k_building
+               WHERE id = :id;
+            ");
+            $statement->bindValue(':id', $id, SQLITE3_INTEGER);
+            $r = $statement->execute()->fetchArray(SQLITE3_ASSOC);
             if ($r){
             if ($r){
                 $this->id = $r["id"];
                 $this->id = $r["id"];
                 $this->name = HTML::e($r["name"]);
                 $this->name = HTML::e($r["name"]);

+ 10 - 9
application/entity/K_Decoration.php

@@ -80,7 +80,7 @@
 
 
             global $db;
             global $db;
 
 
-            $s = "
+            $statement = $db->prepare("
                 SELECT
                 SELECT
                   id,
                   id,
                   name,
                   name,
@@ -90,10 +90,10 @@
                   element,
                   element,
                   max_level
                   max_level
                 FROM k_decoration
                 FROM k_decoration
-                WHERE id = $id;
-            ";
-            $q = $db->query($s);
-            $r = $q->fetchArray(SQLITE3_ASSOC);
+               WHERE id = :id;
+            ");
+            $statement->bindValue(':id', $id, SQLITE3_INTEGER);
+            $r = $statement->execute()->fetchArray(SQLITE3_ASSOC);
             if ($r){
             if ($r){
                 $this->id = $r["id"];
                 $this->id = $r["id"];
                 $this->name = HTML::e($r["name"]);
                 $this->name = HTML::e($r["name"]);
@@ -102,15 +102,16 @@
                 $this->stat = $r["affected_stat"];
                 $this->stat = $r["affected_stat"];
                 $this->element = $r["element"];
                 $this->element = $r["element"];
                 $this->max_level = $r["max_level"];
                 $this->max_level = $r["max_level"];
-                $s = "
+                $statement = $db->prepare("
                     SELECT
                     SELECT
                       level,
                       level,
                       bonus,
                       bonus,
                       cost
                       cost
                     FROM k_decoration_level
                     FROM k_decoration_level
-                    WHERE decoration = $id
-                ";
-                $q = $db->query($s);
+                    WHERE decoration = :id
+                ");
+                $statement->bindValue(':id', $id, SQLITE3_INTEGER);
+                $q = $statement->execute();
                 while ($r = $q->fetchArray(SQLITE3_ASSOC)){
                 while ($r = $q->fetchArray(SQLITE3_ASSOC)){
                     $this->level_bonus[$r["level"]] = $r["bonus"];
                     $this->level_bonus[$r["level"]] = $r["bonus"];
                     $this->level_cost[$r["level"]] = $r["cost"];
                     $this->level_cost[$r["level"]] = $r["cost"];

+ 11 - 10
application/entity/K_Effect.php

@@ -54,16 +54,17 @@
 
 
             global $db;
             global $db;
 
 
-            $s =
-              "SELECT " .
-              "  id, " .
-              "  name, " .
-              "  is_buff, " .
-              "  description " .
-              "FROM k_effect " .
-              "WHERE id = $id;";
-            $q = $db->query($s);
-            $r = $q->fetchArray(SQLITE3_ASSOC);
+            $statement = $db->prepare("
+              SELECT
+                id,
+                name,
+                is_buff,
+                description
+              FROM k_effect
+              WHERE id = :id;
+            ");
+            $statement->bindValue(':id', $id, SQLITE3_INTEGER);
+            $r = $statement->execute()->fetchArray(SQLITE3_ASSOC);
             if ($r){
             if ($r){
                 $this->id = $r["id"];
                 $this->id = $r["id"];
                 $this->name = HTML::e($r["name"]);
                 $this->name = HTML::e($r["name"]);

+ 11 - 10
application/entity/K_Guild_Skill.php

@@ -54,16 +54,17 @@
 
 
             global $db;
             global $db;
 
 
-            $s =
-              "SELECT " .
-              "  id, " .
-              "  skill_group, " .
-              "  level, " .
-              "  effect " .
-              "FROM k_guild_skill " .
-              "WHERE id = $id; ";
-            $q = $db->query($s);
-            $r = $q->fetchArray(SQLITE3_ASSOC);
+            $statement = $db->prepare("
+              SELECT
+                id,
+                skill_group,
+                level,
+                effect
+              FROM k_guild_skill
+              WHERE id = :id;
+            ");
+            $statement->bindValue(':id', $id, SQLITE3_INTEGER);
+            $r = $statement->execute()->fetchArray(SQLITE3_ASSOC);
             if ($r){
             if ($r){
                 $this->id = $r["id"];
                 $this->id = $r["id"];
                 $this->group = $r["skill_group"];
                 $this->group = $r["skill_group"];

+ 20 - 17
application/entity/K_Guild_Skill_Group.php

@@ -55,27 +55,30 @@
 
 
             global $db;
             global $db;
 
 
-            $s =
-              "SELECT " .
-              "  id, " .
-              "  name, " .
-              "  description " .
-              "FROM k_guild_skill_group " .
-              "WHERE id = $id; ";
-            $q = $db->query($s);
-            $r = $q->fetchArray(SQLITE3_ASSOC);
+            $statement = $db->prepare("
+              SELECT
+                id,
+                name,
+                description
+              FROM k_guild_skill_group
+              WHERE id = :id;
+            ");
+            $statement->bindValue(':id', $id, SQLITE3_INTEGER);
+            $r = $statement->execute()->fetchArray(SQLITE3_ASSOC);
             if ($r){
             if ($r){
                 $this->id = $r["id"];
                 $this->id = $r["id"];
                 $this->name = HTML::e($r["name"]);
                 $this->name = HTML::e($r["name"]);
                 $this->description = HTML::e($r["description"]);
                 $this->description = HTML::e($r["description"]);
-            }
-            $s =
-              "SELECT id " .
-              "FROM k_guild_skill " .
-              "WHERE skill_group = $this->id; ";
-            $q = $db->query($s);
-            while ($r = $q->fetchArray(SQLITE3_ASSOC)){
-                array_push($this->skills, new K_Guild_Skill($r["id"]));
+                $statement = $db->prepare("
+                  SELECT id
+                  FROM k_guild_skill
+                  WHERE skill_group = :id;
+                ");
+                $statement->bindValue(':id', $this->id, SQLITE3_INTEGER);
+                $q = $statement->execute();
+                while ($r = $q->fetchArray(SQLITE3_ASSOC)){
+                    array_push($this->skills, new K_Guild_Skill($r["id"]));
+                }
             }
             }
         }
         }
 
 

+ 22 - 18
application/entity/K_Inventory.php

@@ -54,27 +54,31 @@
         public function __construct($id, $type = null){
         public function __construct($id, $type = null){
             global $db;
             global $db;
             $s = "
             $s = "
-                SELECT
-                  k_inventory.id AS id,
-                  k_inventory.name AS name,
-                  k_inventory.description AS description,
-                  k_inventory_type.name AS type
-                FROM
-                  k_inventory,
-                  k_inventory_type
-                WHERE
-                  k_inventory.type = k_inventory_type.id AND
-                  k_inventory.id = $id
+              SELECT
+                k_inventory.id AS id,
+                k_inventory.name AS name,
+                k_inventory.description AS description,
+                k_inventory_type.name AS type
+              FROM
+                k_inventory,
+                k_inventory_type
+              WHERE
+                k_inventory.type = k_inventory_type.id AND
+                k_inventory.id = :id
             ";
             ";
             if ($type != null){
             if ($type != null){
-                $s .= "AND k_inventory.type = $type";
+                $s .= "AND k_inventory.type = :type";
+            }
+            $statement = $db->prepare($s);
+            $statement->bindValue(':id', $id, SQLITE3_INTEGER);
+            $statement->bindValue(':type', $type, SQLITE3_INTEGER);
+            $r = $statement->execute()->fetchArray(SQLITE3_ASSOC);
+            if ($r){
+                $this->type = $r["type"];
+                $this->id = $r["id"];
+                $this->name = HTML::e($r["name"]);
+                $this->description = HTML::e($r["description"]);
             }
             }
-            $q = $db->query($s);
-            $r = $q->fetchArray(SQLITE3_ASSOC);
-            $this->type = $r["type"];
-            $this->id = $r["id"];
-            $this->name = HTML::e($r["name"]);
-            $this->description = HTML::e($r["description"]);
         }
         }
 
 
         /**
         /**

+ 20 - 17
application/entity/K_Leader_Skill.php

@@ -59,22 +59,25 @@
 
 
             global $db;
             global $db;
 
 
-            $s =
-              "SELECT " .
-              "  id, " .
-              "  stat, " .
-              "  amount, " .
-              "  area, " .
-              "  element " .
-              "FROM k_leader_skill " .
-              "WHERE id = $id; ";
-            $q = $db->query($s);
-            $r = $q->fetchArray(SQLITE3_ASSOC);
-            $this->id = $r["id"];
-            $this->attribute = $r["stat"];
-            $this->amount = $r["amount"];
-            $this->area = $r["area"];
-            $this->element = $r["element"]; 
+            $statement = $db->prepare("
+              SELECT
+                id,
+                stat,
+                amount,
+                area,
+                element
+              FROM k_leader_skill
+             WHERE id = :id;
+            ");
+            $statement->bindValue(':id', $id, SQLITE3_INTEGER);
+            $r = $statement->execute()->fetchArray(SQLITE3_ASSOC);
+            if ($r){
+                $this->id = $r["id"];
+                $this->attribute = $r["stat"];
+                $this->amount = $r["amount"];
+                $this->area = $r["area"];
+                $this->element = $r["element"];
+            }
         }
         }
 
 
         /**
         /**
@@ -151,7 +154,7 @@
                     $s = $s . " in Guild content";
                     $s = $s . " in Guild content";
                     break;
                     break;
             }
             }
-            $s = $s . ".";
+            $s = str_replace("  ", " ", $s) . ".";
             return $s;
             return $s;
         }
         }
 
 

+ 11 - 10
application/entity/K_Rune_Set.php

@@ -54,16 +54,17 @@
 
 
             global $db;
             global $db;
 
 
-            $s =
-              "SELECT " .
-              "  id, " .
-              "  name, " .
-              "  amount, " .
-              "  description " .
-              "FROM k_rune_set " .
-              "WHERE id = $id;";
-            $q = $db->query($s);
-            $r = $q->fetchArray(SQLITE3_ASSOC);
+            $statement = $db->prepare("
+              SELECT
+                id,
+                name,
+                amount,
+                description
+              FROM k_rune_set
+              WHERE id = :id;
+            ");
+            $statement->bindValue(':id', $id, SQLITE3_INTEGER);
+            $r = $statement->execute()->fetchArray(SQLITE3_ASSOC);
             if ($r){
             if ($r){
                 $this->id = $r["id"];
                 $this->id = $r["id"];
                 $this->name = HTML::e($r["name"]);
                 $this->name = HTML::e($r["name"]);

+ 51 - 44
application/entity/K_Skill.php

@@ -102,50 +102,57 @@
 
 
             global $db;
             global $db;
 
 
-            $s =
-              "SELECT " .
-              "  id, " .
-              "  name, " .
-              "  description, " .
-              "  slot, " .
-              "  cooltime, " .
-              "  hits, " .
-              "  passive, " .
-              "  aoe, " .
-              "  max_level, " .
-              "  multiplier_formula " .
-              "FROM k_skill " .
-              "WHERE id = $id; ";
-            $q = $db->query($s);
-            $r = $q->fetchArray(SQLITE3_ASSOC);
-            $this->id = $r["id"];
-            $this->name = HTML::e($r["name"]);
-            $this->description = HTML::e($r["description"]);
-            $this->slot = $r["slot"];
-            $this->cooltime = $r["cooltime"];
-            $this->hits = $r["hits"];
-            $this->passive = $r["passive"];
-            $this->aoe = $r["aoe"];
-            $this->max_level = $r["max_level"];
-            $this->multiplier_formula = HTML::e($r["multiplier_formula"]);
-            $s =
-              "SELECT " .
-              "  skill, " .
-              "  level " .
-              "FROM k_skill_level " .
-              "WHERE skill = " . $this->id . " " .
-              "ORDER BY level; ";
-            $q = $db->query($s);
-            while ($r = $q->fetchArray(SQLITE3_ASSOC)){
-                array_push($this->level, new K_Skill_Level($r["skill"], $r["level"]));
-            }
-            $s =
-              "SELECT DISTINCT effect " .
-              "FROM k_skill_effect " .
-              "WHERE skill = " . $this->id . "; ";
-            $q = $db->query($s);
-            while ($r = $q->fetchArray(SQLITE3_ASSOC)){
-                array_push($this->effect, new K_Effect($r["effect"]));
+            $statement = $db->prepare("
+              SELECT
+                id,
+                name,
+                description,
+                slot,
+                cooltime,
+                hits,
+                passive,
+                aoe,
+                max_level,
+                multiplier_formula
+              FROM k_skill
+              WHERE id = :id;
+            ");
+            $statement->bindValue(':id', $id, SQLITE3_INTEGER);
+            $r = $statement->execute()->fetchArray(SQLITE3_ASSOC);
+            if ($r){
+                $this->id = $r["id"];
+                $this->name = HTML::e($r["name"]);
+                $this->description = HTML::e($r["description"]);
+                $this->slot = $r["slot"];
+                $this->cooltime = $r["cooltime"];
+                $this->hits = $r["hits"];
+                $this->passive = $r["passive"];
+                $this->aoe = $r["aoe"];
+                $this->max_level = $r["max_level"];
+                $this->multiplier_formula = HTML::e($r["multiplier_formula"]);
+                $statement = $db->prepare("
+                  SELECT
+                    skill,
+                    level
+                  FROM k_skill_level
+                  WHERE skill = :skill
+                  ORDER BY level;
+                ");
+                $statement->bindValue(':skill', $this->id, SQLITE3_INTEGER);
+                $q = $statement->execute();
+                while ($r = $q->fetchArray(SQLITE3_ASSOC)){
+                    array_push($this->level, new K_Skill_Level($r["skill"], $r["level"]));
+                }
+                $statement = $db->prepare("
+                  SELECT DISTINCT effect
+                  FROM k_skill_effect
+                  WHERE skill = :skill;
+                ");
+                $statement->bindValue(':skill', $this->id, SQLITE3_INTEGER);
+                $q = $statement->execute();
+                while ($r = $q->fetchArray(SQLITE3_ASSOC)){
+                    array_push($this->effect, new K_Effect($r["effect"]));
+                }
             }
             }
         }
         }
 
 

+ 13 - 11
application/entity/K_Skill_Level.php

@@ -50,17 +50,19 @@
 
 
             global $db;
             global $db;
 
 
-            $s =
-              "SELECT " .
-              "  skill, " .
-              "  level, " .
-              "  description " .
-              "FROM k_skill_level " .
-              "WHERE " .
-              "  skill = $skill AND " .
-              "  level = $level;";
-            $q = $db->query($s);
-            $r = $q->fetchArray(SQLITE3_ASSOC);
+            $statement = $db->prepare("
+              SELECT
+                skill,
+                level,
+                description
+              FROM k_skill_level
+              WHERE
+                skill = :skill AND
+                level = :level;
+            ");
+            $statement->bindValue(':skill', $skill, SQLITE3_INTEGER);
+            $statement->bindValue(':level', $level, SQLITE3_INTEGER);
+            $r = $statement->execute()->fetchArray(SQLITE3_ASSOC);
             if ($r){
             if ($r){
                 $this->skill = $r["skill"];
                 $this->skill = $r["skill"];
                 $this->level = $r["level"];
                 $this->level = $r["level"];

+ 11 - 10
application/entity/K_Source.php

@@ -53,16 +53,17 @@
          */
          */
         public function __construct($id){
         public function __construct($id){
             global $db;
             global $db;
-            $s =
-              "SELECT " .
-              "  id, " .
-              "  name, " .
-              "  description, " .
-              "  farmable " .
-              "FROM k_source " .
-              "WHERE id = $id; ";
-            $q = $db->query($s);
-            $r = $q->fetchArray(SQLITE3_ASSOC);
+            $statement = $db->prepare("
+              SELECT
+                id,
+                name,
+                description,
+                farmable
+              FROM k_source
+              WHERE id = :id;
+            ");
+            $statement->bindValue(':id', $id, SQLITE3_INTEGER);
+            $r = $statement->execute()->fetchArray(SQLITE3_ASSOC);
             if ($r){
             if ($r){
                 $this->id = $r["id"];
                 $this->id = $r["id"];
                 $this->name = HTML::e($r["name"]);
                 $this->name = HTML::e($r["name"]);

+ 67 - 60
application/entity/K_Unit.php

@@ -192,7 +192,7 @@
         public $craft_cost;
         public $craft_cost;
 
 
         /**
         /**
-         * @var \K_Unit_Skill[] Unit skills.
+         * @var \K_Skill[] Unit skills.
          */
          */
         public $skill = [];
         public $skill = [];
 
 
@@ -236,44 +236,45 @@
          */
          */
         public function __construct($id, $complete = true){
         public function __construct($id, $complete = true){
             global $db;
             global $db;
-            $s =
-              "SELECT " .
-              "  id, " .
-              "  family, " .
-              "  name, " .
-              "  element, " .
-              "  archetype, " .
-              "  base_stars, " .
-              "  natural_stars, " .
-              "  obtainable, " .
-              "  can_awaken, " .
-              "  awaken_bonus, " .
-              "  skill_ups_to_max, " .
-              "  leader_skill, " .
-              "  hp, " .
-              "  attack, " .
-              "  defense, " .
-              "  speed, " .
-              "  crit_rate, " .
-              "  crit_damage, " .
-              "  resistance, " .
-              "  accuracy, " .
-              "  raw_hp, " .
-              "  raw_attack, " .
-              "  raw_defense, " .
-              "  max_lvl_hp, " .
-              "  max_lvl_attack, " .
-              "  max_lvl_defense, " .
-              "  awakens_from, " .
-              "  awakens_to, " .
-              "  fusion_food, " .
-              "  homunculus, " .
-              "  craft_cost " .
-              "FROM k_unit " .
-              "WHERE id = $id; ";
-            $q = $db->query($s);
-            $r = $q->fetchArray(SQLITE3_ASSOC);
             $this->id = $id;
             $this->id = $id;
+            $statement = $db->prepare("
+              SELECT
+                id,
+                family,
+                name,
+                element,
+                archetype,
+                base_stars,
+                natural_stars,
+                obtainable,
+                can_awaken,
+                awaken_bonus,
+                skill_ups_to_max,
+                leader_skill,
+                hp,
+                attack,
+                defense,
+                speed,
+                crit_rate,
+                crit_damage,
+                resistance,
+                accuracy,
+                raw_hp,
+                raw_attack,
+                raw_defense,
+                max_lvl_hp,
+                max_lvl_attack,
+                max_lvl_defense,
+                awakens_from,
+                awakens_to,
+                fusion_food,
+                homunculus,
+                craft_cost
+              FROM k_unit
+              WHERE id = :id;
+            ");
+            $statement->bindValue(':id', $id, SQLITE3_INTEGER);
+            $r = $statement->execute()->fetchArray(SQLITE3_ASSOC);
             if ($r){
             if ($r){
                 $this->family = $r["family"];
                 $this->family = $r["family"];
                 $this->name = HTML::e($r["name"]);
                 $this->name = HTML::e($r["name"]);
@@ -390,15 +391,17 @@
         public function load_essences(){
         public function load_essences(){
             global $db;
             global $db;
             $this->essences = [];
             $this->essences = [];
-            $s =
-              "SELECT " .
-              "  item, " .
-              "  amount " .
-              "FROM k_unit_essence " .
-              "WHERE " .
-              "  unit = " . $this->id . " " .
-              "ORDER BY item; ";
-            $q = $db->query($s);
+            $statement = $db->prepare("
+              SELECT
+                item,
+                amount
+              FROM k_unit_essence
+              WHERE
+                unit = :unit
+              ORDER BY item;
+            ");
+            $statement->bindValue(':unit', $this->id, SQLITE3_INTEGER);
+            $q = $statement->execute();
             while ($r = $q->fetchArray(SQLITE3_ASSOC)){
             while ($r = $q->fetchArray(SQLITE3_ASSOC)){
                 $e = [
                 $e = [
                     "item" => new K_Inventory($r["item"], INVENTORY_TYPE_ID::ESSENCES),
                     "item" => new K_Inventory($r["item"], INVENTORY_TYPE_ID::ESSENCES),
@@ -420,12 +423,13 @@
         public function load_transformation(){
         public function load_transformation(){
             global $db;
             global $db;
             $this->transformation = null;
             $this->transformation = null;
-            $s = "
+            $statement = $db->prepare("
               SELECT id
               SELECT id
               FROM k_unit_transformation
               FROM k_unit_transformation
-              WHERE  unit = " . $this->id . ";";
-            $q = $db->query($s);
-            $r = $q->fetchArray(SQLITE3_ASSOC);
+              WHERE  unit = :unit;
+            ");
+            $statement->bindValue(':unit', $this->id, SQLITE3_INTEGER);
+            $r = $statement->execute()->fetchArray(SQLITE3_ASSOC);
             if ($r){
             if ($r){
                 $this->transformation = new K_Unit_Transformation($r["id"]);
                 $this->transformation = new K_Unit_Transformation($r["id"]);
             }
             }
@@ -443,17 +447,18 @@
         public function load_skills(){
         public function load_skills(){
             global $db;
             global $db;
             $this->skill = [];
             $this->skill = [];
-            $s = "
+            $statement = $db->prepare("
               SELECT skill
               SELECT skill
               FROM
               FROM
                 k_skill,
                 k_skill,
                 k_unit_skill
                 k_unit_skill
               WHERE
               WHERE
                 id = skill AND
                 id = skill AND
-                unit = " . $this->id . "
+                unit = :unit
               ORDER BY slot;
               ORDER BY slot;
-            ";
-            $q = $db->query($s);
+            ");
+            $statement->bindValue(':unit', $this->id, SQLITE3_INTEGER);
+            $q = $statement->execute();
             while ($r = $q->fetchArray(SQLITE3_ASSOC)){
             while ($r = $q->fetchArray(SQLITE3_ASSOC)){
                 array_push($this->skill, new K_Skill($r["skill"]));
                 array_push($this->skill, new K_Skill($r["skill"]));
             }
             }
@@ -471,11 +476,13 @@
         public function load_sources(){
         public function load_sources(){
             global $db;
             global $db;
             $this->sources = [];
             $this->sources = [];
-            $s =
-              "SELECT source " .
-              "FROM k_unit_source " .
-              "WHERE unit = " . $this->id . ";";
-            $q = $db->query($s);
+            $statement = $db->prepare("
+              SELECT source
+              FROM k_unit_source
+              WHERE unit = :unit;
+            ");
+            $statement->bindValue(':unit', $this->id, SQLITE3_INTEGER);
+            $q = $statement->execute();
             while ($r = $q->fetchArray(SQLITE3_ASSOC)){
             while ($r = $q->fetchArray(SQLITE3_ASSOC)){
                 array_push($this->sources, new K_Source($r["source"]));
                 array_push($this->sources, new K_Source($r["source"]));
             }
             }

+ 6 - 6
application/entity/K_Unit_Transformation.php

@@ -41,7 +41,7 @@
         public $unit;
         public $unit;
 
 
         /**
         /**
-         * @var \K_Monster_Skill[] Skills in the transformed form.
+         * @var \K_Skill[] Skills in the transformed form.
          */
          */
         public $skill = [];
         public $skill = [];
 
 
@@ -56,16 +56,16 @@
          */
          */
         public function __construct($id){
         public function __construct($id){
             global $db;
             global $db;
-            $s = "
+            $statement = $db->prepare("
               SELECT
               SELECT
                 id,
                 id,
                 family,
                 family,
                 unit
                 unit
               FROM k_unit_transformation
               FROM k_unit_transformation
-              WHERE id = $id;
-            ";
-            $q = $db->query($s);
-            $r = $q->fetchArray(SQLITE3_ASSOC);
+               WHERE id = :id;
+            ");
+            $statement->bindValue(':id', $id, SQLITE3_INTEGER);
+            $r = $statement->execute()->fetchArray(SQLITE3_ASSOC);
             if ($r){
             if ($r){
                 $this->id = $r["id"];
                 $this->id = $r["id"];
                 $this->family = $r["family"];
                 $this->family = $r["family"];

+ 58 - 46
application/entity/Player.php

@@ -185,7 +185,7 @@
         public function __construct($id, $complete = true){
         public function __construct($id, $complete = true){
             global $UID;
             global $UID;
             global $db;
             global $db;
-            $s = "
+            $statement = $db->prepare("
               SELECT
               SELECT
                 uid,
                 uid,
                 name,
                 name,
@@ -220,10 +220,10 @@
                 top_rank_toan,
                 top_rank_toan,
                 top_rank_toah
                 top_rank_toah
               FROM player
               FROM player
-              WHERE uid = '$UID';
-            ";
-            $q = $db->query($s);
-            $r = $q->fetchArray(SQLITE3_ASSOC);
+              WHERE uid = :uid;
+            ");
+            $statement->bindValue(':uid', $UID, SQLITE3_INTEGER);
+            $r = $statement->execute()->fetchArray(SQLITE3_ASSOC);
             if ($r){
             if ($r){
                 $this->uid = $r["uid"];
                 $this->uid = $r["uid"];
                 $this->name = $r["name"];
                 $this->name = $r["name"];
@@ -260,25 +260,27 @@
                 $this->top_rank_toan = $r["top_rank_toan"];
                 $this->top_rank_toan = $r["top_rank_toan"];
                 $this->top_rank_toah = $r["top_rank_toah"];
                 $this->top_rank_toah = $r["top_rank_toah"];
             }
             }
-            $s = "
+            $statement = $db->prepare("
                 SELECT unit
                 SELECT unit
                 FROM defense
                 FROM defense
-                WHERE uid = '$UID'
+                WHERE uid = :uid
                 ORDER BY position;
                 ORDER BY position;
-            ";
-            $q = $db->query($s);
+            ");
+            $statement->bindValue(':uid', $UID, SQLITE3_INTEGER);
+            $q = $statement->execute();
             while ($r = $q->fetchArray(SQLITE3_ASSOC)){
             while ($r = $q->fetchArray(SQLITE3_ASSOC)){
                 array_push($this->defense, new Unit($r["unit"], false));
                 array_push($this->defense, new Unit($r["unit"], false));
             }
             }
-            $s = "
+            $statement = $db->prepare("
                 SELECT
                 SELECT
                   unit,
                   unit,
                   position
                   position
                 FROM gw_defense
                 FROM gw_defense
-                WHERE uid = '$UID'
+                WHERE uid = :uid
                 ORDER BY position;
                 ORDER BY position;
-            ";
-            $q = $db->query($s);
+            ");
+            $statement->bindValue(':uid', $UID, SQLITE3_INTEGER);
+            $q = $statement->execute();
             while ($r = $q->fetchArray(SQLITE3_ASSOC)){
             while ($r = $q->fetchArray(SQLITE3_ASSOC)){
                 if ($r["position"] <= 3){
                 if ($r["position"] <= 3){
                     array_push($this->gw_defense[0], new Unit($r["unit"], false));
                     array_push($this->gw_defense[0], new Unit($r["unit"], false));
@@ -287,7 +289,7 @@
                     array_push($this->gw_defense[1], new Unit($r["unit"], false));
                     array_push($this->gw_defense[1], new Unit($r["unit"], false));
                 }
                 }
             }
             }
-            $s = "
+            $statement = $db->prepare("
                 SELECT
                 SELECT
                   building.id,
                   building.id,
                   min(building)
                   min(building)
@@ -295,72 +297,80 @@
                   building,
                   building,
                   k_building
                   k_building
                 WHERE
                 WHERE
-                  uid = '$UID' AND
+                  uid = :uid AND
                   building.building = k_building.id 
                   building.building = k_building.id 
                 GROUP BY building.building;
                 GROUP BY building.building;
-            ";
-            $q = $db->query($s);
+            ");
+            $statement->bindValue(':uid', $UID, SQLITE3_INTEGER);
+            $q = $statement->execute();
             while ($r = $q->fetchArray(SQLITE3_ASSOC)){
             while ($r = $q->fetchArray(SQLITE3_ASSOC)){
                 array_push($this->building, new Building($r["id"]));
                 array_push($this->building, new Building($r["id"]));
             }
             }
-            $s = "
+            $statement = $db->prepare("
                 SELECT id
                 SELECT id
                 FROM decoration
                 FROM decoration
-                WHERE uid = '$UID';
-            ";
-            $q = $db->query($s);
+                WHERE uid = :uid;
+            ");
+            $statement->bindValue(':uid', $UID, SQLITE3_INTEGER);
+            $q = $statement->execute();
             while ($r = $q->fetchArray(SQLITE3_ASSOC)){
             while ($r = $q->fetchArray(SQLITE3_ASSOC)){
                 array_push($this->decoration, new Decoration($r["id"]));
                 array_push($this->decoration, new Decoration($r["id"]));
             }
             }
-            $s = "
+            $statement = $db->prepare("
                 SELECT
                 SELECT
                   id,
                   id,
                   type
                   type
                 FROM inventory
                 FROM inventory
                 WHERE
                 WHERE
-                  uid = '$UID' AND
-                  type = " . INVENTORY_TYPE_ID::SCROLL . " AND
+                  uid = :uid AND
+                  type = :type AND
                   amount > 0
                   amount > 0
                 ORDER BY inventory.type;
                 ORDER BY inventory.type;
-            ";
-            $q = $db->query($s);
+            ");
+            $statement->bindValue(':uid', $UID, SQLITE3_INTEGER);
+            $statement->bindValue(':type', INVENTORY_TYPE_ID::SCROLL, SQLITE3_INTEGER);
+            $q = $statement->execute();
             while ($r = $q->fetchArray(SQLITE3_ASSOC)){
             while ($r = $q->fetchArray(SQLITE3_ASSOC)){
                 array_push($this->inventory_scroll, new Inventory($r["id"], $r["type"]));
                 array_push($this->inventory_scroll, new Inventory($r["id"], $r["type"]));
             }
             }
             // Rune crafting items are marked as generic crafting.
             // Rune crafting items are marked as generic crafting.
-            $s = "
+            $statement = $db->prepare("
                 SELECT
                 SELECT
                   inventory.id AS id,
                   inventory.id AS id,
                   inventory.type AS type
                   inventory.type AS type
                 FROM
                 FROM
                   inventory
                   inventory
                 WHERE
                 WHERE
-                  inventory.uid = '$UID' AND
-                  inventory.type = " . INVENTORY_TYPE_ID::RUNE_CRAFT . " AND
+                  inventory.uid = :uid AND
+                  inventory.type = :type AND
                   amount > 0
                   amount > 0
                 ORDER BY inventory.id;
                 ORDER BY inventory.id;
-            ";
-            $q = $db->query($s);
+            ");
+            $statement->bindValue(':uid', $UID, SQLITE3_INTEGER);
+            $statement->bindValue(':type', INVENTORY_TYPE_ID::ENCHANTMENT, SQLITE3_INTEGER);
+            $q = $statement->execute();
             while ($r = $q->fetchArray(SQLITE3_ASSOC)){
             while ($r = $q->fetchArray(SQLITE3_ASSOC)){
                 array_push($this->inventory_craft_rune, new Inventory($r["id"], $r["type"]));
                 array_push($this->inventory_craft_rune, new Inventory($r["id"], $r["type"]));
             }
             }
-            $s = "
+            $statement = $db->prepare("
                 SELECT
                 SELECT
                   inventory.id AS id,
                   inventory.id AS id,
                   inventory.type AS type
                   inventory.type AS type
                 FROM
                 FROM
                   inventory
                   inventory
                 WHERE
                 WHERE
-                  inventory.uid = '$UID' AND
-                  inventory.type = " . INVENTORY_TYPE_ID::CRAFT_STUFF . " AND
+                  inventory.uid = :uid AND
+                  inventory.type = :type AND
                   amount > 0
                   amount > 0
                 ORDER BY inventory.id;
                 ORDER BY inventory.id;
-            ";
-            $q = $db->query($s);
+            ");
+            $statement->bindValue(':uid', $UID, SQLITE3_INTEGER);
+            $statement->bindValue(':type', INVENTORY_TYPE_ID::CRAFT_STUFF, SQLITE3_INTEGER);
+            $q = $statement->execute();
             while ($r = $q->fetchArray(SQLITE3_ASSOC)){
             while ($r = $q->fetchArray(SQLITE3_ASSOC)){
                 array_push($this->inventory_craft, new Inventory($r["id"], $r["type"]));
                 array_push($this->inventory_craft, new Inventory($r["id"], $r["type"]));
             }
             }
-            $s = "
+            $statement = $db->prepare("
                 SELECT
                 SELECT
                   inventory.id AS id,
                   inventory.id AS id,
                   inventory.type AS type
                   inventory.type AS type
@@ -370,8 +380,8 @@
                 WHERE
                 WHERE
                   inventory.id = k_inventory.id AND
                   inventory.id = k_inventory.id AND
                   inventory.type = k_inventory.type AND
                   inventory.type = k_inventory.type AND
-                  inventory.uid = '$UID' AND
-                  inventory.type = " . INVENTORY_TYPE_ID::ESSENCES . " AND
+                  inventory.uid = :uid AND
+                  inventory.type = :type AND
                   amount > 0
                   amount > 0
                 ORDER BY
                 ORDER BY
                   upper(name) NOT LIKE '%MAGIC%',
                   upper(name) NOT LIKE '%MAGIC%',
@@ -384,21 +394,22 @@
                   upper(name) NOT LIKE '%MID%',
                   upper(name) NOT LIKE '%MID%',
                   upper(name) NOT LIKE '%HIGH%'
                   upper(name) NOT LIKE '%HIGH%'
                 ;
                 ;
-            ";
-            $q = $db->query($s);
+            ");
+            $statement->bindValue(':uid', $UID, SQLITE3_INTEGER);
+            $statement->bindValue(':type', INVENTORY_TYPE_ID::ESSENCES, SQLITE3_INTEGER);
+            $q = $statement->execute();
             while ($r = $q->fetchArray(SQLITE3_ASSOC)){
             while ($r = $q->fetchArray(SQLITE3_ASSOC)){
                 array_push($this->inventory_essence, new Inventory($r["id"], $r["type"]));
                 array_push($this->inventory_essence, new Inventory($r["id"], $r["type"]));
             }
             }
-            $s = "
+            $statement = $db->prepare("
                 SELECT
                 SELECT
                   uid,
                   uid,
                   area_type,
                   area_type,
                   area
                   area
                 FROM record
                 FROM record
-                WHERE uid = '$UID'
+                WHERE uid = :uid
                 ORDER BY
                 ORDER BY
                   CASE
                   CASE
-
                     WHEN (area_type = 2 AND area = 8001) THEN  1 -- Giant's Keep
                     WHEN (area_type = 2 AND area = 8001) THEN  1 -- Giant's Keep
                     WHEN (area_type = 2 AND area = 9001) THEN  2 -- Dragon's Lair
                     WHEN (area_type = 2 AND area = 9001) THEN  2 -- Dragon's Lair
                     WHEN (area_type = 2 AND area = 6001) THEN  3 -- Necropolis
                     WHEN (area_type = 2 AND area = 6001) THEN  3 -- Necropolis
@@ -418,8 +429,9 @@
                     WHEN (area_type = 2 AND area = 1001) THEN 17 -- Hall of Dark
                     WHEN (area_type = 2 AND area = 1001) THEN 17 -- Hall of Dark
                     ELSE area 
                     ELSE area 
                     END ASC
                     END ASC
-            ";
-            $q = $db->query($s);
+            ");
+            $statement->bindValue(':uid', $UID, SQLITE3_INTEGER);
+            $q = $statement->execute();
             while ($r = $q->fetchArray(SQLITE3_ASSOC)){
             while ($r = $q->fetchArray(SQLITE3_ASSOC)){
                 array_push($this->record, new Record($r["uid"], $r["area_type"], $r["area"]));
                 array_push($this->record, new Record($r["uid"], $r["area_type"], $r["area"]));
             }
             }

+ 49 - 43
application/entity/Record.php

@@ -85,7 +85,7 @@
 
 
             global $db;
             global $db;
 
 
-            $s = "
+            $statement = $db->prepare("
                 SELECT
                 SELECT
                   uid,
                   uid,
                   area_type,
                   area_type,
@@ -96,48 +96,54 @@
                   rank
                   rank
                 FROM record
                 FROM record
                 WHERE
                 WHERE
-                  uid = $uid AND
-                  area_type = $area_type AND
-                  area = $area;
-            ";
-            error_log($s);
-            $q = $db->query($s);
-            $r = $q->fetchArray(SQLITE3_ASSOC);
-            $this->uid = $r["uid"];
-            $this->area = new K_Area($r["area"], $r["area_type"]);
-            $this->stage = $r["stage"];
-            $this->time = $r["time"];
-            $this->score = $r["score"];
-            $this->rank = $r["rank"];
-            $s = "
-                SELECT
-                  unit,
-                  k_unit,
-                  (SELECT count(id) FROM unit WHERE unit.id = record_party.unit) AS owned,
-                  leader,
-                  front
-                FROM record_party
-                WHERE
-                  uid = $uid AND
-                  area_type = $area_type AND
-                  area = $area
-                ORDER BY 
-                  front DESC,
-                  leader DESC;
-            ";
-            $q = $db->query($s);
-            while ($r = $q->fetchArray(SQLITE3_ASSOC)){
-                if ($r["owned"] > 0){
-                    array_push($this->party, new Unit($r["unit"], false));
-                }
-                else{
-                    array_push($this->party, new K_Unit($r["k_unit"], false));
-                }
-                if ($r["leader"] == 1){
-                    $this->leader = $r["unit"];
-                }
-                if ($r["front"] == 1){
-                    array_push($this->frontline, $r["unit"]);
+                  uid = :uid AND
+                  area_type = :area_type AND
+                  area = :area;
+            ");
+            $statement->bindValue(':uid', $uid, SQLITE3_INTEGER);
+            $statement->bindValue(':area_type', $area_type, SQLITE3_INTEGER);
+            $statement->bindValue(':area', $area, SQLITE3_INTEGER);
+            $r = $statement->execute()->fetchArray(SQLITE3_ASSOC);
+            if ($r){
+                $this->uid = $r["uid"];
+                $this->area = new K_Area($r["area"], $r["area_type"]);
+                $this->stage = $r["stage"];
+                $this->time = $r["time"];
+                $this->score = $r["score"];
+                $this->rank = $r["rank"];
+                $statement = $db->prepare("
+                    SELECT
+                      unit,
+                      k_unit,
+                      (SELECT count(id) FROM unit WHERE unit.id = record_party.unit) AS owned,
+                      leader,
+                      front
+                    FROM record_party
+                    WHERE
+                      uid = :uid AND
+                      area_type = :area_type AND
+                      area = :area
+                    ORDER BY 
+                      front DESC,
+                      leader DESC;
+                ");
+                $statement->bindValue(':uid', $uid, SQLITE3_INTEGER);
+                $statement->bindValue(':area_type', $area_type, SQLITE3_INTEGER);
+                $statement->bindValue(':area', $area, SQLITE3_INTEGER);
+                $q = $statement->execute();
+                while ($r = $q->fetchArray(SQLITE3_ASSOC)){
+                    if ($r["owned"] > 0){
+                        array_push($this->party, new Unit($r["unit"], false));
+                    }
+                    else{
+                        array_push($this->party, new K_Unit($r["k_unit"], false));
+                    }
+                    if ($r["leader"] == 1){
+                        $this->leader = $r["unit"];
+                    }
+                    if ($r["front"] == 1){
+                        array_push($this->frontline, $r["unit"]);
+                    }
                 }
                 }
             }
             }
         }
         }

+ 267 - 205
application/entity/Run.php

@@ -14,6 +14,7 @@
     require_once(PATH::ENTITY . "Unit.php");
     require_once(PATH::ENTITY . "Unit.php");
     require_once(PATH::ENTITY . "K_Unit.php");
     require_once(PATH::ENTITY . "K_Unit.php");
     require_once(PATH::ENTITY . "Rune.php");
     require_once(PATH::ENTITY . "Rune.php");
+    require_once(PATH::ENTITY . "Enchantment.php");
     require_once(PATH::ENTITY . "Inventory.php");
     require_once(PATH::ENTITY . "Inventory.php");
     require_once(PATH::ENTITY . "K_Area.php");
     require_once(PATH::ENTITY . "K_Area.php");
     require_once(PATH::ENTITY . "K_Rune_Set.php");
     require_once(PATH::ENTITY . "K_Rune_Set.php");
@@ -71,17 +72,27 @@
         /**
         /**
          * @var int Reward mana.
          * @var int Reward mana.
          */
          */
-        public $mana;
+        public $mana = 0;
 
 
         /**
         /**
          * @var int Reward energy.
          * @var int Reward energy.
          */
          */
-        public $energy;
+        public $energy = 0;
 
 
         /**
         /**
          * @var int Reward crystal.
          * @var int Reward crystal.
          */
          */
-        public $crystal;
+        public $crystal = 0;
+
+        /**
+         * @var int Reward Honor Points (Arena).
+         */
+        public $honor_points = 0;
+
+        /**
+         * @var int Reward Guild Points.
+         */
+        public $guild_points = 0;
 
 
         /**
         /**
          * @var bool Indicates if a frind/mentor helped.
          * @var bool Indicates if a frind/mentor helped.
@@ -146,7 +157,12 @@
         /**
         /**
          * @var \Rune[] List of Runes dropped.
          * @var \Rune[] List of Runes dropped.
          */
          */
-        public $rune= [];
+        public $rune = [];
+
+        /**
+         * @var \Enchantment[] List of Enchantments dropped.
+         */
+        public $enchantment = [];
 
 
         /**
         /**
          * Constructor.
          * Constructor.
@@ -161,213 +177,259 @@
 
 
             global $db;
             global $db;
 
 
-            $s = "
-                SELECT
-                  id,
-                  uid,
-                  dtime,
-                  area,
-                  stage,
-                  difficulty,
-                  win,
-                  time,
-                  mana,
-                  energy,
-                  crystal,
-                  helper,
-                  score,
-                  rank
-                FROM run
-                WHERE id = $id;
-            ";
-            $q = $db->query($s);
-            $r = $q->fetchArray(SQLITE3_ASSOC);
-            $this->id = $r["id"];
-            $this->uid = $r["uid"];
-            $this->dtime = $r["dtime"];
-            $type = 0;
-            if (APPLICATION::valid_id("RAID_RIFT_DUNGEON_ID", $r["area"]) && $r["stage"] < 1){
-                $type = AREA_TYPE_ID::RIFT_RAID_DUNGEON;
-            }
-            elseif (APPLICATION::valid_id("SCENARIO_ID", $r["area"])){
-                $type = AREA_TYPE_ID::SCENARIO;
-            }
-            elseif (APPLICATION::valid_id("ELEMENTAL_RIFT_DUNGEON_ID", $r["area"]) && $r["stage"] < 1){
-                $type = AREA_TYPE_ID::RIFT_DUNGEON;
-            }
-            elseif (APPLICATION::valid_id("CAIROS_DUNGEON_ID", $r["area"])){
-                $type = AREA_TYPE_ID::CAIROS_DUNGEON;
-            }
-            elseif (APPLICATION::valid_id("DIMENSION_DUNGEON_ID", $r["area"])){
-                if ($this->id == 1486){
-                    error_log("VALID AREA ID: " . $r["area"] . ", " . AREA_TYPE_ID::DIMENSIONAL_HOLE);
+            $statement = $db->prepare("
+              SELECT
+                id,
+                uid,
+                dtime,
+                area_type,
+                area,
+                stage,
+                difficulty,
+                win,
+                time,
+                mana,
+                energy,
+                crystal,
+                honor_points,
+                guild_points,
+                helper,
+                score,
+                rank
+              FROM run
+              WHERE id = :id;
+            ");
+            $statement->bindValue(':id', $id, SQLITE3_INTEGER);
+            $r = $statement->execute()->fetchArray(SQLITE3_ASSOC);
+            if ($r){
+                $this->id = $r["id"];
+                $this->uid = $r["uid"];
+                $this->dtime = $r["dtime"];
+                $this->area = new K_Area($r["area"], $r["area_type"]);
+                $this->stage = $r["stage"];
+                $this->difficulty = $r["difficulty"];
+                $this->win = $r["win"];
+                $this->time = $r["time"];
+                $this->mana = $r["mana"];
+                $this->energy = $r["energy"];
+                $this->crystal = $r["crystal"];
+                $this->honor_points = $r["honor_points"];
+                $this->guild_points = $r["guild_points"];
+                $this->helper = $r["helper"];
+                $this->score = $r["score"];
+                $this->rank = $r["rank"];
+                $statement = $db->prepare("
+                    SELECT
+                      unit,
+                      k_unit,
+                      (SELECT count(id) FROM unit WHERE unit.id = run_party.unit) AS owned,
+                      leader,
+                      front
+                    FROM run_party
+                    WHERE run = :run
+                    ORDER BY 
+                      front DESC,
+                      leader DESC;
+                ");
+                $statement->bindValue(':run', $id, SQLITE3_INTEGER);
+                $q = $statement->execute();
+                while ($r = $q->fetchArray(SQLITE3_ASSOC)){
+                    if ($r["owned"] > 0){
+                        array_push($this->party, new Unit($r["unit"], false));
+                    }
+                    else{
+                        array_push($this->party, new K_Unit($r["k_unit"], false));
+                    }
+                    if ($r["leader"] == 1){
+                        $this->leader = $r["unit"];
+                    }
+                    if ($r["front"] == 1){
+                        array_push($this->frontline, $r["unit"]);
+                    }
                 }
                 }
-                $type = AREA_TYPE_ID::DIMENSIONAL_HOLE;
-            }
-            if ($this->id == 1486){
-                error_log("INSTANCING DH AREA: " . $r["area"] . ", " . $type);
-            }
-            $this->area = new K_Area($r["area"], $type);
-            $this->stage = $r["stage"];
-            $this->difficulty = $r["difficulty"];
-            $this->win = $r["win"];
-            $this->time = $r["time"];
-            $this->mana = $r["mana"];
-            $this->energy = $r["energy"];
-            $this->crystal = $r["crystal"];
-            $this->helper = $r["helper"];
-            $this->score = $r["score"];
-            $this->rank = $r["rank"];
-            $s = "
-                SELECT
-                  unit,
-                  k_unit,
-                  (SELECT count(id) FROM unit WHERE unit.id = run_party.unit) AS owned,
-                  leader,
-                  front
-                FROM run_party
-                WHERE run = $id
-                ORDER BY 
-                  front DESC,
-                  leader DESC;
-            ";
-            $q = $db->query($s);
-            while ($r = $q->fetchArray(SQLITE3_ASSOC)){
-                if ($r["owned"] > 0){
-                    array_push($this->party, new Unit($r["unit"], false));
+                $statement = $db->prepare("
+                    SELECT
+                      item,
+                      amount
+                    FROM run_drop_item
+                    WHERE run = :run;
+                ");
+                $statement->bindValue(':run', $this->id, SQLITE3_INTEGER);
+                $q = $statement->execute();
+                while ($r = $q->fetchArray(SQLITE3_ASSOC)){
+                    $i = new Inventory($r["item"]);
+                    $i->amount =  $r["amount"];
+                    array_push($this->item, $i);
                 }
                 }
-                else{
-                    array_push($this->party, new K_Unit($r["k_unit"], false));
+                $statement = $db->prepare("
+                    SELECT unit
+                    FROM run_drop_unit
+                    WHERE run = :run;
+                ");
+                $statement->bindValue(':run', $this->id, SQLITE3_INTEGER);
+                $q = $statement->execute();
+                while ($r = $q->fetchArray(SQLITE3_ASSOC)){
+                    array_push($this->unit, new K_Unit($r["unit"]));
                 }
                 }
-                if ($r["leader"] == 1){
-                    $this->leader = $r["unit"];
+                $statement = $db->prepare("
+                    SELECT unit
+                    FROM run_drop_sd
+                    WHERE run = :run;
+                ");
+                $statement->bindValue(':run', $this->id, SQLITE3_INTEGER);
+                $q = $statement->execute();
+                while ($r = $q->fetchArray(SQLITE3_ASSOC)){
+                    array_push($this->sd, new K_Unit($r["unit"]));
                 }
                 }
-                if ($r["front"] == 1){
-                    array_push($this->frontline, $r["unit"]);
+                $statement = $db->prepare("
+                    SELECT
+                      unit,
+                      amount
+                    FROM run_drop_unit_pieces
+                    WHERE run = :run;
+                ");
+                $statement->bindValue(':run', $this->id, SQLITE3_INTEGER);
+                $q = $statement->execute();
+                while ($r = $q->fetchArray(SQLITE3_ASSOC)){
+                    $i = [
+                        "unit" => new K_Unit($r["unit"]),
+                        "amount" => $r["amount"]
+                    ];
+                    array_push($this->unit_piece, $i);
                 }
                 }
-            }
-            $s = "
-                SELECT
-                  item,
-                  amount
-                FROM run_drop_item
-                WHERE run = $this->id;
-            ";
-            $q = $db->query($s);
-            while ($r = $q->fetchArray(SQLITE3_ASSOC)){
-                $i = new Inventory($r["item"]);
-                $i->amount =  $r["amount"];
-                array_push($this->item, $i);
-            }
-            $s = "
-                SELECT unit
-                FROM run_drop_unit
-                WHERE run = $this->id;
-            ";
-            $q = $db->query($s);
-            while ($r = $q->fetchArray(SQLITE3_ASSOC)){
-                array_push($this->unit, new K_Unit($r["unit"]));
-            }
-            $s = "
-                SELECT unit
-                FROM run_drop_sd
-                WHERE run = $this->id;
-            ";
-            $q = $db->query($s);
-            while ($r = $q->fetchArray(SQLITE3_ASSOC)){
-                array_push($this->sd, new K_Unit($r["unit"]));
-            }
-            $s = "
-                SELECT
-                  unit,
-                  amount
-                FROM run_drop_unit_pieces
-                WHERE run = $this->id;
-            ";
-            $q = $db->query($s);
-            while ($r = $q->fetchArray(SQLITE3_ASSOC)){
-                $i = [
-                    "unit" => new K_Unit($r["unit"]),
-                    "amount" => $r["amount"]
-                ];
-                array_push($this->unit_piece, $i);
-            }
-            $s = "
-                SELECT amount
-                FROM run_drop_shapeshifting
-                WHERE run = $this->id;
-            ";
-            $q = $db->query($s);
-            $r = $q->fetchArray(SQLITE3_ASSOC);
-            if ($r){
-                $this->shapeshifting = $r["amount"];
-            }
-            $s = "
-                SELECT
-                  id,
-                  type,
-                  slot,
-                  stars,
-                  ancient,
-                  quality,
-                  value,
-                  efficiency,
-                  main_stat,
-                  main_stat_value,
-                  innate_stat,
-                  innate_stat_value,
-                  substat_1,
-                  substat_1_value,
-                  substat_2,
-                  substat_2_value,
-                  substat_3,
-                  substat_3_value,
-                  substat_4,
-                  substat_4_value
-                FROM run_drop_rune
-                WHERE run = $this->id;
-            ";
-            $q = $db->query($s);
-            while ($r = $q->fetchArray(SQLITE3_ASSOC)){
-                $rune = new Rune($r["id"]);
-                if (!isset($rune->id)){
-                    $rune->id = $r["id"];
-                    $rune->level = 0;
-                    $rune->assigned_to = null;
-                    $rune->type = new K_Rune_Set($r["type"]);
-                    $rune->slot = $r["slot"];
-                    $rune->stars = $r["stars"];
-                    $rune->ancient = $r["ancient"];
-                    $rune->quality = $r["quality"];
-                    $rune->original_quality = $r["quality"];
-                    $rune->value = $r["value"];
-                    $rune->value = 0;
-                    $rune->efficiency = $r["efficiency"];
-                    // TODO: Calculate?
-                    $rune->max_efficiency = $r["efficiency"];
-                    $rune->main_stat = $r["main_stat"];
-                    $rune->main_stat_value = $r["main_stat_value"];
-                    $rune->innate_stat = $r["innate_stat"];
-                    $rune->innate_stat_value = $r["innate_stat_value"];
-                    $rune->substat_1 = $r["substat_1"];
-                    $rune->substat_1_value = $r["substat_1_value"];
-                    $rune->substat_1_enchant = 0;
-                    $rune->substat_1_grind = 0;
-                    $rune->substat_2 = $r["substat_2"];
-                    $rune->substat_2_value = $r["substat_2_value"];
-                    $rune->substat_2_enchant = 0;
-                    $rune->substat_2_grind = 0;
-                    $rune->substat_3 = $r["substat_3"];
-                    $rune->substat_3_value = $r["substat_3_value"];
-                    $rune->substat_3_enchant = 0;
-                    $rune->substat_3_grind = 0;
-                    $rune->substat_4 = $r["substat_4"];
-                    $rune->substat_4_value = $r["substat_4_value"];
-                    $rune->substat_4_enchant = 0;
-                    $rune->substat_4_grind = 0;
-                    $rune->refresh_names();
+                $statement = $db->prepare("
+                    SELECT amount
+                    FROM run_drop_shapeshifting
+                    WHERE run = :run;
+                ");
+                $statement->bindValue(':run', $this->id, SQLITE3_INTEGER);
+                $q = $statement->execute();
+                $r = $q->fetchArray(SQLITE3_ASSOC);
+                if ($r){
+                    $this->shapeshifting = $r["amount"];
+                }
+                $statement = $db->prepare("
+                    SELECT
+                      id,
+                      type,
+                      slot,
+                      stars,
+                      ancient,
+                      quality,
+                      value,
+                      efficiency,
+                      main_stat,
+                      main_stat_value,
+                      innate_stat,
+                      innate_stat_value,
+                      substat_1,
+                      substat_1_value,
+                      substat_2,
+                      substat_2_value,
+                      substat_3,
+                      substat_3_value,
+                      substat_4,
+                      substat_4_value
+                    FROM run_drop_rune
+                    WHERE run = :run;
+                ");
+                $statement->bindValue(':run', $this->id, SQLITE3_INTEGER);
+                $q = $statement->execute();
+                while ($r = $q->fetchArray(SQLITE3_ASSOC)){
+                    $rune = new Rune($r["id"]);
+                    if (!isset($rune->id)){
+                        $rune->id = $r["id"];
+                        $rune->level = 0;
+                        $rune->assigned_to = null;
+                        $rune->type = new K_Rune_Set($r["type"]);
+                        $rune->slot = $r["slot"];
+                        $rune->stars = $r["stars"];
+                        $rune->ancient = $r["ancient"];
+                        $rune->quality = $r["quality"];
+                        $rune->original_quality = $r["quality"];
+                        $rune->value = $r["value"];
+                        $rune->value = 0;
+                        $rune->efficiency = $r["efficiency"];
+                        // TODO: Calculate?
+                        $rune->max_efficiency = $r["efficiency"];
+                        $rune->main_stat = $r["main_stat"];
+                        $rune->main_stat_value = $r["main_stat_value"];
+                        $rune->innate_stat = $r["innate_stat"];
+                        $rune->innate_stat_value = $r["innate_stat_value"];
+                        $rune->substat_1 = $r["substat_1"];
+                        $rune->substat_1_value = $r["substat_1_value"];
+                        $rune->substat_1_enchant = 0;
+                        $rune->substat_1_grind = 0;
+                        $rune->substat_2 = $r["substat_2"];
+                        $rune->substat_2_value = $r["substat_2_value"];
+                        $rune->substat_2_enchant = 0;
+                        $rune->substat_2_grind = 0;
+                        $rune->substat_3 = $r["substat_3"];
+                        $rune->substat_3_value = $r["substat_3_value"];
+                        $rune->substat_3_enchant = 0;
+                        $rune->substat_3_grind = 0;
+                        $rune->substat_4 = $r["substat_4"];
+                        $rune->substat_4_value = $r["substat_4_value"];
+                        $rune->substat_4_enchant = 0;
+                        $rune->substat_4_grind = 0;
+                        $rune->refresh_names();
+                    }
+                    array_push($this->rune, $rune);
+                }
+                $statement = $db->prepare("
+                  SELECT
+                    run_drop_enchantment.id AS id,
+                    type,
+                    run_drop_enchantment.quality AS quality,
+                    rune,
+                    run_drop_enchantment.stat AS stat,
+                    value,
+                    k_enchantment_type.inmemorial AS inmemorial,
+                    k_enchantment_type.ancient AS ancient,
+                    k_enchantment_range.min AS min,
+                    k_enchantment_range.max AS max
+                  FROM
+                    run_drop_enchantment,
+                    k_enchantment_type,
+                    k_enchantment_range
+                  WHERE
+                    run = :run AND
+                    run_drop_enchantment.type = k_enchantment_type.id AND
+                    k_enchantment_type.gem = k_enchantment_range.gem AND
+                    k_enchantment_type.gem = k_enchantment_range.gem AND
+                    k_enchantment_type.ancient = k_enchantment_range.ancient AND
+                    run_drop_enchantment.quality = k_enchantment_range.quality AND
+                    run_drop_enchantment.stat = k_enchantment_range.stat;
+                ");
+                $statement->bindValue(':run', $this->id, SQLITE3_INTEGER);
+                $q = $statement->execute();
+                while ($r = $q->fetchArray(SQLITE3_ASSOC)){
+                    $enchantment = new Enchantment($r["id"]);
+                    if (!isset($enchantment->id)){
+                        $enchantment->id = $r["id"];
+                        if ($r["type"] == CRAFT_ID::ENCHANT_GEM || $r["type"] == CRAFT_ID::IMMEMORIAL_GEM){
+                                $enchantment->gem = 1;
+                        }
+                        else{
+                                $enchantment->gem = 0;
+                        }
+                        $enchantment->quality = $r["quality"];
+                        $enchantment->value = 0;
+                        $enchantment->stat = $r["stat"];
+                        $enchantment->ancient = $r["ancient"];
+                        $enchantment->inmemorial = $r["inmemorial"];
+                        $enchantment->rune = new K_Rune_Set($r["rune"]);
+                        $enchantment->min = $r["min"];
+                        $enchantment->max = $r["max"];
+                        $enchantment->value = $r["value"];
+                        $enchantment->amount = 0;
+                        $enchantment->refresh_names();
+                    }
+                    else{
+                        $enchantment->amount = 0;
+                    }
+                    array_push($this->enchantment, $enchantment);
                 }
                 }
-                array_push($this->rune, $rune);
             }
             }
         }
         }
 
 

+ 47 - 46
application/entity/Rune.php

@@ -65,14 +65,14 @@
         /**
         /**
          * @var int Rune quality.
          * @var int Rune quality.
          *
          *
-         * @see QUALITY
+         * @see QUALITY_ID
          */
          */
         public $quality;
         public $quality;
 
 
         /**
         /**
          * @var int Rune original quality.
          * @var int Rune original quality.
          *
          *
-         * @see QUALITY
+         * @see QUALITY_ID
          */
          */
         public $original_quality;
         public $original_quality;
 
 
@@ -104,7 +104,7 @@
         /**
         /**
          * @var int Main stat of the rune.
          * @var int Main stat of the rune.
          *
          *
-         * @see RUNE_STAT
+         * @see RUNE_STAT_ID
          */
          */
         public $main_stat;
         public $main_stat;
 
 
@@ -121,7 +121,7 @@
         /**
         /**
          * @var int Extra stat of the rune.
          * @var int Extra stat of the rune.
          *
          *
-         * @see RUNE_STAT
+         * @see RUNE_STAT_ID
          */
          */
         public $innate_stat;
         public $innate_stat;
 
 
@@ -143,7 +143,7 @@
         /**
         /**
          * @var int Substat 1 of the rune.
          * @var int Substat 1 of the rune.
          *
          *
-         * @see RUNE_STAT
+         * @see RUNE_STAT_ID
          */
          */
         public $substat_1;
         public $substat_1;
 
 
@@ -165,7 +165,7 @@
         /**
         /**
          * @var int Substat 2 of the rune.
          * @var int Substat 2 of the rune.
          *
          *
-         * @see RUNE_STAT
+         * @see RUNE_STAT_ID
          */
          */
         public $substat_2;
         public $substat_2;
 
 
@@ -187,7 +187,7 @@
         /**
         /**
          * @var int Substat 3 of the rune.
          * @var int Substat 3 of the rune.
          *
          *
-         * @see RUNE_STAT
+         * @see RUNE_STAT_ID
          */
          */
         public $substat_3;
         public $substat_3;
 
 
@@ -209,7 +209,7 @@
         /**
         /**
          * @var int Substat 4 of the rune.
          * @var int Substat 4 of the rune.
          *
          *
-         * @see RUNE_STAT
+         * @see RUNE_STAT_ID
          */
          */
         public $substat_4;
         public $substat_4;
 
 
@@ -241,44 +241,45 @@
 
 
             global $db;
             global $db;
 
 
-            $s =
-              "SELECT " .
-              "  id, " .
-              "  assigned_to, " .
-              "  type, " .
-              "  slot, " .
-              "  stars, " .
-              "  level, " .
-              "  ancient, " .
-              "  quality, " .
-              "  original_quality, " .
-              "  value, " .
-              "  efficiency, " .
-              "  max_efficiency, " .
-              "  main_stat, " .
-              "  main_stat_value, " .
-              "  innate_stat, " .
-              "  innate_stat_value, " .
-              "  substat_1, " .
-              "  substat_1_value, " .
-              "  substat_1_enchant, " .
-              "  substat_1_grind, " .
-              "  substat_2, " .
-              "  substat_2_value, " .
-              "  substat_2_enchant, " .
-              "  substat_2_grind, " .
-              "  substat_3, " .
-              "  substat_3_value, " .
-              "  substat_3_enchant, " .
-              "  substat_3_grind, " .
-              "  substat_4, " .
-              "  substat_4_value, " .
-              "  substat_4_enchant, " .
-              "  substat_4_grind " .
-              "FROM rune " .
-              "WHERE id = '$id'; ";
-            $q = $db->query($s);
-            $r = $q->fetchArray(SQLITE3_ASSOC);
+            $statement = $db->prepare("
+              SELECT
+                id,
+                assigned_to,
+                type,
+                slot,
+                stars,
+                level,
+                ancient,
+                quality,
+                original_quality,
+                value,
+                efficiency,
+                max_efficiency,
+                main_stat,
+                main_stat_value,
+                innate_stat,
+                innate_stat_value,
+                substat_1,
+                substat_1_value,
+                substat_1_enchant,
+                substat_1_grind,
+                substat_2,
+                substat_2_value,
+                substat_2_enchant,
+                substat_2_grind,
+                substat_3,
+                substat_3_value,
+                substat_3_enchant,
+                substat_3_grind,
+                substat_4,
+                substat_4_value,
+                substat_4_enchant,
+                substat_4_grind
+              FROM rune
+              WHERE id = :id;
+            ");
+            $statement->bindValue(':id', $id, SQLITE3_INTEGER);
+            $r = $statement->execute()->fetchArray(SQLITE3_ASSOC);
             if ($r){
             if ($r){
                 $this->id = $r["id"];
                 $this->id = $r["id"];
                 $this->assigned_to = $r["assigned_to"];
                 $this->assigned_to = $r["assigned_to"];

+ 36 - 33
application/entity/Team.php

@@ -58,7 +58,7 @@
         public $frontline = [];
         public $frontline = [];
 
 
         /**
         /**
-         * @var Area Area the team is designed for.
+         * @var \K_Area Area the team is designed for.
          */
          */
         public $area;
         public $area;
 
 
@@ -93,7 +93,7 @@
 
 
             global $db;
             global $db;
 
 
-            $s = "
+            $statement = $db->prepare("
               SELECT
               SELECT
                 uid,
                 uid,
                 id,
                 id,
@@ -105,37 +105,40 @@
                 difficulty,
                 difficulty,
                 score
                 score
               FROM team
               FROM team
-              WHERE id = '$id';
-            ";
-            $q = $db->query($s);
-            $r = $q->fetchArray(SQLITE3_ASSOC);
-            $this->uid = $r["uid"];
-            $this->id = $r["id"];
-            $this->name = HTML::e($r["name"]);
-            $this->description = HTML::e($r["description"]);
-            $this->area = new K_Area($r["area"], $r["area_type"]);
-            $this->stage = $r["stage"];
-            $this->score = $r["score"];
-            if ($complete){
-                $s = "
-                  SELECT
-                    unit,
-                    leader,
-                    front
-                  FROM team_unit
-                  WHERE team = '$id'
-                  ORDER BY 
-                    front DESC,
-                    leader DESC;
-                ";
-                $q = $db->query($s);
-                while ($r = $q->fetchArray(SQLITE3_ASSOC)){
-                    array_push($this->unit, new Unit($r["unit"], false));
-                    if ($r["leader"] == 1){
-                        $this->leader = $r["unit"];
-                    }
-                    if ($r["front"] == 1){
-                        array_push($this->frontline, $r["unit"]);
+              WHERE id = :id;
+            ");
+            $statement->bindValue(':id', $id, SQLITE3_INTEGER);
+            $r = $statement->execute()->fetchArray(SQLITE3_ASSOC);
+            if ($r){
+                $this->uid = $r["uid"];
+                $this->id = $r["id"];
+                $this->name = HTML::e($r["name"]);
+                $this->description = HTML::e($r["description"]);
+                $this->area = new K_Area($r["area"], $r["area_type"]);
+                $this->stage = $r["stage"];
+                $this->score = $r["score"];
+                if ($complete){
+                    $statement = $db->prepare("
+                      SELECT
+                        unit,
+                        leader,
+                        front
+                      FROM team_unit
+                      WHERE team = :team
+                      ORDER BY 
+                        front DESC,
+                        leader DESC;
+                    ");
+                    $statement->bindValue(':team', $this->id, SQLITE3_INTEGER);
+                    $q = $statement->execute();
+                    while ($r = $q->fetchArray(SQLITE3_ASSOC)){
+                        array_push($this->unit, new Unit($r["unit"], false));
+                        if ($r["leader"] == 1){
+                            $this->leader = $r["unit"];
+                        }
+                        if ($r["front"] == 1){
+                            array_push($this->frontline, $r["unit"]);
+                        }
                     }
                     }
                 }
                 }
             }
             }

+ 105 - 81
application/entity/Unit.php

@@ -377,36 +377,38 @@
             if ($uid == 0){
             if ($uid == 0){
                 $uid = $UID;
                 $uid = $UID;
             }
             }
-            $s =
-              "SELECT " .
-              "  uid, " .
-              "  id, " .
-              "  building, " .
-              "  unit, " .
-              "  stars, " .
-              "  level, " .
-              "  hp, " .
-              "  attack, " .
-              "  defense, " .
-              "  speed, " .
-              "  crit_rate, " .
-              "  crit_damage, " .
-              "  resistance, " .
-              "  accuracy, " .
-              "  experience, " .
-              "  exp_gained, " .
-              "  exp_gain_rate, " .
-              "  costume, " .
-              "  source, " .
-              "  create_time, " .
-              "  homunculus_name, " .
-              "  lock " .
-              "FROM unit " .
-              "WHERE " .
-              "  uid = '$uid' AND " .
-              "  id = '$id'; ";
-            $q = $db->query($s);
-            $r = $q->fetchArray(SQLITE3_ASSOC);
+             $statement = $db->prepare("
+              SELECT
+                uid,
+                id,
+                building,
+                unit,
+                stars,
+                level,
+                hp,
+                attack,
+                defense,
+                speed,
+                crit_rate,
+                crit_damage,
+                resistance,
+                accuracy,
+                experience,
+                exp_gained,
+                exp_gain_rate,
+                costume,
+                source,
+                create_time,
+                homunculus_name,
+                lock
+              FROM unit
+              WHERE
+                uid = :uid AND
+                id = :id;
+            ");
+            $statement->bindValue(':id', $id, SQLITE3_INTEGER);
+            $statement->bindValue(':uid', $uid, SQLITE3_INTEGER);
+            $r = $statement->execute()->fetchArray(SQLITE3_ASSOC);
             if ($r){
             if ($r){
                 $this->uid = $r["uid"];
                 $this->uid = $r["uid"];
                 $this->id = $r["id"];
                 $this->id = $r["id"];
@@ -438,29 +440,35 @@
                     $this->load_teams();
                     $this->load_teams();
                     $this->check_storage();
                     $this->check_storage();
                     $this->lock = $r["lock"];
                     $this->lock = $r["lock"];
-                    $s =
-                      "SELECT level " .
-                      "FROM " .
-                      "  unit_skill, " .
-                      "  k_skill " .
-                      "WHERE " .
-                      "  k_skill.id = unit_skill.skill AND " .
-                      "  unit = '$this->id' " .
-                      "ORDER BY slot;";
-                    $q = $db->query($s);
+                    $statement = $db->prepare("
+                      SELECT level
+                      FROM
+                        unit_skill,
+                        k_skill
+                      WHERE
+                        k_skill.id = unit_skill.skill AND
+                        unit = :unit
+                      ORDER BY slot;
+                    ");
+                    $statement->bindValue(':unit', $this->id, SQLITE3_INTEGER);
+                    $q = $statement->execute();
                     while ($r = $q->fetchArray(SQLITE3_ASSOC)){
                     while ($r = $q->fetchArray(SQLITE3_ASSOC)){
                         array_push($this->skill_levels, $r["level"]);
                         array_push($this->skill_levels, $r["level"]);
                     }
                     }
-                    $s =
-                      "SELECT exp " .
-                      "FROM k_experience " .
-                      "WHERE " .
-                      "  stars = $this->stars AND " .
-                      "  level = $this->level;";
-                    $q = $db->query($s);
-                    $r = $q->fetchArray(SQLITE3_ASSOC);
-                    $this->experience_level = $r["exp"];
-                    $this->experience_level_up = $r["exp"] - $this->exp_gained;
+                    $statement = $db->prepare("
+                      SELECT exp
+                      FROM k_experience
+                      WHERE
+                        stars = :stars AND
+                        level = :level;
+                    ");
+                    $statement->bindValue(':stars', $this->stars, SQLITE3_INTEGER);
+                    $statement->bindValue(':level', $this->level, SQLITE3_INTEGER);
+                    $r = $statement->execute()->fetchArray(SQLITE3_ASSOC);
+                    if ($r){
+                        $this->experience_level = $r["exp"];
+                        $this->experience_level_up = $r["exp"] - $this->exp_gained;
+                    }
                 }
                 }
                 if ($this->unit->homunculus){
                 if ($this->unit->homunculus){
                     $this->title = $this->homunculus_name;
                     $this->title = $this->homunculus_name;
@@ -481,24 +489,27 @@
         public function check_storage(){
         public function check_storage(){
             global $UID;
             global $UID;
             global $db;
             global $db;
-            $s = "
+            $statement = $db->prepare("
               SELECT 1
               SELECT 1
               FROM
               FROM
                 unit,
                 unit,
                 building
                 building
               WHERE
               WHERE
-                unit.id = $this->id AND
-                unit.uid = '$UID' AND
-                building.uid = '$UID' AND
+                unit.id = :id AND
+                unit.uid = :uid AND
+                building.uid = :uid AND
                 unit.building = building.id AND
                 unit.building = building.id AND
-                building.building = '" . BUILDING_ID::MONSTER_STORAGE . "';
-            ";
-            $q = $db->query($s);
-            if ($q->fetchArray(SQLITE3_ASSOC) == false){
-                $this->in_storage = false;
+                building.building = :building;
+            ");
+            $statement->bindValue(':id', $this->id, SQLITE3_INTEGER);
+            $statement->bindValue(':uid', $UID, SQLITE3_INTEGER);
+            $statement->bindValue(':building', BUILDING_ID::MONSTER_STORAGE, SQLITE3_INTEGER);
+            $r = $statement->execute()->fetchArray(SQLITE3_ASSOC);
+            if ($r){
+                $this->in_storage = true;
             }
             }
             else{
             else{
-                $this->in_storage = true;
+                $this->in_storage = false;
             }
             }
         }
         }
 
 
@@ -517,11 +528,13 @@
 
 
             // Runes
             // Runes
             $this->rune = [];
             $this->rune = [];
-            $s =
-              "SELECT id " .
-              "FROM rune " .
-              "WHERE assigned_to = '$this->id'; ";
-            $q = $db->query($s);
+            $statement = $db->prepare("
+              SELECT id
+              FROM rune
+              WHERE assigned_to = :assigned;
+            ");
+            $statement->bindValue(':assigned', $this->id, SQLITE3_INTEGER);
+            $q = $statement->execute();
             while ($r = $q->fetchArray(SQLITE3_ASSOC)){
             while ($r = $q->fetchArray(SQLITE3_ASSOC)){
                 array_push($this->rune, new Rune($r["id"]));
                 array_push($this->rune, new Rune($r["id"]));
             }
             }
@@ -538,11 +551,13 @@
             $this->rune_hp = ceil($this->rune_hp);
             $this->rune_hp = ceil($this->rune_hp);
 
 
             // Artifacts
             // Artifacts
-            $s =
-              "SELECT id " .
-              "FROM artifact " .
-              "WHERE assigned_to = '$this->id'; ";
-            $q = $db->query($s);
+            $statement = $db->prepare("
+              SELECT id
+              FROM artifact
+              WHERE assigned_to = :assigned;
+            ");
+            $statement->bindValue(':assigned', $this->id, SQLITE3_INTEGER);
+            $q = $statement->execute();
             while ($r = $q->fetchArray(SQLITE3_ASSOC)){
             while ($r = $q->fetchArray(SQLITE3_ASSOC)){
                 $artifact = new Artifact($r["id"]);
                 $artifact = new Artifact($r["id"]);
                 if ($artifact->type == ARTIFACT_TYPE::ARCHETYPE){
                 if ($artifact->type == ARTIFACT_TYPE::ARCHETYPE){
@@ -565,7 +580,7 @@
             }
             }
 
 
             // Buildings
             // Buildings
-            $s = "
+            $statement = $db->prepare("
               SELECT
               SELECT
                 affected_stat,
                 affected_stat,
                 bonus,
                 bonus,
@@ -575,14 +590,21 @@
                 k_decoration_level,
                 k_decoration_level,
                 decoration
                 decoration
               WHERE
               WHERE
-                decoration.uid = '$UID' AND
+                decoration.uid = :uid AND
                 k_decoration.id = decoration.decoration AND
                 k_decoration.id = decoration.decoration AND
                 decoration.decoration = k_decoration_level.decoration AND
                 decoration.decoration = k_decoration_level.decoration AND
                 decoration.level = k_decoration_level.level AND
                 decoration.level = k_decoration_level.level AND
-                area = " . EFFECT_AREA_ID::GENERAL . " AND
-                affected_stat IN (" . STAT_ID::ATK . ", " . STAT_ID::DEF . ", " . STAT_ID::HP . ", " . STAT_ID::SPD . ", " . STAT_ID::CRIT_DMG . ");
-            ";
-            $q = $db->query($s);
+                area = :area AND
+                affected_stat IN (:stat_atk, :stat_def, :stat_hp, :stat_spd, :stat_crd);
+            ");
+            $statement->bindValue(':uid', $UID, SQLITE3_INTEGER);
+            $statement->bindValue(':area', EFFECT_AREA_ID::GENERAL, SQLITE3_INTEGER);
+            $statement->bindValue(':stat_atk', STAT_ID::ATK, SQLITE3_INTEGER);
+            $statement->bindValue(':stat_def', STAT_ID::DEF, SQLITE3_INTEGER);
+            $statement->bindValue(':stat_hp', STAT_ID::HP, SQLITE3_INTEGER);
+            $statement->bindValue(':stat_spd', STAT_ID::SPD, SQLITE3_INTEGER);
+            $statement->bindValue(':stat_crd', STAT_ID::CRIT_DMG, SQLITE3_INTEGER);
+            $q = $statement->execute();
             while ($r = $q->fetchArray(SQLITE3_ASSOC)){
             while ($r = $q->fetchArray(SQLITE3_ASSOC)){
                 switch($r["affected_stat"]){
                 switch($r["affected_stat"]){
                     case STAT_ID::DEF:
                     case STAT_ID::DEF:
@@ -655,17 +677,19 @@
             global $UID;
             global $UID;
             global $db;
             global $db;
             $this->teams = [];
             $this->teams = [];
-            $s = "
+            $statement = $db->prepare("
               SELECT DISTINCT team.id AS id
               SELECT DISTINCT team.id AS id
               FROM
               FROM
                 team,
                 team,
                 team_unit
                 team_unit
               WHERE
               WHERE
-                team.uid = '$UID' AND
+                team.uid = :uid AND
                 team.id = team_unit.team AND
                 team.id = team_unit.team AND
-                team_unit.unit = '" . $this->id . "';
-            ";
-            $q = $db->query($s);
+                team_unit.unit = :unit;
+            ");
+            $statement->bindValue(':uid', $UID, SQLITE3_INTEGER);
+            $statement->bindValue(':unit', $this->id, SQLITE3_INTEGER);
+            $q = $statement->execute();
             while ($r = $q->fetchArray(SQLITE3_ASSOC)){
             while ($r = $q->fetchArray(SQLITE3_ASSOC)){
                 array_push($this->teams, new Team($r["id"], false));
                 array_push($this->teams, new Team($r["id"], false));
             }
             }

+ 1 - 1
application/helper/APPLICATION_Helper.php

@@ -59,7 +59,7 @@
          *   BUILDING
          *   BUILDING
          * @param string|int $name Filename, with no path or extension. It can also
          * @param string|int $name Filename, with no path or extension. It can also
          * skip the padding. An id can be used.
          * skip the padding. An id can be used.
-         * @return Image URL if found. If not, the URL to an 'unknown' icon.
+         * @return string URL if found. If not, the URL to an 'unknown' icon.
          */
          */
         public static function img($type, $name){
         public static function img($type, $name){
             $pad = 1;
             $pad = 1;

+ 24 - 90
application/helper/HTML_Helper.php

@@ -19,7 +19,7 @@
     require_once(PATH::ENTITY . "K_Decoration.php");
     require_once(PATH::ENTITY . "K_Decoration.php");
     require_once(PATH::ENTITY . "Rune.php");
     require_once(PATH::ENTITY . "Rune.php");
     require_once(PATH::ENTITY . "Artifact.php");
     require_once(PATH::ENTITY . "Artifact.php");
-    require_once(PATH::ENTITY . "Rune_Craft.php");
+    require_once(PATH::ENTITY . "Enchantment.php");
     require_once(PATH::ENTITY . "Inventory.php");
     require_once(PATH::ENTITY . "Inventory.php");
 
 
     /**
     /**
@@ -266,7 +266,6 @@
             $html .= "<td class='grind'>\n";
             $html .= "<td class='grind'>\n";
             $html .= "</td>\n";
             $html .= "</td>\n";
             $html .= "</tr>\n";
             $html .= "</tr>\n";
-            $substats = array($rune->substat_1, $rune->substat_2, $rune->substat_3, $rune->substat_4);
             $substats_name = array($rune->substat_1_name, $rune->substat_2_name, $rune->substat_3_name, $rune->substat_4_name);
             $substats_name = array($rune->substat_1_name, $rune->substat_2_name, $rune->substat_3_name, $rune->substat_4_name);
             $substats_value = array($rune->substat_1_value, $rune->substat_2_value, $rune->substat_3_value, $rune->substat_4_value);
             $substats_value = array($rune->substat_1_value, $rune->substat_2_value, $rune->substat_3_value, $rune->substat_4_value);
             $substats_grind = array($rune->substat_1_grind, $rune->substat_2_grind, $rune->substat_3_grind, $rune->substat_4_grind);
             $substats_grind = array($rune->substat_1_grind, $rune->substat_2_grind, $rune->substat_3_grind, $rune->substat_4_grind);
@@ -484,73 +483,6 @@
             }
             }
             $html .= "</table>\n";
             $html .= "</table>\n";
             $html .= "</td>\n";
             $html .= "</td>\n";
-            // Details
-            /* TODO: Only quaity data, and for that the icon is enough
-            $html .= "<td class='details'>\n";
-            $html .= "<table class='table_details'>\n";
-            $html .= "<tr>\n";
-            $html .= "<td class='title'>\n";
-            $html .= "Quality:\n";
-            $html .= "</td>\n";
-            $html .= "<td class='value'>\n";
-            $html .= "<span class='quality quality_" . strtolower($artifact->quality_name) . "'>\n";
-            $html .= $artifact->quality_name . "\n";
-            $html .= "</span>\n";
-            $html .= "</td>\n";
-            $html .= "</tr>\n";
-            $html .= "<tr>\n";
-            $html .= "<td class='title'>\n";
-            $html .= "Original q.:\n";
-            $html .= "</td>\n";
-            $html .= "<td class='value'>\n";
-            $html .= "<span class='quality quality_" . strtolower($artifact->original_quality_name) . "'>\n";
-            $html .= $artifact->original_quality_name . "\n";
-            $html .= "</span>\n";
-            $html .= "</td>\n";
-            $html .= "</tr>\n";
-            $html .= "<tr>\n";
-            $html .= "<td class='title'>\n";
-            // TODO: No data on value yet
-            $html .= ""; //"Value:\n";
-            $html .= "</td>\n";
-            $html .= "<td class='value'>\n";
-            // TODO: No data on value yet
-            $html .= ""; //number_format($artifact->value, 0, ".", ",") . "\n";
-            $html .= "</td>\n";
-            $html .= "</tr>\n";
-            $html .= "<tr>\n";
-            $html .= "<td class='title'>\n";
-            // TODO: No data on efficiencies yet
-            $html .= ""; //"Efficiency:\n";
-            $html .= "</td>\n";
-            $html .= "<td class='value'>\n";
-            // TODO: No data on efficiencies yet
-            $html .= ""; //number_format($artifact->efficiency, 2, ".", ",") . "%\n";
-            $html .= "</td>\n";
-            $html .= "</tr>\n";
-            $html .= "<tr>\n";
-            $html .= "<td class='title'>\n";
-            // TODO: No data on efficiencies yet
-            $html .= ""; //"Max. eff.:\n";
-            $html .= "</td>\n";
-            $html .= "<td class='value'>\n";
-            // TODO: No data on efficiencies yet
-            $html .= ""; //number_format($artifact->max_efficiency, 2, ".", ",") . "%\n";
-            $html .= "</td>\n";
-            $html .= "</tr>\n";
-            $html .= "<tr>\n";
-            $html .= "<td class='title'>\n";
-            // TODO: No data on efficiencies yet
-            $html .= ""; //"Reached. eff.:\n";
-            $html .= "</td>\n";
-            $html .= "<td class='value'>\n";
-            // TODO: No data on efficiencies yet
-            $html .= ""; //number_format($artifact->efficiency * 100 / $artifact->max_efficiency, 2, ".", ",") . "%\n";
-            $html .= "</td>\n";
-            $html .= "</tr>\n";
-            $html .= "</table>\n";
-            */
-            $html .= "</td>\n";
             $html .= "</tr>\n";
             $html .= "</tr>\n";
             $html .= "</table>\n";
             $html .= "</table>\n";
             return $html;
             return $html;
@@ -559,16 +491,16 @@
         /**
         /**
          * Generates a grindstone or gem panel.
          * Generates a grindstone or gem panel.
          * 
          * 
-         * @param Rune_Craft craft Entity to get the info from.
+         * @param Enchantment Entity to get the info from.
          * @return string HTML content for a rune panel. Empty on error.
          * @return string HTML content for a rune panel. Empty on error.
          */
          */
-        public static function craft_panel($craft) {
-            if (!($craft instanceof Rune_Craft)){
+        public static function enchantment_panel($enchantment) {
+            if (!($enchantment instanceof Enchantment)){
                 return "";
                 return "";
             }
             }
             $html = "";
             $html = "";
-            if ($craft->gem == 1){
-                if ($craft->inmemorial == 1){
+            if ($enchantment->gem == 1){
+                if ($enchantment->inmemorial == 1){
                     $base = URL::IMG["GRIND"] . "gem_inmemorial.png";
                     $base = URL::IMG["GRIND"] . "gem_inmemorial.png";
                 }
                 }
                 else{
                 else{
@@ -576,37 +508,39 @@
                 }
                 }
             }
             }
             else{
             else{
-                if ($craft->inmemorial == 1){
+                if ($enchantment->inmemorial == 1){
                     $base = URL::IMG["GRIND"] . "grind_inmemorial.png";
                     $base = URL::IMG["GRIND"] . "grind_inmemorial.png";
                 }
                 }
                 else{
                 else{
                     $base = URL::IMG["GRIND"] . "grind.png";
                     $base = URL::IMG["GRIND"] . "grind.png";
                 }
                 }
             }
             }
-            if ($craft->inmemorial == 0 && isset($craft->rune)){
-                $icon = "<img class='craft_icon' src='" . $craft->rune->get_image() . "'/>\n";
+            if ($enchantment->inmemorial == 0 && isset($enchantment->rune)){
+                $icon = "<img class='enchantment_icon' src='" . $enchantment->rune->get_image() . "'/>\n";
             }
             }
             else{
             else{
                 $icon = "";
                 $icon = "";
             }
             }
-            if (in_array($craft->stat_name, array("CRR", "CRD", "RES", "ACC", "HP%", "ATK%", "DEF%"))){
-                $stat_name = str_replace("%", "", $craft->stat_name);
-                $stat_value = "+" . $craft->min . "~" . $craft->max . "%";
+            if (in_array($enchantment->stat_name, array("CRR", "CRD", "RES", "ACC", "HP%", "ATK%", "DEF%"))){
+                $stat_name = str_replace("%", "", $enchantment->stat_name);
+                $stat_value = "+" . $enchantment->min . "~" . $enchantment->max . "%";
             }
             }
             else{
             else{
-                $stat_name = $craft->stat_name;
-                $stat_value = "+" . $craft->min . "~" . $craft->max;
+                $stat_name = $enchantment->stat_name;
+                $stat_value = "+" . $enchantment->min . "~" . $enchantment->max;
             }
             }
-            $html .= "<div class='craft_panel craft_quality_" . strtolower($craft->quality_name) . " rune_ancient_" . $craft->ancient . "'>\n";
-            $html .= "<img class='craft_base' src='" . $base . "'/>\n";
+            $html .= "<div class='enchantment_panel enchantment_quality_" . strtolower($enchantment->quality_name) . " enchantment_ancient_" . $enchantment->ancient . "'>\n";
+            $html .= "<img class='enchantment_base' src='" . $base . "'/>\n";
             $html .= $icon;
             $html .= $icon;
-            $html .= "<span class='craft_stat'>\n";
-            $html .= "<span class='craft_stat_name'>" . $stat_name . "</span>\n";
-            $html .= "<span class='craft_stat_value'>" . $stat_value . "</span>\n";
-            $html .= "</span>\n";
-            $html .= "<span class='craft_amount'>\n";
-            $html .= "x" . $craft->amount . "\n";
+            $html .= "<span class='enchantment_stat'>\n";
+            $html .= "<span class='enchantment_stat_name'>" . $stat_name . "</span>\n";
+            $html .= "<span class='enchantment_stat_value'>" . $stat_value . "</span>\n";
             $html .= "</span>\n";
             $html .= "</span>\n";
+            if ($enchantment->amount > 0){
+                $html .= "<span class='enchantment_amount'>\n";
+                $html .= "x" . $enchantment->amount . "\n";
+                $html .= "</span>\n";
+            }
             $html .= "</div>\n";
             $html .= "</div>\n";
             return $html;
             return $html;
         }
         }

+ 0 - 1
application/page/Artifacts_Page.php

@@ -239,7 +239,6 @@
                     break;
                     break;
             }
             }
             $s = $s . " ORDER BY type, attribute, archetype, level DESC, original_quality DESC;";
             $s = $s . " ORDER BY type, attribute, archetype, level DESC, original_quality DESC;";
-            error_log($s);
             return $s;
             return $s;
         }
         }
     }
     }

+ 17 - 0
application/page/Catalog_Page.php

@@ -26,6 +26,11 @@
          */
          */
         public $units = [];
         public $units = [];
 
 
+        /**
+         * @var int[] IDs of the units marked in the catalog.
+         */
+        public $units_open = [];
+
         /**
         /**
          * @var mixed[] Default filter values.
          * @var mixed[] Default filter values.
          */
          */
@@ -45,6 +50,7 @@
          */
          */
         public function __construct(){
         public function __construct(){
             global $db;
             global $db;
+            global $UID;
             $this->view = PATH::VIEW . "catalog.php";
             $this->view = PATH::VIEW . "catalog.php";
             $this->parse_filters();
             $this->parse_filters();
             $s_mon = $this->build_query();
             $s_mon = $this->build_query();
@@ -52,6 +58,17 @@
             while ($r_mon = $q_mon->fetchArray(SQLITE3_ASSOC)){
             while ($r_mon = $q_mon->fetchArray(SQLITE3_ASSOC)){
                 array_push($this->units, new K_Unit($r_mon["id"], false));
                 array_push($this->units, new K_Unit($r_mon["id"], false));
             }
             }
+            $s_open = "
+              SELECT unit
+              FROM collection
+              WHERE
+                uid = $UID AND
+                open = 1
+            ";
+            $q_open = $db->query($s_open);
+            while ($r_open = $q_open->fetchArray(SQLITE3_ASSOC)){
+                array_push($this->units_open, $r_open["unit"]);
+            }
             $this->title = "Catalog - SWDB";
             $this->title = "Catalog - SWDB";
             $this->description = "Catalog of all monsters";
             $this->description = "Catalog of all monsters";
             $this->canonical = URL::BASE . "catalog/";
             $this->canonical = URL::BASE . "catalog/";

+ 6 - 8
application/page/Enchantments_Page.php

@@ -13,7 +13,7 @@
      */
      */
     require_once(PATH::PAGE . "Page.php");
     require_once(PATH::PAGE . "Page.php");
     require_once(PATH::ENTITY . "Custom_Filter.php");
     require_once(PATH::ENTITY . "Custom_Filter.php");
-    require_once(PATH::ENTITY . "Rune_Craft.php");
+    require_once(PATH::ENTITY . "Enchantment.php");
 
 
     /**
     /**
      * Enchantment list page model.
      * Enchantment list page model.
@@ -23,12 +23,12 @@
     class Enchantments_Page extends Page{
     class Enchantments_Page extends Page{
 
 
         /**
         /**
-         * @var \Rune_Craft[] Owned enchantment gems.
+         * @var \Enchantment[] Owned enchantment gems.
          */
          */
         public $gems = [];
         public $gems = [];
 
 
         /**
         /**
-         * @var \Rune_Craft[] Owned enchantment grindstones.
+         * @var \Enchantment[] Owned enchantment grindstones.
          */
          */
         public $grindstones = [];
         public $grindstones = [];
 
 
@@ -58,7 +58,7 @@
             }
             }
             $q = $db->query($s);
             $q = $db->query($s);
             while ($r = $q->fetchArray(SQLITE3_ASSOC)){
             while ($r = $q->fetchArray(SQLITE3_ASSOC)){
-                $enchantment = new Rune_Craft($r["id"]);
+                $enchantment = new Enchantment($r["id"]);
                 //if ($enchantment->gem == true){
                 //if ($enchantment->gem == true){
                 //   array_push($this->gems, $enchantment);
                 //   array_push($this->gems, $enchantment);
                 //}
                 //}
@@ -162,7 +162,7 @@
             $s = "
             $s = "
               SELECT
               SELECT
                 id
                 id
-              FROM rune_craft
+              FROM enchantment
               WHERE uid = '$UID' AND (
               WHERE uid = '$UID' AND (
                 $cond
                 $cond
               )
               )
@@ -182,7 +182,7 @@
             global $UID;
             global $UID;
             $s = "
             $s = "
               SELECT id
               SELECT id
-              FROM rune_craft
+              FROM enchantment
               WHERE
               WHERE
                 uid = '$UID' AND
                 uid = '$UID' AND
                 quality >= " . $this->filters["MIN_QUALITY"] . " AND
                 quality >= " . $this->filters["MIN_QUALITY"] . " AND
@@ -209,7 +209,6 @@
                     $s .= ") ";
                     $s .= ") ";
                 }
                 }
             }
             }
-            error_log( print_r($this->filters["TYPE"], TRUE) );
             if (count($this->filters["TYPE"]) == 1){
             if (count($this->filters["TYPE"]) == 1){
                 // Only one selectd, it's either gems or grindstones
                 // Only one selectd, it's either gems or grindstones
                 if (in_array("GEM", $this->filters["TYPE"])){
                 if (in_array("GEM", $this->filters["TYPE"])){
@@ -282,7 +281,6 @@
             }
             }
             $s = $s . " ORDER BY type, attribute, archetype, level DESC, original_quality DESC;";
             $s = $s . " ORDER BY type, attribute, archetype, level DESC, original_quality DESC;";
             */
             */
-            error_log($s);
             return $s;
             return $s;
         }
         }
     }
     }

+ 59 - 0
application/page/Error_Page.php

@@ -0,0 +1,59 @@
+<?php
+    /**
+     * Landing (login) page file.
+     *
+     * Provides a class with all the properties and methods to display the page.
+     *
+     * @category Page
+     */
+
+    /**
+     * Require dependent files if not present.
+     */
+    require_once(PATH::PAGE . "Page.php");
+
+    /**
+     * Error page model.
+     *
+     * @category Page
+     */
+    class Error_Page extends Page{
+
+        /**
+         * @var int Error code.
+         *
+         * HTTP status code.
+         */
+        public $code = 500;
+
+        /**
+         * Constructor.
+         *
+         * Retrieves the data and initializes the variables.
+         * 
+         * @param int code Error code. Optional.
+         */
+        public function __construct($code = null){
+            $this->view = PATH::VIEW . "error.php";
+            $this->title = "Error - SWDB";
+            
+            if (null == $code || intval($code) < 200 || intval($code) > 599){
+                $code = 500;
+            }
+            switch(intval($code)){
+                case 400:
+                    $this->description = "Invalid request";
+                    break;
+                case 404:
+                    $this->description = "Not found";
+                    break;
+                case 500:
+                    $this->description = "Server error";
+                    break;
+                default:
+                    $this->description = "Unknown error";
+            }
+            $this->code = intval($code);
+        }
+    }
+?>

+ 1 - 1
application/page/Fusion_Page.php

@@ -21,7 +21,7 @@
     class Fusion_Page extends Page{
     class Fusion_Page extends Page{
 
 
         /**
         /**
-         * @var \K_Fusion[] List of top-level fusions to display.
+         * @var \Fusion[] List of top-level fusions to display.
          */
          */
         public $fusion = [];
         public $fusion = [];
 
 

+ 9 - 3
application/page/Landing_Page.php

@@ -19,19 +19,25 @@
      */
      */
     class Landing_Page extends Page{
     class Landing_Page extends Page{
 
 
+        /**
+         * @var string Error message to show when login was unsuccesfull and
+         * the user is back in the login page
+         */
+        public $error_message = "";
+
         /**
         /**
          * Constructor.
          * Constructor.
          *
          *
          * Retrieves the data and initializes the variables.
          * Retrieves the data and initializes the variables.
-         *
-         ** @global resource Database connection.
          */
          */
         public function __construct(){
         public function __construct(){
-            global $db;
             $this->view = PATH::VIEW . "landing.php";
             $this->view = PATH::VIEW . "landing.php";
             $this->title = "Login - SWDB";
             $this->title = "Login - SWDB";
             $this->description = "Login to SWDB";
             $this->description = "Login to SWDB";
             $this->canonical = URL::BASE . "landing/";
             $this->canonical = URL::BASE . "landing/";
+            if (http_response_code() == 401){
+                $this->error_message = "Invalid credentials";
+            }
         }
         }
     }
     }
 ?>
 ?>

+ 0 - 2
application/page/Monster_Info_Page.php

@@ -41,10 +41,8 @@
          * Retrieves the data and initializes the variables.
          * Retrieves the data and initializes the variables.
          *
          *
          * @param int $id Monster id. Can be any of the awakening stages
          * @param int $id Monster id. Can be any of the awakening stages
-         * @global resource Database connection.
          */
          */
         public function __construct($id){
         public function __construct($id){
-            global $db;
             $this->view = PATH::VIEW . "monster_info.php";
             $this->view = PATH::VIEW . "monster_info.php";
             $title = "";
             $title = "";
             $monster = new K_Unit($id);
             $monster = new K_Unit($id);

+ 0 - 2
application/page/Monster_Page.php

@@ -32,10 +32,8 @@
          * Retrieves the data and initializes the variables.
          * Retrieves the data and initializes the variables.
          *
          *
          * @param string $id Selected unit id
          * @param string $id Selected unit id
-         * @global resource Database connection.
          */
          */
         public function __construct($id){
         public function __construct($id){
-            global $db;
             $this->view = PATH::VIEW . "monster.php";
             $this->view = PATH::VIEW . "monster.php";
             $this->unit = new Unit($id);
             $this->unit = new Unit($id);
             $this->title = $this->unit->unit->name ." - SWDB";
             $this->title = $this->unit->unit->name ." - SWDB";

+ 0 - 2
application/page/Monsters_Page.php

@@ -118,11 +118,9 @@
          *
          *
          * @return string The query to be executed.
          * @return string The query to be executed.
          * @global int Player ID.
          * @global int Player ID.
-         * @global resource Database connection.
          */
          */
         private function build_query(){
         private function build_query(){
             global $UID;
             global $UID;
-            global $db;
             $s = "
             $s = "
                 SELECT unit.id AS id
                 SELECT unit.id AS id
                 FROM
                 FROM

+ 1 - 1
application/page/Optimizer_Page.php

@@ -56,7 +56,7 @@
          * Builds the query to the rune table using the selected or default
          * Builds the query to the rune table using the selected or default
          * filters.
          * filters.
          *
          *
-         * @return The query to be executed.
+         * @return string The query to be executed.
          */
          */
         private function build_query(){
         private function build_query(){
             global $UID;
             global $UID;

+ 49 - 50
application/page/Report_Runecraft_Page.php → application/page/Report_Rune_Enchantment_Page.php

@@ -13,14 +13,14 @@
     require_once(PATH::PAGE . "Page.php");
     require_once(PATH::PAGE . "Page.php");
     require_once(PATH::ENTITY . "Unit.php");
     require_once(PATH::ENTITY . "Unit.php");
     require_once(PATH::ENTITY . "Rune.php");
     require_once(PATH::ENTITY . "Rune.php");
-    require_once(PATH::ENTITY . "Rune_Craft.php");
+    require_once(PATH::ENTITY . "Enchantment.php");
 
 
     /**
     /**
      * Upgradeable runes report page model.
      * Upgradeable runes report page model.
      *
      *
      * @category Page
      * @category Page
      */
      */
-    class Report_Runecraft_Page extends Page{
+    class Report_Rune_Enchantment_Page extends Page{
 
 
         /**
         /**
          * @var mixed[] List of available upgrades.
          * @var mixed[] List of available upgrades.
@@ -32,7 +32,7 @@
          *     upgrade = [
          *     upgrade = [
          *       [
          *       [
          *         rune (Rune),
          *         rune (Rune),
-         *         craft = [(Rune_Craft)]
+         *         enchant = [(Enchantment)]
          *       ]
          *       ]
          *     ]
          *     ]
          *   ]
          *   ]
@@ -100,7 +100,7 @@
          */
          */
         public function __construct(){
         public function __construct(){
             global $db;
             global $db;
-            $this->view = PATH::VIEW . "report_runecraft.php";
+            $this->view = PATH::VIEW . "report_rune_enchantment.php";
             $this->parse_filters();
             $this->parse_filters();
             $s = $this->build_query();
             $s = $this->build_query();
             $q = $db->query($s);
             $q = $db->query($s);
@@ -124,7 +124,7 @@
                     ];
                     ];
                     $rupgrade = [
                     $rupgrade = [
                         "rune" => new Rune($r["rune"]),
                         "rune" => new Rune($r["rune"]),
-                        "craft" => [],
+                        "enchantment" => [],
                     ];
                     ];
                 }
                 }
                 if ($r["rune"] != $prev_rune){
                 if ($r["rune"] != $prev_rune){
@@ -134,18 +134,18 @@
                     $prev_rune = $r["rune"];
                     $prev_rune = $r["rune"];
                     $rupgrade = [
                     $rupgrade = [
                         "rune" => new Rune($r["rune"]),
                         "rune" => new Rune($r["rune"]),
-                        "craft" => [],
+                        "enchantment" => [],
                     ];
                     ];
                 }
                 }
-                $rune_craft = new Rune_craft($r["craft"]);
-                array_push($rupgrade["craft"], $rune_craft);
+                $enchantment= new Enchantment($r["enchantment"]);
+                array_push($rupgrade["enchantment"], $enchantment);
             }
             }
             // Last entries
             // Last entries
             array_push($upgrade["upgrade"], $rupgrade);
             array_push($upgrade["upgrade"], $rupgrade);
             array_push($this->upgrades, $upgrade);
             array_push($this->upgrades, $upgrade);
-            $this->title = "Rune craft - SWDB";
-            $this->description = "Find runes that can be upgraded via crafting.";
-            $this->canonical = URL::BASE . "report/runecraft/";
+            $this->title = "Rune enchantment - SWDB";
+            $this->description = "Find runes that can be upgraded via enchantments.";
+            $this->canonical = URL::BASE . "report/rune_enchantment/";
         }
         }
 
 
         /**
         /**
@@ -154,7 +154,6 @@
          * min_stars (1-6) and in_storage (on/off).
          * min_stars (1-6) and in_storage (on/off).
          */
          */
         private function parse_filters(){
         private function parse_filters(){
-            //$this->filters = FILTER::RUNECRAFT;
             // Monster
             // Monster
             if (isset($_GET["monster_min_stars"]) && intval($_GET["monster_min_stars"]) > 0 && intval($_GET["monster_min_stars"]) < 7){
             if (isset($_GET["monster_min_stars"]) && intval($_GET["monster_min_stars"]) > 0 && intval($_GET["monster_min_stars"]) < 7){
                 $this->filters["MONSTER_MIN_STARS"] = $_GET["monster_min_stars"];
                 $this->filters["MONSTER_MIN_STARS"] = $_GET["monster_min_stars"];
@@ -256,20 +255,20 @@
                 SELECT
                 SELECT
                   unit.id AS unit,
                   unit.id AS unit,
                   rune.id AS rune,
                   rune.id AS rune,
-                  rune_craft.id AS craft
+                  enchantment.id AS enchantment
                 FROM
                 FROM
                   unit,
                   unit,
                   k_unit,
                   k_unit,
                   rune,
                   rune,
-                  rune_craft,
-                  k_rune_craft_type
+                  enchantment,
+                  k_enchantment_type
                 WHERE
                 WHERE
                   unit.uid = '$UID' AND
                   unit.uid = '$UID' AND
                   rune.uid = '$UID' AND
                   rune.uid = '$UID' AND
-                  rune_craft.uid = '$UID' AND
+                  enchantment.uid = '$UID' AND
                   unit.id = rune.assigned_to AND
                   unit.id = rune.assigned_to AND
                   unit.unit = k_unit.id AND
                   unit.unit = k_unit.id AND
-                  rune_craft.type = k_rune_craft_type.id AND
+                  enchantment.type = k_enchantment_type.id AND
                   unit.stars >= " . $this->filters["RUNE_MIN_STARS"] . " AND
                   unit.stars >= " . $this->filters["RUNE_MIN_STARS"] . " AND
                   unit.stars <= " . $this->filters["RUNE_MAX_STARS"] . " AND
                   unit.stars <= " . $this->filters["RUNE_MAX_STARS"] . " AND
                   -- RUNE FILTERS
                   -- RUNE FILTERS
@@ -286,10 +285,10 @@
                   rune.max_efficiency >= " . $this->filters["RUNE_MIN_MAX_EFFICIENCY"] . " AND
                   rune.max_efficiency >= " . $this->filters["RUNE_MIN_MAX_EFFICIENCY"] . " AND
                   rune.max_efficiency <= " . $this->filters["RUNE_MAX_MAX_EFFICIENCY"] . " AND
                   rune.max_efficiency <= " . $this->filters["RUNE_MAX_MAX_EFFICIENCY"] . " AND
                   (
                   (
-                    rune.type = rune_craft.rune OR 
-                    k_rune_craft_type.inmemorial = 1
+                    rune.type = enchantment.rune OR 
+                    k_enchantment_type.inmemorial = 1
                   ) AND
                   ) AND
-                  k_rune_craft_type.ancient = rune.ancient AND
+                  k_enchantment_type.ancient = rune.ancient AND
                 ";
                 ";
             if (strlen($this->filters["MONSTER_NAME"]) > 0){
             if (strlen($this->filters["MONSTER_NAME"]) > 0){
                 $s = $s . " upper(k_unit.name) LIKE upper('%" . $this->filters["MONSTER_NAME"] . "%') AND ";
                 $s = $s . " upper(k_unit.name) LIKE upper('%" . $this->filters["MONSTER_NAME"] . "%') AND ";
@@ -305,13 +304,13 @@
                 $s = $s . "-1) AND ";
                 $s = $s . "-1) AND ";
             }
             }
             $s .= "
             $s .= "
-                rune_craft.stat <> rune.main_stat AND
-                rune_craft.stat <> rune.innate_stat AND
+                enchantment.stat <> rune.main_stat AND
+                enchantment.stat <> rune.innate_stat AND
                   (
                   (
-                    k_rune_craft_type.gem = 1 AND
+                    k_enchantment_type.gem = 1 AND
                     (
                     (
                       -- GEM FILTERS
                       -- GEM FILTERS
-                      rune_craft.quality >= " . $this->filters["GEM_MIN_QUALITY"] . " AND
+                      enchantment.quality >= " . $this->filters["GEM_MIN_QUALITY"] . " AND
             ";
             ";
             if (count($this->filters["GEM_STAT_FROM"]) > 0){
             if (count($this->filters["GEM_STAT_FROM"]) > 0){
                 $in = "(";
                 $in = "(";
@@ -327,19 +326,19 @@
                     $in = $in . "$t, ";
                     $in = $in . "$t, ";
                 }
                 }
                 $in = $in . "-1)";
                 $in = $in . "-1)";
-                $s .= " rune_craft.stat IN $in AND ";
+                $s .= " enchantment.stat IN $in AND ";
             }
             }
             $s .= "
             $s .= "
                       (
                       (
-                        rune_craft.stat <> rune.substat_1 AND
-                        rune_craft.stat <> rune.substat_2 AND
-                        rune_craft.stat <> rune.substat_3 AND
-                        rune_craft.stat <> rune.substat_4
+                        enchantment.stat <> rune.substat_1 AND
+                        enchantment.stat <> rune.substat_2 AND
+                        enchantment.stat <> rune.substat_3 AND
+                        enchantment.stat <> rune.substat_4
                       )
                       )
                     )
                     )
                   ) |
                   ) |
                   (
                   (
-                    k_rune_craft_type.gem = 0 AND
+                    k_enchantment_type.gem = 0 AND
                     (
                     (
                       -- GRINDSTONE FILTERS
                       -- GRINDSTONE FILTERS
             ";
             ";
@@ -349,34 +348,34 @@
                     $in = $in . "$t, ";
                     $in = $in . "$t, ";
                 }
                 }
                 $in = $in . "-1)";
                 $in = $in . "-1)";
-                $s .= " rune_craft.stat IN $in AND ";
+                $s .= " enchantment.stat IN $in AND ";
             }
             }
             $s .= "
             $s .= "
-                      rune_craft.quality >= " . $this->filters["GRIND_MIN_QUALITY"] . " AND
+                      enchantment.quality >= " . $this->filters["GRIND_MIN_QUALITY"] . " AND
                       (
                       (
                         (
                         (
-                          rune_craft.stat = rune.substat_1 AND
-                          rune_craft.stat <> rune.substat_2 AND
-                          rune_craft.stat <> rune.substat_3 AND
-                          rune_craft.stat <> rune.substat_4
+                          enchantment.stat = rune.substat_1 AND
+                          enchantment.stat <> rune.substat_2 AND
+                          enchantment.stat <> rune.substat_3 AND
+                          enchantment.stat <> rune.substat_4
                         ) OR
                         ) OR
                         (
                         (
-                          rune_craft.stat <> rune.substat_1 AND
-                          rune_craft.stat = rune.substat_2 AND
-                          rune_craft.stat <> rune.substat_3 AND
-                          rune_craft.stat <> rune.substat_4
+                          enchantment.stat <> rune.substat_1 AND
+                          enchantment.stat = rune.substat_2 AND
+                          enchantment.stat <> rune.substat_3 AND
+                          enchantment.stat <> rune.substat_4
                         ) OR
                         ) OR
                         (
                         (
-                          rune_craft.stat <> rune.substat_1 AND
-                          rune_craft.stat <> rune.substat_2 AND
-                          rune_craft.stat = rune.substat_3 AND
-                          rune_craft.stat <> rune.substat_4
+                          enchantment.stat <> rune.substat_1 AND
+                          enchantment.stat <> rune.substat_2 AND
+                          enchantment.stat = rune.substat_3 AND
+                          enchantment.stat <> rune.substat_4
                         ) OR
                         ) OR
                         (
                         (
-                          rune_craft.stat <> rune.substat_1 AND
-                          rune_craft.stat <> rune.substat_2 AND
-                          rune_craft.stat <> rune.substat_3 AND
-                          rune_craft.stat = rune.substat_4
+                          enchantment.stat <> rune.substat_1 AND
+                          enchantment.stat <> rune.substat_2 AND
+                          enchantment.stat <> rune.substat_3 AND
+                          enchantment.stat = rune.substat_4
                         )
                         )
                       )
                       )
                     )
                     )
@@ -392,8 +391,8 @@
                   rune.level DESC,
                   rune.level DESC,
                   rune.id, 
                   rune.id, 
                   rune.slot, 
                   rune.slot, 
-                  rune_craft.quality DESC,
-                  rune_craft.stat DESC;
+                  enchantment.quality DESC,
+                  enchantment.stat DESC;
                 ";
                 ";
             return $s;
             return $s;
         }
         }

+ 0 - 1
application/page/Report_Skillup_Page.php

@@ -273,7 +273,6 @@
                 CAST(lvl AS FLOAT) / CAST(max_lvl AS FLOAT),
                 CAST(lvl AS FLOAT) / CAST(max_lvl AS FLOAT),
                 max_lvl - lvl DESC
                 max_lvl - lvl DESC
             ";
             ";
-            error_log($s);
             return $s;
             return $s;
         }
         }
     }
     }

+ 0 - 7
application/page/Stats_Page.php

@@ -90,7 +90,6 @@
         public function __construct(){
         public function __construct(){
             global $UID;
             global $UID;
             global $db;
             global $db;
-            $best_run = null;
             $this->view = PATH::VIEW . "stats.php";
             $this->view = PATH::VIEW . "stats.php";
             $this->title = "Stats - SWDB";
             $this->title = "Stats - SWDB";
             $this->description = "Player statistics";
             $this->description = "Player statistics";
@@ -104,12 +103,6 @@
                 return;
                 return;
             }
             }
 
 
-            // TODO DEBUG Force NB10
-            /*$this->filters["AREA"] = 6001;
-            $this->filters["AREA_TYPE"] = 2;
-            $this->filters["STAGE"] = 10;*/
-            // TODO END DEBUG
-
             // Build query modifier:
             // Build query modifier:
             $query_where = "
             $query_where = "
               run.uid = '$UID' AND
               run.uid = '$UID' AND

+ 6 - 6
application/page/Teams_Page.php

@@ -49,12 +49,13 @@
             while ($r = $q->fetchArray(SQLITE3_ASSOC)){
             while ($r = $q->fetchArray(SQLITE3_ASSOC)){
                 array_push($this->teams, new Team($r["id"]));
                 array_push($this->teams, new Team($r["id"]));
             }
             }
-            $s = "
+            $statement = $db->prepare("
               SELECT id
               SELECT id
               FROM unit
               FROM unit
-              WHERE unit.uid = '$UID';
-            ";
-            $q = $db->query($s);
+              WHERE unit.uid = :uid;
+            ");
+            $statement->bindValue(':uid', $UID, SQLITE3_INTEGER);
+            $q = $statement->execute();
             while ($r = $q->fetchArray(SQLITE3_ASSOC)){
             while ($r = $q->fetchArray(SQLITE3_ASSOC)){
                 array_push($this->units, new Unit($r["id"], false));
                 array_push($this->units, new Unit($r["id"], false));
             }
             }
@@ -82,10 +83,9 @@
          * Builds the query to the rune table using the selected or default
          * Builds the query to the rune table using the selected or default
          * filters.
          * filters.
          *
          *
-         * @return The query to be executed.
+         * @return string The query to be executed.
          */
          */
         private function build_query(){
         private function build_query(){
-            global $ELEMENT;
             global $UID;
             global $UID;
             $s = "
             $s = "
               SELECT id
               SELECT id

BIN
application/sw.sqlite


+ 3 - 2
application/view/artifacts.php

@@ -5,7 +5,8 @@
      * Contains the view layout and ome code to present the data.
      * Contains the view layout and ome code to present the data.
      *
      *
      * @category View
      * @category View
-     * @property_read Artifacts_Page $page The page model.
+     * @var Artifacts_Page $page The page model.
+     * @var int $UID User id.
      */
      */
 ?>
 ?>
 <!DOCTYPE html>
 <!DOCTYPE html>
@@ -72,8 +73,8 @@
 ?>
 ?>
                             </select>
                             </select>
                         </td>
                         </td>
-                    <tr>
                     </tr>
                     </tr>
+                    <tr>
                         <td class='label'>
                         <td class='label'>
                             Type:
                             Type:
                         </td>
                         </td>

+ 9 - 3
application/view/catalog.php

@@ -5,8 +5,8 @@
      * Contains the view layout and some code to present the data
      * Contains the view layout and some code to present the data
      *
      *
      * @category View
      * @category View
-     * @property_read Catalog_Page $page The page model
-     * @property_read int $UID Player ID
+     * @var Catalog_Page $page The page model
+     * @var int $UID Player ID
      */
      */
 ?>
 ?>
 <!DOCTYPE html>
 <!DOCTYPE html>
@@ -112,8 +112,14 @@
                             }
                             }
                             $element = $mon->element;
                             $element = $mon->element;
                         }
                         }
+                        if (!in_array($mon->id, $page->units_open)){
+                            $closed = "closed";
+                        }
+                        else{
+                            $closed = "";
+                        }
 ?>
 ?>
-                        <div class='monster'>
+                        <div class='monster <?=$closed?>'>
                             <a href='/<?=$UID?>/catalog/<?=$mon->id?>'>
                             <a href='/<?=$UID?>/catalog/<?=$mon->id?>'>
                                 <div class='monster_panel'>
                                 <div class='monster_panel'>
                                     <?=HTML::unit_panel($mon)?>
                                     <?=HTML::unit_panel($mon)?>

+ 3 - 4
application/view/enchantments.php

@@ -5,7 +5,8 @@
      * Contains the view layout and ome code to present the data.
      * Contains the view layout and ome code to present the data.
      *
      *
      * @category View
      * @category View
-     * @property_read Artifacts_Page $page The page model.
+     * @var Artifacts_Page $page The page model.
+     * @var int $UID User id.
      */
      */
 ?>
 ?>
 <!DOCTYPE html>
 <!DOCTYPE html>
@@ -220,9 +221,7 @@
                 <div id='filter_apply'>
                 <div id='filter_apply'>
                     <input type='submit' value='Apply'/>
                     <input type='submit' value='Apply'/>
                 </div>
                 </div>
-                </div>
             </form>
             </form>
-
         </aside> <!-- #filters -->
         </aside> <!-- #filters -->
         <main>
         <main>
             <section class='content' id='enchantments'>
             <section class='content' id='enchantments'>
@@ -273,7 +272,7 @@
 <?php
 <?php
                         }
                         }
 ?>
 ?>
-                        <?=HTML::craft_panel($grindstone)?>
+                        <?=HTML::enchantment_panel($grindstone)?>
 <?php
 <?php
                     }
                     }
 ?>
 ?>

+ 45 - 0
application/view/error.php

@@ -0,0 +1,45 @@
+<?php
+    /**
+     * Error view.
+     *
+     * Contains the view layout and some code to present the data.
+     *
+     * @category View
+     * @var Landing_Page $page The page model.
+     */
+?>
+<!DOCTYPE html>
+<html lang='en'>
+    <head>
+        <meta content='text/html; charset=utf-8' http-equiv='content-type'/>
+        <meta name='viewport' content='width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1'/>
+        <title><?=$page->title?></title>
+        <link rel='shortcut icon' href='<?=$page->favicon?>'/>
+        <!-- CSS files -->
+        <link rel='stylesheet' type='text/css' href='<?=URL::CSS?>ui.css'/>
+        <link rel='stylesheet' type='text/css' href='<?=URL::CSS?>error.css'/>
+        <!-- Meta tags -->
+        <meta name='robots' content='noindex nofollow'/>
+    </head>
+    <body>
+<?php
+        include __DIR__ . "/inc/header.php";
+?>
+        <aside>
+        </aside>
+        <main>
+            <section class='list'>
+                <h2>
+                    Error
+                </h2>
+                <article>
+                    Error <?=$page->code?>: <?=$page->description?>
+                </article>
+            </section> <!-- #catalog -->
+        </main>
+
+<?php
+        include __DIR__ . "/inc/footer.php";
+?>
+    </body>
+</html>

+ 2 - 2
application/view/fusion.php

@@ -5,8 +5,8 @@
      * Contains the view layout and some code to present the data.
      * Contains the view layout and some code to present the data.
      *
      *
      * @category View
      * @category View
-     * @property_read Fusion_Page $page The page model.
-     * @property_read int $UID Player ID.
+     * @var Fusion_Page $page The page model.
+     * @var int $UID Player ID.
      */
      */
 ?>
 ?>
 <!DOCTYPE html>
 <!DOCTYPE html>

+ 1 - 1
application/view/guild.php

@@ -5,7 +5,7 @@
      * Contains the view layout and some code to present the data.
      * Contains the view layout and some code to present the data.
      *
      *
      * @category View
      * @category View
-     * @property_read Guild_Page $page The page model.
+     * @var Guild_Page $page The page model.
      */
      */
 ?>
 ?>
 <!DOCTYPE html>
 <!DOCTYPE html>

+ 1 - 1
application/view/help.php

@@ -5,7 +5,7 @@
      * Contains the view layout and some code to present the data.
      * Contains the view layout and some code to present the data.
      *
      *
      * @category View
      * @category View
-     * @property_read Page $page The page model.
+     * @var Page $page The page model.
      */
      */
     // TODO: Implement
     // TODO: Implement
 ?>
 ?>

+ 3 - 2
application/view/home.php

@@ -5,7 +5,9 @@
      * Contains the view layout and some code to present the data.
      * Contains the view layout and some code to present the data.
      *
      *
      * @category View
      * @category View
-     * @property_read Home_Page $page The page model.
+     * @var Home_Page $page The page model.
+     * @var int $UID User id.
+     * @var int[] $EFFECT_AREA Required constants.
      */
      */
 ?>
 ?>
 <!DOCTYPE html>
 <!DOCTYPE html>
@@ -484,7 +486,6 @@
 <?php
 <?php
                                                     }
                                                     }
                                                     if ($party instanceof K_Unit){
                                                     if ($party instanceof K_Unit){
-                                                        $enable_save = false;
                                                         $disabled = "disabled";
                                                         $disabled = "disabled";
                                                     }
                                                     }
                                                     else{
                                                     else{

+ 2 - 0
application/view/inc/header.php

@@ -6,6 +6,8 @@
      *
      *
      * @category View
      * @category View
      */
      */
+
+    /** @var int $UID User id. */
 ?>
 ?>
 <header>
 <header>
     <div id='logo'>
     <div id='logo'>

+ 12 - 1
application/view/landing.php

@@ -5,7 +5,7 @@
      * Contains the view layout and some code to present the data.
      * Contains the view layout and some code to present the data.
      *
      *
      * @category View
      * @category View
-     * @property_read Landing_Page $page The page model.
+     * @var Landing_Page $page The page model.
      */
      */
 ?>
 ?>
 <!DOCTYPE html>
 <!DOCTYPE html>
@@ -77,6 +77,17 @@
                                     <input type='submit' value='Go'/>
                                     <input type='submit' value='Go'/>
                                 </td>
                                 </td>
                             </tr>
                             </tr>
+<?php
+                            if ($page->error_message != ""){
+?>
+                                <tr>
+                                    <td class='error' colspan='2'>
+                                        <?=$page->error_message?>
+                                    </td>
+                                </tr>
+<?php
+                            }
+?>
                         </table>
                         </table>
                     </form>
                     </form>
                 </article>
                 </article>

+ 3 - 3
application/view/monster.php

@@ -5,8 +5,8 @@
      * Contains the view layout and some code to present the data.
      * Contains the view layout and some code to present the data.
      *
      *
      * @category View
      * @category View
-     * @property_read Monster_Page $page The page model.
-     * @property_read int $UID Player ID.
+     * @var Monster_Page $page The page model.
+     * @var int $UID Player ID.
      */
      */
 ?>
 ?>
 <!DOCTYPE html>
 <!DOCTYPE html>
@@ -66,7 +66,7 @@
 ?>
 ?>
                 <div id='monster_details'>
                 <div id='monster_details'>
                     <div id='exp'>
                     <div id='exp'>
-                        <span id='exp_bar' style='width:<?=$exp_pct?>%'></span>
+                        <span id='exp_bar' style='width:<?=$exp_pct?>%'>
                         </span>
                         </span>
                         <span id='exp_text'>
                         <span id='exp_text'>
                             <?=$exp_txt?>
                             <?=$exp_txt?>

+ 3 - 2
application/view/monster_info.php

@@ -5,8 +5,9 @@
      * Contains the view layout and ome code to present the data.
      * Contains the view layout and ome code to present the data.
      *
      *
      * @category View
      * @category View
-     * @property_read Monster_Info_Page The page model.
+     * @var Monster_Info_Page $page The page model.
      */
      */
+
 ?>
 ?>
 <!DOCTYPE html>
 <!DOCTYPE html>
 <html lang='en'>
 <html lang='en'>
@@ -55,7 +56,7 @@
 ?>
 ?>
                     <a href='#section_<?=$i?>'>
                     <a href='#section_<?=$i?>'>
                         <div class='monster_panel'>
                         <div class='monster_panel'>
-                            <?=HTML::unit_panel($page->monster[$i])?>
+                            <?=HTML::unit_panel($monster)?>
                         </div>
                         </div>
                     </a>
                     </a>
 <?php
 <?php

+ 3 - 3
application/view/monsters.php

@@ -5,8 +5,8 @@
      * Contains the view layout and ome code to present the data.
      * Contains the view layout and ome code to present the data.
      *
      *
      * @category View
      * @category View
-     * @property_read Monsters_Page $page The page model.
-     * @property_read int $UID Player ID.
+     * @var Monsters_Page $page The page model.
+     * @var int $UID Player ID.
      */
      */
 ?>
 ?>
 <!DOCTYPE html>
 <!DOCTYPE html>
@@ -109,7 +109,7 @@
                             }
                             }
 ?>
 ?>
                             <input type='checkbox' name='without_runes' id='filter_without_runes' <?=$checked?>/>
                             <input type='checkbox' name='without_runes' id='filter_without_runes' <?=$checked?>/>
-                            <label for='filter_without_runes'>Monsters without runes<label>
+                            <label for='filter_without_runes'>Monsters without runes</label>
                         </td>
                         </td>
                     </tr>
                     </tr>
                     <tr>
                     <tr>

+ 2 - 2
application/view/optimizer.php

@@ -5,8 +5,8 @@
      * Contains the view layout and ome code to present the data.
      * Contains the view layout and ome code to present the data.
      *
      *
      * @category View
      * @category View
-     * @property_read Teams_Page $page The page model.
-     * @property_read int $page Player ID.
+     * @var Teams_Page $page The page model.
+     * @var int $UID User id.
      */
      */
 ?>
 ?>
 <!DOCTYPE html>
 <!DOCTYPE html>

+ 3 - 11
application/view/optimizer_unit.php

@@ -5,8 +5,8 @@
      * Contains the view layout and some code to present the data.
      * Contains the view layout and some code to present the data.
      *
      *
      * @category View
      * @category View
-     * @property_read Monster_Page $page The page model.
-     * @property_read int $UID Player ID.
+     * @var Monster_Page $page The page model.
+     * @var int $UID Player ID.
      */
      */
 ?>
 ?>
 <!DOCTYPE html>
 <!DOCTYPE html>
@@ -1125,14 +1125,6 @@
                     <?=HTML::unit_panel($page->unit)?>
                     <?=HTML::unit_panel($page->unit)?>
                 </div>
                 </div>
 <?php
 <?php
-                if ($page->unit->experience_level != 0){
-                    $exp_pct = ceil($page->unit->exp_gained * 100 / $page->unit->experience_level);
-                    $exp_txt = $page->unit->exp_gained . " / " . $page->unit->experience_level;
-                }
-                else{
-                    $exp_pct = 100;
-                    $exp_txt = "MAX";
-                }
                 $now = time();
                 $now = time();
                 //$datediff = $now - $page->unit->create_time->getTimestamp();
                 //$datediff = $now - $page->unit->create_time->getTimestamp();
                 $datediff = $now - strtotime($page->unit->create_time->format('Y-m-d H:i:s'));
                 $datediff = $now - strtotime($page->unit->create_time->format('Y-m-d H:i:s'));
@@ -1497,7 +1489,7 @@
                             </td>
                             </td>
                             <td class='value'>
                             <td class='value'>
                                 <input id='min_hp' type='range' value='<?=$page->unit->total_hp?>' min='<?=$page->unit->hp?>' max='50000' oninput='updateMinValue("hp", this);'>
                                 <input id='min_hp' type='range' value='<?=$page->unit->total_hp?>' min='<?=$page->unit->hp?>' max='50000' oninput='updateMinValue("hp", this);'>
-                                <input type='number' id='lbl_min_hp' value='<?=$page->unit->total_hp?>' min='<?=$page->unit->hp?>' max='50000' onChange='updateMinValue("hp", this);'></input></input><span class='slider_percent'> </span>
+                                <input type='number' id='lbl_min_hp' value='<?=$page->unit->total_hp?>' min='<?=$page->unit->hp?>' max='50000' onChange='updateMinValue("hp", this);'></input><span class='slider_percent'> </span>
                                 <a title='Remove filter' class='filter_control a_button' onclick='removeFilter("hp");'>
                                 <a title='Remove filter' class='filter_control a_button' onclick='removeFilter("hp");'>
                                     <img alt='Remove filter' src='<?=URL::IMG["ICON"]?>nok.png'/>
                                     <img alt='Remove filter' src='<?=URL::IMG["ICON"]?>nok.png'/>
                                 </a>
                                 </a>

+ 3 - 3
application/view/profile.php

@@ -5,8 +5,8 @@
      * Contains the view layout and ome code to present the data.
      * Contains the view layout and ome code to present the data.
      *
      *
      * @category View
      * @category View
-     * @property_read Profile_Page $page The page model.
-     * @property_read int $UID Player ID.
+     * @var Profile_Page $page The page model.
+     * @var int $UID Player ID.
      */
      */
 ?>
 ?>
 <!DOCTYPE html>
 <!DOCTYPE html>
@@ -277,7 +277,7 @@
                                 Visibility:
                                 Visibility:
                             </td>
                             </td>
                             <td id='visibility'>
                             <td id='visibility'>
-                                <input type='checkbox' name='defeat' id='filter_defeat' <?=$checked?> onChange='toggleVisibility(this.value);'/>
+                                <input type='checkbox' name='visible' onChange='toggleVisibility(this.value);'/>
                                 <label for='filter_defeat'>Public profile</label>
                                 <label for='filter_defeat'>Public profile</label>
                                 <div class='help_tooltip'>
                                 <div class='help_tooltip'>
                                     <p>
                                     <p>

+ 3 - 2
application/view/report.php

@@ -5,7 +5,8 @@
      * Contains the view layout and ome code to present the data.
      * Contains the view layout and ome code to present the data.
      *
      *
      * @category View
      * @category View
-     * @property_read Report_Page $page The page model.
+     * @var Report_Page $page The page model.
+     * @var int $UID User id.
      */
      */
 ?>
 ?>
 <!DOCTYPE html>
 <!DOCTYPE html>
@@ -75,7 +76,7 @@
                         Shows monsters with runes that can be grinded or enchanted.
                         Shows monsters with runes that can be grinded or enchanted.
                         It list the grindstones and gems that are available for each rune.
                         It list the grindstones and gems that are available for each rune.
                     </p>
                     </p>
-                    <a class='a_button' href='/<?=$UID?>/report/runecraft/'>
+                    <a class='a_button' href='/<?=$UID?>/report/rune_enchantment/'>
                         Go
                         Go
                     </a>
                     </a>
                 </article>
                 </article>

+ 10 - 9
application/view/report_runecraft.php → application/view/report_rune_enchantment.php

@@ -1,11 +1,12 @@
 <?php
 <?php
     /**
     /**
-     * Rune craft report view.
+     * Rune Enchantment report view.
      *
      *
      * Contains the view layout and ome code to present the data.
      * Contains the view layout and ome code to present the data.
      *
      *
      * @category View
      * @category View
-     * @property_read Report_Runecraft_Page $page The page model.
+     * @var Report_Rune_Enchantment_Page $page The page model.
+     * @var int $UID User id.
      */
      */
 ?>
 ?>
 <!DOCTYPE html>
 <!DOCTYPE html>
@@ -17,7 +18,7 @@
         <link rel='shortcut icon' href='<?=$page->favicon?>'/>
         <link rel='shortcut icon' href='<?=$page->favicon?>'/>
         <!-- CSS files -->
         <!-- CSS files -->
         <link rel='stylesheet' type='text/css' href='<?=URL::CSS?>ui.css'/>
         <link rel='stylesheet' type='text/css' href='<?=URL::CSS?>ui.css'/>
-        <link rel='stylesheet' type='text/css' href='<?=URL::CSS?>report_runecraft.css'/>
+        <link rel='stylesheet' type='text/css' href='<?=URL::CSS?>report_rune_enchantment.css'/>
         <!-- Meta tags -->
         <!-- Meta tags -->
         <link rel='canonical' href='<?=$page->canonical?>'/>
         <link rel='canonical' href='<?=$page->canonical?>'/>
         <link rel='author' href='<?=$page->author?>'/>
         <link rel='author' href='<?=$page->author?>'/>
@@ -102,7 +103,7 @@
             <h2>
             <h2>
                 Report filters
                 Report filters
             </h2>
             </h2>
-            <form action='/<?=$UID?>/report/runecraft/' method='get' id='filter_runecraft' class='filter'>
+            <form action='/<?=$UID?>/report/runeenchantment/' method='get' id='filter_runeenchantment' class='filter'>
                 <table>
                 <table>
                     <tr>
                     <tr>
                         <td colspan='2' class='header'>
                         <td colspan='2' class='header'>
@@ -444,7 +445,7 @@
                                     }
                                     }
 ?>
 ?>
                                 </select>
                                 </select>
-                            </td>
+                            </div>
                         </td>
                         </td>
                     </tr>
                     </tr>
                 </table>
                 </table>
@@ -455,7 +456,7 @@
             <section id='results' class='content'>
             <section id='results' class='content'>
                 <h2>
                 <h2>
                     <span>
                     <span>
-                        <?=$upgrade["unit"]->title?>
+                        Available enchantments
                     </span>
                     </span>
                 </h2>
                 </h2>
                 <table id='results'>
                 <table id='results'>
@@ -464,7 +465,7 @@
     ?>
     ?>
                         <tr>
                         <tr>
                             <td class='header' colspan='2'>
                             <td class='header' colspan='2'>
-                                <a href='/<?=$UID?>/monsters/<?=$unit->id?>/' target='_blank'>
+                                <a href='/<?=$UID?>/monsters/<?=$upgrade["unit"]->id?>/' target='_blank'>
                                     <div class='monster_panel'>
                                     <div class='monster_panel'>
                                         <?=HTML::unit_panel($upgrade["unit"])?>
                                         <?=HTML::unit_panel($upgrade["unit"])?>
                                     </div>
                                     </div>
@@ -483,9 +484,9 @@
                                 </td>
                                 </td>
                                 <td class='upgrades'>
                                 <td class='upgrades'>
 <?php
 <?php
-                                    foreach ($rupgrade["craft"] as $craft){
+                                    foreach ($rupgrade["enchantment"] as $enchantment){
     ?>
     ?>
-                                        <?=HTML::craft_panel($craft)?>
+                                        <?=HTML::enchantment_panel($enchantment)?>
 <?php
 <?php
                                     }
                                     }
     ?>
     ?>

+ 3 - 3
application/view/report_skillup.php

@@ -5,7 +5,8 @@
      * Contains the view layout and ome code to present the data.
      * Contains the view layout and ome code to present the data.
      *
      *
      * @category View
      * @category View
-     * @property_read Report_Skillup_Page $page The page model.
+     * @var Report_Skillup_Page $page The page model.
+     * @var int $UID User id.
      */
      */
 ?>
 ?>
 <!DOCTYPE html>
 <!DOCTYPE html>
@@ -119,7 +120,6 @@
                                         Include monsters that have family members with less stars than seleced in the stars filters.
                                         Include monsters that have family members with less stars than seleced in the stars filters.
                                     </p>
                                     </p>
                                 </div>
                                 </div>
-                                </span>
                             </td>
                             </td>
                         </tr>
                         </tr>
                         <tr>
                         <tr>
@@ -216,7 +216,7 @@
                             case 11:
                             case 11:
                             case 12:
                             case 12:
                             case 13:
                             case 13:
-                                $index_title = $index . "<span class='superindex'>th</span> - " . $unit_title;
+                                $index_title = $index . "<span class='superindex'>th</span> - " . $unit->title;
                                 break;
                                 break;
                         }
                         }
 ?>
 ?>

+ 3 - 1
application/view/runes.php

@@ -5,7 +5,8 @@
      * Contains the view layout and ome code to present the data.
      * Contains the view layout and ome code to present the data.
      *
      *
      * @category View
      * @category View
-     * @property_read Runes_Page $page The page model.
+     * @var Runes_Page $page The page model.
+     * @var int $UID User id.
      */
      */
 ?>
 ?>
 <!DOCTYPE html>
 <!DOCTYPE html>
@@ -196,6 +197,7 @@
                             <input type='number' name='max_efficiency' id='filter_efficiency_max' min='0' max='100' value='<?=$page->filters["MAX_EFFICIENCY"]?>'/>%
                             <input type='number' name='max_efficiency' id='filter_efficiency_max' min='0' max='100' value='<?=$page->filters["MAX_EFFICIENCY"]?>'/>%
                         </td>
                         </td>
                     </tr>
                     </tr>
+                    <tr>
                         <td class='label'>
                         <td class='label'>
                             Max. eff.:
                             Max. eff.:
                         </td>
                         </td>

Некоторые файлы не были показаны из-за большого количества измененных файлов