Bläddra i källkod

Rune craft items info extracted. Crafting report added.

Iñigo Valentin 7 år sedan
förälder
incheckning
f54b5e1352

+ 5 - 0
application/Controller.php

@@ -89,6 +89,11 @@
                     require_once($path["page"] . "Report_Runeupgrade_Page.php");
                         $page = new Report_Runeupgrade_Page($db, $pars[1]);
                     }
+                    elseif (strtoupper($pars[1]) == "RUNECRAFT"){
+                    require_once($path["page"] . "Report_Runecraft_Page.php");
+                        $page = new Report_Runecraft_Page($db, $pars[1]);
+                    }
+
                 }
             }
             // Load the view, or set an error code.

+ 1 - 0
application/entity/K_Rune_Set.php

@@ -49,6 +49,7 @@
               "  description " .
               "FROM k_rune_set " .
               "WHERE id = $id;";
+error_log("RUNESET QUERY: " . $s);
             $q = $this->db->query($s);
             $r = $q->fetchArray(SQLITE3_ASSOC);
             if ($r){

+ 205 - 0
application/entity/Rune_Craft.php

@@ -0,0 +1,205 @@
+<?php
+
+    require_once($path["entity"] . "Entity.php");
+    require_once($path["entity"] . "K_Rune_Set.php");
+
+    /**
+     * Owned rune craft item.
+     *
+     * Represents an object from the table 'rune_craft'.
+     */
+    class Rune_Craft extends Entity{
+
+        /**
+         * Owner identifier.
+         */
+        public $uid;
+
+        /**
+         * Item identifier.
+         */
+        public $id;
+
+        /**
+         * Item quality.
+         */
+        public $quality;
+
+        /**
+         * Item quality name.
+         */
+        public $quality_name;
+
+        /**
+         * {@see K_Rune_Set} the item modifies.
+         */
+        public $rune;
+
+        /**
+         * Stat the item modifies.
+         */
+        public $stat;
+
+        /**
+         * Stat name.
+         */
+        public $stat_name;
+
+        /**
+         * Indicates if the Item is a gem.
+         */
+        public $gem;
+
+        /**
+         * Indicates if the Item is ancient.
+         */
+        public $ancient;
+
+        /**
+         * Indicates if the Item is inmemorial.
+         */
+        public $inmemorial;
+
+        /**
+         * Item name.
+         */
+        public $name;
+
+        /**
+         * Minimum value of the stat.
+         */
+        public $min;
+
+        /**
+         * Maximum value of the stat.
+         */
+        public $max;
+
+        /**
+         * Sell value.
+         */
+        public $value;
+
+        /**
+         * Constructor.
+         *
+         * Searches the database and retrieves the information about the
+         * rune, populating it and it's items.
+         *
+         * @param SQLite3 $db Connection to the database.
+         * @param int $id Rune id.
+         */
+        public function __construct($db, $id){
+            global $path;
+            parent::__construct($db);
+            $s =
+              "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, " .
+              "  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 " .
+              "FROM " .
+              "  rune_craft, ".
+              "  k_rune_craft_type, " .
+              "  k_rune_craft_range " .
+              "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 = $this->db->query($s);
+            $r = $q->fetchArray(SQLITE3_ASSOC);
+            if ($r){
+                $this->id = $r["id"];
+                $this->gem = $r["gem"];
+                $this->quality = $r["quality"];
+                $this->quality_name = $this->quality_name($r["quality"]);
+                $this->stat = $r["stat"];
+                $this->stat_name = $this->stat_name($r["stat"]);
+                $this->ancient = $r["ancient"];
+                $this->inmemorial = $r["inmemorial"];
+                if ($this->inmemorial == 0){
+                    $this->rune = new K_Rune_Set($this->db, $r["rune"]);
+                    $this->name = $this->rune->name . " " . $r["stat"];
+                }
+                else{
+                    $this->name = "Inmemorial " . $r["stat"];
+                }
+                $this->min = $r["min"];
+                $this->max = $r["max"];
+                $this->value = $r["value"];
+            }
+        }
+
+        /**
+         * Gets a stat name from the maps.
+         *
+         * @param int $stat Stat id.
+         * @return string Stat name (Uppercase)
+         */
+        private function stat_name($stat){
+            global $RUNE_STAT;
+            switch ($stat){
+                case $RUNE_STAT["HP"]:
+                    return "HP";
+                case $RUNE_STAT["HP%"]:
+                    return "HP%";
+                case $RUNE_STAT["ATK"]:
+                    return "ATK";
+                case $RUNE_STAT["ATK%"]:
+                    return "ATK%";
+                case $RUNE_STAT["DEF"]:
+                    return "DEF";
+                case $RUNE_STAT["DEF%"]:
+                    return "DEF%";
+                case $RUNE_STAT["SPD"]:
+                    return "SPD";
+                case $RUNE_STAT["CRR"]:
+                    return "CRR";
+                case $RUNE_STAT["CRD"]:
+                    return "CRD";
+                case $RUNE_STAT["RES"]:
+                    return "RES";
+                case $RUNE_STAT["ACC"]:
+                    return "ACC";
+                default:
+                    return "";
+            }
+        }
+
+        /**
+         * Gets a stat name from the maps.
+         *
+         * @param int $q Quality id.
+         * @return string Quality (Uppercase)
+         */
+        private function quality_name($q){
+            global $QUALITY;
+            switch ($q){
+                case $QUALITY["NORMAL"]:
+                    return "NORMAL";
+                case $QUALITY["MAGIC"]:
+                    return "MAGIC";
+                case $QUALITY["RARE"]:
+                    return "RARE";
+                case $QUALITY["HERO"]:
+                    return "HERO";
+                case $QUALITY["LEGEND"]:
+                    return "LEGEND";
+                default:
+                    return "";
+            }
+        }
+
+    }
+?>

+ 53 - 0
application/helper/html.php

@@ -252,4 +252,57 @@
         return $html;
     }
 
