|
|
@@ -54,6 +54,19 @@
|
|
|
"ehp": <?=$page->unit->effective_hp?>,
|
|
|
"dmg": <?=$page->unit->effective_dmg?>
|
|
|
}
|
|
|
+
|
|
|
+ var base_stats = {
|
|
|
+ "attack": <?=$page->unit->attack?>,
|
|
|
+ "defense": <?=$page->unit->defense?>,
|
|
|
+ "hp": <?=$page->unit->hp?>,
|
|
|
+ "speed": <?=$page->unit->speed?>,
|
|
|
+ "crit_rate": <?=$page->unit->crit_rate?>,
|
|
|
+ "crit_damage": <?=$page->unit->crit_damage?>,
|
|
|
+ "accuracy": <?=$page->unit->accuracy?>,
|
|
|
+ "resistance": <?=$page->unit->resistance?>,
|
|
|
+ "ehp": <?=$page->unit->effective_hp?>,
|
|
|
+ "dmg": <?=$page->unit->effective_dmg?>
|
|
|
+ }
|
|
|
|
|
|
<?php
|
|
|
// Get current rune sets
|
|
|
@@ -83,6 +96,25 @@
|
|
|
* To calculate time.
|
|
|
*/
|
|
|
var timestamp = 0;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Enables or disables a new search.
|
|
|
+ *
|
|
|
+ * When disabled, the apply button will be disabled and a waiting
|
|
|
+ * icon will be shown.
|
|
|
+ *
|
|
|
+ * @param enable true to enable, false to disable.
|
|
|
+ */
|
|
|
+ function enableNewSearch(enable){
|
|
|
+ if (enable === true){
|
|
|
+ document.getElementById('apply').removeAttribute('disabled');
|
|
|
+ document.getElementById('wait').style.display = 'none';
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ document.getElementById('apply').setAttribute('disabled', 'disabled');
|
|
|
+ document.getElementById('wait').style.display = 'block';
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
/**
|
|
|
* Updates the value next to the sliders when they change.
|
|
|
@@ -124,17 +156,33 @@
|
|
|
document.getElementById('min_' + stat).value = document.getElementById('min_' + stat).min;
|
|
|
}
|
|
|
|
|
|
+ function log(text){
|
|
|
+ var log_window = document.getElementById('log_window');
|
|
|
+ var span = document.createElement('span');
|
|
|
+ span.setAttribute('class', 'log_message');
|
|
|
+ text = document.createTextNode(text);
|
|
|
+ span.appendChild(text);
|
|
|
+ log_window.appendChild(span);
|
|
|
+ log_window.scrollTo(0, 2 * log_window.offsetHeight);
|
|
|
+ }
|
|
|
+ function clearLog(){
|
|
|
+ const elements = document.querySelectorAll('.log_message');
|
|
|
+ Array.from(elements).forEach((element, index) => {
|
|
|
+ element.remove();
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 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.
|
|
|
+ * not, builds the url to fetch all candidate runes.
|
|
|
*
|
|
|
* @return false on error, true on success.
|
|
|
*/
|
|
|
function apply(){
|
|
|
+ log("Start optimization...");
|
|
|
|
|
|
var params = '';
|
|
|
var x;
|
|
|
@@ -229,17 +277,16 @@
|
|
|
var xhttp = new XMLHttpRequest();
|
|
|
xhttp.onreadystatechange = function() {
|
|
|
if (this.readyState == 4){
|
|
|
- document.getElementById('apply').removeAttribute('disabled');
|
|
|
- document.getElementById('wait').style.display = 'none';
|
|
|
if (this.status == 200) {
|
|
|
time = ((+ new Date()) - timestamp) / 1000;
|
|
|
- showOptimizations(this.response, time);
|
|
|
+ calculateOptimizations(this.response, time);
|
|
|
}
|
|
|
- else if (this.status == 413) { // Payload too large
|
|
|
- showMessage('Error', 'Too many combination found. Plesase narow your criteria and retry.');
|
|
|
- }
|
|
|
- else if (this.status == 500) { // Server error
|
|
|
- showMessage('Error', 'Too many rune combination found. Plesase narow your criteria and retry.');
|
|
|
+ else{
|
|
|
+ enableNewSearch(true);
|
|
|
+ var time = ((+ new Date()) - timestamp) / 1000;
|
|
|
+ log('Error ' + this.status + '(' + time + 's)');
|
|
|
+
|
|
|
+ showMessage('Error', 'Unexpected error ' + this.status);
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
@@ -253,35 +300,371 @@
|
|
|
while (container.firstChild) {
|
|
|
container.removeChild(container.firstChild);
|
|
|
}
|
|
|
- document.getElementById('apply').setAttribute('disabled', 'disabled');
|
|
|
- document.getElementById('wait').style.display = 'block';
|
|
|
+ enableNewSearch(false);
|
|
|
document.getElementById('results').style.display = 'none';
|
|
|
|
|
|
// Start timer
|
|
|
timestamp = + new Date();
|
|
|
|
|
|
// Make the request
|
|
|
- xhttp.open('POST', '/action/optimize/', true);
|
|
|
+ xhttp.open('POST', '/action/optimize_get_rune_list/', true);
|
|
|
xhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
|
|
|
xhttp.send(params);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Parses the received content and creates the HTML with the new
|
|
|
- * rune options.
|
|
|
+ * Checks if a rune combination is a valid set. To do so, checks:
|
|
|
+ *
|
|
|
+ * - That the sets are valid
|
|
|
+ * - That the sets are the same as requested
|
|
|
+ * - That it complies with the filters min values.
|
|
|
+ *
|
|
|
+ * @param candidates Array of 6 runes
|
|
|
+ * @return true if the set matches the criteria, false otherwise.
|
|
|
+ */
|
|
|
+ function valid_set(candidates){
|
|
|
+
|
|
|
+ // Number of applied sets with the current candidates.
|
|
|
+ var sets = {
|
|
|
+ 'RUNE_SET_<?=RUNE_SET_ID::ENERGY?>': 0, // ENERGY
|
|
|
+ 'RUNE_SET_<?=RUNE_SET_ID::GUARD?>': 0, // GUARD
|
|
|
+ 'RUNE_SET_<?=RUNE_SET_ID::SWIFT?>': 0, // SWIFT
|
|
|
+ 'RUNE_SET_<?=RUNE_SET_ID::BLADE?>': 0, // BLADE
|
|
|
+ 'RUNE_SET_<?=RUNE_SET_ID::RAGE?>': 0, // RAGE
|
|
|
+ 'RUNE_SET_<?=RUNE_SET_ID::FOCUS?>': 0, // FOCUS
|
|
|
+ 'RUNE_SET_<?=RUNE_SET_ID::ENDURE?>': 0, // ENDURE
|
|
|
+ 'RUNE_SET_<?=RUNE_SET_ID::FATAL?>': 0, // FATAL
|
|
|
+ 'RUNE_SET_<?=RUNE_SET_ID::DESPAIR?>': 0, // DESPAIR
|
|
|
+ 'RUNE_SET_<?=RUNE_SET_ID::VAMPIRE?>': 0, // VAMPIRE
|
|
|
+ 'RUNE_SET_<?=RUNE_SET_ID::VIOLENT?>': 0, // VIOLENT
|
|
|
+ 'RUNE_SET_<?=RUNE_SET_ID::NEMESIS?>': 0, // NEMESIS
|
|
|
+ 'RUNE_SET_<?=RUNE_SET_ID::WILL?>': 0, // WILL
|
|
|
+ 'RUNE_SET_<?=RUNE_SET_ID::SHIELD?>': 0, // SHIELD
|
|
|
+ 'RUNE_SET_<?=RUNE_SET_ID::REVENGE?>': 0, // REVENGE
|
|
|
+ 'RUNE_SET_<?=RUNE_SET_ID::DESTROY?>': 0, // DESTROY
|
|
|
+ 'RUNE_SET_<?=RUNE_SET_ID::FIGHT?>': 0, // FIGHT
|
|
|
+ 'RUNE_SET_<?=RUNE_SET_ID::DETERMINATION?>': 0, // DETERMINATION
|
|
|
+ 'RUNE_SET_<?=RUNE_SET_ID::ENHANCE?>': 0, // ENHANCE
|
|
|
+ 'RUNE_SET_<?=RUNE_SET_ID::ACCURACY?>': 0, // ACCURACY
|
|
|
+ 'RUNE_SET_<?=RUNE_SET_ID::TOLERANCE?>': 0 // TOLERANCE
|
|
|
+ };
|
|
|
+ for (var i = 0; i <= 5; i ++){
|
|
|
+ sets['RUNE_SET_' + candidates[i].TYPE] ++;
|
|
|
+ }
|
|
|
+ // TEST I think i dont need to check for valid sets, only that
|
|
|
+ // they match the requested sets.
|
|
|
+ /*for (var i = 0; i < sets.length; 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;
|
|
|
+ }
|
|
|
+ }*/
|
|
|
+
|
|
|
+ // Its a valid set, but does it match the requested sets?
|
|
|
+ var requested_sets = {
|
|
|
+ 'RUNE_SET_<?=RUNE_SET_ID::ENERGY?>': 0, // ENERGY
|
|
|
+ 'RUNE_SET_<?=RUNE_SET_ID::GUARD?>': 0, // GUARD
|
|
|
+ 'RUNE_SET_<?=RUNE_SET_ID::SWIFT?>': 0, // SWIFT
|
|
|
+ 'RUNE_SET_<?=RUNE_SET_ID::BLADE?>': 0, // BLADE
|
|
|
+ 'RUNE_SET_<?=RUNE_SET_ID::RAGE?>': 0, // RAGE
|
|
|
+ 'RUNE_SET_<?=RUNE_SET_ID::FOCUS?>': 0, // FOCUS
|
|
|
+ 'RUNE_SET_<?=RUNE_SET_ID::ENDURE?>': 0, // ENDURE
|
|
|
+ 'RUNE_SET_<?=RUNE_SET_ID::FATAL?>': 0, // FATAL
|
|
|
+ 'RUNE_SET_<?=RUNE_SET_ID::DESPAIR?>': 0, // DESPAIR
|
|
|
+ 'RUNE_SET_<?=RUNE_SET_ID::VAMPIRE?>': 0, // VAMPIRE
|
|
|
+ 'RUNE_SET_<?=RUNE_SET_ID::VIOLENT?>': 0, // VIOLENT
|
|
|
+ 'RUNE_SET_<?=RUNE_SET_ID::NEMESIS?>': 0, // NEMESIS
|
|
|
+ 'RUNE_SET_<?=RUNE_SET_ID::WILL?>': 0, // WILL
|
|
|
+ 'RUNE_SET_<?=RUNE_SET_ID::SHIELD?>': 0, // SHIELD
|
|
|
+ 'RUNE_SET_<?=RUNE_SET_ID::REVENGE?>': 0, // REVENGE
|
|
|
+ 'RUNE_SET_<?=RUNE_SET_ID::DESTROY?>': 0, // DESTROY
|
|
|
+ 'RUNE_SET_<?=RUNE_SET_ID::FIGHT?>': 0, // FIGHT
|
|
|
+ 'RUNE_SET_<?=RUNE_SET_ID::DETERMINATION?>': 0, // DETERMINATION
|
|
|
+ 'RUNE_SET_<?=RUNE_SET_ID::ENHANCE?>': 0, // ENHANCE
|
|
|
+ 'RUNE_SET_<?=RUNE_SET_ID::ACCURACY?>': 0, // ACCURACY
|
|
|
+ 'RUNE_SET_<?=RUNE_SET_ID::TOLERANCE?>': 0 // TOLERANCE
|
|
|
+ };
|
|
|
+ var selected_1 = document.getElementById('set_1').options[document.getElementById('set_1').selectedIndex].value;
|
|
|
+ var selected_2 = document.getElementById('set_2').options[document.getElementById('set_2').selectedIndex].value;
|
|
|
+ var selected_3 = document.getElementById('set_3').options[document.getElementById('set_3').selectedIndex].value;
|
|
|
+ var requested_values = [
|
|
|
+ document.getElementById('set_1').options[document.getElementById('set_1').selectedIndex].value,
|
|
|
+ document.getElementById('set_2').options[document.getElementById('set_2').selectedIndex].value,
|
|
|
+ document.getElementById('set_3').options[document.getElementById('set_3').selectedIndex].value
|
|
|
+ ];
|
|
|
+ for (var i = 0; i < 3; i ++){
|
|
|
+ switch (requested_values[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?>':
|
|
|
+ requested_sets['RUNE_SET_' + requested_values[i]] += 2;
|
|
|
+ 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?>':
|
|
|
+ requested_sets['RUNE_SET_' + i] += 4;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (JSON.stringify(sets) !== JSON.stringify(requested_sets)){
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Compare with filters
|
|
|
+ var new_stats = {
|
|
|
+ "ATK": base_stats["attack"],
|
|
|
+ "DEF": base_stats["defense"],
|
|
|
+ "HP": base_stats["hp"],
|
|
|
+ "SPD": base_stats["speed"],
|
|
|
+ "CRR": base_stats["crit_rate"],
|
|
|
+ "CRD": base_stats["crit_damage"],
|
|
|
+ "ACC": base_stats["accuracy"],
|
|
|
+ "RES": base_stats["resistance"],
|
|
|
+ "EHP": 0,
|
|
|
+ "DMG": 0
|
|
|
+ }
|
|
|
+ for (var i = 0; i <= 5; i ++){
|
|
|
+ new_stats["ATK"] += candidates[i].ATK;
|
|
|
+ new_stats["DEF"] += candidates[i].DEF;
|
|
|
+ new_stats["HP"] += candidates[i].HP;
|
|
|
+ new_stats["SPD"] += candidates[i].SPD;
|
|
|
+ new_stats["CRR"] += candidates[i].CRR;
|
|
|
+ new_stats["CRD"] += candidates[i].CRD;
|
|
|
+ new_stats["ACC"] += candidates[i].ACC;
|
|
|
+ new_stats["RES"] += candidates[i].RES;
|
|
|
+ }
|
|
|
+ new_stats["EHP"] = Math.ceil((((new_stats["DEF"] * 3.5) + 1140) * new_stats["HP"]) / 1000);
|
|
|
+ new_stats["DMG"] = Math.ceil((new_stats["ATK"] * (100 - new_stats["CRR"]) / 100) + ((new_stats["ATK"] + (new_stats["ATK"] * new_stats["CRD"] / 100)) * new_stats["CRR"] / 100));
|
|
|
+ if (
|
|
|
+ new_stats["ATK"] >= document.getElementById('min_attack').value &&
|
|
|
+ new_stats["DEF"] >= document.getElementById('min_defense').value &&
|
|
|
+ new_stats["HP"] >= document.getElementById('min_hp').value &&
|
|
|
+ new_stats["SPD"] >= document.getElementById('min_speed').value &&
|
|
|
+ new_stats["CRR"] >= document.getElementById('min_crit_rate').value &&
|
|
|
+ new_stats["CRD"] >= document.getElementById('min_crit_damage').value &&
|
|
|
+ new_stats["ACC"] >= document.getElementById('min_accuracy').value &&
|
|
|
+ new_stats["RES"] >= document.getElementById('min_resistance').value &&
|
|
|
+ new_stats["EHP"] >= document.getElementById('min_ehp').value &&
|
|
|
+ new_stats["DMG"] >= document.getElementById('min_dmg').value
|
|
|
+ ){
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Parses the received runes and looks for valid candidates.
|
|
|
+ * Once it's done, it calls the server agai to get rune info.
|
|
|
*
|
|
|
* @param content JSON received from server.
|
|
|
*/
|
|
|
- function showOptimizations(content, time){
|
|
|
+ async function calculateOptimizations(content, time){
|
|
|
var container = document.getElementById('optimizations');
|
|
|
var data = JSON.parse(content);
|
|
|
- if (Number(data.total) == 0){
|
|
|
+
|
|
|
+ // Create a 0-index array grouped by slot
|
|
|
+ var candidates = [
|
|
|
+ data[1],
|
|
|
+ data[2],
|
|
|
+ data[3],
|
|
|
+ data[4],
|
|
|
+ data[5],
|
|
|
+ data[6]
|
|
|
+ ];
|
|
|
+
|
|
|
+ // Calculate total combinations.
|
|
|
+ var total_runes = data[1].length + data[2].length + data[3].length + data[4].length + data[5].length + data[6].length;
|
|
|
+ var total_combinations = data[1].length * data[2].length * data[3].length * data[4].length * data[5].length * data[6].length;
|
|
|
+ if (total_combinations == 0){
|
|
|
+ var time = ((+ new Date()) - timestamp) / 1000;
|
|
|
+ log('No rune combinations found (' + time + 's)');
|
|
|
+ showMessage('No results', 'No runes found matching your criteria.');
|
|
|
+ }
|
|
|
+ var time = ((+ new Date()) - timestamp) / 1000;
|
|
|
+ log(total_runes + ' runes found (' + total_combinations + ' combinations) (' + time + 's)');
|
|
|
+ // TODO Prevent user on high numbers
|
|
|
+ var checked_combinations = 0;
|
|
|
+
|
|
|
+ // Valid combinations that match the minimum requeriments
|
|
|
+ var valid_combinations = [];
|
|
|
+
|
|
|
+ // Counters to keep track on array indexes
|
|
|
+ var counters = [0, 0, 0, 0, 0, 0];
|
|
|
+ // Loop all posible combinations. When a valid set is found,
|
|
|
+ // add it to valid_combinations
|
|
|
+ while (true){
|
|
|
+
|
|
|
+ if (valid_set([
|
|
|
+ candidates[0][counters[0]],
|
|
|
+ candidates[1][counters[1]],
|
|
|
+ candidates[2][counters[2]],
|
|
|
+ candidates[3][counters[3]],
|
|
|
+ candidates[4][counters[4]],
|
|
|
+ candidates[5][counters[5]]
|
|
|
+ ])){
|
|
|
+ valid_combinations.push({
|
|
|
+ 'score': 0,
|
|
|
+ 'runes': [
|
|
|
+ candidates[0][counters[0]],
|
|
|
+ candidates[1][counters[1]],
|
|
|
+ candidates[2][counters[2]],
|
|
|
+ candidates[3][counters[3]],
|
|
|
+ candidates[4][counters[4]],
|
|
|
+ candidates[5][counters[5]]
|
|
|
+ ]
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ // Increase counters
|
|
|
+ checked_combinations ++;
|
|
|
+ counters[5] ++;
|
|
|
+ if (counters[5] >= candidates[5].length){
|
|
|
+ counters[5] = 0;
|
|
|
+ counters[4] ++;
|
|
|
+ }
|
|
|
+ if (counters[4] >= candidates[4].length){
|
|
|
+ counters[4] = 0;
|
|
|
+ counters[3] ++;
|
|
|
+ }
|
|
|
+ if (counters[3] >= candidates[3].length){
|
|
|
+ counters[3] = 0;
|
|
|
+ counters[2] ++;
|
|
|
+ }
|
|
|
+ if (counters[2] >= candidates[2].length){
|
|
|
+ counters[2] = 0;
|
|
|
+ counters[1] ++;
|
|
|
+ }
|
|
|
+ if (counters[1] >= candidates[1].length){
|
|
|
+ counters[1] = 0;
|
|
|
+ counters[0] ++;
|
|
|
+ }
|
|
|
+ if (counters[0] >= candidates[0].length){
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*if (checked_combinations % 1000 == 0){
|
|
|
+ console.log("COMBINATIONS CHECKED: " + checked_combinations + " / " + total_combinations + "(" + (checked_combinations * 100 / total_combinations) + "%)");
|
|
|
+ console.log(" 0: " + counters[0] + "/" + candidates[0].length);
|
|
|
+ console.log(" 1: " + counters[1] + "/" + candidates[1].length);
|
|
|
+ console.log(" 2: " + counters[2] + "/" + candidates[2].length);
|
|
|
+ console.log(" 3: " + counters[3] + "/" + candidates[3].length);
|
|
|
+ console.log(" 4: " + counters[4] + "/" + candidates[4].length);
|
|
|
+ console.log(" 5: " + counters[5] + "/" + candidates[5].length);
|
|
|
+ }*/
|
|
|
+ }
|
|
|
+
|
|
|
+ // If no valid combinations: exit now
|
|
|
+ if (valid_combinations.length == 0){
|
|
|
+ enableNewSearch(true);
|
|
|
+ var time = ((+ new Date()) - timestamp) / 1000;
|
|
|
+ log('No suitable combination found (' + time + 's).');
|
|
|
showMessage('No results', 'No suitable combination found. Plesase relax your criteria and retry.');
|
|
|
+ }
|
|
|
+ // Foreach valid combination, rate it and sort the array
|
|
|
+ for (var i = 0; i < valid_combinations.length; i ++){
|
|
|
+ for (var r = 0; r < 6; r ++){
|
|
|
+ valid_combinations[i]['score'] += valid_combinations[i]["runes"][r]["ATK"];
|
|
|
+ valid_combinations[i]['score'] += valid_combinations[i]["runes"][r]["DEF"];
|
|
|
+ valid_combinations[i]['score'] += (valid_combinations[i]["runes"][r]["HP"] / 15);
|
|
|
+ valid_combinations[i]['score'] += (valid_combinations[i]["runes"][r]["SPD"] * 1.5);
|
|
|
+ valid_combinations[i]['score'] += (valid_combinations[i]["runes"][r]["CRR"] * 1.2);
|
|
|
+ valid_combinations[i]['score'] += (valid_combinations[i]["runes"][r]["CRD"] * 1.2);
|
|
|
+ valid_combinations[i]['score'] += (valid_combinations[i]["runes"][r]["ACC"] * 1.2);
|
|
|
+ valid_combinations[i]['score'] += (valid_combinations[i]["runes"][r]["ATK"] * 1.2);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ var time = ((+ new Date()) - timestamp) / 1000;
|
|
|
+ log(valid_combinations.length + ' suitable combinations found (' + time + 's)');
|
|
|
+ valid_combinations.sort(function(a, b) {return b['score'] - a['score'];});
|
|
|
+ if (valid_combinations.length > document.getElementById('limit').value){
|
|
|
+ var time = ((+ new Date()) - timestamp) / 1000;
|
|
|
+ log('Selecting the ' + document.getElementById('limit').value + ' best combinations (' + time + 's)');
|
|
|
+ valid_combinations = valid_combinations.slice(0, document.getElementById('limit').value);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Request to fetch the runes.
|
|
|
+ var xhttp = new XMLHttpRequest();
|
|
|
+ xhttp.onreadystatechange = function() {
|
|
|
+ if (this.readyState == 4){
|
|
|
+ if (this.status == 200) {
|
|
|
+ //time = ((+ new Date()) - timestamp) / 1000;
|
|
|
+ presentOptions(this.response, timestamp);
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ enableNewSearch(true);
|
|
|
+ showMessage('Error', 'Unexpected error ' + this.status);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+ params = 'uid=<?=$UID?>&unit=<?=$page->unit->id?>&tuning=' + document.getElementById('tuning').options[document.getElementById('tuning').selectedIndex].value;
|
|
|
+ params += '&options=' + JSON.stringify(valid_combinations);
|
|
|
+ xhttp.open('POST', '/action/optimize_get_options/', true);
|
|
|
+ xhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
|
|
|
+ xhttp.send(params);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Displays the options.
|
|
|
+ *
|
|
|
+ * Builds a table with the calculated options and their scores.
|
|
|
+ * If none. It will show a message. In any case, it reenables the search
|
|
|
+ * button
|
|
|
+ *
|
|
|
+ * @param content Response from /action/optimize_get_options/
|
|
|
+ * @param timestamp Time counter
|
|
|
+ */
|
|
|
+ function presentOptions(content, timestamp){
|
|
|
+ var container = document.getElementById('optimizations');
|
|
|
+ var data = JSON.parse(content);
|
|
|
+ if (data.length == 0){
|
|
|
+ enableNewSearch(true);
|
|
|
return;
|
|
|
}
|
|
|
- document.getElementById('num_results').innerHTML = data.total;
|
|
|
- document.getElementById('num_skipped').innerHTML = data.skipped;
|
|
|
- document.getElementById('num_seconds').innerHTML = time;
|
|
|
var option;
|
|
|
var tr;
|
|
|
var td;
|
|
|
@@ -290,8 +673,8 @@
|
|
|
var stat_td;
|
|
|
var span;
|
|
|
var text;
|
|
|
- for (i = 0; i < data.options.length; i++){
|
|
|
- option = data.options[i];
|
|
|
+ for (i = 0; i < data.length; i++){
|
|
|
+ option = data[i];
|
|
|
tr = document.createElement('tr');
|
|
|
td = document.createElement('td');
|
|
|
td.setAttribute('class', 'option_stats');
|
|
|
@@ -671,6 +1054,20 @@
|
|
|
document.getElementById('results').style.display = 'block';
|
|
|
|
|
|
}
|
|
|
+ time = ((+ new Date()) - timestamp) / 1000;
|
|
|
+ log('Done in ' + time + ' seconds');
|
|
|
+ enableNewSearch(true);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Function to sort rune combinations based on their score.
|
|
|
+ *
|
|
|
+ * @param a One combination.
|
|
|
+ * @param b Other combination.
|
|
|
+ * @return Numeric index for sorting.
|
|
|
+ */
|
|
|
+ function sortOptions(a, b) {
|
|
|
+ return b["score"] - a["score"];
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -691,6 +1088,28 @@
|
|
|
function closeMessage(){
|
|
|
document.getElementById('message_container').style.display = 'none';
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * DEBUG FUNCTION
|
|
|
+ *
|
|
|
+ * Sets filters to a known value for debugging.
|
|
|
+ */
|
|
|
+ function debug(){
|
|
|
+ document.getElementById('set_1').selectedIndex = 0;
|
|
|
+ document.getElementById('set_2').selectedIndex = 0;
|
|
|
+ document.getElementById('set_3').selectedIndex = 1;
|
|
|
+ removeFilter('attack');
|
|
|
+ removeFilter('defense');
|
|
|
+ removeFilter('speed');
|
|
|
+ removeFilter('crit_rate');
|
|
|
+ removeFilter('crit_damage');
|
|
|
+ removeFilter('accuracy');
|
|
|
+ removeFilter('resistance');
|
|
|
+ removeFilter('ehp');
|
|
|
+ removeFilter('dmg');
|
|
|
+ document.getElementById('lbl_min_hp').value = 13500;
|
|
|
+ updateMinValue('hp', document.getElementById('lbl_min_hp'));
|
|
|
+ }
|
|
|
</script>
|
|
|
</head>
|
|
|
<body>
|
|
|
@@ -1004,7 +1423,6 @@
|
|
|
//foreach ($page->unit->rune as $rune){
|
|
|
foreach ($show_list as $i){
|
|
|
$rune = $page->unit->rune[$i - 1];
|
|
|
- $total_runes ++;
|
|
|
?>
|
|
|
<?=HTML::rune_table($rune)?>
|
|
|
<?php
|
|
|
@@ -1211,9 +1629,15 @@
|
|
|
</td>
|
|
|
</tr>
|
|
|
<tr>
|
|
|
- <td class='empty'>
|
|
|
- </td>
|
|
|
- <td class='empty'>
|
|
|
+ <td id='log' colspan='2' rowspan='4'>
|
|
|
+ <div id='log_title'>
|
|
|
+ LOG
|
|
|
+ <span id='log_clear' onClick='clearLog();'>
|
|
|
+ clear
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ <div id='log_window'>
|
|
|
+ </div>
|
|
|
</td>
|
|
|
<td class='empty'>
|
|
|
</td>
|
|
|
@@ -1232,10 +1656,10 @@
|
|
|
</td>
|
|
|
</tr>
|
|
|
<tr>
|
|
|
- <td class='empty'>
|
|
|
- </td>
|
|
|
- <td class='empty'>
|
|
|
- </td>
|
|
|
+ <!--<td class='empty'>
|
|
|
+ </td>-->
|
|
|
+ <!--<td class='empty'>
|
|
|
+ </td>-->
|
|
|
<td class='empty'>
|
|
|
</td>
|
|
|
<td class='name'>
|
|
|
@@ -1253,10 +1677,10 @@
|
|
|
</td>
|
|
|
</tr>
|
|
|
<tr>
|
|
|
- <td class='empty'>
|
|
|
- </td>
|
|
|
- <td class='empty'>
|
|
|
- </td>
|
|
|
+ <!--<td class='empty'>
|
|
|
+ </td>-->
|
|
|
+ <!--<td class='empty'>
|
|
|
+ </td>-->
|
|
|
<td class='empty'>
|
|
|
</td>
|
|
|
<td class='name'>
|
|
|
@@ -1274,10 +1698,10 @@
|
|
|
</td>
|
|
|
</tr>
|
|
|
<tr>
|
|
|
- <td class='empty'>
|
|
|
- </td>
|
|
|
- <td class='empty'>
|
|
|
- </td>
|
|
|
+ <!--<td class='empty'>
|
|
|
+ </td>-->
|
|
|
+ <!--<td class='empty'>
|
|
|
+ </td>-->
|
|
|
<td class='empty'>
|
|
|
</td>
|
|
|
<td class='name'>
|
|
|
@@ -1297,6 +1721,7 @@
|
|
|
<tr>
|
|
|
<td class='action'>
|
|
|
<input id='apply' type='button' value='Apply' onClick='apply();'/>
|
|
|
+ <!--<input id='apply' type='button' value='DEBUG' onClick='debug();'/>-->
|
|
|
</td>
|
|
|
<td class='empty'>
|
|
|
<img id='wait' src='<?=URL::IMG["ICON"] . "wait.gif";?>'>
|
|
|
@@ -1317,10 +1742,6 @@
|
|
|
</a>
|
|
|
</td>
|
|
|
</tr>
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
</table>
|
|
|
</article>
|
|
|
</section>
|
|
|
@@ -1329,9 +1750,6 @@
|
|
|
Optimization results
|
|
|
</h2>
|
|
|
<article>
|
|
|
- <div id='results_info'>
|
|
|
- <span id='num_results'></span> results (<span id='num_skipped'></span> skipped) in <span id='num_seconds'></span> seconds
|
|
|
- </div>
|
|
|
<table id='table_optimizations'>
|
|
|
<tbody id='optimizations'>
|
|
|
</tbody>
|