NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript==
// @name Materia inserter for Ariyala
// @version 0.1.5
// @description Provides buttons to automatically insert materia into slots
// @author ShadeX91
// @match http://ffxiv.ariyala.com/*
// @require https://code.jquery.com/jquery-3.2.1.slim.js
// @grant none
// ==/UserScript==
(function() {
'use strict';
var healers = ["White Mage", "Scholar", "Astrologian"];
var tanks = ["Dark Knight", "Warrior", "Paladin"];
var dpsDex = ["Bard", "Machinist", "Ninja"];
var dpsStr = ["Monk", "Samurai", "Dragoon"];
var dpsInt = ["Black Mage", "Summoner", "Red Mage"];
var prio1 = ["STR", "DHT", "DET", "CRT", "TEN"];
var materiaSelector = $("#materiaWindow .placer:nth-child(2)");
// Materia chances: $("#materiaWindow tr td.right")
var prioInput = "<label for='prioInput'>Priorities:</label><input type='text' value='STR, DHT, DET, CRT, SKS, TEN' id='prioInput' style='display:block; margin: 5px auto 15px auto; width: 200px'>";
materiaSelector.append(prioInput);
//var debugButton = "<input type='submit' value='Show Debug Info' id='myDebugButton'>";
//materiaSelector.append(debugButton);
var testButton = "<input type='submit' value='Fill Materia' id='myTestButton'>";
materiaSelector.append(testButton);
//var resetButton = "<input type='submit' value='Reset Materia' id='myResetButton'>";
//materiaSelector.append(resetButton);
//document.getElementById("materiaSelect1").selectedIndex=5;
//document.getElementById("materiaSelect1").dispatchEvent(new Event("change"));
$("#myTestButton").click(function() {
$("#materiaTableClearButton").click();
// Use maximum or safe melds
var doMaximum = false;
// Whether this is a piece of accessory
var isAccessory = false;
// Total number of available slots
var numTotal = 0;
// Number of safe materia slots
var materiaChances = $("#materiaWindow tr td.right");
var numSafe = 0;
// Get number of "safe" materia slots
$.each(materiaChances, function(index, value) {
if($(value).html() === "100%")
numSafe++;
});
// If the second select box does not offer Vit, then it is an accessory
var vitIndex = getIndexByValue("#materiaSelect2", "VIT:0");
if(vitIndex === -1) {
isAccessory = true;
}
var materiaSelectors = $(".materiaTable select");
$.each(materiaSelectors, function(index, value) {
if(! $(value).is(":disabled") )
numTotal++;
});
var prios = getPriosFromInput();
// Example values: isAccessory = false, numTotal = 5, numSafe = 2, doMaximum = false
var res = calculateMelds(getAttributeOrder(), getAttributesToMax(), prios, numTotal, numSafe, isAccessory, true);
// Insert our values into the website
for(var i = 0; i < res.length; i++) {
$("#materiaSelect"+(i+1)).val(res[i]).change();
}
});
// Calculate optimal melds with the given parameters.
function calculateMelds(attributes, toMax, priorities, numTotal, numSafe, isAccessory, doMax) {
var result = [];
var maxVals = toMax;
var pIndex = 0;
var targetGrade = 5;
// TODO: This needs serious cleanup
var i=0;
while(i < numTotal) {
pIndex = 0;
targetGrade = 5;
if(numSafe - i < 0) {
targetGrade = 4;
}
var attrString = priorities[pIndex];
if(isMainStat(attrString) && isAccessory && i > 0) {
while(isMainStat(attrString)) {
pIndex++;
if(pIndex >= priorities.length) {
return result;
}
attrString = priorities[pIndex];
}
}
var attrIndex = $.inArray(attrString, attributes);
var attrToMax = maxVals[attrIndex];
var matGrade = calculateMateriaGrade(attrString, attrToMax, doMax);
if(matGrade >= targetGrade) {
matGrade = Math.min(matGrade, targetGrade);
result[i] = attrString + ":" + matGrade;
maxVals[attrIndex] = attrToMax - getStatsFromMateriaGrade(attrString, matGrade);
} else {
pIndex++;
var found = false;
do {
attrString = priorities[pIndex];
attrIndex = $.inArray(attrString, attributes);
attrToMax = maxVals[attrIndex];
matGrade = calculateMateriaGrade(attrString, attrToMax, doMax);
if(matGrade >= targetGrade) {
matGrade = Math.min(matGrade, targetGrade);
result[i] = attrString + ":" + matGrade;
maxVals[attrIndex] = attrToMax - getStatsFromMateriaGrade(attrString, matGrade);
found = true;
} else if(pIndex+1 < priorities.length) {
pIndex++;
} else {
pIndex = 0;
targetGrade--;
}
} while(targetGrade > 0 && !found);
}
i++;
}
return result;
}
function getPriosFromInput() {
var text = $("#prioInput").val().replace(/ /g, '');
var arr = text.split(",");
return arr;
}
function getStatsFromMateriaGrade(attribute, grade) {
var values = [2,4,6,9,12,40];
if(isMainStat(attribute)) {
values = [1,2,4,7,15,25];
}
return values[grade];
}
// Calculate which grade materia (0-5) to use depending on the stat we give it
function calculateMateriaGrade(attribute, toMax, overfill) {
var grade = 0;
var values = [2,4,6,9,12,40];
if(isMainStat(attribute)) {
values = [1,2,4,7,15,25];
}
$.each(values,function(index, value) {
if(toMax >= value || (overfill && index==values.length-1 && toMax-value > -15) ) {
grade++;
} else
return false;
});
return grade-1;
}
function isMainStat(attribute) {
return $.inArray(attribute, ["STR","DEX","INT","MND","VIT"]) !== -1;
}
$("#myResetButton").click(function() {
$("#materiaTableClearButton").click();
});
$("#myDebugButton").click(function() {
var attributes = getAttributesToMax();
// Debug info, current value of attributes and so on.
console.log(attributes);
console.log(getAttributeOrder());
});
// Not really necessary since we can change selected values via .val(value)
function getIndexByValue(selectbox, value) {
var count = 0;
$(selectbox +" option").each(
function(){
if($(this).attr("value") === value)
return false;
else
count++;
}
);
if(count == $(selectbox +" option").length) return -1;
return count;
}
function getAttributesToMax() {
var table = $("#materiaWindow .placer:nth-child(1) tr");
table = table.splice(1,table.length-1);
var attributes = [];
$(table).each(function(index, value) {
var text = $(this).find("td").eq(2).html();
attributes[index] = parseInt(text);
});
return attributes;
}
// Create an array with the order of all attributes for this class
function getAttributeOrder() {
var playerClass = getClassName();
console.log(playerClass);
if($.inArray(playerClass, healers) !== -1) {
return ["MND", "DHT", "CRT", "DET", "SPS", "PIE", "VIT"];
} else if($.inArray(playerClass, tanks) !== -1) {
return ["STR", "DHT", "CRT", "DET", "SKS", "VIT", "TEN"];
} else if($.inArray(playerClass, dpsStr) !== -1) {
return ["STR", "DHT", "CRT", "DET", "SKS", "VIT"];
} else if($.inArray(playerClass, dpsDex) !== -1) {
return ["DEX", "DHT", "CRT", "DET", "SKS", "VIT"];
} else if($.inArray(playerClass, dpsInt) !== -1) {
return ["INT", "DHT", "CRT", "DET", "SPS", "VIT"];
} else {
return [];
}
}
function getClassName() {
var playerClass = $("#categoryBoxContentName").html();
return playerClass;
}
})();