+    /**
+     * Generates a grindstone or gem panel.
+     * 
+     * @param Rune_Craft craft Entity to get the info from.
+     * @return string HTML content for a rune panel. Empty on error.
+     */
+    function html_craft_panel($craft) {
+        global $path;
+        if (!($craft instanceof Rune_Craft)){
+            return "";
+        }
+        $html = "";
+        if ($craft->gem == 1){
+            if ($craft->inmemorial == 1){
+                $base = $path["img"]["layout"] . "grind/gem_inmemorial.png";
+            }
+            else{
+                $base = $path["img"]["layout"] . "grind/gem.png";
+            }
+        }
+        else{
+            if ($craft->inmemorial == 1){
+                $base = $path["img"]["layout"] . "grind/grind_inmemorial.png";
+            }
+            else{
+                $base = $path["img"]["layout"] . "grind/grind.png";
+            }
+        }
+        if ($craft->inmemorial == 0 && isset($craft->rune)){
+            $icon = "<img class='craft_icon' src='" . $craft->rune->get_image() . "'/>\n";
+        }
+        else{
+            $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 . "%";
+        }
+        else{
+            $stat_name = $craft->stat_name;
+            $stat_value = "+ " . $craft->min . "~" . $craft->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 .= $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 .= "</div>\n";
+        return $html;
+    }
+
 ?>

+ 393 - 0
application/page/Report_Runecraft_Page.php

@@ -0,0 +1,393 @@
+ <?php
+
+    require_once($path["page"] . "Page.php");
+    require_once($path["entity"] . "Unit.php");
+    require_once($path["entity"] . "Rune.php");
+    require_once($path["entity"] . "Rune_Craft.php");
+
+    /**
+     * Upgradeable runes report page.
+     */
+    class Report_Runecraft_Page extends Page{
+
+        /**
+         * Filters the report can handle.
+         */
+        public $filters = [
+            "monster_name" => "",
+            "monster_min_stars" => 5,
+            "monster_max_stars" => 6,
+            "monster_storage" => false,
+            "rune_min_stars" => 5,
+            "rune_max_stars" => 6,
+            "rune_min_level" => 0,
+            "rune_max_level" => 15,
+            "rune_min_quality" => 0,
+            "rune_max_quality" => 4,
+            "rune_min_original_quality" => 0,
+            "rune_max_original_quality" => 4,
+            "rune_min_efficiency" => 0,
+            "rune_max_efficiency" => 100,
+            "rune_min_max_efficiency" => 0,
+            "rune_max_max_efficiency" => 100,
+            "rune_slot" => [],
+            "grind" => 1,
+            "grind_min_quality" => 0,
+            "grind_stat" => [],
+            "gem" => 1,
+            "gem_min_quality" => 3,
+            "gem_stat_from" => [],
+            "gem_stat_to" => [],
+        ];
+
+        /**
+         * List of available upgrades. Can be described as:
+         * $upgrades = [
+         *   [
+         *     unit (Unit),
+         *     upgrade = [
+         *       [
+         *         rune (Rune),
+         *         craft = [(Rune_Craft)]
+         *       ]
+         *     ]
+         *   ]
+         * ]
+         */
+        public $upgrades = [];
+
+        /**
+         * Constructor.
+         *
+         * Retrieves the data and initializes the variables.
+         *
+         * @param SQLite3 $db Connection to the database.
+         */
+        public function __construct($db){
+            global $path;
+            global $root;
+            parent::__construct($db);
+            $this->view = $path["view"] . "report_runecraft.php";
+            $this->parse_filters();
+            $s = $this->build_query();
+            error_log($s);
+            $q = $this->db->query($s);
+            $prev_monster = "";
+            $prev_rune = "";
+            $upgrade = null;
+            $rupgrade = null;
+            while ($r = $q->fetchArray(SQLITE3_ASSOC)){
+                if ($r["unit"] != $prev_monster){
+                    if ($prev_rune != ""){
+                        array_push($upgrade["upgrade"], $rupgrade);
+                    }
+                    if ($prev_monster != ""){
+                        error_log("PUSH!");
+                        array_push($this->upgrades, $upgrade);
+                    }
+                    $prev_monster = $r["unit"];
+                    $prev_rune = "";
+                    $upgrade = [
+                        "unit" => new Unit($this->db, $r["unit"]),
+                        "upgrade" => [],
+                    ];
+                    $rupgrade = [
+                        "rune" => new Rune($this->db, $r["rune"]),
+                        "craft" => [],
+                    ];
+                }
+                if ($r["rune"] != $prev_rune){
+                    if ($prev_rune != ""){
+                        array_push($upgrade["upgrade"], $rupgrade);
+                    }
+                    $prev_rune = $r["rune"];
+                    $rupgrade = [
+                        "rune" => new Rune($this->db, $r["rune"]),
+                        "craft" => [],
+                    ];
+                }
+                $rune_craft = new Rune_craft($this->db, $r["craft"]);
+                array_push($rupgrade["craft"], $rune_craft);
+            }
+            // Last entries
+            array_push($upgrade["upgrade"], $rupgrade);
+            error_log("PUSH!");
+            array_push($this->upgrades, $upgrade);
+            $this->title = "Rune craft - SWDB";
+            $this->description = "Find runes that can be upgraded via crafting.";
+            $this->canonical = $root . "report/runecraft/";
+        }
+
+        /**
+         * Parses the filters passed in the request and sets $filters.
+         * Filters must be in $_GET, nd the available ones are max_stars (1-6),
+         * min_stars (1-6) and in_storage (on/off).
+         */
+        private function parse_filters(){
+            global $RUNE_STAT;
+            // Monster
+            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"];
+            }
+            if (isset($_GET["monster_max_stars"]) && intval($_GET["monster_max_stars"]) > 0 && intval($_GET["monster_max_stars"]) < 7){
+                $this->filters["monster_max_stars"] = $_GET["monster_max_stars"];
+            }
+            if (isset($_GET["monster_in_storage"]) && $_GET["monster_in_storage"] == "on"){
+                $this->filters["monster_in_storage"] = true;
+            }
+            else{
+                $this->filters["monster_in_storage"] = false;
+            }
+            if (isset($_GET["monster_name"]) && strlen($_GET["monster_name"]) > 0){
+                $this->filters["monster_name"] = SQLite3::escapeString($_GET["monster_name"]);
+            }
+            // Runes
+            if (isset($_GET["rune_min_stars"]) && intval($_GET["rune_min_stars"]) > 0 && intval($_GET["rune_min_stars"]) < 7){
+                $this->filters["rune_min_stars"] = $_GET["rune_min_stars"];
+            }
+            if (isset($_GET["rune_max_stars"]) && intval($_GET["rune_max_stars"]) > 0 && intval($_GET["rune_max_stars"]) < 7){
+                $this->filters["rune_max_stars"] = $_GET["rune_max_stars"];
+            }
+            if (isset($_GET["rune_min_level"]) && intval($_GET["rune_min_level"]) >= 0 && intval($_GET["rune_min_level"]) <= 15){
+                $this->filters["rune_min_level"] = $_GET["rune_min_level"];
+            }
+            if (isset($_GET["rune_max_level"]) && intval($_GET["max_level"]) >= 0 && intval($_GET["rune_max_level"]) <= 15){
+                $this->filters["rune_max_level"] = $_GET["rune_max_level"];
+            }
+            if (isset($_GET["rune_min_quality"]) && intval($_GET["rune_min_quality"]) >= 0 && intval($_GET["rune_min_quality"]) < 5){
+                $this->filters["rune_min_quality"] = $_GET["rune_min_quality"];
+            }
+            if (isset($_GET["rune_max_quality"]) && intval($_GET["rune_max_quality"]) >= 0 && intval($_GET["rune_max_quality"]) < 5){
+                $this->filters["rune_max_quality"] = $_GET["rune_max_quality"];
+            }
+            if (isset($_GET["rune_min_original_quality"]) && intval($_GET["rune_min_original_quality"]) >= 0 && intval($_GET["rune_min_original_quality"]) < 5){
+                $this->filters["rune_min_original_quality"] = $_GET["rune_min_original_quality"];
+            }
+            if (isset($_GET["rune_max_original_quality"]) && intval($_GET["rune_max_original_quality"]) >= 0 && intval($_GET["rune_max_original_quality"]) < 5){
+                $this->filters["rune_max_original_quality"] = $_GET["rune_max_original_quality"];
+            }
+            if (isset($_GET["rune_min_efficiency"]) && intval($_GET["rune_min_efficiency"]) >= 0 && intval($_GET["rune_min_efficiency"]) <= 100){
+                $this->filters["rune_min_efficiency"] = $_GET["rune_min_efficiency"];
+            }
+            if (isset($_GET["rune_max_efficiency"]) && intval($_GET["rune_max_efficiency"]) >= 0 && intval($_GET["rune_max_efficiency"]) <= 100){
+                $this->filters["rune_max_efficiency"] = $_GET["rune_max_efficiency"];
+            }
+            if (isset($_GET["rune_min_max_efficiency"]) && intval($_GET["rune_min_max_efficiency"]) >= 0 && intval($_GET["rune_min_max_efficiency"]) <= 100){
+                $this->filters["rune_min_max_efficiency"] = $_GET["rune_min_max_efficiency"];
+            }
+            if (isset($_GET["rune_max_max_efficiency"]) && intval($_GET["rune_max_max_efficiency"]) >= 0 && intval($_GET["rune_max_max_efficiency"]) <= 100){
+                $this->filters["rune_max_max_efficiency"] = $_GET["rune_max_max_efficiency"];
+            }
+            if (isset($_GET["rune_slot"])){
+                $slots = $_GET["rune_slot"];
+                foreach ($slots as $slot){
+                    if (intval($slot) >= 1 && intval($slot) < 7){
+                        array_push($this->filters["rune_slot"], intval($slot));
+                    }
+                }
+            }
+            // Grindstones
+            if (isset($_GET["grind_min_quality"]) && intval($_GET["grind_min_quality"]) >= $QUALITY["NORMAL"] && intval($_GET["grind_min_quality"]) < $QUALITY["LEGEND"]){
+                $this->filters["grind_min_quality"] = $_GET["grind_min_quality"];
+            }
+            if (isset($_GET["grind_stat"])){
+                $stats = $_GET["grind_stat"];
+                foreach ($stats as $stat){
+                    array_push($this->filters["grind_stat"], intval($stat));
+                }
+            }
+            else{
+                $this->filters["grind_stat"] = [
+                    $RUNE_STAT["HP%"],
+                    $RUNE_STAT["ATK%"],
+                    $RUNE_STAT["DEF%"],
+                    $RUNE_STAT["SPD"],
+                    $RUNE_STAT["CRD"],
+                    $RUNE_STAT["CRR"],
+                    $RUNE_STAT["ACC"]
+                ];
+            }
+            if (isset($_GET["gem_stat_from"])){
+                $stats = $_GET["gem_stat_from"];
+                foreach ($stats as $stat){
+                    array_push($this->filters["gem_stat_from"], intval($stat));
+                }
+            }
+            else{
+                $this->filters["gem_stat_from"] = [
+                    $RUNE_STAT["HP"],
+                    $RUNE_STAT["ATK"],
+                    $RUNE_STAT["DEF"],
+                    $RUNE_STAT["RES"]
+                ];
+            }
+            if (isset($_GET["gem_stat_to"])){
+                $stats = $_GET["gem_stat_to"];
+                foreach ($stats as $stat){
+                    array_push($this->filters["gem_stat_to"], intval($stat));
+                }
+            }
+            else{
+                $this->filters["gem_stat_to"] = [
+                    $RUNE_STAT["HP%"],
+                    $RUNE_STAT["ATK%"],
+                    $RUNE_STAT["DEF%"],
+                    $RUNE_STAT["SPD"],
+                    $RUNE_STAT["CRD"],
+                    $RUNE_STAT["CRR"],
+                    $RUNE_STAT["ACC"]
+                ];
+            }
+            return;
+        }
+
+        /**
+         * Builds the query for the page, using the providded or default filters.
+         *
+         * @return The query to be executed.
+         */
+        private function build_query(){
+            $s = "
+                SELECT
+                  unit.id AS unit,
+                  rune.id AS rune,
+                  rune_craft.id AS craft
+                FROM
+                  unit,
+                  k_unit,
+                  rune,
+                  rune_craft,
+                  k_rune_craft_type
+                WHERE
+                  unit.id = rune.assigned_to AND
+                  unit.unit = k_unit.id AND
+                  rune_craft.type = k_rune_craft_type.id AND
+                  unit.stars >= " . $this->filters["rune_min_stars"] . " AND
+                  unit.stars <= " . $this->filters["rune_max_stars"] . " AND
+                  -- RUNE FILTERS
+                  rune.quality >= " . $this->filters["rune_min_quality"] . " AND
+                  rune.quality <= " . $this->filters["rune_max_quality"] . " AND
+                  rune.level >= " . $this->filters["rune_min_level"] . " AND
+                  rune.level <= " . $this->filters["rune_max_level"] . " AND
+                  rune.stars >= " . $this->filters["rune_min_stars"] . " AND
+                  rune.stars <= " . $this->filters["rune_max_stars"] . " AND
+                  rune.original_quality >= " . $this->filters["rune_min_original_quality"] . " AND
+                  rune.original_quality <= " . $this->filters["rune_max_original_quality"] . " AND
+                  rune.efficiency >= " . $this->filters["rune_min_efficiency"] . " AND
+                  rune.efficiency <= " . $this->filters["rune_max_efficiency"] . " AND
+                  rune.max_efficiency >= " . $this->filters["rune_min_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
+                  ) AND
+                  k_rune_craft_type.ancient = rune.ancient AND
+                ";
+            if (strlen($this->filters["monster_name"]) > 0){
+                $s = $s . " AND upper(k_unit.name) LIKE = upper('%" . $this->filters["monster_name"] . "%') ";
+            }
+            if (!$this->filters["monster_in_storage"]){
+                //$s = $s . " AND unit.in_storage = 0 ";
+            }
+            if (count($this->filters["rune_slot"]) > 0){
+                $s = $s . " rune.slot IN ( ";
+                foreach($this->filters["rune_slot"] as $t){
+                    $s = $s . "$t, ";
+                }
+                $s = $s . "-1) AND ";
+            }
+            $s .= "
+                rune_craft.stat <> rune.main_stat AND
+                rune_craft.stat <> rune.innate_stat AND
+                  (
+                    k_rune_craft_type.gem = 1 AND
+                    (
+                      -- GEM FILTERS
+                      rune_craft.quality >= " . $this->filters["gem_min_quality"] . " AND
+            ";
+            if (count($this->filters["gem_stat_from"]) > 0){
+                $in = "(";
+                foreach($this->filters["gem_stat_from"] as $t){
+                    $in = $in . "$t, ";
+                }
+                $in = $in . "-1)";
+                $s .= " (rune.substat_1 IN $in OR rune.substat_2 IN $in OR rune.substat_3 IN $in OR rune.substat_4 IN $in) AND ";
+            }
+            if (count($this->filters["gem_stat_to"]) > 0){
+                $in = "(";
+                foreach($this->filters["gem_stat_to"] as $t){
+                    $in = $in . "$t, ";
+                }
+                $in = $in . "-1)";
+                $s .= " rune_craft.stat IN $in AND ";
+            }
+            $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
+                      )
+                    )
+                  ) |
+                  (
+                    k_rune_craft_type.gem = 0 AND
+                    (
+                      -- GRINDSTONE FILTERS
+            ";
+            if (count($this->filters["grind_stat"]) > 0){
+                $in = "(";
+                foreach($this->filters["grind_stat"] as $t){
+                    $in = $in . "$t, ";
+                }
+                $in = $in . "-1)";
+                $s .= " rune_craft.stat IN $in AND ";
+            }
+            $s .= "
+                      rune_craft.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
+                        ) 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
+                        ) 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
+                        ) 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
+                        )
+                      )
+                    )
+                  )
+                ";
+            $s .= "
+                ORDER BY
+                  unit.stars DESC,
+                  unit.level DESC,
+                  unit.id,
+                  rune.stars DESC,
+                  rune.original_quality DESC,
+                  rune.level DESC,
+                  rune.id, 
+                  rune.slot, 
+                  rune_craft.quality DESC,
+                  rune_craft.stat DESC;
+                ";
+            return $s;
+        }
+    }
+?>

