Jelajahi Sumber

Optimizer main page and team scores.

Iñigo Valentin 5 tahun lalu
induk
melakukan
9a2a03bdc1

+ 1265 - 0
application/Constant.php

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

+ 15 - 1
application/Controller.php

@@ -115,6 +115,11 @@
                         action();
                         return;
                         break;
+                    case "OPTIMIZE":
+                        require_once(PATH::ACTION . "optimize.php");
+                        action();
+                        return;
+                        break;
                     case "EDIT_PROFILE":
                         require_once(PATH::ACTION . "edit_profile.php");
                         $response = action();
@@ -260,7 +265,16 @@
                         require_once(PATH::PAGE . "Report_Runecraft_Page.php");
                         $page = new Report_Runecraft_Page($pars[1]);
                     }
-
+                }
+                elseif (strtoupper($pars[0]) == "OPTIMIZER"){
+                    if (count($pars) == 1){
+                        require_once(PATH::PAGE . "Optimizer_Page.php");
+                        $page = new Optimizer_Page();
+                    }
+                    else{
+                        require_once(PATH::PAGE . "Optimizer_Unit_Page.php");
+                        $page = new Optimizer_Unit_Page($pars[1]);
+                    }
                 }
             }
             // Load the view, or set an error code.

+ 3 - 1
application/action/new_team.php

@@ -43,6 +43,7 @@
         $leader_id = filter_input(INPUT_POST, 'leader');
         $total_front = filter_input(INPUT_POST, 'front');
         $description = filter_input(INPUT_POST, 'description');
