[], 2 => [], 3 => [], 4 => [], 5 => [], 6 => [] ]; $options = []; $response = null; $uid = filter_input(INPUT_POST, 'uid'); if ($uid == null){ return -1; } $unit_id = filter_input(INPUT_POST, 'unit'); if ($unit_id == null){ 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){ 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){ return -4; } $tuning = filter_input(INPUT_POST, 'tuning'); if ($tuning == null){ return -5; } $min = [ "attack" => intval(filter_input(INPUT_POST, 'min_attack')), "defense" => intval(filter_input(INPUT_POST, 'min_defense')), "hp" => intval(filter_input(INPUT_POST, 'min_hp')), "speed" => intval(filter_input(INPUT_POST, 'min_speed')), "crit_rate" => intval(filter_input(INPUT_POST, 'min_crit_rate')), "crit_damage" => intval(filter_input(INPUT_POST, 'min_crit_damage')), "accuracy" => intval(filter_input(INPUT_POST, 'min_accuracy')), "resistance" => intval(filter_input(INPUT_POST, 'min_resistance')), "ehp" => intval(filter_input(INPUT_POST, 'min_ehp')), "dmg" => intval(filter_input(INPUT_POST, 'min_dmg')) ]; // Get Buld query: $s = " SELECT id, slot FROM rune WHERE uid = $uid AND type IN ( "; foreach ($sets as $set){ $s .= ($set . ","); } $s .= "-1) AND "; switch ($source){ case 0: // Storage only (or itself) $s .= " ( assigned_to = $unit_id OR assigned_to IS NULL )"; break; case 1: // Units in no teams (or itself) $s .= " ( assigned_to = $unit_id OR assigned_to IS NULL OR assigned_to NOT IN (SELECT DISTINCT unit FROM team_unit) ) "; break; case 2: // Units in teams with 0 score (or itself) $s .= " ( assigned_to = $unit_id OR assigned_to IS NULL OR assigned_to NOT IN (SELECT DISTINCT unit FROM team_unit) OR assigned_to NOT IN ( SELECT DISTINCT unit FROM team, team_unit WHERE team.id = team_unit.team AND team.score > 0 ) ) "; break; case 3: // Units with lower overall score (or itself) // TODO break; case 4: // All runes - dont filter $s .= " 1 = 1 "; break; default: // Invalid options - return nothing $s .= " 1 = 0 "; } // Even slots stats $s .= " AND ( slot <> 2 OR ( slot = 2 AND main_stat = " . $stats[0] . " ) ) AND ( slot <> 4 OR ( slot = 4 AND main_stat = " . $stats[1] . " ) ) AND ( slot <> 6 OR ( slot = 6 AND main_stat = " . $stats[2] . " ) ) "; error_log($s); $q = $db->query($s); $total_candidates = 0; while ($r = $q->fetchArray(SQLITE3_ASSOC)){ array_push($candidates[$r["slot"]], new Rune($r["id"])); $total_candidates ++; } $max_combinations = sizeof($candidates[1]) * sizeof($candidates[2]) * sizeof($candidates[3]) * sizeof($candidates[4]) * sizeof($candidates[5]) * sizeof($candidates[6]); if ($max_combinations == 0){ $res = [ "total" => 0, "options" => [] ]; $response = json_encode($res); return $response; } // Get the unit and its base stats $unit = new Unit($unit_id, true, $uid); $unit_attack = $unit->attack + $unit->artifact_attack + $unit->building_attack; $unit_base_attack = $unit->attack; $unit_defense = $unit->defense + $unit->artifact_defense + $unit->building_defense; $unit_base_defense = $unit->defense; $unit_hp = $unit->hp + $unit->artifact_hp + $unit->building_hp; $unit_base_hp = $unit->hp; $unit_speed = $unit->speed + $unit->artifact_speed + $unit->building_speed; $unit_base_speed = $unit->speed; $unit_crit_rate = $unit->crit_rate + $unit->artifact_crit_rate + $unit->building_crit_rate; $unit_base_crit_rate = $unit->crit_rate; $unit_crit_damage = $unit->crit_damage + $unit->artifact_crit_damage + $unit->building_crit_damage; $unit_base_crit_damage = $unit->crit_damage; $unit_accuracy = $unit->accuracy + $unit->artifact_accuracy + $unit->building_accuracy; $unit_base_accuracy = $unit->accuracy; $unit_resistance = $unit->resistance + $unit->artifact_resistance + $unit->building_resistance; $unit_base_resistance = $unit->resistance; $i = [0, 0, 0, 0, 0, 0, 0]; // 7, so I can start with 1 while (true){ // Check if set combination is valid if (valid_sets($candidates, $i)){ // Do things $iteration = [ "attack" => $unit_attack, "defense" => $unit_defense, "hp" => $unit_hp, "speed" => $unit_speed, "crit_rate" => $unit_crit_rate, "crit_damage" => $unit_crit_damage, "accuracy" => $unit_accuracy, "resistance" => $unit_resistance, "ehp" => 0, // TODO "dmg" => 0, // TODO ]; for ($r = 1; $r <= 6; $r ++){ // Loop selected runes and calculate stats sum_rune_stat( $candidates[$r][$i[$r]]->main_stat, $candidates[$r][$i[$r]]->main_stat_value, $iteration, $unit_base_attack, $unit_base_defense, $unit_base_hp, ); sum_rune_stat( $candidates[$r][$i[$r]]->innate_stat, $candidates[$r][$i[$r]]->innate_stat_value, $iteration, $unit_base_attack, $unit_base_defense, $unit_base_hp, ); sum_rune_stat( $candidates[$r][$i[$r]]->substat_1, $candidates[$r][$i[$r]]->substat_1_value, $iteration, $unit_base_attack, $unit_base_defense, $unit_base_hp, ); sum_rune_stat( $candidates[$r][$i[$r]]->substat_2, $candidates[$r][$i[$r]]->substat_2_value, $iteration, $unit_base_attack, $unit_base_defense, $unit_base_hp, ); sum_rune_stat( $candidates[$r][$i[$r]]->substat_3, $candidates[$r][$i[$r]]->substat_3_value, $iteration, $unit_base_attack, $unit_base_defense, $unit_base_hp, ); sum_rune_stat( $candidates[$r][$i[$r]]->substat_4, $candidates[$r][$i[$r]]->substat_4_value, $iteration, $unit_base_attack, $unit_base_defense, $unit_base_hp, ); } // Compare with filters: // TODO: Calculat EHP and DMG if ( $iteration["attack"] >= $min["attack"] && $iteration["defense"] >= $min["defense"] && $iteration["hp"] >= $min["hp"] && $iteration["speed"] >= $min["speed"] && $iteration["crit_rate"] >= $min["crit_rate"] && $iteration["crit_damage"] >= $min["crit_damage"] && $iteration["accuracy"] >= $min["accuracy"] && $iteration["resistance"] >= $min["resistance"] // TODO ehp dmg ){ // Calculate the variation $variation = 0; $variation += (($iteration["attack"] - $unit->total_attack) * 1); $variation += (($iteration["defense"] - $unit->total_defense) * 1); $variation += (($iteration["hp"] - $unit->total_hp) * (1 / 15)); $variation += (($iteration["speed"] - $unit->total_speed) * 1.5); $variation += (($iteration["crit_rate"] - $unit->total_crit_rate) * 0.85); $variation += (($iteration["crit_damage"] - $unit->total_crit_damage) * 0.9); $variation += (($iteration["accuracy"] - $unit->total_accuracy) * 0.85); $variation += (($iteration["resistance"] - $unit->total_resistance) * 0.85); $variation = ceil($variation); // Build the array $option = [ "variation" => $variation, "runes" => [ [ "id" => $candidates[1][$i[1]]->id, "html" => (HTML::rune_table($candidates[1][$i[1]])) ], [ "id" => $candidates[2][$i[2]]->id, "html" => (HTML::rune_table($candidates[2][$i[2]])) ], [ "id" => $candidates[3][$i[3]]->id, "html" => (HTML::rune_table($candidates[3][$i[3]])) ], [ "id" => $candidates[4][$i[4]]->id, "html" => (HTML::rune_table($candidates[4][$i[4]])) ], [ "id" => $candidates[5][$i[5]]->id, "html" => (HTML::rune_table($candidates[5][$i[5]])) ], [ "id" => $candidates[1][$i[1]]->id, "html" => HTML::rune_table($candidates[6][$i[6]]) ] ], "stats" => [ "attack" => ceil($iteration["attack"]), "defense" => ceil($iteration["defense"]), "hp" => ceil($iteration["hp"]), "speed" => ceil($iteration["speed"]), "crit_rate" => ceil($iteration["crit_rate"]), "crit_damage" => ceil($iteration["crit_damage"]), "accuracy" => ceil($iteration["accuracy"]), "attack" => ceil($iteration["attack"]), "resistance" => ceil($iteration["resistance"]), "ehp" => ceil($iteration["ehp"]), "dmg" => ceil($iteration["dmg"]) ] ]; array_push($options, $option); if (sizeof($options) > 100){ http_response_code(413); // Payload too large; die(); return; } } } // Increase counters $i[6] ++; if ($i[6] == sizeof($candidates[6])){ $i[6] = 0; $i[5] ++; } if ($i[5] == sizeof($candidates[5])){ $i[5] = 0; $i[4] ++; } if ($i[4] == sizeof($candidates[4])){ $i[4] = 0; $i[3] ++; } if ($i[3] == sizeof($candidates[3])){ $i[3] = 0; $i[2] ++; } if ($i[2] == sizeof($candidates[2])){ $i[2] = 0; $i[1] ++; } // Calculate exit condition if ( $i[1] >= sizeof($candidates[1]) - 1 && $i[2] >= sizeof($candidates[2]) - 1 && $i[3] >= sizeof($candidates[3]) - 1 && $i[4] >= sizeof($candidates[4]) - 1 && $i[5] >= sizeof($candidates[5]) - 1 && $i[6] >= sizeof($candidates[6]) - 1 ){ break; } } // Sort options by variation usort($options, "sortOptions"); $res = [ "total" => sizeof($options), "options" => $options ]; $response = json_encode($res); if ($response == null){ return 0; } else{ return $response; } } /** * Validates a rune combination. * * Checks that set numbers are OK. * * TODO: Verify that it complies with filters * * @param \Rune[][] $candidates Candidate runes. * @param int[] $indexes Currently selected indexes. */ function valid_sets($candidates, $indexes){ $sets = [ RUNE_SET_ID::ENERGY => 0, RUNE_SET_ID::GUARD => 0, RUNE_SET_ID::SWIFT => 0, RUNE_SET_ID::BLADE => 0, RUNE_SET_ID::RAGE => 0, RUNE_SET_ID::FOCUS => 0, RUNE_SET_ID::ENDURE => 0, RUNE_SET_ID::FATAL => 0, RUNE_SET_ID::DESPAIR => 0, RUNE_SET_ID::VAMPIRE => 0, RUNE_SET_ID::VIOLENT => 0, RUNE_SET_ID::NEMESIS => 0, RUNE_SET_ID::WILL => 0, RUNE_SET_ID::SHIELD => 0, RUNE_SET_ID::REVENGE => 0, RUNE_SET_ID::DESTROY => 0, RUNE_SET_ID::FIGHT => 0, RUNE_SET_ID::DETERMINATION => 0, RUNE_SET_ID::ENHANCE => 0, RUNE_SET_ID::ACCURACY => 0, RUNE_SET_ID::TOLERANCE => 0 ]; for ($i = 1; $i <= 6; $i++){ $sets[$candidates[$i][$indexes[$i]]->type->id] ++; } for ($i = 0; $i < sizeof($sets); $i ++){ switch ($i){ case RUNE_SET_ID::ENERGY: case RUNE_SET_ID::GUARD: case RUNE_SET_ID::NEMESIS: case RUNE_SET_ID::BLADE: case RUNE_SET_ID::FOCUS: case RUNE_SET_ID::ENDURE: case RUNE_SET_ID::WILL: case RUNE_SET_ID::SHIELD: case RUNE_SET_ID::REVENGE: case RUNE_SET_ID::DESTROY: case RUNE_SET_ID::FIGHT: case RUNE_SET_ID::DETERMINATION: case RUNE_SET_ID::ENHANCE: case RUNE_SET_ID::ACCURACY: case RUNE_SET_ID::TOLERANCE: if ($sets[$i] % 2 != 0){ return false; } break; case RUNE_SET_ID::DESPAIR: case RUNE_SET_ID::SWIFT: case RUNE_SET_ID::RAGE: case RUNE_SET_ID::FATAL: case RUNE_SET_ID::VAMPIRE: case RUNE_SET_ID::VIOLENT: if ($sets[$i] != 4 && $sets[$i != 0]){ return false; } break; } } return true; } /** * Calculates the stat increase by a rune property. * * @param string $stat Stat type. * @param int $value Stat increase value. * @param int[] Reference to iteration stats array. */ function sum_rune_stat($stat, $value, &$iteration, $base_atk, $base_def, $base_hp){ switch ($stat){ case RUNE_STAT_ID::ATK: $iteration["attack"] += $value; break; case RUNE_STAT_ID::DEF: $iteration["defense"] += $value; break; case RUNE_STAT_ID::HP: $iteration["hp"] += $value; break; case RUNE_STAT_ID::SPD: $iteration["speed"] += $value; break; case RUNE_STAT_ID::CRR: $iteration["crit_rate"] += $value; break; case RUNE_STAT_ID::CRD: $iteration["crit_damage"] += $value; break; case RUNE_STAT_ID::ACC: $iteration["accuracy"] += $value; break; case RUNE_STAT_ID::RES: $iteration["resistance"] += $value; break; case RUNE_STAT_ID::ATK_P: $iteration["attack"] += ($base_atk * $value / 100); break; case RUNE_STAT_ID::DEF_P: $iteration["defense"] += ($base_def * $value / 100); break; case RUNE_STAT_ID::HP_P: $iteration["hp"] += ($base_hp * $value / 100); break; } } function sortOptions($a, $b) { return $b["variation"] - $a["variation"]; } ?>