+ 344 - 0
application/view/report_runecraft.php

@@ -0,0 +1,344 @@
+<?php
+    global $RUNE_STAT;
+?>
+<!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='<?=$path["css"]?>ui.css'/>
+        <link rel='stylesheet' type='text/css' href='<?=$path["css"]?>report_runecraft.css'/>
+        <!-- Script files -->
+        <script src="<?=$path["js"]?>ui.js"></script>
+        <!-- Meta tags -->
+        <link rel='canonical' href='<?=$page->canonical?>'/>
+        <link rel='author' href='<?=$page->author?>'/>
+        <link rel='publisher' href='<?=$page->author?>'/>
+        <meta name='description' content='<?=$page->description?>'/>
+        <meta property='og:title' content='<?=$page->title?>'/>
+        <meta property='og:url' content='<?=$page->canonical?>'/>
+        <meta property='og:description' content='<?=$page->description?>'/>
+        <meta property='og:image' content='<?=$page->icon?>'/>
+        <meta property='og:site_name' content='<?=$page->name?>'/>
+        <meta property='og:type' content='website'/>
+        <meta property='og:locale' content='en'/>
+        <meta name='twitter:card' content='summary'/>
+        <meta name='twitter:title' content='<?=$page->title?>'/>
+        <meta name='twitter:description' content='<?=$page->description?>'/>
+        <meta name='twitter:image' content='<?=$page->icon?>'/>
+        <meta name='twitter:url' content='<?=$page->canonical?>'/>
+        <meta name='robots' content='index follow'/>
+    </head>
+    <body>
+<?php
+        include __DIR__ . "/inc/header.php";
+?>
+        <section class='filters'>
+            <h2>
+                <span>
+                    Report filters
+                </span>
+            </h2>
+            <form action='/report/runecraft/' method='get'>
+                <table>
+                    <tr>
+                        <td class='filter filter_title' rowspan='2'>
+                            <span>
+                                Monster
+                            </span>
+                        </td>
+                        <td class='filter' colspan='3'>
+                            <span>Name:</span>
+                            <input type='text' name='monster_name' id='filter_name' value='<?=$page->filters["monster_name"]?>'/>
+                        </td>
+                        <td class='filter'>
+                            <span>Stars:</span>
+                            <input type='number' name='monster_min_stars' id='filter_stars_min' min='1' max='6' value='<?=$page->filters["monster_min_stars"]?>'/>
+                            -
+                            <input type='number' name='monster_max_stars' id='filter_stars_max' min='1' max='6' value='<?=$page->filters["monster_max_stars"]?>'/>
+                        </td>
+                    </tr>
+                        <td class='filter' colspan='4'>
+<?php
+                            $checked = "";
+                            if ($page->filters["monster_in_storage"]){
+                                $checked = "checked";
+                            }
+?>
+                            <input type='checkbox' name='monster_in_storage' <?=$checked?>/>
+                            Show monsters in storage
+                        </td>
+                    </tr>
+                    <tr>
+                        <td class='filter filter_title filter_separator' rowspan='5'>
+                            <span>
+                                Runes
+                            </span>
+                        </td>
+                        <td class='filter filter_stars filter_separator' colspan='2'>
+                            <span>Stars:</span>
+                            <input type='number' name='rune_min_stars' id='filter_stars_min' min='1' max='6' value='<?=$page->filters["rune_min_stars"]?>'/>
+                            -
+                            <input type='number' name='rune_max_stars' id='filter_stars_max' min='1' max='6' value='<?=$page->filters["rune_max_stars"]?>'/>
+                        </td>
+                        <td class='filter filter_separator' colspan='2'>
+                            <span>Level:</span>
+                            <input type='number' name='rune_min_level' id='filter_level_min' min='0' max='15' value='<?=$page->filters["rune_min_level"]?>'/>
+                            -
+                            <input type='number' name='rune_max_level' id='filter_level_max' min='0' max='15' value='<?=$page->filters["rune_max_level"]?>'/>
+                        </td>
+                    </tr>
+                    <tr>
+                        <td class='filter' rowspan='4'>
+                            <span>Slot:</span>
+                            <select multiple name='rune_slot[]' id='filter_slot'>
+<?php
+                                for ($i = 1; $i <= 6; $i ++){
+                                    if (in_array($i, $page->filters["rune_slot"])){
+                                        $selected = "selected='selected'";
+                                    }
+                                    else{
+                                        $selected = "";
+                                    }
+?>
+                                    <option value='<?=$i?>' <?=$selected?>><?=$i?></option>
+<?php
+                                }
+?>
+                            </select>
+                        </td>
+                        <td class='filter' colspan='3'>
+                            <span>Quality:</span>
+<?php
+
+                            $selected = Array("", "", "", "", "");
+                            $selected[$page->filters["rune_min_quality"]] = "selected";
+?>
+                            <select name='rune_min_quality' id='filter_quality_min'>
+                                <option value='0' <?=$selected[0]?>>Normal</option>
+                                <option value='1' <?=$selected[1]?>>Magic</option>
+                                <option value='2' <?=$selected[2]?>>Rare</option>
+                                <option value='3' <?=$selected[3]?>>Hero</option>
+                                <option value='4' <?=$selected[4]?>>Legend</option>
+                            </select>
+                            -
+<?php
+                            $selected = Array("", "", "", "", "");
+                            $selected[$page->filters["rune_max_quality"]] = "selected";
+?>
+                            <select name='rune_max_quality' id='filter_quality_max'>
+                                <option value='0' <?=$selected[0]?>>Normal</option>
+                                <option value='1' <?=$selected[1]?>>Magic</option>
+                                <option value='2' <?=$selected[2]?>>Rare</option>
+                                <option value='3' <?=$selected[3]?>>Hero</option>
+                                <option value='4' <?=$selected[4]?>>Legend</option>
+                            </select>
+                        </td>
+                    </tr>
+                    <tr>
+                        <td class='filter' colspan='3'>
+                            <span>Original quality:</span>
+<?php
+                            $selected = Array("", "", "", "", "");
+                            $selected[$page->filters["rune_min_original_quality"]] = "selected";
+?>
+                            <select name='rune_min_original_quality' id='filter_original_quality_min'>
+                                <option value='0' <?=$selected[0]?>>Normal</option>
+                                <option value='1' <?=$selected[1]?>>Magic</option>
+                                <option value='2' <?=$selected[2]?>>Rare</option>
+                                <option value='3' <?=$selected[3]?>>Hero</option>
+                                <option value='4' <?=$selected[4]?>>Legend</option>
+                            </select>
+                            -
+<?php
+                            $selected = Array("", "", "", "", "");
+                            $selected[$page->filters["rune_max_original_quality"]] = "selected";
+?>
+                            <select name='rune_max_original_quality' id='filter_original_quality_max'>
+                                <option value='0' <?=$selected[0]?>>Normal</option>
+                                <option value='1' <?=$selected[1]?>>Magic</option>
+                                <option value='2' <?=$selected[2]?>>Rare</option>
+                                <option value='3' <?=$selected[3]?>>Hero</option>
+                                <option value='4' <?=$selected[4]?>>Legend</option>
+                            </select>
+                        </td>
+                    </tr>
+                    <tr>
+                        <td class='filter' colspan='3'>
+                            <span>Efficiency:</span>
+                            <input type='number' name='rune_min_efficiency' id='filter_efficiency_min' min='0' max='100' value='<?=$page->filters["rune_min_efficiency"]?>'/>%
+                            -
+                            <input type='number' name='rune_max_efficiency' id='filter_efficiency_max' min='0' max='100' value='<?=$page->filters["rune_max_efficiency"]?>'/>%
+                        </td>
+                    </tr>
+                    <tr>
+                        <td class='filter' colspan='3'>
+                            <span>Maximum efficiency:</span>
+                            <input type='number' name='rune_min_max_efficiency' id='filter_max_efficiency_min' min='0' max='100' value='<?=$page->filters["rune_min_max_efficiency"]?>'/>%
+                            -
+                            <input type='number' name='rune_max_max_efficiency' id='filter_max_efficiency_max' min='0' max='100' value='<?=$page->filters["rune_max_max_efficiency"]?>'/>%
+                        </td>
+                    </tr>
+                    <tr>
+                        <td class='filter filter_title filter_separator'>
+                            <span>
+                                Grindstones
+                            </span>
+                        </td>
+                        <td class='filter filter_stars filter_separator'>
+<?php
+                            $checked = "";
+                            if ($page->filters["grind"]){
+                                $checked = "checked";
+                            }
+?>
+                            <input type='checkbox' name='grind' <?=$checked?>/> Grindstones
+                        </td>
+                        <td class='filter filter_separator'>
+                            <span>Min. quality:</span>
+<?php
+                            $selected = Array("", "", "", "", "");
+                            $selected[$page->filters["grind_min_quality"]] = "selected";
+?>
+                            <select name='grind_min_quality'>
+                                <option value='0' <?=$selected[0]?>>Normal</option>
+                                <option value='1' <?=$selected[1]?>>Magic</option>
+                                <option value='2' <?=$selected[2]?>>Rare</option>
+                                <option value='3' <?=$selected[3]?>>Hero</option>
+                                <option value='4' <?=$selected[4]?>>Legend</option>
+                            </select>
+                        </td>
+                        <td class='filter filter_separator' colspan='2'>
+                            <span>Stats:</span>
+                            <select multiple name='grind_stat' id='filter_grind_stat'>
+<?php
+                                foreach($RUNE_STAT as $k=>$n){
+                                    $selected = "";
+                                    if (in_array($n, $page->filters["grind_stat"])){
+                                        $selected = "selected='selected'";
+                                    }
+                                    $name = ucwords($k);
+?>
+                                    <option value='<?=$n?>' <?=$selected?>><?=$name?></option>
+<?php
+                                }
+?>
+                            </select>
+                        </td>
+                    </tr>
+                    <tr>
+                        <td class='filter filter_title filter_separator'>
+                            <span>
+                                Gems
+                            </span>
+                        </td>
+                        <td class='filter filter_stars filter_separator'>
+<?php
+                            $checked = "";
+                            if ($page->filters["gem"]){
+                                $checked = "checked";
+                            }
+?>
+                            <input type='checkbox' name='gem' <?=$checked?>/> Gems
+                        </td>
+                        <td class='filter filter_separator'>
+                            <span>Min. quality:</span>
+<?php
+                            $selected = Array("", "", "", "", "");
+                            $selected[$page->filters["gem_min_quality"]] = "selected";
+?>
+                            <select name='gem_min_quality'>
+                                <option value='0' <?=$selected[0]?>>Normal</option>
+                                <option value='1' <?=$selected[1]?>>Magic</option>
+                                <option value='2' <?=$selected[2]?>>Rare</option>
+                                <option value='3' <?=$selected[3]?>>Hero</option>
+                                <option value='4' <?=$selected[4]?>>Legend</option>
+                            </select>
+                        </td>
+                        <td class='filter filter_separator'>
+                            <span>Replace...</span>
+                            <select multiple name='gem_stat_from' id='filter_gem_stat_from'>
+<?php
+                                foreach($RUNE_STAT as $k=>$n){
+                                    $selected = "";
+                                    if (in_array($n, $page->filters["gem_stat_from"])){
+                                        $selected = "selected='selected'";
+                                    }
+                                    $name = ucwords($k);
+?>
+                                    <option value='<?=$n?>' <?=$selected?>><?=$name?></option>
+<?php
+                                }
+?>
+                            </select>
+                        </td>
+                        <td class='filter filter_separator'>
+                            <span>...with...</span>
+                            <select multiple name='gem_stat_from' id='filter_gem_stat_to'>
+<?php
+                                foreach($RUNE_STAT as $k=>$n){
+                                    $selected = "";
+                                    if (in_array($n, $page->filters["gem_stat_to"])){
+                                        $selected = "selected='selected'";
+                                    }
+                                    $name = ucwords($k);
+?>
+                                    <option value='<?=$n?>' <?=$selected?>><?=$name?></option>
+<?php
+                                }
+?>
+                            </select>
+                        </td>
+                    </tr>
+                </table>
+                <div id='filter_apply'>
+                    <input type='submit' value='Apply'/>
+                </div>
+            </form>
+        </section> <!-- #filters -->
+<?php
+            foreach ($page->upgrades as $upgrade){
+?>
+            <section class='content'>
+                <h2>
+                    <span>
+                        <?=$upgrade["unit"]->title?>
+                    </span>
+                </h2>
+                <article>
+                    <div class='monster'>
+                        <div class='profile'>
+                            <div class='monster_panel'>
+                                <?=html_unit_panel($upgrade["unit"])?>
+                            </div>
+                        </div> <!-- .profile -->
+                    </div>
+                    <div class='monster_runes'>
+<?php
+                        foreach ($upgrade["upgrade"] as $rupgrade){
+?>
+                            <?=html_rune_table($rupgrade["rune"])?>
+                            <div class='craft'>
+<?php
+                                foreach ($rupgrade["craft"] as $craft){
+?>
+                                    <?=html_craft_panel($craft)?>
+<?php
+                                }
+?>
+                            </div>
+<?php
+                        }
+?>
+                    </div> <!-- .monster_runes -->
+                </article>
+            </section>
+<?php
+            }
+        include __DIR__ . "/inc/footer.php";
+?>
+    </body>
+</html>

