Browse Source

Artifact data. Artifacts can be seen on the monster view. New cairos dungeons and level data added.

Iñigo Valentin 6 years ago
parent
commit
8574d6d361
35 changed files with 1051 additions and 113 deletions
  1. 153 3
      application/API/v2/bin/upload_profile.py
  2. 0 1
      application/API/v2/upload_profile.php
  3. 53 0
      application/Constant.php
  4. 0 7
      application/action/login.php
  5. 7 1
      application/action/new_team.php
  6. 1 0
      application/config.php
  7. 355 0
      application/entity/Artifact.php
  8. 9 83
      application/entity/K_Area.php
  9. 39 0
      application/entity/Unit.php
  10. 187 1
      application/helper/HTML_Helper.php
  11. BIN
      application/sw.sqlite
  12. 7 1
      application/view/monster.php
  13. 9 1
      application/view/teams.php
  14. 46 0
      install_data/install_base.sql
  15. 36 2
      install_data/install_data.sql
  16. 149 13
      public/css/ui.css
  17. BIN
      public/img/artifact/element_dark.png
  18. BIN
      public/img/artifact/element_fire.png
  19. BIN
      public/img/artifact/element_hero.png
  20. BIN
      public/img/artifact/element_legend.png
  21. BIN
      public/img/artifact/element_light.png
  22. BIN
      public/img/artifact/element_magic.png
  23. BIN
      public/img/artifact/element_normal.png
  24. BIN
      public/img/artifact/element_rare.png
  25. BIN
      public/img/artifact/element_water.png
  26. BIN
      public/img/artifact/element_wind.png
  27. BIN
      public/img/artifact/type_attack.png
  28. BIN
      public/img/artifact/type_defense.png
  29. BIN
      public/img/artifact/type_hero.png
  30. BIN
      public/img/artifact/type_hp.png
  31. BIN
      public/img/artifact/type_legend.png
  32. BIN
      public/img/artifact/type_magic.png
  33. BIN
      public/img/artifact/type_normal.png
  34. BIN
      public/img/artifact/type_rare.png
  35. BIN
      public/img/artifact/type_support.png

+ 153 - 3
application/API/v2/bin/upload_profile.py

@@ -110,6 +110,7 @@ def clearData(db, data):
         cursor.execute('DELETE FROM unit_skill WHERE unit IN (SELECT id FROM unit WHERE uid = ?)', [uid])
         cursor.execute('DELETE FROM unit WHERE uid = ?', [uid])
         cursor.execute('DELETE FROM rune WHERE uid = ?', [uid])
+        cursor.execute('DELETE FROM artifact WHERE uid = ?', [uid])
         cursor.execute('DELETE FROM building WHERE uid = ?', [uid])
         cursor.execute('DELETE FROM decoration WHERE uid = ?', [uid])
         cursor.execute('DELETE FROM inventory WHERE uid = ?', [uid])
@@ -714,7 +715,9 @@ def parseRunes(db, data):
             efficiency = 100;
         if max_efficiency > 100:
             max_efficiency = 100;
-        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))
+        # TODO: Locked status not in JSO file.
+        locked = 0
+        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, locked))
     # Equipped runes
     for mon in data["unit_list"]:
         for rune in mon["runes"]:
@@ -820,9 +823,151 @@ def parseRunes(db, data):
                 efficiency = 100;
             if max_efficiency > 100:
                 max_efficiency = 100;
-            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))
+            # TODO: Locked status not in JSO file.
+            locked = 0
+            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, locked))
     db.commit()
 
