optimize_get_rune_list.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. <?php
  2. /**
  3. * File for the rune optimization action.
  4. *
  5. * Implements an action function to be called from the {@see Controller}.
  6. *
  7. * @author Iñigo Valentin <i@inigovalentin.com>
  8. * @license https://www.gnu.org/licenses/gpl-3.0.en.html GNU General Public License V3
  9. * @package SWDB
  10. */
  11. /**
  12. * Selects the runes for optimization.
  13. *
  14. * Reads the POST parameters looking for the following KEYS:
  15. * player: Player ID.
  16. * mode: Game mode ({@see GAME_MODE_ID}).
  17. * unit: Unit ID.
  18. * source: Source of the runes to select (assigned, unassigned, ...).
  19. * limit: {@todo: Currently not in use. Implement or delete}.
  20. * tuning: {@todo Document properly}.
  21. * set[]: Selected rune sets ({@see RUNE_SET_ID}).
  22. *
  23. * Then it selects all the runes matching the cryteria.
  24. *
  25. * @return int|string a JSON with the runes on success, negative integers on error. 0 if no errors
  26. * ocurred, but no results were found.
  27. * @category Action
  28. */
  29. function action(){
  30. // Increase max execution time.
  31. set_time_limit(60);
  32. $candidates = [
  33. 1 => [],
  34. 2 => [],
  35. 3 => [],
  36. 4 => [],
  37. 5 => [],
  38. 6 => []
  39. ];
  40. $response = null;
  41. $player = filter_input(INPUT_POST, 'player');
  42. if ($player == null){
  43. return -1;
  44. }
  45. $game_mode = GAME_MODE_ID::NORMAL;
  46. if (filter_input(INPUT_POST, 'mode') == GAME_MODE_ID::RTA){
  47. $game_mode = GAME_MODE_ID::RTA;
  48. }
  49. $unit_id = filter_input(INPUT_POST, 'unit');
  50. if ($unit_id == null){
  51. return -2;
  52. }
  53. // Sets
  54. $sets = [];
  55. foreach ($_POST["set"] as $x){
  56. array_push($sets, intval($x));
  57. }
  58. if (sizeof($sets) < 2 || sizeof($sets) > 3){
  59. return -3;
  60. }
  61. // Main stats in even slots.
  62. $stats = [];
  63. foreach ($_POST["stat"] as $x){
  64. array_push($stats, intval($x));
  65. }
  66. $source = filter_input(INPUT_POST, 'source');
  67. if ($source == null){
  68. return -4;
  69. }
  70. $limit = intval(filter_input(INPUT_POST, 'limit'));
  71. if ($limit == 0){
  72. return -5;
  73. }
  74. $tuning = filter_input(INPUT_POST, 'tuning');
  75. if ($tuning == null){
  76. return -6;
  77. }
  78. // Instantiate the unit
  79. $unit = new Unit($unit_id);
  80. // Get build query:
  81. $base_s = "
  82. SELECT
  83. id,
  84. type,
  85. slot,
  86. level,
  87. stars,
  88. (SELECT stat FROM rune_stat WHERE rune = rune.id AND slot = " . RUNE_STAT_SLOT_ID::MAIN . " ) AS main_stat,
  89. (SELECT value FROM rune_stat WHERE rune = rune.id AND slot = " . RUNE_STAT_SLOT_ID::MAIN . " ) AS main_stat_value,
  90. (SELECT stat FROM rune_stat WHERE rune = rune.id AND slot = " . RUNE_STAT_SLOT_ID::INNATE . " ) AS innate_stat,
  91. (SELECT value FROM rune_stat WHERE rune = rune.id AND slot = " . RUNE_STAT_SLOT_ID::INNATE . " ) AS innate_stat_value,
  92. (SELECT stat FROM rune_stat WHERE rune = rune.id AND slot = " . RUNE_STAT_SLOT_ID::SUBSTAT_1 . " ) AS substat_1,
  93. (SELECT value + grind FROM rune_stat WHERE rune = rune.id AND slot = " . RUNE_STAT_SLOT_ID::SUBSTAT_1 . " ) AS substat_1_value,
  94. (SELECT stat FROM rune_stat WHERE rune = rune.id AND slot = " . RUNE_STAT_SLOT_ID::SUBSTAT_2 . " ) AS substat_2,
  95. (SELECT value + grind FROM rune_stat WHERE rune = rune.id AND slot = " . RUNE_STAT_SLOT_ID::SUBSTAT_2 . " ) AS substat_2_value,
  96. (SELECT stat FROM rune_stat WHERE rune = rune.id AND slot = " . RUNE_STAT_SLOT_ID::SUBSTAT_3 . " ) AS substat_3,
  97. (SELECT value + grind FROM rune_stat WHERE rune = rune.id AND slot = " . RUNE_STAT_SLOT_ID::SUBSTAT_3 . " ) AS substat_3_value,
  98. (SELECT stat FROM rune_stat WHERE rune = rune.id AND slot = " . RUNE_STAT_SLOT_ID::SUBSTAT_4 . " ) AS substat_4,
  99. (SELECT value + grind FROM rune_stat WHERE rune = rune.id AND slot = " . RUNE_STAT_SLOT_ID::SUBSTAT_4 . " ) AS substat_4_value
  100. FROM rune
  101. WHERE
  102. player = :player AND
  103. type IN (
  104. ";
  105. foreach ($sets as $set){
  106. $base_s .= ($set . ",");
  107. }
  108. $base_s .= "-1) AND ";
  109. switch ($source){
  110. case 0: // Storage only (or itself)
  111. $base_s .= "
  112. (
  113. rune.id IN (SELECT DISTINCT unit FROM unit_rune WHERE unit = :unit_id AND rta = " . $game_mode . ")
  114. OR rune.id NOT IN (SELECT DISTINCT unit FROM unit_rune WHERE rta = " . $game_mode . ")
  115. )";
  116. break;
  117. case 1: // Units in no teams (or itself)
  118. $base_s .= "
  119. (
  120. rune.id IN (SELECT DISTINCT unit FROM unit_rune WHERE unit = :unit_id AND rta = " . $game_mode . ")
  121. OR rune.id NOT IN (SELECT DISTINCT unit FROM unit_rune WHERE rta = " . $game_mode . ")
  122. OR rune.id NOT IN (SELECT DISTINCT unit FROM unit_rune WHERE rta = " . $game_mode . " AND unit NOT IN (SELECT DISTINCT unit FROM team_unit))
  123. )
  124. ";
  125. break;
  126. case 2: // Units in teams with 0 score (or itself)
  127. $base_s .= "
  128. (
  129. rune.id IN (SELECT DISTINCT unit FROM unit_rune WHERE unit = :unit_id AND rta = " . $game_mode . ")
  130. OR rune.id NOT IN (SELECT DISTINCT unit FROM unit_rune WHERE rta = " . $game_mode . ")
  131. OR rune.id NOT IN (
  132. SELECT DISTINCT unit
  133. FROM unit_rune
  134. WHERE
  135. rta = " . $game_mode . "
  136. AND unit NOT IN (
  137. SELECT DISTINCT unit
  138. FROM
  139. team,
  140. team_unit
  141. WHERE
  142. team.id = team_unit.team
  143. AND team.score > 0
  144. )
  145. )
  146. )
  147. ";
  148. break;
  149. case 3: // Units with lower overall score (or itself)
  150. // TODO
  151. break;
  152. case 4: // All runes - dont filter
  153. $base_s .= " 1 = 1 ";
  154. break;
  155. default: // Invalid options - return nothing
  156. $base_s .= " 1 = 0 ";
  157. }
  158. $s_order = " ORDER BY stars DESC, original_quality DESC, max_efficiency DESC, efficiency DESC, level DESC";
  159. $s_in = " main_stat IN (:stat_0, :stat_1, :stat_2) ";
  160. $s = ["", "", "", "", "", "", ""];
  161. $s[1] = $base_s . " AND slot = 1 " . $s_order;
  162. $s[3] = $base_s . " AND slot = 3 " . $s_order;
  163. $s[5] = $base_s . " AND slot = 5 " . $s_order;
  164. $s[2] = $base_s . " AND slot = 2 AND " . $s_in . $s_order;
  165. $s[4] = $base_s . " AND slot = 4 AND " . $s_in . $s_order;
  166. $s[6] = $base_s . " AND slot = 6 AND " . $s_in . $s_order;
  167. $total_candidates = 0;
  168. for ($i = 1; $i <= 6; $i ++){
  169. //error_log($s[$i]);
  170. $statement = get_context()->get_db()->prepare($s[$i]);
  171. $statement->bindValue(':player', $player, SQLITE3_TEXT);
  172. $statement->bindValue(':unit_id', $unit_id, SQLITE3_TEXT);
  173. $statement->bindValue(':stat_0', $stats[0], SQLITE3_TEXT);
  174. $statement->bindValue(':stat_1', $stats[1], SQLITE3_TEXT);
  175. $statement->bindValue(':stat_2', $stats[2], SQLITE3_TEXT);
  176. $q = $statement->execute();
  177. while ($r = $q->fetchArray(SQLITE3_ASSOC)){
  178. $rune = create_rune_array($unit, $r, $tuning);
  179. //array_push($candidates[$i], new Rune($r["id"]));
  180. array_push($candidates[$i], $rune);
  181. $total_candidates ++;
  182. }
  183. }
  184. //$max_combinations = sizeof($candidates[1]) * sizeof($candidates[2]) * sizeof($candidates[3]) * sizeof($candidates[4]) * sizeof($candidates[5]) * sizeof($candidates[6]);
  185. // Build response
  186. $response = json_encode($candidates);
  187. if ($response == null){
  188. return 0;
  189. }
  190. else{
  191. return $response;
  192. }
  193. }
  194. /**
  195. * Creates an array with the stats provided by a rune on a unit.
  196. *
  197. * @param Unit $unit Target unit.
  198. * @param int $r Rune main stat ID.
  199. * @param int $stars Rune stars.
  200. * @return int Value of the main stat at the selected level.
  201. */
  202. function create_rune_array($unit, $r, $tuning){
  203. $rune = [
  204. "ID" => $r["id"],
  205. "TYPE" => $r["type"],
  206. "ATK" => 0,
  207. "DEF" => 0,
  208. "HP" => 0,
  209. "SPD" => 0,
  210. "CRR" => 0,
  211. "CRD" => 0,
  212. "ACC" => 0,
  213. "RES" => 0
  214. ];
  215. // Calculate main stat value based on requested level.
  216. $level = $r["level"];
  217. $main_value = $r["main_stat_value"];
  218. switch ($tuning){
  219. case 1: // All +12
  220. if ($level < 12){
  221. $main_value = get_main_stat_at_level(12, $r["main_stat"], $r["stars"]);
  222. }
  223. break;
  224. case 2: // Even +15, Odd + 12
  225. if ($level < 15 && $r["slot"] % 2 == 0){
  226. $main_value = get_main_stat_at_level(15, $r["main_stat"], $r["stars"]);
  227. }
  228. elseif ($level < 12 && $r["slot"] % 2 != 0){
  229. $main_value = get_main_stat_at_level(12, $r["main_stat"], $r["stars"]);
  230. }
  231. break;
  232. case 3: // All +15
  233. if ($level < 15){
  234. $main_value = get_main_stat_at_level(15, $r["main_stat"], $r["stars"]);
  235. }
  236. break;
  237. }
  238. // Array to loop.
  239. $stats = [
  240. [
  241. "STAT" => $r["main_stat"],
  242. "VALUE" => $main_value
  243. ],
  244. [
  245. "STAT" => $r["innate_stat"],
  246. "VALUE" => $r["innate_stat_value"]
  247. ],
  248. [
  249. "STAT" => $r["substat_1"],
  250. "VALUE" => $r["substat_1_value"]
  251. ],
  252. [
  253. "STAT" => $r["substat_2"],
  254. "VALUE" => $r["substat_2_value"]
  255. ],
  256. [
  257. "STAT" => $r["substat_3"],
  258. "VALUE" => $r["substat_3_value"]
  259. ],
  260. [
  261. "STAT" => $r["substat_4"],
  262. "VALUE" => $r["substat_4_value"]
  263. ]
  264. ];
  265. foreach ($stats as $stat){
  266. switch ($stat["STAT"]){
  267. case RUNE_STAT_ID::ATK:
  268. $rune["ATK"] += $stat["VALUE"];
  269. break;
  270. case RUNE_STAT_ID::ATK_P:
  271. $rune["ATK"] += ($unit->get_base_stats()["atk"] * $stat["VALUE"] / 100);
  272. break;
  273. case RUNE_STAT_ID::DEF:
  274. $rune["DEF"] += $stat["VALUE"];
  275. break;
  276. case RUNE_STAT_ID::DEF_P:
  277. $rune["DEF"] += ($unit->get_base_stats()["def"] * $stat["VALUE"] / 100);
  278. break;
  279. case RUNE_STAT_ID::HP:
  280. $rune["HP"] += $stat["VALUE"];
  281. break;
  282. case RUNE_STAT_ID::HP_P:
  283. $rune["HP"] += ($unit->get_base_stats()["hp"] * $stat["VALUE"] / 100);
  284. break;
  285. case RUNE_STAT_ID::SPD:
  286. $rune["SPD"] += $stat["VALUE"];
  287. break;
  288. case RUNE_STAT_ID::CRR:
  289. $rune["CRR"] += $stat["VALUE"];
  290. break;
  291. case RUNE_STAT_ID::CRD:
  292. $rune["CRD"] += $stat["VALUE"];
  293. break;
  294. case RUNE_STAT_ID::ACC:
  295. $rune["ACC"] += $stat["VALUE"];
  296. break;
  297. case RUNE_STAT_ID::RES:
  298. $rune["RES"] += $stat["VALUE"];
  299. break;
  300. }
  301. }
  302. return $rune;
  303. }
  304. /**
  305. * Gets the value of the main stat at an arbitrary level.
  306. *
  307. * @param int $level Desired level.
  308. * @param int $stat Rune main stat ID.
  309. * @param int $stars Rune stars.
  310. * @return int Value of the main stat at the selected level.
  311. */
  312. function get_main_stat_at_level($level, $stat, $stars){
  313. $level = intval($level);
  314. if ($level < 0 || $level > 15){
  315. return 0;
  316. }
  317. switch ($stat){
  318. case RUNE_STAT_ID::HP:
  319. return RUNE_STAT_VALUES::HP[$stars][$level];
  320. case RUNE_STAT_ID::HP_P:
  321. return RUNE_STAT_VALUES::HP_P[$stars][$level];
  322. case RUNE_STAT_ID::ATK:
  323. return RUNE_STAT_VALUES::ATK[$stars][$level];
  324. case RUNE_STAT_ID::ATK_P:
  325. return RUNE_STAT_VALUES::ATK_P[$stars][$level];
  326. case RUNE_STAT_ID::DEF:
  327. return RUNE_STAT_VALUES::DEF[$stars][$level];
  328. case RUNE_STAT_ID::DEF_P:
  329. return RUNE_STAT_VALUES::DEF_P[$stars][$level];
  330. case RUNE_STAT_ID::SPD:
  331. return RUNE_STAT_VALUES::SPD[$stars][$level];
  332. case RUNE_STAT_ID::CRR:
  333. return RUNE_STAT_VALUES::CRR[$stars][$level];
  334. case RUNE_STAT_ID::CRD:
  335. return RUNE_STAT_VALUES::CRD[$stars][$level];
  336. case RUNE_STAT_ID::RES:
  337. return RUNE_STAT_VALUES::RES[$stars][$level];
  338. case RUNE_STAT_ID::ACC:
  339. return RUNE_STAT_VALUES::ACC[$stars][$level];
  340. default:
  341. return 0;
  342. }
  343. }