+ 1 - 0
application/view/report_runeupgrade.php

@@ -104,6 +104,7 @@
                                     <option value='$i' <?=$selected?>>%i</option>
 <?php
                                 }
+?>
                             </select>
                         </td>
                         <td class='filter' colspan='3'>

+ 232 - 0
data.sql

@@ -36,6 +36,10 @@ CREATE TABLE IF NOT EXISTS k_guild_skill_group(id INT, name TEXT, description TE
 
 CREATE TABLE IF NOT EXISTS k_guild_skill(id INT, skill_group INT, level INT, effect TEXT);
 
+CREATE TABLE IF NOT EXISTS k_rune_craft_type(id INT, name TEXT, gem INT, inmemorial INT, ancient INT);
+
+CREATE TABLE IF NOT EXISTS k_rune_craft_range(gem INT, ancient INT, quality INT, stat INT, min INT, max INT);
+
 
 INSERT INTO k_difficulty VALUES (0, 'Easy');
 INSERT INTO k_difficulty VALUES (1, 'Normal');
@@ -665,3 +669,231 @@ INSERT INTO k_guild_skill VALUES (28, 5, 20, 'Add 1 more Guild Magic Shop slot')
 INSERT INTO k_guild_skill VALUES (29, 6, 15, 'Gain 5% additional Mana Stones');
 INSERT INTO k_guild_skill VALUES (30, 7, 30, 'Gain 5% additional EXP');
 
+INSERT INTO k_rune_craft_type VALUES (1, 'Enchant Gem', 1, 0, 0);
+INSERT INTO k_rune_craft_type VALUES (2, 'Grindstone', 0, 0, 0);
+INSERT INTO k_rune_craft_type VALUES (3, 'Inmemorial Gem', 1, 1, 0);
+INSERT INTO k_rune_craft_type VALUES (4, 'Inmemorial Grindstone', 0, 1, 0);
+INSERT INTO k_rune_craft_type VALUES (5, 'Ancient Gem', 1, 0, 1);
+INSERT INTO k_rune_craft_type VALUES (6, 'Ancient Grindstone', 0, 0, 1);
+
+INSERT INTO k_rune_craft_range VALUES (0, 0, 1, 1, 80, 120);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 2, 1, 100, 200);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 3, 1, 180, 250);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 4, 1, 230, 450);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 5, 1, 430, 550);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 1, 2, 1, 3);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 2, 2, 2, 5);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 3, 2, 3, 6);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 4, 2, 4, 7);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 5, 2, 5, 10);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 1, 3, 4, 8);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 2, 3, 6, 12);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 3, 3, 10, 18);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 4, 3, 12, 22);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 5, 3, 18, 30);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 1, 4, 1, 3);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 2, 4, 2, 5);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 3, 4, 3, 6);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 4, 4, 4, 7);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 5, 4, 5, 10);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 1, 5, 4, 8);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 2, 5, 6, 12);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 3, 5, 10, 18);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 4, 5, 12, 22);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 5, 5, 18, 30);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 1, 6, 1, 3);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 2, 6, 2, 5);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 3, 6, 3, 6);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 4, 6, 4, 7);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 5, 6, 5, 10);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 1, 8, 1, 2);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 2, 8, 1, 2);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 3, 8, 2, 3);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 4, 8, 3, 4);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 5, 8, 4, 5);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 1, 9, 1, 2);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 2, 9, 1, 3);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 3, 9, 2, 4);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 4, 9, 3, 5);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 5, 9, 4, 6);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 1, 10, 1, 3);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 2, 10, 2, 4);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 3, 10, 2, 5);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 4, 10, 3, 5);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 5, 10, 4, 7);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 1, 11, 1, 3);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 2, 11, 2, 4);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 3, 11, 2, 5);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 4, 11, 3, 7);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 5, 11, 4, 8);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 1, 12, 1, 3);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 2, 12, 2, 4);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 3, 12, 2, 5);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 4, 12, 3, 7);
+INSERT INTO k_rune_craft_range VALUES (0, 0, 5, 12, 4, 8);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 1, 1, 100, 150);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 2, 1, 130, 220);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 3, 1, 200, 310);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 4, 1, 290, 420);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 5, 1, 400, 580);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 1, 2, 2, 4);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 2, 2, 3, 7);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 3, 2, 5, 9);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 4, 2, 7, 11);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 5, 2, 9, 13);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 1, 3, 8, 12);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 2, 3, 10, 16);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 3, 3, 15, 23);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 4, 3, 20, 30);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 5, 3, 28, 40);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 1, 4, 2, 4);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 2, 4, 3, 7);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 3, 4, 5, 9);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 4, 4, 7, 11);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 5, 4, 9, 13);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 1, 5, 8, 12);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 2, 5, 10, 16);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 3, 5, 15, 23);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 4, 5, 20, 30);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 5, 5, 28, 40);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 1, 6, 2, 4);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 2, 6, 3, 7);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 3, 6, 5, 9);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 4, 6, 7, 11);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 5, 6, 9, 13);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 1, 8, 1, 3);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 2, 8, 2, 4);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 3, 8, 3, 6);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 4, 8, 5, 8);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 5, 8, 7, 10);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 1, 9, 1, 3);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 2, 9, 2, 4);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 3, 9, 3, 5);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 4, 9, 4, 7);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 5, 9, 6, 9);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 1, 10, 2, 4);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 2, 10, 3, 5);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 3, 10, 4, 6);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 4, 10, 5, 8);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 5, 10, 7, 10);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 1, 11, 2, 4);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 2, 11, 3, 6);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 3, 11, 5, 8);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 4, 11, 6, 9);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 5, 11, 8, 11);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 1, 12, 2, 4);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 2, 12, 3, 6);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 3, 12, 5, 8);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 4, 12, 6, 9);
+INSERT INTO k_rune_craft_range VALUES (1, 0, 5, 12, 8, 11);
+-- TODO: Fix ancient ranges
+INSERT INTO k_rune_craft_range VALUES (0, 1, 1, 1, 80, 120);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 2, 1, 100, 200);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 3, 1, 180, 250);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 4, 1, 230, 450);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 5, 1, 430, 550);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 1, 2, 1, 3);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 2, 2, 2, 5);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 3, 2, 3, 6);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 4, 2, 4, 7);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 5, 2, 5, 10);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 1, 3, 4, 8);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 2, 3, 6, 12);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 3, 3, 10, 18);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 4, 3, 12, 22);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 5, 3, 18, 30);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 1, 4, 1, 3);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 2, 4, 2, 5);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 3, 4, 3, 6);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 4, 4, 4, 7);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 5, 4, 5, 10);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 1, 5, 4, 8);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 2, 5, 6, 12);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 3, 5, 10, 18);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 4, 5, 12, 22);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 5, 5, 18, 30);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 1, 6, 1, 3);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 2, 6, 2, 5);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 3, 6, 3, 6);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 4, 6, 4, 7);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 5, 6, 5, 10);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 1, 8, 1, 2);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 2, 8, 1, 2);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 3, 8, 2, 3);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 4, 8, 3, 4);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 5, 8, 4, 5);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 1, 9, 1, 2);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 2, 9, 1, 3);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 3, 9, 2, 4);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 4, 9, 3, 5);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 5, 9, 4, 6);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 1, 10, 1, 3);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 2, 10, 2, 4);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 3, 10, 2, 5);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 4, 10, 3, 5);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 5, 10, 4, 7);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 1, 11, 1, 3);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 2, 11, 2, 4);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 3, 11, 2, 5);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 4, 11, 3, 7);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 5, 11, 4, 8);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 1, 12, 1, 3);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 2, 12, 2, 4);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 3, 12, 2, 5);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 4, 12, 3, 7);
+INSERT INTO k_rune_craft_range VALUES (0, 1, 5, 12, 4, 8);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 1, 1, 100, 150);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 2, 1, 130, 220);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 3, 1, 200, 310);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 4, 1, 290, 420);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 5, 1, 400, 580);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 1, 2, 2, 4);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 2, 2, 3, 7);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 3, 2, 5, 9);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 4, 2, 7, 11);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 5, 2, 9, 13);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 1, 3, 8, 12);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 2, 3, 10, 16);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 3, 3, 15, 23);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 4, 3, 20, 30);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 5, 3, 28, 40);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 1, 4, 2, 4);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 2, 4, 3, 7);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 3, 4, 5, 9);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 4, 4, 7, 11);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 5, 4, 9, 13);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 1, 5, 8, 12);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 2, 5, 10, 16);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 3, 5, 15, 23);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 4, 5, 20, 30);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 5, 5, 28, 40);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 1, 6, 2, 4);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 2, 6, 3, 7);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 3, 6, 5, 9);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 4, 6, 7, 11);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 5, 6, 9, 13);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 1, 8, 1, 3);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 2, 8, 2, 4);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 3, 8, 3, 6);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 4, 8, 5, 8);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 5, 8, 7, 10);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 1, 9, 1, 3);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 2, 9, 2, 4);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 3, 9, 3, 5);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 4, 9, 4, 7);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 5, 9, 6, 9);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 1, 10, 2, 4);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 2, 10, 3, 5);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 3, 10, 4, 6);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 4, 10, 5, 8);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 5, 10, 7, 10);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 1, 11, 2, 4);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 2, 11, 3, 6);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 3, 11, 5, 8);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 4, 11, 6, 9);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 5, 11, 8, 11);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 1, 12, 2, 4);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 2, 12, 3, 6);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 3, 12, 5, 8);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 4, 12, 6, 9);
+INSERT INTO k_rune_craft_range VALUES (1, 1, 5, 12, 8, 11);