+"""
+Parses artifact data (table artifact).
+
+:param db: Sqlite database connection.
+:param data: Data in json format.
+"""
+def parseArtifacts(db, data):
+    print("Parsing artifacts...")
+    uid = data["wizard_info"]["wizard_id"]
+    # Unequipped artifacts
+    for artifact in data["artifacts"]:
+        id = artifact["rid"]
+        assigned_to = None
+        type = artifact["type"]
+        attribute = artifact["attribute"]
+        if attribute == 0:
+            attribute = None
+        archetype = artifact["unit_style"]
+        if archetype == 0:
+            archetype = None
+        level = artifact["level"]
+        quality = artifact["rank"]
+        original_quality = artifact["natural_rank"]
+        # TODO: Vaue not in JSON file. Can it be calculated?
+        value = 0;
+        main_stat = artifact["pri_effect"][0]
+        main_stat_value = artifact["pri_effect"][1]
+        locked = artifact["locked"]
+        if len(artifact["sec_effects"]) > 0:
+            effect_1 = artifact["sec_effects"][0][0]
+            effect_1_value = artifact["sec_effects"][0][1]
+            effect_1_enchant = artifact["sec_effects"][0][2]
+            effect_1_grind = artifact["sec_effects"][0][3]
+        else:
+            effect_1 = None
+            effect_1_value = 0
+            effect_1_enchant = 0
+            effect_1_grind = 0
+        if len(artifact["sec_effects"]) > 1:
+            effect_2 = artifact["sec_effects"][1][0]
+            effect_2_value = artifact["sec_effects"][1][1]
+            effect_2_enchant = artifact["sec_effects"][1][2]
+            effect_2_grind = artifact["sec_effects"][1][3]
+        else:
+            effect_2 = None
+            effect_2_value = 0
+            effect_2_enchant = 0
+            effect_2_grind = 0
+        if len(artifact["sec_effects"]) > 2:
+            effect_3 = artifact["sec_effects"][2][0]
+            effect_3_value = artifact["sec_effects"][2][1]
+            effect_3_enchant = artifact["sec_effects"][2][2]
+            effect_3_grind = artifact["sec_effects"][2][3]
+        else:
+            effect_3 = None
+            effect_3_value = 0
+            effect_3_enchant = 0
+            effect_3_grind = 0
+        if len(artifact["sec_effects"]) > 3:
+            effect_4 = artifact["sec_effects"][3][0]
+            effect_4_value = artifact["sec_effects"][3][1]
+            effect_4_enchant = artifact["sec_effects"][3][2]
+            effect_4_grind = artifact["sec_effects"][3][3]
+        else:
+            effect_4 = None
+            effect_4_value = 0
+            effect_4_enchant = 0
+            effect_4_grind = 0
+        # TODO: efficiences
+        efficiency = 0
+        max_efficiency = 0
+        insert(db, "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))
+    # Equipped artifacts
+    for mon in data["unit_list"]:
+        for artifact in mon["artifacts"]:
+            id = artifact["rid"]
+            assigned_to = artifact["occupied_id"]
+            if assigned_to == 0:
+                assigned_to = None
+            type = artifact["type"]
+            attribute = artifact["attribute"]
+            if attribute == 0:
+                attribute = None
+            archetype = artifact["unit_style"]
+            if archetype == 0:
+                archetype = None
+            level = artifact["level"]
+            quality = artifact["rank"]
+            original_quality = artifact["natural_rank"]
+            # TODO: Vaue not in JSON file. Can it be calculated?
+            value = 0;
+            main_stat = artifact["pri_effect"][0]
+            main_stat_value = artifact["pri_effect"][1]
+            locked = artifact["locked"]
+            if len(artifact["sec_effects"]) > 0:
+                effect_1 = artifact["sec_effects"][0][0]
+                effect_1_value = artifact["sec_effects"][0][1]
+                effect_1_enchant = artifact["sec_effects"][0][2]
+                effect_1_grind = artifact["sec_effects"][0][3]
+            else:
+                effect_1 = None
+                effect_1_value = 0
+                effect_1_enchant = 0
+                effect_1_grind = 0
+            if len(artifact["sec_effects"]) > 1:
+                effect_2 = artifact["sec_effects"][1][0]
+                effect_2_value = artifact["sec_effects"][1][1]
+                effect_2_enchant = artifact["sec_effects"][1][2]
+                effect_2_grind = artifact["sec_effects"][1][3]
+            else:
+                effect_2 = None
+                effect_2_value = 0
+                effect_2_enchant = 0
+                effect_2_grind = 0
+            if len(artifact["sec_effects"]) > 2:
+                effect_3 = artifact["sec_effects"][2][0]
+                effect_3_value = artifact["sec_effects"][2][1]
+                effect_3_enchant = artifact["sec_effects"][2][2]
+                effect_3_grind = artifact["sec_effects"][2][3]
+            else:
+                effect_3 = None
+                effect_3_value = 0
+                effect_3_enchant = 0
+                effect_3_grind = 0
+            if len(artifact["sec_effects"]) > 3:
+                effect_4 = artifact["sec_effects"][3][0]
+                effect_4_value = artifact["sec_effects"][3][1]
+                effect_4_enchant = artifact["sec_effects"][3][2]
+                effect_4_grind = artifact["sec_effects"][3][3]
+            else:
+                effect_4 = None
+                effect_4_value = 0
+                effect_4_enchant = 0
+                effect_4_grind = 0
+            # TODO: efficiences
+            efficiency = 0
+            max_efficiency = 0
+            insert(db, "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))
+        
+
 """
 calculates the max efficiency of a rune.
 
@@ -1132,7 +1277,12 @@ else:
     try:
         parseRunes(db, data)
     except Exception as e:
-        print("Error parsing runes data: " + str(e))
+        print("Error parsing rune data: " + str(e))
+        sys.exit(400)
+    try:
+        parseArtifacts(db, data)
+    except Exception as e:
+        print("Error parsing artifact data: " + str(e))
         sys.exit(400)
     try:
         parseRuneCraft(db, data)

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

@@ -62,7 +62,6 @@
         $out = [];
         $ret = 0;
         try{
-error_log ($cmd);
             exec($cmd, $out, $ret);
         }
         catch(Exception $e) {

+ 53 - 0
application/Constant.php

@@ -492,6 +492,16 @@
          */
         const NECROPOLIS = 6001;
 
+        /**
+         * Punisher's Crypt.
+         */
+        const PUNISHERS_CRYPT = 9502;
+
+        /**
+         * Steel Fortress
+         */
+        const STEEL_FORTRESS = 9602; // TODO: Find out
+
         /**
          * Hall of Light.
          */
@@ -1372,6 +1382,49 @@
         const ACC = 12;
     };
 
+    /**
+     * Artifact types.
+     *
+     * The two types of artifacts.
+     */
+    final class ARTIFACT_TYPE{
+
+        /**
+         * Elemental attribute.
+         */
+        const ELEMENT = 1;
+
+        /**
+         * Type artifact.
+         */
+        const ARCHETYPE = 2;
+     }
+    
+    /**
+     * Artifact stat constants.
+     *
+     * The stats an artifact can have. For unit stats, see{@see $STAT_ID}.
+     *
+     * @category Data
+     */
+    final class ARTIFACT_STAT_ID{
+
+        /**
+         * HP.
+         */
+        const HP = 100;
+
+        /**
+         * ATK.
+         */
+        const ATK = 101;
+
+        /**
+         * DEF.
+         */
+        const DEF = 102;
+    }
+
     /**
      * Rune (and other items) quality constants.
      *

+ 0 - 7
application/action/login.php

@@ -26,26 +26,20 @@
         global $db;
 
         if (!isset($_POST['uname'], $_POST['password'])){
-error_log("-1");
             return -1;
         }
         $uname = SQLite3::escapeString($_POST['uname']);
         if (strlen($uname) == 0){
-error_log("-2");
             return -2;
         }
         $password = SQLite3::escapeString($_POST['password']);
         if (strlen($password) == 0){
-error_log("-3");
             return -3;
         }
         $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"]);
         if (!$r){
-error_log("-4");
             return -4;
         }
         $uid = $r["uid"];
@@ -56,7 +50,6 @@ error_log("-4");
         $_SESSION['uid'] = $uid;
         header("Location: /$uid/");
         die();
-error_log("0");
         return 0;
     }
 ?>

+ 7 - 1
application/action/new_team.php

@@ -64,7 +64,13 @@
                 }
                 break;
             case AREA_TYPE_ID::CAIROS_DUNGEON:
-                if ($stage < 0 || $stage > 10){
+                if ($stage < 0){
+                    return -35;
+                }
+                if ($stage > 12 && ($stage == DUNGEON_ID::GIANTS_KEEP || $stage == DUNGEON_ID::DRAGONS_LAIR || $stage == DUNGEON_ID::NECROPOLIS)){
+                    return -35;
+                }
+                if ($stage > 10 && $stage =! DUNGEON_ID::GIANTS_KEEP && $stage =! DUNGEON_ID::DRAGONS_LAIR && $stage != DUNGEON_ID::NECROPOLIS){
                     return -35;
                 }
                 $difficulty = null;

+ 1 - 0
application/config.php

@@ -65,6 +65,7 @@
             "SKILL" => BASE_URL . "img/skill/",
             "ESSENCE" => BASE_URL . "img/essence/",
             "RUNE" => BASE_URL . "img/rune/",
+            "ARTIFACT" => BASE_URL . "img/artifact/",
             "GRIND" => BASE_URL . "img/grind/",
             "ELEMENT" => BASE_URL . "img/element/",
             "SKILL_GUILD" => BASE_URL . "img/skill_guild/",

+ 355 - 0
application/entity/Artifact.php

@@ -0,0 +1,355 @@
+<?php
+    /**
+     * Artifact entity file.
+     *
+     * Creates the entity and makes it available.
+     *
+     * @category Entity
+     */
+
+    /**
+     * Require dependent entities if not present.
+     */
+    require_once(PATH::ENTITY . "Entity.php");
+
+    /**
+     * Owned artifact.
+     *
+     * Represents an object from the table 'artifac'.
+     *
+     * @category Entity
+     */
+    class Artifact extends Entity{
+
+        /**
+         * @var int Owner identifier.
+         */
+        public $uid;
+
+        /**
+         * @var int Artifact identifier.
+         */
+        public $id;
+
+        /**
+         * @var int ID of the monster the rune is assigned to.
+         */
+        public $assigned_to;
+
+        /**
+         * @var int Artifact type (null if element artifact).
+         *
+         * @see ARTIFACT_TYPE
+         */
+        public $type;
+
+        /**
+         * @var int Artifact element (null if type artifact).
+         *
+         * @see ELEMENT_ID
+         */
+        public $element;
+
+        /**
+         * @var int Artifact archetype (null if elemental artifact).
+         *
+         * @see ARCHETYPE_ID
+         */
+        public $archetype;
+
+        /**
+         * @var int Level of the rune.
+         */
+        public $level;
+
+        /**
+         * @var int Artifact quality.
+         *
+         * @see QUALITY
+         */
+        public $quality;
+
+        /**
+         * @var int Artifact original quality.
+         *
+         * @see QUALITY
+         */
+        public $original_quality;
+
+        /**
+         * @var string Artifact quality name (uppercase).
+         */
+        public $quality_name;
+
+        /**
+         * @var string Artifact original quality name (uppercase).
+         */
+        public $original_quality_name;
+
+        /**
+         * @var int Price of the artifact.
+         */
+        public $value;
+
+        /**
+         * @var float Current efficiency of the artifact.
+         */
+        public $efficiency;
+
+        /**
+         * @var float Maximum potential efficiency of the artifact.
+         */
+        public $max_efficiency;
+
+        /**
+         * @var int Main stat of the artifact.
+         *
+         * @see STAT_ID
+         */
+        public $main_stat;
+
+        /**
+         * @var string Main stat name (uppercase).
+         */
+        public $main_stat_name;
+
+        /**
+         * @var int Main stat value of the artifact.
+         */
+        public $main_stat_value;
+
+        /**
+         * @var string Extra stat value of the artifact.
+         */
+        public $innate_stat_value;
+
+        /**
+         * @var int Number of substats.
+         */
+        public $substats;
+
+        /**
+         * @var int Effect 1 of the artifact.
+         */
+        public $effect_1;
+
+        /**
+         * @var int Effect 1 value of the artifact.
+         */
+        public $effect_1_value;
+
+        /**
+         * @var string Effect 1 description.
+         */
+        public $effect_1_description;
+
+        /**
+         * @var int Effect 2 of the artifact.
+         */
+        public $effect_2;
+
+        /**
+         * @var int Effect 2 value of the artifact.
+         */
+        public $effect_2_value;
+
+        /**
+         * @var string Effect 2 description.
+         */
+        public $effect_2_description;
+
+        /**
+         * @var int Effect 3 of the artifact.
+         */
+        public $effect_3;
+
+        /**
+         * @var int Effect 3 value of the artifact.
+         */
+        public $effect_3_value;
+
+        /**
+         * @var string Effect 3 description.
+         */
+        public $effect_3_description;
+
+        /**
+         * @var int Effect 4 of the artifact.
+         */
+        public $effect_4;
+
+        /**
+         * @var int Effect 4 value of the artifact.
+         */
+        public $effect_4_value;
+
+        /**
+         * @var string Effect 4 description.
+         */
+        public $effect_4_description;
+
+        /**
+         * Constructor.
+         *
+         * Searches the database and retrieves the information about the
+         * artifact, populating it and it's items.
+         *
+         * @param int $id Artifact id.
+         * @global resource Database connection.
+         */
+        public function __construct($id){
+
+            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);
+            if ($r){
+                $this->id = $r["id"];
+                $this->assigned_to = $r["assigned_to"];
+                $this->type = $r["type"];
+                $this->attribute = $r["attribute"];
+                $this->archetype = $r["archetype"];
+                $this->level = $r["level"];
+                $this->quality = $r["quality"];
+                $this->original_quality = $r["original_quality"];
+                $this->value = $r["value"];
+                $this->efficiency = $r["efficiency"];
+                $this->max_efficiency = $r["max_efficiency"];
+                $this->main_stat = $r["main_stat"];
+                $this->main_stat_value = $r["main_stat_value"];
+                $this->effect_1 = $r["effect_1"];
+                $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_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_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_value = $r["effect_4_value"];
+                //$this->effect_4_enchant = $r["effect_4_enchant"];
+                //$this->effect_4_grind = $r["effect_4_grind"];
+                $this->refresh_names();
+            }
+        }
+
+        /**
+         * Calculates name variables.
+         */
+        public function refresh_names(){
+            $this->main_stat_name = $this->stat_name($this->main_stat);
+            $this->effect_1_description = $this->effect_description($this->effect_1, $this->effect_1_value);
+            $this->effect_2_description = $this->effect_description($this->effect_2, $this->effect_2_value);
+            $this->effect_3_description = $this->effect_description($this->effect_3, $this->effect_3_value);
+            $this->effect_4_description = $this->effect_description($this->effect_4, $this->effect_4_value);
+            $this->quality_name = $this->get_quality_name($this->quality);
+            $this->original_quality_name = $this->get_quality_name($this->original_quality);
+        }
+
+        /**
+         * Gets a stat name from the mappings.
+         *
+         * @param int $stat Stat id.
+         * @return string Stat name (Uppercase)
+         */
+        private function stat_name($stat){
+            switch ($stat){
+                case ARTIFACT_STAT_ID::HP:
+                    return "HP";
+                case ARTIFACT_STAT_ID::ATK:
+                    return "ATK";
+                case ARTIFACT_STAT_ID::DEF:
+                    return "DEF";
+                default:
+                    return "";
+            }
+        }
+
+        /**
+         * Composes an effect description.
+         *
+         * @param int $effect Effect id.
+         * @param int $value Effect value.
+         * @return string Effect description, null if unavailable.
+         * @global resource Database connection.
+         */
+        private function effect_description($effect, $value){
+
+            global $db;
+
+            $s =
+              "SELECT name " .
+              "FROM k_artifact_effect " .
+              "WHERE id = '$effect'; ";
+            $q = $db->query($s);
+            $r = $q->fetchArray(SQLITE3_ASSOC);
+            if ($r){
+                return str_replace("{}", $value, $r["name"]);
+            }
+            else{
+                return null;
+            }
+        }
+
+        /**
+         * Gets the quality name from the mappings.
+         *
+         * @param int $q Quality id.
+         * @return string Quality (Uppercase)
+         */
+        private function get_quality_name($q){
+            switch ($q){
+                case QUALITY_ID::NORMAL:
+                    return "NORMAL";
+                case QUALITY_ID::MAGIC:
+                    return "MAGIC";
+                case QUALITY_ID::RARE:
+                    return "RARE";
+                case QUALITY_ID::HERO:
+                    return "HERO";
+                case QUALITY_ID::LEGEND:
+                    return "LEGEND";
+                default:
+                    return "";
+            }
+        }
+
+    }
+?>

+ 9 - 83
application/entity/K_Area.php

@@ -101,93 +101,19 @@
             elseif ($this->type == AREA_TYPE_ID::CAIROS_DUNGEON && APPLICATION::valid_id("DUNGEON_ID", $this->id)){
                 switch ($this->id){
                     case DUNGEON_ID::GIANTS_KEEP:
-                        switch ($stage){
-                            case 1:
-                            case 6:
-                                // Light
-                                return APPLICATION::img("UNIT", 60204);
-                                break;
-                            case 2:
-                            case 7:
-                                // Dark
-                                return APPLICATION::img("UNIT", 60204);
-                                break;
-                            case 3:
-                            case 8:
-                                // Wind
-                                return APPLICATION::img("UNIT", 60203);
-                                break;
-                            case 4:
-                            case 9:
-                                // Fire
-                                return APPLICATION::img("UNIT", 60202);
-                                break;
-                            case 5:
-                            case 10:
-                                // Water
-                                return APPLICATION::img("UNIT", 60201);
-                                break;
-                        }
+                        return APPLICATION::img("UNIT", 60201);
                         break;
                     case DUNGEON_ID::DRAGONS_LAIR:
-                        switch ($stage){
-                            case 1:
-                            case 6:
-                                // Wind
-                                return APPLICATION::img("UNIT", 60303);
-                                break;
-                                break;
-                            case 2:
-                            case 7:
-                                // Light
-                                return APPLICATION::img("UNIT", 60304);
-                                break;
-                            case 3:
-                            case 8:
-                                // Water
-                                return APPLICATION::img("UNIT", 60301);
-                                break;
-                            case 4:
-                            case 9:
-                                // Dark
-                                return APPLICATION::img("UNIT", 60305);
-                                break;
-                            case 5:
-                            case 10:
-                                // Fire
-                                return APPLICATION::img("UNIT", 60302);
-                                break;
-                        }
+                        return APPLICATION::img("UNIT", 60302);
                         break;
                     case DUNGEON_ID::NECROPOLIS:
-                        switch ($stage){
-                            case 1:
-                            case 6:
-                                // Water
-                                return APPLICATION::img("UNIT", 62101);
-                                break;
-                                break;
-                            case 2:
-                            case 7:
-                                // Fire
-                                return APPLICATION::img("UNIT", 62102);
-                                break;
-                            case 3:
-                            case 8:
-                                // Wind
-                                return APPLICATION::img("UNIT", 62103);
-                                break;
-                            case 4:
-                            case 9:
-                                // Light
-                                return APPLICATION::img("UNIT", 62104);
-                                break;
-                            case 5:
-                            case 10:
-                                // Dark
-                                return APPLICATION::img("UNIT", 62105);
-                                break;
-                        }
+                        return APPLICATION::img("UNIT", 62105);
+                        break;
+                    case DUNGEON_ID::STEEL_FORTRESS:
+                        return APPLICATION::img("UNIT", 62105); // TODO: Correct image.
+                        break;
+                    case DUNGEON_ID::PUNISHERS_CRYPT:
+                        return APPLICATION::img("UNIT", 62105); // TODO: Correct image.
                         break;
                     case DUNGEON_ID::HALL_OF_WATER:
                         return APPLICATION::img("UNIT", 60101);

+ 39 - 0
application/entity/Unit.php

@@ -14,6 +14,7 @@
     require_once(PATH::ENTITY . "K_Unit.php");
     require_once(PATH::ENTITY . "Team.php");
     require_once(PATH::ENTITY . "Rune.php");
+    require_once(PATH::ENTITY . "Artifact.php");
     require_once(PATH::ENTITY . "Building.php");
 
     /**
@@ -185,6 +186,16 @@
          */
         public $rune = [];
 
+        /**
+         * @var Artifact Type artifact equipped.
+         */
+        public $artifact_type;
+
+        /**
+         * @var Artifact Elemental artifact equipped.
+         */
+        public $artifact_element;
+
         /**
          * @var \Team[] The Teamss the unit is on.
          */
@@ -290,6 +301,7 @@
             $this->homunculus_name = $r["homunculus_name"];
             if ($complete){
                 $this->load_runes();
+                $this->load_artifacts();
                 $this->load_teams();
                 $this->check_storage();
                 $this->lock = $r["lock"];
@@ -414,6 +426,33 @@
             $this->rune_hp = ceil($this->rune_hp);
         }
 
+        /**
+         * Loads the information about the equiped artifacts. 
+         * It is autoatically called at construction time if the
+         * $complete parameter is true (by default). No point in calling it
+         * twice.
+         *
+         * @global resource Database connection.
+         */
+        public function load_artifacts(){
+            global $db;
+            $s =
+              "SELECT id " .
+              "FROM artifact " .
+              "WHERE assigned_to = '$this->id'; ";
+            $q = $db->query($s);
+            while ($r = $q->fetchArray(SQLITE3_ASSOC)){
+                $artifact = new Artifact($r["id"]);
+                if ($artifact->type == ARTIFACT_TYPE::ARCHETYPE){
+                    $this->artifact_type = $artifact;
+                }
+                else{
+                    $this->artifact_element = $artifact;
+                }
+                $this->sum_rune_stat($artifact->main_stat, $artifact->main_stat_value);
+            }
+        }
+
         /**
          * Calculates the stat increase by a rune property.
          * 

+ 187 - 1
application/helper/HTML_Helper.php

@@ -18,6 +18,7 @@
     require_once(PATH::ENTITY . "Decoration.php");
     require_once(PATH::ENTITY . "K_Decoration.php");
     require_once(PATH::ENTITY . "Rune.php");
+    require_once(PATH::ENTITY . "Artifact.php");
     require_once(PATH::ENTITY . "Rune_Craft.php");
     require_once(PATH::ENTITY . "Inventory.php");
 
@@ -297,7 +298,7 @@
             $html .= "</tr>\n";
             $html .= "<tr>\n";
             $html .= "<td class='title'>\n";
-            $html .= "Origina q.:\n";
+            $html .= "Original q.:\n";
             $html .= "</td>\n";
             $html .= "<td class='value'>\n";
             $html .= "<span class='quality quality_" . strtolower($rune->original_quality_name) . "'>\n";
@@ -344,6 +345,191 @@
             return $html;
         }
 
+        // TODO: Icon and background selection must go in the entity code.
+        /**
+         * Generates an artifact panel.
+         * 
+         * @param Artifact artifact Entity to get the info from.
+         * @param Unit unit Optional. The unit the artifact is assigned to.
+         * @return string HTML content for an artifact panel. Empty on error.
+         */
+        public static function artifact_panel($artifact, $unit = null) {
+            if (!($artifact instanceof Artifact)){
+                return "";
+            }
+            $html = "";
+            $html .= "<div class='artifact_panel artifact_level_" . $artifact->level . " artifact_quality_" . strtolower($artifact->quality_name) . " artifact_original_quality_" . strtolower($artifact->original_quality_name) . " '>\n";
+            $background = "";
+            $icon = "";
+            if ($artifact->type == ARTIFACT_TYPE::ARCHETYPE){
+                $background = URL::IMG["ARTIFACT"] . "type_" . strtolower($artifact->quality_name) . ".png";
+                $icon = URL::IMG["ARTIFACT"] . "type_";
+                switch ($artifact->type){
+                    case ARCHETYPE_ID::ATTACK:
+                        $icon .= "attack";
+                        break;
+                    case ARCHETYPE_ID::DEFENSE:
+                        $icon .= "defense";
+                        break;
+                    case ARCHETYPE_ID::HP:
+                        $icon .= "hp";
+                        break;
+                    case ARCHETYPE_ID::SUPPORT:
+                        $icon .= "support";
+                        break;
+                }
+                $icon .= ".png";
+            }
+            else{
+                $background = URL::IMG["ARTIFACT"] . "element_" . strtolower($artifact->quality_name) . ".png";
+                $icon = URL::IMG["ARTIFACT"] . "element_";
+                switch ($artifact->attribute){
+                    case ELEMENT_ID::WATER:
+                        $icon .= "water";
+                        break;
+                    case ELEMENT_ID::WIND:
+                        $icon .= "wind";
+                        break;
+                    case ELEMENT_ID::FIRE:
+                        $icon .= "fire";
+                        break;
+                    case ELEMENT_ID::LIGHT:
+                        $icon .= "light";
+                        break;
+                    case ELEMENT_ID::DARK:
+                        $icon .= "dark";
+                        break;
+                }
+                $icon .= ".png";
+            }
+            $html .= "<img class='artifact_base' src='" . $background . "'/>\n";
+            $html .= "<img class='artifact_icon' src='" . $icon . "'/>\n";
+            $html .= "<span class='artifact_stars'>\n";
+            $html .= "</span>\n";
+            $html .= "<span class='artifact_level'>\n";
+            $html .= $artifact->level . "\n";
+            $html .= "</span>\n";
+            $html .= "</div>\n";
+            if ($unit instanceof Unit){
+                $html .= "<div class='assigned'>\n";
+                $html .= "<a target='blank' href='/monsters/" . $unit->id . "'>\n";
+                $html .= "<img title='" . $unit->title . "' class='monster_image border_" . $unit->unit->element_name . "' src='" . $unit->unit->get_image() . "'/>\n";
+                $html .= "</a>\n";
+                $html .= "</div>\n";
+            }
+            return $html;
+        }
+
+        /**
+         * Generates a artifact table.
+         * 
+         * @param Artifact artifact Entity to get the info from.
+         * @param Unit unit Optional. The unit the artifact is assigned to.
+         * @return string HTML content for a artifact table. Empty on error.
+         */
+        public static function artifact_table($artifact, $unit = null) {
+            if (!($artifact instanceof Artifact)){
+                return "";
+            }
+            $html = "";
+            $html .= "<table class='artifact' id='artifact-" . $artifact->id . "'>\n";
+            $html .= "<tr>\n";
+            $html .= "<td class='icon'>\n";
+            $html .= HTML::artifact_panel($artifact, $unit) . "\n";
+            $html .= "</td>\n";
+            $html .= "<td class='effects'>\n";
+            $html .= "<table>\n";
+            // Main stat
+            $html .= "<tr class='effect main_stat'>\n";
+            $html .= "<td class='effect'>\n";
+            $stat_name = $artifact->main_stat_name;
+            $stat_value = "+ " . $artifact->main_stat_value;
+            $html .= $stat_name . "\n";
+            $html .= $stat_value . "\n";
+            $html .= "</td>\n";
+            $html .= "</tr>\n";
+            $effects = array($artifact->effect_1_description, $artifact->effect_2_description, $artifact->effect_3_description, $artifact->effect_4_description);
+            for ($i = 0; $i < 4; $i ++){
+                $html .= "<tr class='effect'>\n";
+                $html .= "<td class='effect'>\n";
+                $html .= $effects[$i];
+                $html .= "</td>\n";
+                $html .= "</tr>\n";
+            }
+            $html .= "</table>\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 .= "</table>\n";
+            return $html;
+        }
+
         /**
          * Generates a grindstone or gem panel.
          * 

BIN
application/sw.sqlite


+ 7 - 1
application/view/monster.php

@@ -445,9 +445,15 @@
         <section id='runes' class='list'>
             <h2>
                 <span>
-                    Runes
+                    Runes and Artifacts
                 </span>
             </h2>
+            <article>
+                <?=HTML::artifact_table($page->unit->artifact_type)?>
+            </article>
+            <article>
+                <?=HTML::artifact_table($page->unit->artifact_element)?>
+            </article>
 <?php
             $total_efficiency = 0;
             $total_max_efficiency = 0;

+ 9 - 1
application/view/teams.php

@@ -576,7 +576,13 @@
                         break;
                     case '<?=AREA_TYPE_ID::CAIROS_DUNGEON?>':
                         document.getElementById('new_area_stage').style.display = 'inline';
-                        populateStage(10);
+                        var area = document.getElementById('new_area_cairos_dungeon').options[document.getElementById('new_area_cairos_dungeon').selectedIndex].value;
+                        if (area == <?=DUNGEON_ID::GIANTS_KEEP?> || area == <?=DUNGEON_ID::DRAGONS_LAIR?> || area == <?=DUNGEON_ID::NECROPOLIS?>){
+                            populateStage(12);
+                        }
+                        else{
+                            populateStage(10);
+                        }
                         populateDifficulty();
                         break;
                     case '<?=AREA_TYPE_ID::RIFT_DUNGEON?>':
@@ -792,6 +798,8 @@
                                 <option value='<?=DUNGEON_ID::GIANTS_KEEP?>'>Giant&#39;s Keep</option>
                                 <option value='<?=DUNGEON_ID::DRAGONS_LAIR?>'>Dragon&#39;s Lair</option>
                                 <option value='<?=DUNGEON_ID::NECROPOLIS?>'>Necropolis</option>
+                                <option value='<?=DUNGEON_ID::STEEL_FORTRESS?>'>Steel Fortress</option>
+                                <option value='<?=DUNGEON_ID::PUNISHERS_CRYPT?>'>Punisher&#39;s Crypt</option>
                                 <option value='<?=DUNGEON_ID::HALL_OF_MAGIC?>'>Hall of Magic</option>
                                 <option value='<?=DUNGEON_ID::HALL_OF_FIRE?>'>Hall of Fire</option>
                                 <option value='<?=DUNGEON_ID::HALL_OF_WATER?>'>Hall of Water</option>

+ 46 - 0
install_data/install_base.sql

@@ -563,6 +563,52 @@ INSERT INTO k_quality VALUES(2,'Magic');
 INSERT INTO k_quality VALUES(3,'Rare');
 INSERT INTO k_quality VALUES(4,'Hero');
 INSERT INTO k_quality VALUES(5,'Legend');
+CREATE TABLE k_artifact_effect(
+    id INT NOT NULL PRIMARY KEY,
+    name TEXT UNIQUE
+);
+INSERT INTO k_artifact_effect VALUES (200, 'ATK+ Proportional to Lost HP up to {}%');
+INSERT INTO k_artifact_effect VALUES (201, 'DEF+ Proportional to Lost HP up to {}%');
+INSERT INTO k_artifact_effect VALUES (202, 'SPD+ Proportional to Lost HP up to {}%');
+INSERT INTO k_artifact_effect VALUES (203, 'SPD Under Inability +{}%');
+INSERT INTO k_artifact_effect VALUES (204, 'ATK Increasing Effect +{}%');
+INSERT INTO k_artifact_effect VALUES (205, 'DEF Increasing Effect +{}%');
+INSERT INTO k_artifact_effect VALUES (206, 'SPD Increasing Effect +{}%');
+INSERT INTO k_artifact_effect VALUES (207, 'CRIT Rate Increasing Effect +{}%');
+INSERT INTO k_artifact_effect VALUES (208, 'Damage Dealt by Counterattack +{}%');
+INSERT INTO k_artifact_effect VALUES (209, 'Damage Dealt by Attacking Together +{}%');
+INSERT INTO k_artifact_effect VALUES (210, 'Bomb Damage +{}%');
+INSERT INTO k_artifact_effect VALUES (211, 'Damage Dealt by Reflect DMG +{}%');
+INSERT INTO k_artifact_effect VALUES (212, 'Crushing Hit DMG +{}%');
+INSERT INTO k_artifact_effect VALUES (213, 'Damage Received Under Inability -{}%');
+INSERT INTO k_artifact_effect VALUES (214, 'CRIT DMG Received -{}%');
+INSERT INTO k_artifact_effect VALUES (215, 'Life Drain +{}%');
+INSERT INTO k_artifact_effect VALUES (216, 'HP when Revived +{}%');
+INSERT INTO k_artifact_effect VALUES (217, 'Attack Bar when Revived +{}%');
+INSERT INTO k_artifact_effect VALUES (218, 'Additional Damage by {}% of HP');
+INSERT INTO k_artifact_effect VALUES (219, 'Additional Damage by {}% of ATK');
+INSERT INTO k_artifact_effect VALUES (220, 'Additional Damage by {}% of DEF');
+INSERT INTO k_artifact_effect VALUES (221, 'Additional Damage by {}% of SPD');
+INSERT INTO k_artifact_effect VALUES (300, 'Damage Dealt on Fire +{}%');
+INSERT INTO k_artifact_effect VALUES (301, 'Damage Dealt on Water +{}%');
+INSERT INTO k_artifact_effect VALUES (302, 'Damage Dealt on Wind +{}%');
+INSERT INTO k_artifact_effect VALUES (303, 'Damage Dealt on Light +{}%');
+INSERT INTO k_artifact_effect VALUES (304, 'Damage Dealt on Dark +{}%');
+INSERT INTO k_artifact_effect VALUES (305, 'Damage Received from Fire -{}%');
+INSERT INTO k_artifact_effect VALUES (306, 'Damage Received from Water -{}%');
+INSERT INTO k_artifact_effect VALUES (307, 'Damage Received from Wind -{}%');
+INSERT INTO k_artifact_effect VALUES (308, 'Damage Received from Light -{}%');
+INSERT INTO k_artifact_effect VALUES (309, 'Damage Received from Dark -{}%');
+INSERT INTO k_artifact_effect VALUES (400, '[Skill 1] CRIT DMG +{}%');
+INSERT INTO k_artifact_effect VALUES (401, '[Skill 2] CRIT DMG +{}%');
+INSERT INTO k_artifact_effect VALUES (402, '[Skill 3] CRIT DMG +{}%');
+INSERT INTO k_artifact_effect VALUES (403, '[Skill 4] CRIT DMG +{}%');
+INSERT INTO k_artifact_effect VALUES (404, '[Skill 1] Recovery +{}%');
+INSERT INTO k_artifact_effect VALUES (405, '[Skill 2] Recovery +{}%');
+INSERT INTO k_artifact_effect VALUES (406, '[Skill 3] Recovery +{}%');
+INSERT INTO k_artifact_effect VALUES (407, '[Skill 1] Accuracy +{}%');
+INSERT INTO k_artifact_effect VALUES (408, '[Skill 2] Accuracy +{}%');
+INSERT INTO k_artifact_effect VALUES (409, '[Skill 3] Accuracy +{}%');
 CREATE TABLE k_craft(
     id INT NOT NULL PRIMARY KEY,
     name TEXT UNIQUE

+ 36 - 2
install_data/install_data.sql

@@ -91,7 +91,7 @@ CREATE TABLE rune(
     efficiency FLOAT NOT NULL CHECK(efficiency BETWEEN 0 AND 100),
     max_efficiency FLOAT NOT NULL CHECK(max_efficiency BETWEEN 0 AND 100),
     main_stat INT NOT NULL REFERENCES k_rune_stat(id),
-    main_stat_value INT NOT NULL CHECK(value > 0),
+    main_stat_value INT NOT NULL CHECK(main_stat_value > 0),
     innate_stat INT REFERENCES k_rune_stat(id),
     innate_stat_value INT CHECK(innate_stat_value >= 0),
     substat_1 INT REFERENCES k_rune_stat(id),
@@ -109,7 +109,41 @@ CREATE TABLE rune(
     substat_4 INT REFERENCES k_rune_stat(id),
     substat_4_value INT CHECK(substat_4_value >= 0),
     substat_4_enchant INT CHECK(substat_4_enchant IN (0, 1)),
-    substat_4_grind INT CHECK(substat_4_grind >= 0)
+    substat_4_grind INT CHECK(substat_4_grind >= 0),
+    locked INT NOT NULL CHECK(locked IN (0, 1))
+);
+CREATE TABLE artifact(
+    uid INT NOT NULL REFERENCES player(id),
+    id INT PRIMARY KEY NOT NULL,
+    assigned_to INT REFERENCES unit(id),
+    type INT REFERENCES k_archetype(id),
+    attribute INT REFERENCES k_element(id),
+    archetype INT REFERENCES k_archetype(id),
+    level INT NOT NULL CHECK(level BETWEEN 0 AND 15),
+    quality INT NOT NULL REFERENCES k_quality(id),
+    original_quality INT NOT NULL REFERENCES k_quality(id),
+    value INT NOT NULL CHECK(value >= 0),
+    efficiency FLOAT NOT NULL CHECK(efficiency BETWEEN 0 AND 100),
+    max_efficiency FLOAT NOT NULL CHECK(max_efficiency BETWEEN 0 AND 100),
+    main_stat INT NOT NULL REFERENCES k_stat(id),
+    main_stat_value INT NOT NULL CHECK(main_stat_value > 0),
+    effect_1 INT REFERENCES k_artiffact_effect(id),
+    effect_1_value INT CHECK(effect_1_value >= 0),
+    effect_1_enchant INT,
+    effect_1_grind INT,
+    effect_2 INT REFERENCES k_artiffact_effect(id),
+    effect_2_value INT CHECK(effect_2_value >= 0),
+    effect_2_enchant INT,
+    effect_2_grind INT,
+    effect_3 INT REFERENCES k_artiffact_effect(id),
+    effect_3_value INT CHECK(effect_3_value >= 0),
+    effect_3_enchant INT,
+    effect_3_grind INT,
+    effect_4 INT REFERENCES k_artiffact_effect(id),
+    effect_4_value INT CHECK(effect_4_value >= 0),
+    effect_4_enchant INT,
+    effect_4_grind INT,
+    locked INT NOT NULL CHECK(locked IN (0, 1))
 );
 CREATE TABLE inventory(
     uid INT NOT NULL REFERENCES player(id),

+ 149 - 13
public/css/ui.css

@@ -417,19 +417,19 @@ div.rune_panel{
     position: relative;
     text-align: center;
 }
-div.rune_panel.rune_quality_normal{ /* Normal */
+div.rune_panel.rune_original_quality_normal{ /* Normal */
     background-image: repeating-radial-gradient(#ffffff, #cccccc 30%, #ffffff 60%);
 }
-div.rune_panel.rune_quality_magic{ /* Magic */
+div.rune_panel.rune_original_quality_magic{ /* Magic */
     background-image: repeating-radial-gradient(#aaffaa, #88cc88 30%, #aaffaa 60%);
 }
-div.rune_panel.rune_quality_rare{ /* Rare */
+div.rune_panel.rune_original_quality_rare{ /* Rare */
     background-image: repeating-radial-gradient(#aaaaff, #8888cc 30%, #aaaaff 60%);
 }
-div.rune_panel.rune_quality_hero{ /* Hero */
+div.rune_panel.rune_original_quality_hero{ /* Hero */
     background-image: repeating-radial-gradient(#ffaacc, #cc88aa 30%, #ffaacc 60%);
 }
-div.rune_panel.rune_quality_legend{ /* Legend */
+div.rune_panel.rune_original_quality_legend{ /* Legend */
     background-image: repeating-radial-gradient(#f48200, #b76201 30%, #f48200 60%);
 }
 div.rune_panel img.rune_base{
@@ -475,11 +475,11 @@ div.rune_panel.rune_slot_6 img.rune_icon{
     top: 2.9em;
     left: 3.3em;
 }
-div.rune_panel.rune_original_quality_normal img.rune_icon{filter: sepia(100%) saturate(500%) grayscale(100%);}
-div.rune_panel.rune_original_quality_magic img.rune_icon{filter: sepia(100%) saturate(500%) hue-rotate(60deg);}
-div.rune_panel.rune_original_quality_rare img.rune_icon{filter: sepia(100%) saturate(500%) hue-rotate(120deg);}
-div.rune_panel.rune_original_quality_hero img.rune_icon{filter: sepia(100%) saturate(500%) hue-rotate(230deg);}
-div.rune_panel.rune_original_quality_legend img.rune_icon{filter: sepia(100%) saturate(500%) hue-rotate(330deg);}
+div.rune_panel.rune_quality_normal img.rune_icon{filter: sepia(100%) saturate(500%) grayscale(100%);}
+div.rune_panel.rune_quality_magic img.rune_icon{filter: sepia(100%) saturate(500%) hue-rotate(60deg);}
+div.rune_panel.rune_quality_rare img.rune_icon{filter: sepia(100%) saturate(500%) hue-rotate(120deg);}
+div.rune_panel.rune_quality_hero img.rune_icon{filter: sepia(100%) saturate(500%) hue-rotate(230deg);}
+div.rune_panel.rune_quality_legend img.rune_icon{filter: sepia(100%) saturate(500%) hue-rotate(330deg);}
 div.rune_panel span.rune_stars{
     position: absolute;
     width: 9em;
@@ -511,6 +511,64 @@ div.rune_panel.rune_level_15 span.rune_level{color: #ff6f2d;}
  */
 
 
+/**
+ * Artifact boxes
+ */
+div.artifact_panel{
+    width: 8em;
+    height: 8em;
+    border: 0.2em solid #000000;
+    border-radius: 1em;
+    position: relative;
+    text-align: center;
+}
+div.artifact_panel.artifact_original_quality_normal{ /* Normal */
+    background-image: repeating-radial-gradient(#ffffff, #cccccc 30%, #ffffff 60%);
+}
+div.artifact_panel.artifact_original_quality_magic{ /* Magic */
+    background-image: repeating-radial-gradient(#aaffaa, #88cc88 30%, #aaffaa 60%);
+}
+div.artifact_panel.artifact_original_quality_rare{ /* Rare */
+    background-image: repeating-radial-gradient(#aaaaff, #8888cc 30%, #aaaaff 60%);
+}
+div.artifact_panel.artifact_original_quality_hero{ /* Hero */
+    background-image: repeating-radial-gradient(#ffaacc, #cc88aa 30%, #ffaacc 60%);
+}
+div.artifact_panel.artifact_original_quality_legend{ /* Legend */
+    background-image: repeating-radial-gradient(#f48200, #b76201 30%, #f48200 60%);
+}
+div.artifact_panel img.artifact_base{
+    position: absolute;
+    width: 8em;
+    height: 8em;
+    margin: 0;
+    top: 0.1em;
+    left: 0;
+}
+div.artifact_panel img.artifact_icon{
+    position: absolute;
+    height: 4em;
+    top: 2em;
+    left: 2em;
+}
+div.artifact_panel.artifact_level_15 span.artifact_stars img.star{filter: sepia(100%) saturate(300%) hue-rotate(320deg) saturate(400%) drop-shadow(0 0 0.1em #000000) drop-shadow(0 0 0.1em #000000);}
+div.artifact_panel span.artifact_level{
+    font-size: 130%;
+    font-weight: bold;
+    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: relative;
+    top: 4.7em;
+    left: 1.5em;
+}
+div.artifact_panel span.artifact_level::before {
+  content: "+";
+}
+div.artifact_panel.artifact_level_15 span.artifact_level{color: #ff6f2d;}
+/**
+ * /Artifact boxes
+ */
+
+
 /**
  * Monster panel
  */
@@ -656,9 +714,9 @@ div.monster_transformation_panel img.monster_transformation{
  */
  
  
- /**
-  * Rune table
-  */
+/**
+ * Rune table
+ */
 table.rune{
     border-collapse: collapse;
     display: inline-block;
@@ -754,6 +812,84 @@ table.rune td.details table.table_details span.quality.quality_legend{background
  */
 
 
+/**
+ * Artifact table
+ */
+table.artifact{
+    border-collapse: collapse;
+    display: inline-block;
+    vertical-align: top;
+    font-size: 80%;
+    position: relative;
+    border-radius: 1em;
+    margin: 0.5em;
+    background-color: #7d6640;
+    font-size: 70%;
+    border: 0.3em solid #3c2929;
+}
+table.artifact td.icon div.assigned{
+    max-width: 2.5em;
+    max-height: 2.5em;
+    position: absolute;
+    left: 0.5em;
+    bottom: 1em;
+}
+table.artifact td.icon div.assigned img.monster_image{
+    width: 2.5em;
+    height: 2.5em;
+    border-style: solid;
+    border-width: 0.2em;
+    border-radius: 15%;
+}
+table.artifact td.icon div.artifact_panel{font-size: 70%;}
+/* TODO: While no details panel, stats can be wider. Normaly is 8em*/
+table.artifact td.effects{
+    width: 21.5em;
+    text-align: left;
+}
+
+table.artifact td.effects table{font-size: 90%;}
+
+table.artifact td.effects table tr.main_stat{
+    font-weight: bold;
+    font-size: 110%;
+}
+
+table.artifact td.details{
+    padding-left: 0.5em;
+    width: 16em;
+    font-size: 80%;
+}
+
+table.artifact td.details table.table_details td.title{text-align: right;}
+table.artifact td.details table.table_details td.value{
+    text-align: left;
+    padding-left: 1em;
+}
+
+table.artifact td.details table.table_details span.quality{
+    border: 0.1em solid #000000;
+    border-radius: 0.2em;
+    font-weight: bold;
+    text-shadow: 0 0 0.1em #000000;
+    padding: 0 0.3em;
+    width: 5em;
+}
+
+table.artifact td.details table.table_details span.quality.quality_normal{background-color: #cccccc;}
+
+table.artifact td.details table.table_details span.quality.quality_magic{background-color: #55ff55;}
+
+table.artifact td.details table.table_details span.quality.quality_rare{background-color: #15c6e1;}
+
+table.artifact td.details table.table_details span.quality.quality_hero{background-color: #ad7fa8;}
+
+table.artifact td.details table.table_details span.quality.quality_legend{background-color: #f57900;}
+/**
+ * /Artifact table
+ */
+
+
 
 /**
  * Craft item panel

BIN
public/img/artifact/element_dark.png


BIN
public/img/artifact/element_fire.png


BIN
public/img/artifact/element_hero.png


BIN
public/img/artifact/element_legend.png


BIN
public/img/artifact/element_light.png


BIN
public/img/artifact/element_magic.png


BIN
public/img/artifact/element_normal.png


BIN
public/img/artifact/element_rare.png


BIN
public/img/artifact/element_water.png


BIN
public/img/artifact/element_wind.png


BIN
public/img/artifact/type_attack.png


BIN
public/img/artifact/type_defense.png


BIN
public/img/artifact/type_hero.png


BIN
public/img/artifact/type_hp.png


BIN
public/img/artifact/type_legend.png


BIN
public/img/artifact/type_magic.png


BIN
public/img/artifact/type_normal.png


BIN
public/img/artifact/type_rare.png


BIN
public/img/artifact/type_support.png