+        $score = 0;
         $id = preg_split("/[\s,]+/", $ids);
         $id_count = sizeof($id);
         if ($name == null || strlen($name) == 0){
@@ -170,7 +171,7 @@
         $q = $db->query($s);
         $r = $q->fetchArray(SQLITE3_ASSOC);
         $team_id = $r["id"];
-        $statement = $db->prepare('INSERT INTO team (uid, id, name, description, area_type, area, stage, difficulty) VALUES (:uid, :id, :name, :description, :area_type, :area, :stage, :difficulty);');
+        $statement = $db->prepare('INSERT INTO team (uid, id, name, description, area_type, area, stage, difficulty, score) VALUES (:uid, :id, :name, :description, :area_type, :area, :stage, :difficulty, :score);');
         $statement->bindValue(':uid', $player);
         $statement->bindValue(':id', $team_id);
         $statement->bindValue(':name', $name);
@@ -179,6 +180,7 @@
         $statement->bindValue(':area', $area);
         $statement->bindValue(':stage', $stage);
         $statement->bindValue(':difficulty', $difficulty);
+        $statement->bindValue(':score', $score);
         $res = $statement->execute();
         if (!$res){
             return -5;

+ 139 - 0
application/action/optimize.php

@@ -0,0 +1,139 @@
+<?php
+
+    /**
+     * File for the optimization action.
+     *
+     * Implements an action function to be called from the {@see Controller}.
+     * 
+     * @category Action
+     */
+
+    /**
+     * Executes the optimization action.
+     *
+     * Reads the POST parameters looking for the following KEYS:
+     *  mail
+     *  pass + currentPass
+     *  api
+     * Then it updates the selected info with the prameter vlue. Multiple
+     * itemas can be updated at the same time.
+     * 
+     * @return int|string 0 on success, negative values on error. If the API
+     * key has been updated, the new key.
+     * @category Action
+     * @global resource Database connection.
+     */
+    function action(){
+
+        global $db;
+
+        $response = null;
+
+        $uid = filter_input(INPUT_POST, 'uid');
+        if ($uid == null){
+error_log("-1");
+            return -1;
+        }
+
+        $unit = filter_input(INPUT_POST, 'unit');
+        if ($uid == null){
+error_log("-2");
+            return -2;
+        }
+
+        // Sets
+        // TODO: Check if valid.
+        // TODO: Check if compatible sets, not just size.
+        $sets = [];
+        foreach ($_POST["set"] as $x){
+            array_push($sets, intval($x));
+        }
+        if (sizeof($sets) < 2 || sizeof($sets) > 3){
+error_log("-3");
+            return -3;
+        }
+
+        // Main stats in even slots.
+        // TODO: Check if valid.
+        // TODO: Check if valid per slot
+        $stats = [];
+        foreach ($_POST["stat"] as $x){
+            array_push($stats, intval($x));
+        }
+
+        $source = filter_input(INPUT_POST, 'source');
+        if ($source == null){
+error_log("-4");
+            return -4;
+        }
+
+        $tuning = filter_input(INPUT_POST, 'tuning');
+        if ($tuning == null){
+error_log("-5");
+            return -5;
+        }
+
+        // Get optimization id and create the view:
+        $optmization_id = $uid . "-" . $unit . "-" . rand(0,1000);
+        $db->query($s);
+        $s = "
+          SELECT *
+          FROM rune
+          WHERE
+            uid = $uid AND
+            set IN (
+        ";
+        foreach ($sets as $set){
+            $s .= ($set . ",");
+        }
+        $s .= "-1) AND ";
+        switch ($source){
+            case 0: // Storage only
+                $s .= "assigned_to IS NULL";
+                break;
+            case 1: // Units in no teams
+                $s .= "
+                  (
+                    assigned_to IS NULL OR 
+                    assigned_to NOT IN (SELECT DISTINCT unit FROM team_unit)
+                  )
+                ";
+                break;
+            case 2: // Units in teams with 0 score
+                $s .= "
+                  (
+                    assigned_to IS NULL OR 
+                    assigned_to NOT IN (SELECT DISTINCT unit FROM team_unit) OR
+                    assigned_to NOT IN (
+                      SELECT DISTINCT unit 
+                      FROM
+                        team,
+                        team_unit
+                      WHERE
+                        team.id = team_unit.team AND
+                        team.score > 0
+                    )
+                  )
+                ";
+                break;
+            case 3: // Units with lower overall score
+                // TODO
+                break;
+            case 4: // All runes - dont filter
+                $s .= " 1 = 1 ";
+                break;
+            default: // Invalid options - return nothing
+                $s .= " 1 = 0 ";
+        }
+
+error_log($s);
+        $response = $s;
+
+        if ($response == null){
+            return 0;
+        }
+        else{
+            return $response;
+        }
+    }
+?>

+ 2 - 1
application/action/save_run_team.php

@@ -40,7 +40,7 @@
         if (!$r){
             return -2;
         }
-        $statement = $db->prepare('INSERT INTO team (uid, id, name, description, area_type, area, stage, difficulty) VALUES (:uid, :id, :name, :description, :area_type, :area, :stage, :difficulty);');
+        $statement = $db->prepare('INSERT INTO team (uid, id, name, description, area_type, area, stage, difficulty, score) VALUES (:uid, :id, :name, :description, :area_type, :area, :stage, :difficulty, :score);');
         $statement->bindValue(':uid', $player);
         $statement->bindValue(':id', $team_id);
         $statement->bindValue(':name', $name);
@@ -49,6 +49,7 @@
         $statement->bindValue(':area', $r["area"]);
         $statement->bindValue(':stage', $r["stage"]);
         $statement->bindValue(':difficulty', $r["difficulty"]);
+        $statement->bindValue(':score', $score);
         $res = $statement->execute();
         if (!$res){
             return -3;

+ 2 - 1
application/entity/K_Unit.php

@@ -273,8 +273,8 @@
               "WHERE id = $id; ";
             $q = $db->query($s);
             $r = $q->fetchArray(SQLITE3_ASSOC);
+            $this->id = $id;
             if ($r){
-                $this->id = $r["id"];
                 $this->family = $r["family"];
                 $this->name = HTML::e($r["name"]);
                 $this->element = $r["element"];
@@ -382,6 +382,7 @@
               "WHERE " .
               "  unit = " . $this->id . " " .
               "ORDER BY item; ";
+            error_log($s);
             $q = $db->query($s);
             while ($r = $q->fetchArray(SQLITE3_ASSOC)){
                 $e = [

+ 39 - 0
application/entity/Rune.php

@@ -316,6 +316,45 @@
             }
         }
 
+        /**
+         * Gets the value of the main stat at an arbitrary level.
+         *
+         * @param int $level Desired level.
+         * @return int Value of the main stat at the selected level.
+         */
+        public function get_main_stat_at_level($level){
+            $level = intval($level);
+            if ($level < 0 || $level > 15){
+                return 0;
+            }
+            switch ($this->main_stat){
+                    case RUNE_STAT_ID::HP:
+                        return RUNE_STAT_VALUES::HP[$this->stars][$level];
+                    case RUNE_STAT_ID::HP_P:
+                        return RUNE_STAT_VALUES::HP_P[$this->stars][$level];
+                    case RUNE_STAT_ID::ATK:
+                        return RUNE_STAT_VALUES::ATK[$this->stars][$level];
+                    case RUNE_STAT_ID::ATK_P:
+                        return RUNE_STAT_VALUES::ATK_P[$this->stars][$level];
+                    case RUNE_STAT_ID::DEF:
+                        return RUNE_STAT_VALUES::DEF[$this->stars][$level];
+                    case RUNE_STAT_ID::DEF_P:
+                        return RUNE_STAT_VALUES::DEF_P[$this->stars][$level];
+                    case RUNE_STAT_ID::SPD:
+                        return RUNE_STAT_VALUES::SPD[$this->stars][$level];
+                    case RUNE_STAT_ID::CRR:
+                        return RUNE_STAT_VALUES::CRR[$this->stars][$level];
+                    case RUNE_STAT_ID::CRD:
+                        return RUNE_STAT_VALUES::CRD[$this->stars][$level];
+                    case RUNE_STAT_ID::RES:
+                        return RUNE_STAT_VALUES::RES[$this->stars][$level];
+                    case RUNE_STAT_ID::ACC:
+                        return RUNE_STAT_VALUES::ACC[$this->stars][$level];
+                    default:
+                        return 0;
+            }
+        }
+
         /**
          * Calculates name variables.
          */

+ 8 - 1
application/entity/Team.php

@@ -74,6 +74,11 @@
          */
         public $difficulty;
 
+        /**
+         * @var int Team score for the optmizer
+         */
+        public $score;
+
         /**
          * Constructor.
          *
@@ -97,7 +102,8 @@
                 area_type,
                 area,
                 stage,
-                difficulty
+                difficulty,
+                score
               FROM team
               WHERE id = '$id';
             ";
@@ -109,6 +115,7 @@
             $this->description = HTML::e($r["description"]);
             $this->area = new K_Area($r["area"], $r["area_type"]);
             $this->stage = $r["stage"];
+            $this->score = $r["score"];
             if ($complete){
                 $s = "
                   SELECT

+ 72 - 0
application/page/Optimizer_Page.php

@@ -0,0 +1,72 @@
+ <?php
+    /**
+     * Optimizer team list page file.
+     *
+     * Provides a class with all the properties and methods to display the page.
+     *
+     * @category Page
+     */
+
+    /**
+     * Require dependent files if not present.
+     */
+    require_once(PATH::PAGE . "Page.php");
+    require_once(PATH::ENTITY . "Team.php");
+
+    /**
+     * Optimizer team list page model.
+     *
+     * @category Page
+     */
+    class Optimizer_Page extends Page{
+
+        /**
+         * @var \Team[] Teams to show.
+         */
+        public $teams = [];
+
+        /**
+         * Constructor.
+         *
+         * Retrieves the data and initializes the variables.
+         *
+         * @global int Player ID.
+         * @global resource Database connection.
+         */
+        public function __construct(){
+            global $UID;
+            global $db;
+            $this->view = PATH::VIEW . "optimizer.php";
+            $s = $this->build_query();
+            $q = $db->query($s);
+            while ($r = $q->fetchArray(SQLITE3_ASSOC)){
+                array_push($this->teams, new Team($r["id"]));
+            }
+            $s = "
+              SELECT id
+              FROM unit
+              WHERE unit.uid = '$UID';
+            ";
+            $this->title = "Optmizer - SWDB";
+            $this->description = "Optimizer";
+            $this->canonical = URL::BASE . "optmizer/";
+        }
+
+        /**
+         * Builds the query to the rune table using the selected or default
+         * filters.
+         *
+         * @return The query to be executed.
+         */
+        private function build_query(){
+            global $UID;
+            $s = "
+              SELECT id
+              FROM team
+              WHERE uid = '$UID'
+            ";
+            return $s;
+        }
+
+    }
+?>

+ 155 - 0
application/page/Optimizer_Unit_Page.php

@@ -0,0 +1,155 @@
+ <?php
+    /**
+     * Optimizer unit page file.
+     *
+     * Provides a class with all the properties and methods to display the page.
+     *
+     * @category Page
+     */
+
+    /**
+     * Require dependent files if not present.
+     */
+    require_once(PATH::PAGE . "Page.php");
+    require_once(PATH::ENTITY . "Unit.php");
+
+    /**
+     * Optimizer team list page model.
+     *
+     * @category Page
+     */
+    class Optimizer_Unit_Page extends Page{
+
+        /**
+         * @var Unit The unit to optimize.
+         */
+        public $unit;
+
+        /**
+         * @var mixed[] Stats gained by building.
+         */
+        public $building_stats = [
+            "atk" => 0,
+            "def" => 0,
+            "hp" => 0,
+            "spd" => 0,
+            "crd" => 0,
+            "elm" => [
+                1 => 0,
+                2 => 0,
+                3 => 0,
+                4 => 0,
+                5 => 0
+            ]
+        ];
+
+        /**
+         * @var int[] Stats gained by artifacts.
+         */
+        public $artifact_stats = [
+            "atk" => 0,
+            "def" => 0,
+            "hp" => 0
+        ];
+
+        /**
+         * Constructor.
+         *
+         * Retrieves the data and initializes the variables.
+         *
+         * @param string $id Selected unit id
+         */
+        public function __construct($id){
+            $this->view = PATH::VIEW . "optimizer_unit.php";
+            $this->unit = new Unit($id);
+            $this->calculate_buildings();
+            $this->calculate_artifacts();
+            $this->title = "Optimize " . $this->unit->unit->name . " - SWDB";
+            $this->description = "Optimize " . $this->unit->unit->name;
+            $this->canonical = URL::BASE . "optmizer/$id";
+        }
+
+        /**
+         * Calculates the stats gained from bulding upgrades and populates the
+         * $building_stats array.
+         *
+         * @gobal int User ID.
+         * @global resource Database connection.
+         */
+        private function calculate_buildings(){
+            global $UID;
+            global $db;
+            $s = "
+              SELECT
+                affected_stat,
+                bonus,
+                element
+              FROM
+                k_decoration,
+                k_decoration_level,
+                decoration
+              WHERE
+                decoration.uid = '$UID' AND
+                k_decoration.id = decoration.decoration AND
+                decoration.decoration = k_decoration_level.decoration AND
+                decoration.level = k_decoration_level.level AND
+                area = " . EFFECT_AREA_ID::GENERAL . " AND
+                affected_stat IN (" . STAT_ID::ATK . ", " . STAT_ID::DEF . ", " . STAT_ID::HP . ", " . STAT_ID::SPD . ", " . STAT_ID::CRIT_DMG . ");
+            ";
+            $q = $db->query($s);
+            while ($r = $q->fetchArray(SQLITE3_ASSOC)){
+                switch($r["affected_stat"]){
+                    case STAT_ID::DEF:
+                        $this->building_stats["def"] += $r["bonus"];
+                        break;
+                    case STAT_ID::HP:
+                        $this->building_stats["hp"] += $r["bonus"];
+                        break;
+                    case STAT_ID::SPD:
+                        $this->building_stats["spd"] += $r["bonus"];
+                        break;
+                    case STAT_ID::CRIT_DMG:
+                        $this->building_stats["crd"] += $r["bonus"];
+                        break;
+                    case STAT_ID::ATK:
+                        if(strlen($r["element"]) > 0){
+                            $this->building_stats["elm"][$r["element"]] += $r["bonus"];
+                        }
+                        else{
+                            $this->building_stats["atk"] += $r["bonus"];
+                        }
+                        break;
+                }
+            }
+        }
+
+        private function calculate_artifacts(){
+            if ($this->unit->artifact_type != null){
+                switch ($this->unit->artifact_type->main_stat){
+                    case ARTIFACT_STAT_ID::HP:
+                        $this->artifact_stats["hp"] += $this->unit->artifact_type->main_stat_value;
+                        break;
+                    case ARTIFACT_STAT_ID::DEF:
+                        $this->artifact_stats["def"] += $this->unit->artifact_type->main_stat_value;
+                        break;
+                    case ARTIFACT_STAT_ID::ATK:
+                        $this->artifact_stats["atk"] += $this->unit->artifact_type->main_stat_value;
+                        break;
+                }
+            }
+            if ($this->unit->artifact_element != null){
+                switch ($this->unit->artifact_element->main_stat){
+                    case ARTIFACT_STAT_ID::HP:
+                        $this->artifact_stats["hp"] += $this->unit->artifact_element->main_stat_value;
+                        break;
+                    case ARTIFACT_STAT_ID::DEF:
+                        $this->artifact_stats["def"] += $this->unit->artifact_element->main_stat_value;
+                        break;
+                    case ARTIFACT_STAT_ID::ATK:
+                        $this->artifact_stats["atk"] += $this->unit->artifact_element->main_stat_value;
+                        break;
+                }
+            }
+        }
+    }
+?>

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

@@ -57,6 +57,9 @@
             <a href='/<?=$UID?>/report/'>
                 Reports
             </a>
+            <a href='/<?=$UID?>/optimizer/'>
+                Optimizer
+            </a>
         </nav>
         <nav id='profile'>
             <a href='/<?=$UID?>/profile/'>

+ 244 - 0
application/view/optimizer.php

@@ -0,0 +1,244 @@
+<?php
+    /**
+     * Optimizer teams view.
+     *
+     * Contains the view layout and ome code to present the data.
+     *
+     * @category View
+     * @property_read Teams_Page $page The page model.
+     * @property_read int $page Player ID.
+     */
+?>
+<!DOCTYPE html>
+<html lang='en'>
+    <head>
+        <meta content='text/html; charset=utf-8' http-equiv='content-type'/>
+        <meta name='viewport' content='width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1'/>
+        <title><?=$page->title?></title>
+        <link rel='shortcut icon' href='<?=$page->favicon?>'/>
+        <!-- CSS files -->
+        <link rel='stylesheet' type='text/css' href='<?=URL::CSS?>ui.css'/>
+        <link rel='stylesheet' type='text/css' href='<?=URL::CSS?>optimizer.css'/>
+        <link rel='stylesheet' type='text/css' href='<?=URL::CSS?>filters.css'/>
+        <!-- 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'/>
+        <script>
+            units = [];
+<?php
+            $units_added = [];
+            foreach ($page->teams as $team){
+                foreach ($team->unit as $unit){
+                    if (!in_array($unit->id, $units_added)){
+                        array_push($units_added, $unit->id);
+                        $panel = json_encode("<div class='monster_panel'>" . HTML::unit_panel($unit) . "</div>");
+?>
+                        units.push(
+                            {
+                                id: "<?=$unit->id?>",
+                                score: <?=$team->score?>,
+                                panel: <?=$panel?>
+                            }
+                        );
+<?php
+                    }
+                    else{
+                        // Find in array and increase score
+?>
+                        for (let i = 0; i < units.length; i++) {
+                            if (units[i].id == "<?=$unit->id?>"){
+                                units[i].score += <?=$team->score?>;
+                                break;
+                            }
+                        }
+<?php
+                    }
+                }
+            }
+?>
+            /**
+             * Changes the score of a team.
+             *
+             * @param team ID of the team to change.
+             * @param score New score.
+             * @return true on success, false on error.
+             */
+            function changeScore(team, score){
+                // TODO
+                return true;
+            }
+
+            /**
+             * Redirect to a unit optimization page.
+             *
+             * @param unit ID of the unit to optimize.
+             */
+            function optimize(unit){
+                window.location.href = "/<?=$UID?>/optimizer/" + unit;
+            }
+
+            /**
+             * Builds the unitpriority table.
+             *
+             * Calculates the score of each unit acording to teams score, and
+             * builds a sorted table enabling a link to optimization.
+             */
+            function calculateScores(){
+                // Sort array, descending score
+                units = units.sort(function(a, b){return b.score - a.score;});
+
+                // Draw table
+                const container = document.getElementById('unit_list');
+                while (container.firstChild) {
+                    container.removeChild(container.lastChild);
+                }
+                let table = document.createElement('table');
+                let tr = document.createElement('tr');
+                let th = document.createElement('th');
+                th.innerHTML = 'Unit';
+                th.setAttribute('class', 'unit');
+                tr.appendChild(th);
+                th = document.createElement('th');
+                th.setAttribute('class', 'score');
+                th.innerHTML = 'Score';
+                tr.appendChild(th);
+                th = document.createElement('th');
+                th.innerHTML = 'Action';
+                th.setAttribute('class', 'action');
+                tr.appendChild(th);
+                table.appendChild(tr);
+                var odd = 'odd';
+                for (let i = 0; i < units.length; i++) {
+                    let tr = document.createElement('tr');
+                    let td = document.createElement('td');
+                    td.setAttribute('class', 'unit ' + odd);
+                    td.innerHTML = units[i].panel;
+                    tr.appendChild(td);
+                    td = document.createElement('td');
+                    td.setAttribute('class', 'score ' + odd);
+                    td.innerHTML = units[i].score;
+                    tr.appendChild(td);
+                    td = document.createElement('td');
+                    td.setAttribute('class', 'action ' + odd);
+                    btn = document.createElement('input');
+                    btn.setAttribute('type', 'button');
+                    btn.setAttribute('value', 'Optimize');
+                    btn.setAttribute('onclick', 'optimize("' + units[i].id + '")'); 
+                    td.appendChild(btn);
+                    tr.appendChild(td);
+                    table.appendChild(tr);
+                    if (odd == ''){
+                        odd = 'odd';
+                    }
+                    else{
+                        odd = '';
+                    }
+                }
+                container.appendChild(table);
+            }
+
+        </script>
+    </head>
+    <body onLoad='calculateScores();'>
+<?php
+        include __DIR__ . "/inc/header.php";
+?>
+        <section class='list'>
+            <h2>
+                Teams
+            </h2>
+            <article>
+                <table id='teams'>
+                    <tr>
+                        <th>
+                            Team
+                        </th>
+                        <th>
+                            Description
+                        </th>
+                        <th>
+                            Units
+                        </th>
+                        <th>
+                            Score
+                        </th>
+                    </tr>
+<?php
+                    $odd = "odd";
+                    foreach ($page->teams as $team){
+?>
+                        <tr>
+                            <td class='team <?=$odd?>'>
+                                <?=$team->name?>
+                            </td>
+                            <td class='description <?=$odd?>'>
+                                <?=$team->description?>
+                            </td>
+                            <td class='units <?=$odd?>'>
+<?php
+                                $prev_front = false;
+                                $front = "undefined";
+                                foreach ($team->unit as $unit){
+                                    $front = in_array($unit->id, $team->frontline);
+                                    if ($front != "undefined" && $prev_front != $front){
+?>
+                                        <hr class='frontline'/>
+<?php
+                                    }
+?>
+                                    <a href='/<?=$UID?>/monsters/<?=$unit->id?>' target='_blank'>
+                                        <div class='monster_panel'>
+                                            <?=HTML::unit_panel($unit)?>
+<?php
+                                            if ($unit->id == $team->leader){
+?>
+                                                <img alt='Leader' class='leader' src='<?=URL::IMG["ICON"]?>leader.png'/>
+<?php
+                                            }
+?>
+                                        </div>
+                                    </a>
+<?php
+                                    $prev_front = $front;
+                                }
+?>
+                            </td>
+                            <td class='score <?=$odd?>'>
+                                <input type='number' min='0' max='20' value='<?=$team->score?>' onChange='changeScore(<?=$team->id?>, this.value);'/>
+                            </td>
+                        </tr>
+<?php
+                        if ($odd == ""){
+                            $odd = "odd";
+                        }
+                        else{
+                            $odd = "";
+                        }
+                    }
+?>
+                </table>
+                <div id='unit_list'>
+                </div>
+            </article>
+        </section> <!-- .list -->
+
+<?php
+        include __DIR__ . "/inc/footer.php";
+?>
+    </body>
+</html>

+ 716 - 0
application/view/optimizer_unit.php

@@ -0,0 +1,716 @@
+<?php
+    /**
+     * Monster view.
+     *
+     * Contains the view layout and some code to present the data.
+     *
+     * @category View
+     * @property_read Monster_Page $page The page model.
+     * @property_read int $UID Player ID.
+     */
+?>
+<!DOCTYPE html>
+<html lang='en'>
+    <head>
+        <meta content='text/html; charset=utf-8' http-equiv='content-type'/>
+        <meta name='viewport' content='width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1'/>
+        <title><?=$page->title?></title>
+        <link rel='shortcut icon' href='<?=$page->favicon?>'/>
+        <!-- CSS files -->
+        <link rel='stylesheet' type='text/css' href='<?=URL::CSS?>ui.css'/>
+        <link rel='stylesheet' type='text/css' href='<?=URL::CSS?>optimizer.css'/>
+        <!-- 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'/>
+        <script>
+
+            /**
+             * Updates the value next to the sliders when they change.
+             *
+             * @param stat Name of the stat to set.
+             * @param value Value of the slider.
+             */
+            function updateMinValue(stat, value){
+                document.getElementById('lbl_min_' + stat).innerHTML = value;
+            }
+
+            /**
+             * Starts the optimization.
+             *
+             * Checks for error in the combination of the parameters, and
+             * shows an error window if there is an invalid conbination. If
+             * not, builds the url to calculate the new rune combinations,
+             * and presents th received response.
+             *
+             * @return false on error, true on success.
+             */
+            function apply(){
+                // TODO: Check for valid set combinations
+
+                var params = '';
+                var x;
+
+                // Player id - mandatory
+                params = 'uid=<?=$UID?>';
+
+                // Unit id - mandatory
+                params += '&unit=<?=$page->unit->id?>';
+
+                // Rune set 1 - mandatory
+                params += '&set[]=' + document.getElementById('set_1').options[document.getElementById('set_1').selectedIndex].value;
+
+                // Rune set 2 - mandatory
+                params += '&set[]=' + document.getElementById('set_2').options[document.getElementById('set_2').selectedIndex].value;
+
+                // Rune set 3 - optional
+                x = document.getElementById('set_3').options[document.getElementById('set_3').selectedIndex].value;
+                if (x != ''){
+                    params += '&set[]=' + x;
+                }
+
+                // Slot 2 - mandatory
+                params += '&stat[]=' + document.getElementById('slot_2').options[document.getElementById('slot_2').selectedIndex].value;
+
+                // Slot 4 - mandatory
+                params += '&stat[]=' + document.getElementById('slot_4').options[document.getElementById('slot_4').selectedIndex].value;
+
+                // Slot 5 - mandatory
+                params += '&stat[]=' + document.getElementById('slot_6').options[document.getElementById('slot_6').selectedIndex].value;
+
+                // Rune source - mandatory
+                params += '&source=' + document.getElementById('rune_source').options[document.getElementById('rune_source').selectedIndex].value;
+
+                // Optimizer tuning - mandatory
+                params += '&tuning=' + document.getElementById('tuning').options[document.getElementById('tuning').selectedIndex].value;
+
+                // Min HP - Optional
+                if (document.getElementById('min_hp').value > document.getElementById('min_hp').min){
+                    params += '&min_hp=' + document.getElementById('min_hp').value;
+                }
+
+                // Min ATK - Optional
+                if (document.getElementById('min_attack').value > document.getElementById('min_attack').min){
+                    params += '&min_attack=' + document.getElementById('min_attack').value;
+                }
+
+                // Min DEF - Optional
+                if (document.getElementById('min_defense').value > document.getElementById('min_defense').min){
+                    params += '&min_defense=' + document.getElementById('min_defense').value;
+                }
+
+                // Min SPD - Optional
+                if (document.getElementById('min_speed').value > document.getElementById('min_speed').min){
+                    params += '&min_speed=' + document.getElementById('min_speed').value;
+                }
+
+                // Min CRR - Optional
+                if (document.getElementById('min_crit_rate').value > document.getElementById('min_crit_rate').min){
+                    params += '&min_crit_rate=' + document.getElementById('min_crit_rate').value;
+                }
+
+                // Min CRD - Optional
+                if (document.getElementById('min_crit_damage').value > document.getElementById('min_crit_damage').min){
+                    params += '&min_crit_damage=' + document.getElementById('min_crit_damage').value;
+                }
+
+                // Min ACC - Optional
+                if (document.getElementById('min_accuracy').value > document.getElementById('min_accuracy').min){
+                    params += '&min_accuracy=' + document.getElementById('min_accuracy').value;
+                }
+
+                // Min RES - Optional
+                if (document.getElementById('min_resistance').value > document.getElementById('min_resistance').min){
+                    params += '&min_resistance=' + document.getElementById('min_resistance').value;
+                }
+
+                // Send th request
+                var xhttp = new XMLHttpRequest();
+                xhttp.onreadystatechange = function() {
+                    if (this.readyState == 4 && this.status == 200) {
+                        showOptimizations(this.response);
+                    }
+                };
+                xhttp.open("POST", "/action/optimize/", true);
+                xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
+                xhttp.send(params);
+            }
+
+            function showOptimizations(content){
+                console.log("RESPONSE: " + content);
+            }
+        </script>
+    </head>
+    <body>
+<?php
+        include __DIR__ . "/inc/header.php";
+?>
+        <section id='monster' class='content'>
+            <h2>
+                Optimize <?=$page->unit->title?>
+            </h2>
+            <article id='profile'>
+                <div id='monster_info'>
+                    <div class='monster_panel'>
+                        <?=HTML::unit_panel($page->unit)?>
+                    </div>
+<?php
+                    if ($page->unit->experience_level != 0){
+                        $exp_pct = ceil($page->unit->exp_gained * 100 / $page->unit->experience_level);
+                        $exp_txt = $page->unit->exp_gained . " / " . $page->unit->experience_level;
+                    }
+                    else{
+                        $exp_pct = 100;
+                        $exp_txt = "MAX";
+                    }
+                    $now = time();
+                    //$datediff = $now - $page->unit->create_time->getTimestamp();
+                    $datediff = $now - strtotime($page->unit->create_time->format('Y-m-d H:i:s'));
+                    $datediff = floor($datediff / (60 * 60 * 24));
+?>
+                    <div id='monster_details'>
+<?php
+                        if (sizeof($page->unit->teams) > 0){
+?>
+                            <div id='teams'>
+                                <h4>
+                                    Teams:
+                                </h4>
+                                <ul>
+<?php
+                                    foreach($page->unit->teams as $team){
+?>
+                                        <li>
+                                            <a target='blank' href='/<?=$UID?>/teams/<?=$team->id?>'>
+                                                <?=$team->name?>
+                                            </a>
+                                        </li>
+<?php
+                                    }
+?>
+                                </ul>
+                            </div>
+<?php
+                        }
+?>
+                    </div>
+                </div>
+<?php
+                $building_attack = floor(($page->unit->attack * $page->building_stats["atk"] / 100) + ($page->unit->attack * $page->building_stats["elm"][$page->unit->unit->element] / 100));
+                $building_defense = floor($page->building_stats["def"] * $page->unit->defense / 100);
+                $building_hp = floor($page->building_stats["hp"] * $page->unit->hp / 100);
+                $building_speed = $page->building_stats["spd"];
+                $building_crit_rate = 0;
+                $building_crit_damage = $page->building_stats["crd"];
+                $building_accuracy = 0;
+                $building_resistance = 0;
+?>
+                <table id='stats'>
+                    <tr>
+                        <th>
+                            Stats
+                        </th>
+                        <th>
+                            Base
+                        </th>
+                        <th>
+                            Runes
+                        </th>
+                        <th>
+                            Artifacts
+                        </th>
+                        <th>
+                            Buildings
+                        </th>
+                        <th>
+                            Total
+                        </th>
+                    </tr>
+                    <tr>
+                        <th>
+                            ATK
+                        </th>
+                        <td class='base'>
+                            <?=$page->unit->attack?>
+                        </td>
+                        <td class='extra'>
+                            +<?=$page->unit->rune_attack?>
+                        </td>
+                        <td class='extra'>
+                            +<?=$page->artifact_stats["atk"]?>
+                        </td>
+                        <td class='extra'>
+                            +<?=$building_attack?>
+                        </td>
+                        <td class='total'>
+                            <?=$page->unit->attack + $page->unit->rune_attack + $building_attack + $page->artifact_stats["atk"]?>
+                        </td>
+                    </tr>
+                    <tr>
+                        <th>
+                            DEF
+                        </th>
+                        <td class='base'>
+                            <?=$page->unit->defense?>
+                        </td>
+                        <td class='extra'>
+                            +<?=$page->unit->rune_defense?>
+                        </td>
+                        <td class='extra'>
+                            +<?=$page->artifact_stats["def"]?>
+                        </td>
+                        <td class='extra'>
+                            +<?=$building_defense?>
+                        </td>
+                        <td class='total'>
+                            <?=$page->unit->defense + $page->unit->rune_defense + $building_defense + $page->artifact_stats["def"]?>
+                        </td>
+                    </tr>
+                    <tr>
+                        <th>
+                            HP
+                        </th>
+                        <td class='base'>
+                            <?=$page->unit->hp?>
+                        </td>
+                        <td class='extra'>
+                            +<?=$page->unit->rune_hp?>
+                        </td>
+                        <td class='extra'>
+                            +<?=$page->artifact_stats["hp"]?>
+                        </td>
+                        <td class='extra'>
+                            +<?=$building_hp?>
+                        </td>
+                        <td class='total'>
+                            <?=$page->unit->hp + $page->unit->rune_hp + $building_hp + $page->artifact_stats["hp"]?>
+                        </td>
+                    </tr>
+                    <tr>
+                        <th>
+                            SPD
+                        </th>
+                        <td class='base'>
+                            <?=$page->unit->speed?>
+                        </td>
+                        <td class='extra'>
+                            +<?=$page->unit->rune_speed?>
+                        </td>
+                        <td class='extra'>
+                            +0
+                        </td>
+                        <td class='extra'>
+                            +<?=$building_speed?>
+                        </td>
+                        <td class='total'>
+                            <?=$page->unit->speed + $page->unit->rune_speed + $building_speed?>
+                        </td>
+                    </tr>
+                    <tr>
+                        <th>
+                            CRR
+                        </th>
+                        <td class='base'>
+                            <?=$page->unit->crit_rate?>%
+                        </td>
+                        <td class='extra'>
+                            +<?=$page->unit->rune_crit_rate?>%
+                        </td>
+                        <td class='extra'>
+                            +0%
+                        </td>
+                        <td class='extra'>
+                            +<?=$building_crit_rate?>%
+                        </td>
+                        <td class='total'>
+                            <?=$page->unit->crit_rate + $page->unit->rune_crit_rate + $building_crit_rate?>%
+                        </td>
+                    </tr>
+                    <tr>
+                        <th>
+                            CRD
+                        </th>
+                        <td class='base'>
+                            <?=$page->unit->crit_damage?>%
+                        </td>
+                        <td class='extra'>
+                            +<?=$page->unit->rune_crit_damage?>%
+                        </td>
+                        <td class='extra'>
+                            +0%
+                        </td>
+                        <td class='extra'>
+                            +<?=$building_crit_damage?>%
+                        </td>
+                        <td class='total'>
+                            <?=$page->unit->crit_damage + $page->unit->rune_crit_damage + $building_crit_damage?>%
+                        </td>
+                    </tr>
+                    <tr>
+                        <th>
+                            ACC
+                        </th>
+                        <td class='base'>
+                            <?=$page->unit->accuracy?>%
+                        </td>
+                        <td class='extra'>
+                            +<?=$page->unit->rune_accuracy?>%
+                        </td>
+                        <td class='extra'>
+                            +0%
+                        </td>
+                        <td class='extra'>
+                            +<?=$building_accuracy?>%
+                        </td>
+                        <td class='total'>
+                            <?=$page->unit->accuracy + $page->unit->rune_accuracy + $building_accuracy?>%
+                        </td>
+                    </tr>
+                    <tr>
+                        <th>
+                            RES
+                        </th>
+                        <td class='base'>
+                            <?=$page->unit->resistance?>%
+                        </td>
+                        <td class='extra'>
+                            +<?=$page->unit->rune_resistance?>%
+                        </td>
+                        <td class='extra'>
+                            +0%
+                        </td>
+                        <td class='extra'>
+                            +<?=$building_resistance?>%
+                        </td>
+                        <td class='total'>
+                            <?=$page->unit->resistance + $page->unit->rune_resistance + $building_resistance?>%
+                        </td>
+                    </tr>
+                </table>
+                <div id='artifacts'>
+                    <?=HTML::artifact_table($page->unit->artifact_type)?>
+                    <?=HTML::artifact_table($page->unit->artifact_element)?>
+                </div>
+            </article> <!-- #profile -->
+            <article id='current_runes'>
+<?php
+                $total_efficiency = 0;
+                $total_max_efficiency = 0;
+                $total_reached_efficiency = 0;
+                $total_level = 0;
+                $total_stars = 0;
+                $total_value = 0;
+                $total_runes = 0;
+                $show_list = [6, 1, 2, 3, 4, 5];
+                //foreach ($page->unit->rune as $rune){
+                foreach ($show_list as $i){
+                    $rune = $page->unit->rune[$i - 1];
+                    $total_efficiency += $rune->efficiency;
+                    $total_max_efficiency += $rune->max_efficiency;
+                    $total_reached_efficiency += ($rune->efficiency * 100 / $rune->max_efficiency);
+                    $total_level += $rune->level;
+                    $total_stars += $rune->stars;
+                    $total_value += $rune->value;
+                    $total_runes ++;
+?>
+                    <?=HTML::rune_table($rune)?>
+<?php
+                    if ($i == 2){
+?>
+                        <br/>
+<?php
+                    }
+                }
+?>
+            </article>
+            <article id='rune_averages'>
+                <table id='table_averages'>
+                    <tr>
+                        <td class='title'>
+                            Avg. level:
+                        </td>
+                        <td class='value'>
+                            <?=number_format($total_level / $total_runes, 2)?>
+                        </td>
+                    </tr>
+                    <tr>
+                        <td class='title'>
+                            Avg. stars:
+                        </td>
+                        <td class='value'>
+                            <?=number_format($total_stars / $total_runes, 2)?>
+                        </td>
+                    </tr>
+                    <tr>
+                        <td class='title'>
+                            Avg. value:
+                        </td>
+                        <td class='value'>
+                            <?=number_format($total_value / $total_runes, 2, '.', '')?>
+                        </td>
+                    </tr>
+                    <tr>
+                        <td class='title'>
+                            Total value:
+                        </td>
+                        <td class='value'>
+                            <?=$total_value?>
+                        </td>
+                    </tr>
+                    <tr>
+                        <td class='title'>
+                            Avg. efficiency:
+                        </td>
+                        <td class='value'>
+                            <?=number_format($total_efficiency / $total_runes, 2)?>%
+                        </td>
+                    </tr>
+                    <tr>
+                        <td class='title'>
+                            Avg. max. efficiency:
+                        </td>
+                        <td class='value'>
+                            <?=number_format($total_max_efficiency / $total_runes, 2)?>%
+                        </td>
+                    </tr>
+                    <tr>
+                        <td class='title'>
+                            Avg. reached efficiency:
+                        </td>
+                        <td class='value'>
+                            <?=number_format($total_reached_efficiency / $total_runes, 2)?>%
+                        </td>
+                    </tr>
+                </table>
+            </article>
+        </section> <!-- runes -->
+        <section id='parameters' class='content'>
+            <h2>
+                Optimization parameters
+            </h2>
+            <article>
+                <table>
+                    <tr>
+                        <td class='name'>
+                            Rune sets
+                        </td>
+                        <td class='value'>
+<?php
+                            $reflect = new ReflectionClass("RUNE_SET_ID");
+?>
+                            <select id='set_1'>
+<?php
+                            foreach($reflect->getConstants() as $name => $id){
+                                $selected = "";
+                                if (in_array($id, $filters["MAIN"])){
+                                    $selected = "selected='selected'";
+                                }
+?>
+                                <option value='<?=$id?>' <?=$selected?>><?=$name?></option>
+<?php
+                            }
+?>
+                            </select>
+                            <select id='set_2'>
+<?php
+                            foreach($reflect->getConstants() as $name => $id){
+                                $selected = "";
+                                if (in_array($id, $filters["MAIN"])){
+                                    $selected = "selected='selected'";
+                                }
+?>
+                                <option value='<?=$id?>' <?=$selected?>><?=$name?></option>
+<?php
+                            }
+?>
+                            </select>
+                            <select id='set_3'>
+                                <option value='' <?=$selected?>></option>
+<?php
+                            foreach($reflect->getConstants() as $name => $id){
+                                $selected = "";
+                                if (in_array($id, $filters["MAIN"])){
+                                    $selected = "selected='selected'";
+                                }
+?>
+                                <option value='<?=$id?>' <?=$selected?>><?=$name?></option>
+<?php
+                            }
+?>
+                            </select>
+                        </td>
+                        <td class='empty'>
+                        </td>
+                        <td class='name'>
+                            Min HP
+                        </td>
+                        <td class='value'>
+                            <input id='min_hp' type='range' value='<?=$page->unit->hp?>' value='<?=$page->unit->hp?>' min='<?=$page->unit->hp?>' max='50000' oninput='updateMinValue("hp", this.value);'>
+                            <span id='lbl_min_hp'><?=$page->unit->hp?></span>
+                        </td>
+                    </tr>
+                    <tr>
+                        <td class='name'>
+                            Even slots
+                        </td>
+                        <td class='value'>
+                            <select id='slot_2'>
+                                <option value='<?=RUNE_STAT_ID::HP_P?>'>HP%</option>
+                                <option value='<?=RUNE_STAT_ID::ATK_P?>'>ATK%</option>
+                                <option value='<?=RUNE_STAT_ID::DEF_P?>'>DEF%</option>
+                                <option value='<?=RUNE_STAT_ID::SPD?>'>SPD</option>
+                            </select>
+                            <select id='slot_4'>
+                                <option value='<?=RUNE_STAT_ID::HP_P?>'>HP%</option>
+                                <option value='<?=RUNE_STAT_ID::ATK_P?>'>ATK%</option>
+                                <option value='<?=RUNE_STAT_ID::DEF_P?>'>DEF%</option>
+                                <option value='<?=RUNE_STAT_ID::CRR?>'>CRR</option>
+                                <option value='<?=RUNE_STAT_ID::CRR?>'>CRD</option>
+                            </select>
+                            <select id='slot_6'>
+                                <option value='<?=RUNE_STAT_ID::HP_P?>'>HP%</option>
+                                <option value='<?=RUNE_STAT_ID::ATK_P?>'>ATK%</option>
+                                <option value='<?=RUNE_STAT_ID::DEF_P?>'>DEF%</option>
+                                <option value='<?=RUNE_STAT_ID::ACC?>'>ACC</option>
+                                <option value='<?=RUNE_STAT_ID::RES?>'>RES</option>
+                            </select>
+                        </td>
+                        <td class='empty'>
+                        </td>
+                        <td class='name'>
+                            Min ATK
+                        </td>
+                        <td class='value'>
+                            <input id='min_attack' type='range' value='<?=$page->unit->attack?>' value='<?=$page->unit->attack?>' min='<?=$page->unit->attack?>' max='10000' oninput='updateMinValue("attack", this.value);'>
+                            <span id='lbl_min_attack'><?=$page->unit->attack?></span>
+                        </td>
+                    </tr>
+                    <tr>
+                        <td class='name'>
+                            Use runes from
+                        </td>
+                        <td class='value'>
+                            <select id='rune_source'>
+                                <option value='0'>Storage only</option>
+                                <option value='1'>Units in no teams</option>
+                                <option value='2'>Units in teams with 0 score</option>
+                                <option value='3'>Units with lower overall score</option>
+                                <option value='4'>All runes</option>
+                            </select>
+                        </td>
+                        <td class='empty'>
+                        </td>
+                        <td class='name'>
+                            Min DEF
+                        </td>
+                        <td class='value'>
+                            <input id='min_defense' type='range' value='<?=$page->unit->defense?>' value='<?=$page->unit->defense?>' min='<?=$page->unit->defense?>' max='10000' oninput='updateMinValue("defense", this.value);'>
+                            <span id='lbl_min_defense'><?=$page->unit->defense?></span>
+                        </td>
+                    </tr>
+                    <tr>
+                        <td class='name'>
+                            Tune optimizer for
+                        </td>
+                        <td class='value'>
+                            <select id='tuning'>
+                                <option value='0'>Rune current levels</option>
+                                <option value='1'>+12</option>
+                                <option value='2'>2/4/6 +15, 1/3/5 + 12</option>
+                                <option value='3'>+15</option>
+                            </select>
+                        </td>
+                        <td class='empty'>
+                        </td>
+                        <td class='name'>
+                            Min SPD
+                        </td>
+                        <td class='value'>
+                            <input id='min_speed' type='range' value='<?=$page->unit->speed?>' value='<?=$page->unit->speed?>' min='<?=$page->unit->speed?>' max='400' oninput='updateMinValue("speed", this.value);'>
+                            <span id='lbl_min_speed'><?=$page->unit->speed?></span>
+                        </td>
+                    </tr>
+                    <tr>
+                        <td class='empty'>
+                        </td>
+                        <td class='empty'>
+                        </td>
+                        <td class='empty'>
+                        </td>
+                        <td class='name'>
+                            Min CRR
+                        </td>
+                        <td class='value'>
+                            <input id='min_crit_rate' type='range' value='<?=$page->unit->crit_rate?>' value='<?=$page->unit->crit_rate?>' min='<?=$page->unit->crit_rate?>' max='100' oninput='updateMinValue("crit_rate", this.value);'>
+                            <span id='lbl_min_crit_rate'><?=$page->unit->crit_rate?></span>
+                        </td>
+                    </tr>
+                    <tr>
+                        <td class='empty'>
+                        </td>
+                        <td class='empty'>
+                        </td>
+                        <td class='empty'>
+                        </td>
+                        <td class='name'>
+                            Min CRD
+                        </td>
+                        <td class='value'>
+                            <input id='min_crit_damage' type='range' value='<?=$page->unit->crit_damage?>' value='<?=$page->unit->crit_damage?>' min='<?=$page->unit->crit_damage?>' max='400' oninput='updateMinValue("crit_damage", this.value);'>
+                            <span id='lbl_min_crit_damage'><?=$page->unit->crit_damage?></span>
+                        </td>
+                    </tr>
+                    <tr>
+                        <td class='empty'>
+                        </td>
+                        <td class='empty'>
+                        </td>
+                        <td class='empty'>
+                        </td>
+                        <td class='name'>
+                            Min ACC
+                        </td>
+                        <td class='value'>
+                            <input id='min_accuracy' type='range' value='<?=$page->unit->accuracy?>' value='<?=$page->unit->accuracy?>' min='<?=$page->unit->accuracy?>' max='85' oninput='updateMinValue("accuracy", this.value);'>
+                            <span id='lbl_min_accuracy'><?=$page->unit->accuracy?></span>
+                        </td>
+                    </tr>
+                    <tr>
+                        <td class='action'>
+                            <input type='button' value='Apply' onClick='apply();'/>
+                        </td>
+                        <td class='empty'>
+                        </td>
+                        <td class='empty'>
+                        </td>
+                        <td class='name'>
+                            Min RES
+                        </td>
+                        <td class='value'>
+                            <input id='min_resistance' type='range' value='<?=$page->unit->resistance?>' value='<?=$page->unit->resistance?>' min='<?=$page->unit->resistance?>' max='100' oninput='updateMinValue("resistance", this.value);'>
+                            <span id='lbl_min_resistance'><?=$page->unit->resistance?></span>
+                        </td>
+                    </tr>
+                </table>
+            </article>
+        </section>
+
+<?php
+        include __DIR__ . "/inc/footer.php";
+?>
+    </body>
+</html>

+ 2 - 1
install_data/install_data.sql

@@ -297,7 +297,8 @@ CREATE TABLE team(
     area_type INT NOT NULL REFERENCES k_area_type(id),
     area INT REFERENCES k_area(id),
     stage INT,
-    difficulty INT REFERENCES k_difficulty(id)
+    difficulty INT REFERENCES k_difficulty(id),
+    score INT NOT NULL DEFAULT 0
 );
 CREATE TABLE building(
     -- No primary key, can have multiple towers

+ 182 - 0
public/css/optimizer.css

@@ -0,0 +1,182 @@
+table#teams{
+    width: 60%;
+    border-collapse: collapse;
+    border: 0.1em solid #000000;
+    display: inline-block;
+    vertical-align: top;
+}
+
+table#teams th{
+    border-top: 0.1em solid #000000;
+    border-bottom: 0.1em solid #000000;
+}
+
+table#teams td{
+    border-bottom: 0.1em solid #000000;
+    text-align: left;
+    padding: 0.2em;
+}
+
+table#teams td.odd{
+    background-color: #00000033;
+}
+
+table#teams td.team{
+    font-weight: bold;
+}
+
+table#teams td.description{
+    font-size: 90%;
+}
+
+
+table#teams td.units{
+    width: 12em;
+}
+
+table#teams td.units hr.frontline{
+    display: block;
+    width: 9em;
+    margin: -0.6em 0 0.2em 0;
+    color: #666666;
+}
+
+table#teams td.units div.monster_panel{
+    font-size: 25%;
+    margin-bottom: -2em;
+}
+
+table#teams td.units div.monster_panel img.leader{
+    width: 5em;
+    height: 5em;
+    display: block;
+    position: absolute;
+    top: -1.7em;
+    left: -0.7em;
+}
+
+div#unit_list{
+    display: inline-block;
+    width: 30%;
+    vertical-align: top;
+    text-align: center
+}
+
+div#unit_list table{
+    border-collapse: collapse;
+    border: 0.1em solid #000000;
+}
+
+div#unit_list table th{
+    padding: 0.2em 0.4em;
+}
+
+div#unit_list table td{
+    vertical-align: middle;
+    text-align: center;
+    margin: 0;
+}
+
+div#unit_list table td.odd{
+    background-color: #00000033;
+}
+
+div#unit_list table div.monster_panel{
+    font-size: 25%;
+    margin: 2em 0 0 0;
+}
+
+div#unit_list table td.action input[type="button"]{
+    font-size: 90%;
+    padding: 0.1em;
+}
+
+section#monster article#profile div#monster_info{
+    display: inline-block;
+    vertical-align: top;
+    max-width: 10em;
+}
+
+section#monster article#profile div#monster_info div#monster_details{
+    display: block;
+    font-size: 70%;
+    margin-top: -3em;
+}
+
+section#monster article#profile div#monster_info div#monster_details div#teams{
+    text-align: left;
+}
+
+section#monster article#profile div#monster_info div#monster_details div#teams h4{
+    margin: 0.2em auto;
+}
+
+section#monster article#profile div#monster_info div#exp{
+    border: 0.3em solid var(--ui-color-border);
+    border-radius: 0.5em;
+    height: 1em;
+    background-color: #00000088;
+    position: relative;
+    font-size: 100%;
+}
+section#monster article#profile div#monster_info div#exp span#exp_bar{
+    height: 1em;
+    border-radius: 0.4em;
+    display: block;
+    background-color: #cc0000;
+}
+section#monster article#profile div#monster_info div#exp span#exp_text{
+    display: block;
+    text-align: center;
+    margin-top: -1.5em;
+    font-weight: bold;
+    font-size: 0.5em;
+    text-shadow: 0 0 0.1em #000000, 0 0 0.1em #000000, 0 0 0.1em #000000, 0 0 0.1em #000000, 0 0 0.1em #000000;
+}
+
+section#monster article#profile table#stats{
+    font-size: 90%;
+    vertical-align: top;
+    display: inline-block;
+    border: 0.1em solid black;
+    color: #ffffff;
+    margin: auto;
+    border-collapse: collapse;
+    border-radius: 0.4em;
+}
+
+section#monster article#profile table#stats th{
+    font-weight: bold;
+    background-color: #00000066;
+}
+
+section#monster article#profile table#stats td{
+    font-weight: bold;
+    background-color: #ffffff33;
+}
+
+section#monster article#profile table#stats td, th{
+    padding: 0.2em;
+    border: 0.1em solid #000000;
+}
+
+section#monster article#profile table#stats td.extra{
+    color: #aaaaff;
+}
+
+section#monster article#profile table#stats td.total{
+    color: #f2c920;
+    font-weight: bold;
+}
+
+section#monster article#profile div#artifacts{
+    display: inline-block;
+}
+
+section#monster article#profile div#artifacts table.artifact{
+    display: block;
+}
+
+section#parameters article{
+    text-align: left;
+}