+ 11 - 0
install_base.py

@@ -377,6 +377,17 @@ def createDatabase(name):
                 has_defense INT
             );
         ''')
+        cursor.execute('''
+            CREATE TABLE IF NOT EXISTS rune_craft(
+                uid TEXT,
+                id INT,
+                type INT,
+                quality INT,
+                rune INT,
+                stat INT,
+                value INT
+            );
+        ''')
         db.commit()
         cursor.close()
         return db

+ 27 - 1
install_user.py

@@ -42,6 +42,7 @@ def openDatabase(name):
         cursor.execute('''DELETE FROM summon_special''')
         cursor.execute('''DELETE FROM guild''')
         cursor.execute('''DELETE FROM guild_member''')
+        cursor.execute('''DELETE FROM rune_craft''')
         db.commit()
         cursor.close()
         return db
@@ -437,6 +438,31 @@ def parseRunes(db, data):
             insert(db, "rune", (uid, id, assigned_to, runeset, 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))
     db.commit()
 
+"""
+Parses rune craft item data (table rune_craft).
+
+:param db: Sqlite database connection.
+:param data: Data in SWEX json file.
+"""
+def parseRuneCraft(db, data):
+    print("Parsing rune craft itmes...")
+    uid = data["wizard_info"]["wizard_id"]
+    for item in data["rune_craft_item_list"]:
+        id = item["craft_item_id"]
+        type = item["craft_type"]
+        value = item["sell_value"]
+        info = str(item["craft_type_id"])
+        """
+        info : 5 or 6 digit number: RRSSQ
+          RR: Rune
+          SS: Stat
+          Q:  Quality
+        """
+        quality = int(info[-1:])
+        stat = int(info[-4:-2])
+        rune = int(info[:-4])
+        insert(db, "rune_craft", (uid, id, type, quality, rune, stat, value))
+
 """
 Parses guild data (tables guild, guild_member).
 
@@ -497,6 +523,6 @@ parseUnits(db, data)
 parseSummonSpecial(db, data)
 parseInventory(db, data)
 parseRunes(db, data)
+parseRuneCraft(db, data)
 parseGuild(db, data)
-# TODO rune_craft_item_list
 

+ 84 - 0
public/css/report_runecraft.css

@@ -0,0 +1,84 @@
+section.filters table{
+    border-collapse: collapse;
+}
+
+section.filters table td select#filter_grind_stat, select#filter_gem_stat_from, select#filter_gem_stat_to{
+    height: 16em;
+}
+
+section.filters td.filter_title{
+    font-weight: bold;
+    border-right: 0.2em solid #ffffff;
+    text-align: center;
+    vertical-align: bottom;
+    padding-bottom: 0.5em;
+}
+section.filters td.filter_title span{
+    display: block;
+    width: 0.8em;
+    word-break: break-all;
+    margin-top: 0em;
+    line-height: 90%;
+    text-align: left;
+}
+section.filters td.filter_separator{
+    border-top: 0.2em solid #ffffff;
+}
+section.filters select#filter_slot{
+    height: 10em;
+}
+
+section.content article{
+    text-align: left;
+}
+
+@media screen and (max-width : 990px){
+    section.content article{
+        width: 95%;
+        max-width: 95%;
+        margin: 0.2em auto;
+        display: block;
+    }
+}
+
+section.content article div.monster{
+    display: block;
+    width: 8em;
+}
+@media screen and (max-width : 990px){
+    section.content article div.monster{
+        display: block;
+        max-width: 100%;
+        width: initial;
+    }
+}
+
+section.content article div.monster_runes{
+    display:inline-block;
+    vertical-align: top;
+    width: 100%;
+}
+@media screen and (max-width : 990px){
+    section.content article div.monster_runes{
+        display: block;
+        max-width: 100%;
+    }
+}
+
+section.content article div.monster_runes > table.rune{
+    font-size: 80%;
+    max-width: 50%;
+    vertical-align: top;
+    margin: 0 -0.5em 0.5em 0.5em;
+}
+
+section.content article div.monster_runes div.craft{
+    display: inline-block;
+    vertical-align: top;
+    max-width: 45%;
+    min-width: 35%;
+    padding: 1em;
+    margin: 0 0 1em 0;
+    font-size: 80%;
+    background: linear-gradient(47deg, rgba(255,255,255,0.3) 0%, rgba(255,255,255,0.1) 50%, rgba(255,255,255,0) 70%);
+}

+ 82 - 0
public/css/ui.css

@@ -725,3 +725,85 @@ table.rune td.details table.table_details span.quality.quality_legend{
 /**
  * /Rune table
  */
+
+
+
+/**
+ * Craft item panel
+ */
+div.craft_panel{
+    width: 3em;
+    height: 3em;
+    border: 0.2em solid #000000;
+    border-radius: 0.5em;
+    position: relative;
+    text-align: center;
+    display: inline-block;
+}
+div.craft_panel.craft_quality_normal{ /* Normal */
+    background-image: repeating-radial-gradient(#ffffff, #cccccc 30%, #ffffff 60%);
+}
+div.craft_panel.craft_quality_magic{ /* Magic */
+    background-image: repeating-radial-gradient(#aaffaa, #88cc88 30%, #aaffaa 60%);
+}
+div.craft_panel.craft_quality_rare{ /* Rare */
+    background-image: repeating-radial-gradient(#aaaaff, #8888cc 30%, #aaaaff 60%);
+}
+div.craft_panel.craft_quality_hero{ /* Hero */
+    background-image: repeating-radial-gradient(#ffaacc, #cc88aa 30%, #ffaacc 60%);
+}
+div.craft_panel.craft_quality_legend{ /* Legend */
+    background-image: repeating-radial-gradient(#f48200, #b76201 30%, #f48200 60%);
+}
+div.craft_panel img.craft_base{
+    position: absolute;
+    width: 3em;
+    height: 3em;
+    margin: -0.5em;
+    top: 0.1em;
+    left: 0.5em;
+}
+div.craft_panel img.craft_icon{
+    position: absolute;
+    width: 1em;
+    height: 1em;
+    top: 0.6em;
+    left: 1em;
+}
+div.craft_panel.craft_ancient_1 img.craft_base{
+    filter: brightness(150%) contrast(90%) saturate(100%) drop-shadow(0 0 0.3em #ffffff) drop-shadow(0 0 0.1em #ffffff);
+}
+div.craft_panel.craft_quality_normal img.craft_base{
+    filter: sepia(100%) saturate(500%) grayscale(100%);
+}
+div.craft_panel.craft_quality_magic img.craft_base{
+    filter: sepia(100%) saturate(500%) hue-rotate(60deg);
+}
+div.craft_panel.craft_quality_rare img.craft_base{
+    filter: sepia(100%) saturate(500%) hue-rotate(120deg);
+}
+div.craft_panel.craft_quality_hero img.craft_base{
+    filter: sepia(100%) saturate(500%) hue-rotate(230deg);
+}
+div.craft_panel.craft_quality_legend img.craft_base{
+    filter: sepia(100%) saturate(500%) hue-rotate(330deg);
+}
+div.craft_panel span.craft_stat{
+    display: block;
+    width: 100%;
+    text-align: center;
+    font-size: 60%;
+    color: #ffffff;
+    text-shadow: 0 0 0.2em #000000, 0 0 0.2em #000000, 0 0 0.2em #000000, 0 0 0.2em #000000, 0 0 0.2em #000000;
+    position: absolute;
+    top: 2.7em;
+}
+div.craft_panel span.craft_stat span.craft_stat_name{
+    display: block;
+    margin: 0;
+}
+div.craft_panel span.craft_stat span.craft_stat_value{
+    display: block;
+    font-weight: bold;
+    margin: 0;
+}