Difference between revisions of "MediaWiki:SCalScript.js"
From Istaria Lexica
(Big script import) |
(Big script import) |
||
Line 1: | Line 1: | ||
/** | /** | ||
− | * Skeleton Key Calculator V 0. | + | * Skeleton Key Calculator V 0.4 |
* Elteria Shadowhand | * Elteria Shadowhand | ||
*/ | */ | ||
Line 7: | Line 7: | ||
let baseResources; // Collection of the needed base resources. To be filled. | let baseResources; // Collection of the needed base resources. To be filled. | ||
let refinedResources; // Collection of the needed refined resources. To be filled. | let refinedResources; // Collection of the needed refined resources. To be filled. | ||
− | let | + | let skills = {}; // A list of all skills needed, containing their names, a html id and their min/opt values. |
let initialKeyCount = 10; | let initialKeyCount = 10; | ||
let maxKeyCount = 5000; | let maxKeyCount = 5000; | ||
let maxSkillCount = 2000; | let maxSkillCount = 2000; | ||
− | |||
− | // | + | // the dataset |
− | // | + | // Note that the skill is NOT the actual skill you need to create the product. |
− | + | // It is the skill you need to create it's parent product. So if you created a Spell Shard which needs Spellcraft, | |
− | products | + | // the subcomponent (i.e. a Stone Brick, which would be Stoneworking) of it would be Spellcraft. The minXXX and maxXXX |
− | + | // parameters behave the same. | |
− | + | let products = { | |
− | + | 'Skeleton Key': { skill: 'Tinkering', minCount: 1, maxCount: 1, minSkill: 1100, maxSkill: 1425, type: 'SCalProduct', subs: | |
− | + | { | |
− | + | 'Enchanted Adamantium-Mithril Bar': { skill: 'Tinkering', minCount: 3, maxCount: 6, minSkill: 1100, maxSkill: 1425, type: 'SCalProduct', subs: | |
− | + | { | |
− | + | 'Gozar\'s Blessing': { skill: 'Tinkering', minCount: 2, maxCount: 4, minSkill: 1100, maxSkill: 1425, type: 'SCalProduct', subs: | |
− | + | { | |
− | + | 'Meltanis\' Prayer': { skill: 'Scribing', minCount: 1, maxCount: 3, minSkill: 1100, maxSkill: 1425, type: 'SCalProduct', subs: | |
− | + | { | |
− | + | 'Travertine Spell Shard': { skill: 'Spellcraft', minCount: 1, maxCount: 5, minSkill: 1100, maxSkill: 1425, type: 'SCalRefinedResource', subs: | |
− | + | { | |
− | + | 'Travertine Brick': { skill: 'Stoneworking', minCount: 2, maxCount: 5, minSkill: 1000, maxSkill: 1325, type: 'SCalRefinedResource', subs: | |
− | + | { | |
− | + | 'Travertine Slab': { skill: 'Stoneworking', minCount: 2, maxCount: 5, minSkill: 1000, maxSkill: 1325 } | |
− | + | } | |
− | + | } | |
− | + | } | |
− | + | }, 'Radiant Essence Orb': { skill: 'Spellcraft', minCount: 4, maxCount: 10, minSkill: 1100, maxSkill: 1425, type: 'SCalRefinedResource', subs: | |
− | + | { | |
− | + | 'Radiant Essence': { skill: 'Essence Shaping', minCount: 2, maxCount: 5, minSkill: 1000, maxSkill: 1325 } | |
− | + | } | |
− | + | } | |
− | + | } | |
− | + | }, 'Primal Burst III': { skill: 'Spellcraft', minCount: 1, maxCount: 3,minSkill: 930, maxSkill: 1130, type: 'SCalProduct', subs: | |
− | + | { | |
− | + | 'Marble Spell Shard': { skill: 'Spellcraft', minCount: 5, maxCount: 5, minSkill: 930, maxSkill: 1130, type: 'SCalRefinedResource', subs: | |
− | + | { | |
− | + | 'Marble Brick': { skill: 'Spellcraft', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100, type: 'SCalRefinedResource', subs: | |
− | + | { | |
− | + | 'Marble Slab': { skill: 'Stoneworking', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100 } | |
− | + | } | |
− | + | } | |
− | + | } | |
− | + | }, 'Shining Essence Orb': { skill: 'Spellcraft', minCount: 9, maxCount: 18, minSkill: 930, maxSkill: 1130, type: 'SCalRefinedResource', subs: | |
− | + | { | |
− | + | 'Shining Essence': { skill: 'Essence Shaping', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100 } | |
− | + | } | |
− | + | } | |
− | + | } | |
− | + | }, 'Energy Strike V': { skill: 'Spellcraft', minCount: 1, maxCount: 3, minSkill: 850, maxSkill: 1050, type: 'SCalProduct', subs: | |
− | + | { | |
− | + | 'Marble Spell Shard': { skill: 'Spellcraft', minCount: 4, maxCount: 4, minSkill: 850, maxSkill: 1050, type: 'SCalRefinedResource', subs: | |
− | + | { | |
− | + | 'Marble Brick': { skill: 'Spellcraft', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100, type: 'SCalRefinedResource', subs: | |
− | + | { | |
− | + | 'Marble Slab': { skill: 'Stoneworking', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100 } | |
− | + | } | |
− | + | } | |
− | + | } | |
− | + | }, 'Shining Essence Orb': { skill: 'Spellcraft', minCount: 7, maxCount: 14, minSkill: 800, maxSkill: 1100, type: 'SCalRefinedResource', subs: | |
− | + | { | |
− | + | 'Shining Essence': { skill: 'Essence Shaping', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100 } | |
− | + | } | |
− | + | } | |
− | + | } | |
− | + | }, 'Ice Bomb V': { skill: 'Spellcraft', minCount: 1, maxCount: 3, minSkill: 920, maxSkill: 1120, type: 'SCalProduct', subs: | |
− | + | { | |
− | + | 'Marble Spell Shard': { skill: 'Spellcraft', minCount: 5, maxCount: 5, minSkill: 800, maxSkill: 1100, type: 'SCalRefinedResource', subs: | |
− | + | { | |
− | + | 'Marble Brick': { skill: 'Stoneworking', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100, type: 'SCalRefinedResource', subs: | |
− | + | { | |
− | + | 'Marble Slab': { skill: 'Stoneworking', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100 } | |
− | + | } | |
− | + | } | |
− | + | } | |
− | + | }, 'Shining Essence Orb': { skill: 'Spellcraft', minCount: 9, maxCount: 18, minSkill: 920, maxSkill: 1120, type: 'SCalRefinedResource', subs: | |
− | + | { | |
− | + | 'Shining Essence': { skill: 'Essence Shaping', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100 } | |
− | + | } | |
− | + | } | |
− | + | } | |
− | + | }, 'Fiery Strike V': { skill: 'Spellcraft', minCount: 1, maxCount: 3, minSkill: 980, maxSkill: 1180, type: 'SCalProduct', subs: | |
− | + | { | |
− | + | 'Marble Spell Shard': { skill: 'Spellcraft', minCount: 6, maxCount: 6, minSkill: 800, maxSkill: 1100, type: 'SCalRefinedResource', subs: | |
− | + | { | |
− | + | 'Marble Brick': { skill: 'Stoneworking', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100, type: 'SCalRefinedResource', subs: | |
− | + | { | |
− | + | 'Marble Slab': { skill: 'Stoneworking', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100 } | |
− | + | } | |
− | + | } | |
− | + | } | |
− | + | }, 'Shining Essence Orb': { skill: 'Spellcraft', minCount: 11, maxCount: 22, minSkill: 980, maxSkill: 1180, type: 'SCalRefinedResource', subs: | |
− | + | { | |
− | + | 'Shining Essence': { skill: 'Essence Shaping', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100 } | |
− | + | } | |
− | + | } | |
− | + | } | |
− | + | }, 'Gold Papyrus Sheet': { skill: 'Scribing', minCount: 2, maxCount: 5, minSkill: 1100, maxSkill: 1425, type: 'SCalRefinedResource', subs: | |
− | + | { | |
− | + | 'Gold Papyrus Stem': { skill: 'Papermaking', minCount: 2, maxCount: 5, minSkill: 1000, maxSkill: 1325 } | |
− | + | } | |
− | + | } | |
− | + | } | |
− | + | }, 'Hardened Adamantium-Mithril Bar': { skill: 'Tinkering', minCount: 2, maxCount: 5, minSkill: 1100, maxSkill: 1425, type: 'SCalRefinedResource', subs: | |
− | + | { | |
− | + | 'Solution of Majorita': { skill: 'Tinkering', minCount: 2, maxCount: 5, minSkill: 1100, maxSkill: 1425, type: 'SCalRefinedResource', subs: | |
− | + | { | |
− | + | 'Thornwood Bowl': { skill: 'Alchemy', minCount: 1, maxCount: 3, minSkill: 1100, maxSkill: 1425, type: 'SCalRefinedResource', subs: | |
− | + | { | |
− | + | 'Thornwood Sap': { skill: 'Fletching', minCount: 3, maxCount: 6, minSkill: 1100, maxSkill: 1425 } | |
− | + | , 'Thornwood Board': { skill: 'Fletching', minCount: 5, maxCount: 10, minSkill: 1100, maxSkill: 1425, type: 'SCalRefinedResource', subs: | |
− | + | { | |
− | + | 'Thornwood Log': { skill: 'Lumbering', minCount: 2, maxCount: 5, minSkill: 1000, maxSkill: 1325 } | |
− | + | } | |
− | + | } | |
− | + | } | |
− | + | }, 'Crystallized Travertine Brick': { skill: 'Alchemy', minCount: 5, maxCount: 10, minSkill: 1000, maxSkill: 1325, type: 'SCalRefinedResource', subs: | |
− | + | { | |
− | + | 'Unfocused Violet Azulyte Crystal': { skill: 'Stoneworking', minCount: 1, maxCount: 5, minSkill: 1000, maxSkill: 1325 } | |
− | + | , 'Travertine Slab': { skill: 'Stoneworking', minCount: 1, maxCount: 5, minSkill: 1000, maxSkill: 1325 } | |
− | + | } | |
− | + | }, 'Purified Radiant Essence Orb': { skill: 'Alchemy', minCount: 1, maxCount: 4, minSkill: 1100, maxSkill: 1425, type: 'SCalRefinedResource', subs: | |
− | + | { | |
− | + | 'Radiant Essence Orb': { skill: 'Alchemy', minCount: 1, maxCount: 4, minSkill: 1100, maxSkill: 1325, type: 'SCalRefinedResource', subs: | |
− | + | { | |
− | + | 'Radiant Essence': { skill: 'Essence Shaping', minCount: 2, maxCount: 5, minSkill: 1000, maxSkill: 1325 } | |
− | + | } | |
− | + | } | |
− | + | } | |
− | + | }, 'Water': { skill: 'Alchemy', minCount: 15, maxCount: 30, minSkill: 1100, maxSkill: 1425 } | |
− | + | } | |
− | + | }, 'Adamantium-Mithril Bar': { skill: 'Tinkering', minCount: 1, maxCount: 1, minSkill: 1100, maxSkill: 1425, type: 'SCalRefinedResource', subs: | |
− | + | { | |
− | + | 'Mithril Ore': { skill: 'Smelting', minCount: 3, maxCount: 6, minSkill: 1100, maxSkill: 1425 } | |
− | + | , 'Adamantium Ore': { skill: 'Smelting', minCount: 3, maxCount: 6, minSkill: 1100, maxSkill: 1425 } | |
− | + | } | |
− | + | } | |
− | + | } | |
− | + | } | |
− | + | } | |
− | + | }, 'Skeleton Key Mold': { skill: 'Tinkering', minCount: 1, maxCount: 1, minSkill: 1100, maxSkill: 1425, type: 'SCalProduct', subs: | |
− | + | { | |
− | + | 'Skeleton Key Pattern': { skill: 'Earthencraft', minCount: 1, maxCount: 1, minSkill: 1100, maxSkill: 1425 } | |
− | + | , 'Porcelain Clay Chunk': { skill: 'Earthencraft', minCount: 2, maxCount: 5, minSkill: 1100, maxSkill: 1425 } | |
− | + | } | |
− | + | } | |
− | + | } | |
− | + | } | |
− | + | }; | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
printHeader(); | printHeader(); | ||
+ | recursiveDetermineSkills(products); | ||
+ | printSkillInputs(); | ||
$('#SCalMain').append('<center><table>' | $('#SCalMain').append('<center><table>' | ||
Line 302: | Line 171: | ||
$('#SCalResourcesrow1').append('<div id="SCalResources"></div>'); | $('#SCalResourcesrow1').append('<div id="SCalResources"></div>'); | ||
− | printLists(); | + | if(validateInputs()) { // check if the input fields contain valid entries |
+ | printLists(); | ||
+ | } | ||
//FUNCTIONS: | //FUNCTIONS: | ||
function printHeader() { | function printHeader() { | ||
+ | var keyCount = getCookie('SCalCountInput'); | ||
+ | if(!isRealInteger(keyCount)) keyCount = initialKeyCount; | ||
$('#SCalMain').append('<h1 id="SCalH1">The Calculator</h1>'); | $('#SCalMain').append('<h1 id="SCalH1">The Calculator</h1>'); | ||
$('#SCalMain').append('<center><label for="SCalCountInput" id="SCalCountInputLbl">How many Skeleton Keys would you want to create?</label></center>'); | $('#SCalMain').append('<center><label for="SCalCountInput" id="SCalCountInputLbl">How many Skeleton Keys would you want to create?</label></center>'); | ||
− | $('#SCalMain').append('<center><input type="number" id="SCalCountInput" name="SCalCountInput" value="' + | + | $('#SCalMain').append('<center><input type="number" id="SCalCountInput" name="SCalCountInput" value="' + keyCount + '" size="6"></center>'); |
$('#SCalMain').append('<br />'); | $('#SCalMain').append('<br />'); | ||
$('#SCalMain').append('<hr />'); | $('#SCalMain').append('<hr />'); | ||
Line 321: | Line 194: | ||
$('#SCalMaxSkillsBtn').click(function() { | $('#SCalMaxSkillsBtn').click(function() { | ||
if(confirm('This will reset all of the skills! Are you really sure? ')) { | if(confirm('This will reset all of the skills! Are you really sure? ')) { | ||
− | for (var v of | + | for (var v of Object.values(skills)) { |
− | $('# | + | $('#' + v.id).val(v.maxSkill); |
− | $('# | + | $('#' + v.id).change(); |
}; | }; | ||
} | } | ||
}); | }); | ||
− | $('#SCalCountBtn').click(function() { | + | $('#SCalCountBtn').click(function(event) { |
− | printLists(); | + | if(validateInputs()) { |
+ | printLists(); | ||
+ | checkIntegerAndSetCookieById(event.target.id); | ||
+ | } | ||
}); | }); | ||
$('#SCalCountInput').keypress(function(event) { | $('#SCalCountInput').keypress(function(event) { | ||
− | if (event.key === 'Enter') printLists(); | + | if (event.key === 'Enter' && validateInputs()) { |
+ | printLists(); | ||
+ | checkIntegerAndSetCookieById(event.target.id); | ||
+ | } | ||
}); | }); | ||
− | $('#SCalCountInput').change(function() { | + | $('#SCalCountInput').change(function(event) { |
− | printLists(); | + | if(validateInputs()) { |
+ | printLists(); | ||
+ | checkIntegerAndSetCookieById(event.target.id); | ||
+ | } | ||
}); | }); | ||
− | |||
− | |||
} | } | ||
function printLists() { | function printLists() { | ||
− | + | // (re-)initialize to be updated lists | |
− | + | baseResources = {}; | |
− | + | refinedResources = {}; | |
− | |||
− | |||
− | + | recursiveCalculateNeededResources(products, parseInt($('#SCalCountInput').val())); | |
− | + | $('#SCalResources').html(''); | |
− | + | $('#SCalResources').append('<h2>Tree of needed products</h2>'); | |
− | + | var html = recursivePrintTreeProduct(products); | |
− | + | $('#SCalResources').append(html); | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | printBaseResources(); | |
+ | printRefinedResources(); | ||
+ | printNeededSkills(); | ||
− | + | mw.loader.using('jquery.tablesorter', function() { | |
− | + | $('table.sortable').tablesorter({ sortList: [{ 0: 'asc' }] }) | |
− | + | }); | |
− | } | ||
} | } | ||
function printNeededSkills() { | function printNeededSkills() { | ||
− | |||
− | |||
$('#SCalResourcesrow2').append('<h2>Required skills</h2>'); | $('#SCalResourcesrow2').append('<h2>Required skills</h2>'); | ||
$('#SCalResourcesrow2').append('<table id="SCalNeededSkillsTable" class="wikitable sortable"><thead>' | $('#SCalResourcesrow2').append('<table id="SCalNeededSkillsTable" class="wikitable sortable"><thead>' | ||
Line 408: | Line 255: | ||
var tablecontent = '<tbody>'; | var tablecontent = '<tbody>'; | ||
− | + | for(var [key, value] of Object.entries(skills).sort()) { | |
tablecontent += '<tr>' | tablecontent += '<tr>' | ||
+ '<td><a href="' + mw.util.getUrl(key) + '">' + key + '</a></td>' | + '<td><a href="' + mw.util.getUrl(key) + '">' + key + '</a></td>' | ||
− | + '<td>' + value | + | + '<td>' + value.minSkill + '</td>' |
− | + '<td>' + value | + | + '<td>' + value.maxSkill + '</td>' |
+ '</tr>'; | + '</tr>'; | ||
− | } | + | } |
tablecontent += '</tbody>'; | tablecontent += '</tbody>'; | ||
Line 422: | Line 269: | ||
function printSkillInputs() { | function printSkillInputs() { | ||
− | + | for (var [key, value] of Object.entries(skills)) { | |
− | for (var [key, value] of | + | var id = value.id; |
− | var id = | + | var skill = getCookie(id); |
− | var skill = getCookie(id | + | if(!isRealInteger(skill)) { // default to max value if cookie not correctly set |
− | + | skill = value.maxSkill; | |
− | if(!isRealInteger(skill)) { | ||
− | skill = | ||
} | } | ||
− | $('#SCalSkills').append('<input type="number" id="' + id + ' | + | $('#SCalSkills').append('<input type="number" id="' + id + '" name="' + id + '" size="6"><label for="' + id + '"> ' + key + '</label><br />'); |
− | $('#' + id | + | |
− | if (event.key === 'Enter') { | + | $('#' + id).keypress(function(event) { |
+ | if (event.key === 'Enter' && validateInputs()) { | ||
printLists(); | printLists(); | ||
− | + | checkIntegerAndSetCookieById(event.target.id); | |
} | } | ||
}); | }); | ||
− | $('#' + id | + | |
− | printLists(); | + | $('#' + id).change(function(event) { |
− | + | if(validateInputs()) { | |
+ | printLists(); | ||
+ | checkIntegerAndSetCookieById(event.target.id); | ||
+ | } | ||
}); | }); | ||
− | $('# | + | |
+ | $('#' + id).val(skill); | ||
} | } | ||
} | } | ||
− | function recursiveDetermineSkills( | + | // Tests if the provided input field has a valid integer and sets a cookie for it |
− | product. | + | function checkIntegerAndSetCookieById(id) { |
− | if( | + | hashedId = '#' + id; |
− | skills. | + | if(isRealInteger($(hashedId).val())) |
+ | setCookie(id, $(hashedId).val(), new Date(3030,1,4)); | ||
+ | } | ||
+ | |||
+ | // Adds skillnames, ids, minskill and maxskill to a skills list | ||
+ | function recursiveDetermineSkills(currentproducts) { | ||
+ | for (var product of Object.values(currentproducts)) { | ||
+ | var skillName = product.skill; | ||
+ | var newSkills = {}; | ||
+ | |||
+ | // compare min and max skills and set accordingly | ||
+ | newSkills.minSkill = product.minSkill; | ||
+ | newSkills.maxSkill = product.maxSkill; | ||
+ | |||
+ | if(skills.hasOwnProperty(skillName)) { | ||
+ | if(skills[skillName].minSkill < newSkills.minSkill) { | ||
+ | newSkills.minSkill = skills[skillName].minSkill; | ||
+ | } | ||
+ | |||
+ | if(skills[skillName].maxSkill > newSkills.maxSkill) { | ||
+ | newSkills.maxSkill = skills[skillName].maxSkill; | ||
+ | } | ||
} | } | ||
− | if( | + | // set the id |
− | recursiveDetermineSkills( | + | newSkills.id = 'SCalSkill' + skillName.replace(/\s/, '') + 'Input'; |
+ | |||
+ | skills[skillName] = newSkills; | ||
+ | |||
+ | if(product.hasOwnProperty('subs')) { | ||
+ | recursiveDetermineSkills(product.subs); | ||
} | } | ||
− | } | + | } |
} | } | ||
function recursivePrintTreeProduct(product) { | function recursivePrintTreeProduct(product) { | ||
var html = ''; | var html = ''; | ||
− | + | for(var [key, value] of Object.entries(product)) { | |
html += '<ul>'; | html += '<ul>'; | ||
html += '<li>'; | html += '<li>'; | ||
− | html += '<span class="' + | + | html += '<span class="' + value.type + '"><a href="' + mw.util.getUrl(key) + '">' + key + '</a>: ' + value.needed + '</span>'; |
− | if( | + | if(value.hasOwnProperty('subs')) { |
− | html += recursivePrintTreeProduct( | + | html += recursivePrintTreeProduct(value.subs); |
} | } | ||
html += '</ul>'; | html += '</ul>'; | ||
html += '</li>' | html += '</li>' | ||
− | } | + | } |
return html; | return html; | ||
} | } | ||
− | function | + | // Adds needed resources to the dataset and counts up the base and refined resources |
− | + | function recursiveCalculateNeededResources(products, previousCount) { | |
− | var | + | for(var [key, values] of Object.entries(products)) { |
− | + | var currentSkill = $('#' + skills[values.skill].id).val(); | |
− | + | ||
− | + | var percent = (currentSkill - values.minSkill) / (values.maxSkill - values.minSkill); | |
− | + | var needEffective = values.maxCount - ((values.maxCount - values.minCount) * percent); | |
− | |||
− | var percent = (currentSkill - | ||
− | var needEffective = | ||
needEffective = Math.ceil(needEffective); | needEffective = Math.ceil(needEffective); | ||
− | if (needEffective < | + | if (needEffective < values.minCount) needEffective = values.minCount; |
− | if (needEffective > | + | if (needEffective > values.maxCount) needEffective = values.maxCount; |
− | + | needEffective *= previousCount; | |
− | + | // Process base resources | |
− | if(baseResources. | + | // we assume that a product without subs is a base resource |
− | baseResources | + | if(!values.hasOwnProperty('subs')) { |
+ | if(baseResources.hasOwnProperty(key)) { | ||
+ | baseResources[key] = needEffective + baseResources[key]; | ||
} else { | } else { | ||
− | baseResources | + | baseResources[key] = needEffective; |
} | } | ||
} | } | ||
− | if( | + | // Process refined resources |
− | if(refinedResources. | + | if(values.type == 'SCalRefinedResource') { |
− | refinedResources | + | if(refinedResources.hasOwnProperty(key)) { |
+ | refinedResources[key] = needEffective + refinedResources[key]; | ||
} else { | } else { | ||
− | refinedResources | + | refinedResources[key] = needEffective; |
} | } | ||
} | } | ||
+ | |||
+ | values.needed = needEffective; | ||
+ | products[key] = values; | ||
− | if( | + | if(values.hasOwnProperty('subs')) { |
− | + | values.subs = recursiveCalculateNeededResources(values.subs, needEffective); | |
} | } | ||
− | } | + | } |
− | + | return products; | |
− | return | ||
} | } | ||
function printRefinedResources() { | function printRefinedResources() { | ||
− | |||
− | |||
$('#SCalResourcesrow2').append('<h2>Overview of refined resources</h2>'); | $('#SCalResourcesrow2').append('<h2>Overview of refined resources</h2>'); | ||
$('#SCalResourcesrow2').append('<table id="SCalRefinedResourceTable" class="wikitable sortable"><thead>' | $('#SCalResourcesrow2').append('<table id="SCalRefinedResourceTable" class="wikitable sortable"><thead>' | ||
Line 527: | Line 403: | ||
var tablecontent = '<tbody>'; | var tablecontent = '<tbody>'; | ||
− | refinedResources. | + | for(var [key, value] of Object.entries(refinedResources).sort()) { |
tablecontent += '<tr>' | tablecontent += '<tr>' | ||
+ '<td><a href="' + mw.util.getUrl(key) + '">' + key + '</a></td>' | + '<td><a href="' + mw.util.getUrl(key) + '">' + key + '</a></td>' | ||
+ '<td>' + value + '</td>' | + '<td>' + value + '</td>' | ||
+ '</tr>'; | + '</tr>'; | ||
− | } | + | } |
tablecontent += '</tbody>'; | tablecontent += '</tbody>'; | ||
Line 540: | Line 416: | ||
function printBaseResources() { | function printBaseResources() { | ||
− | |||
− | |||
$('#SCalResourcesrow2').html(''); | $('#SCalResourcesrow2').html(''); | ||
$('#SCalResourcesrow2').append('<h2>Overview of base resources</h2>'); | $('#SCalResourcesrow2').append('<h2>Overview of base resources</h2>'); | ||
Line 553: | Line 427: | ||
var tablecontent = '<tbody>'; | var tablecontent = '<tbody>'; | ||
− | baseResources. | + | for (var [key, value] of Object.entries(baseResources).sort()) { |
tablecontent += '<tr>' | tablecontent += '<tr>' | ||
+ '<td><a href="' + mw.util.getUrl(key) + '">' + key + '</a></td>' | + '<td><a href="' + mw.util.getUrl(key) + '">' + key + '</a></td>' | ||
+ '<td>' + value + '</td>' | + '<td>' + value + '</td>' | ||
+ '</tr>'; | + '</tr>'; | ||
− | } | + | } |
tablecontent += '</tbody>'; | tablecontent += '</tbody>'; | ||
Line 570: | Line 444: | ||
} | } | ||
+ | // check if the input fields contain valid entries | ||
function validateInputs() { | function validateInputs() { | ||
var ready = true; | var ready = true; | ||
Line 591: | Line 466: | ||
//check the skills counters | //check the skills counters | ||
− | for (var [skill, | + | for (var [skill, values] of Object.entries(skills)) { |
− | var inputObj = $('# | + | var inputObj = $('#' + values.id); |
− | |||
inputObj.removeClass('SCalErroreousInput'); | inputObj.removeClass('SCalErroreousInput'); | ||
Line 611: | Line 485: | ||
} | } | ||
− | if(number < | + | if(number < values.minSkill) { |
− | $('#SCalErrorText').append('<center>Skill ' + skill + ' is too low (have:' + number + ', need: ' + | + | $('#SCalErrorText').append('<center>Skill ' + skill + ' is too low (have:' + number + ', need: ' + values.minSkill + ')</center>'); |
inputObj.addClass('SCalErroreousInput'); | inputObj.addClass('SCalErroreousInput'); | ||
} | } | ||
if(!inputObj.hasClass('SCalErroreousInput')) { | if(!inputObj.hasClass('SCalErroreousInput')) { | ||
− | if(number >= | + | if(number >= values.maxSkill) inputObj.addClass('SCalOptimalInput'); |
} | } | ||
} | } |
Revision as of 16:07, 21 June 2022
/** * Skeleton Key Calculator V 0.4 * Elteria Shadowhand */ $(document).ready(function() { if (document.getElementById('SCalMain')) { let baseResources; // Collection of the needed base resources. To be filled. let refinedResources; // Collection of the needed refined resources. To be filled. let skills = {}; // A list of all skills needed, containing their names, a html id and their min/opt values. let initialKeyCount = 10; let maxKeyCount = 5000; let maxSkillCount = 2000; // the dataset // Note that the skill is NOT the actual skill you need to create the product. // It is the skill you need to create it's parent product. So if you created a Spell Shard which needs Spellcraft, // the subcomponent (i.e. a Stone Brick, which would be Stoneworking) of it would be Spellcraft. The minXXX and maxXXX // parameters behave the same. let products = { 'Skeleton Key': { skill: 'Tinkering', minCount: 1, maxCount: 1, minSkill: 1100, maxSkill: 1425, type: 'SCalProduct', subs: { 'Enchanted Adamantium-Mithril Bar': { skill: 'Tinkering', minCount: 3, maxCount: 6, minSkill: 1100, maxSkill: 1425, type: 'SCalProduct', subs: { 'Gozar\'s Blessing': { skill: 'Tinkering', minCount: 2, maxCount: 4, minSkill: 1100, maxSkill: 1425, type: 'SCalProduct', subs: { 'Meltanis\' Prayer': { skill: 'Scribing', minCount: 1, maxCount: 3, minSkill: 1100, maxSkill: 1425, type: 'SCalProduct', subs: { 'Travertine Spell Shard': { skill: 'Spellcraft', minCount: 1, maxCount: 5, minSkill: 1100, maxSkill: 1425, type: 'SCalRefinedResource', subs: { 'Travertine Brick': { skill: 'Stoneworking', minCount: 2, maxCount: 5, minSkill: 1000, maxSkill: 1325, type: 'SCalRefinedResource', subs: { 'Travertine Slab': { skill: 'Stoneworking', minCount: 2, maxCount: 5, minSkill: 1000, maxSkill: 1325 } } } } }, 'Radiant Essence Orb': { skill: 'Spellcraft', minCount: 4, maxCount: 10, minSkill: 1100, maxSkill: 1425, type: 'SCalRefinedResource', subs: { 'Radiant Essence': { skill: 'Essence Shaping', minCount: 2, maxCount: 5, minSkill: 1000, maxSkill: 1325 } } } } }, 'Primal Burst III': { skill: 'Spellcraft', minCount: 1, maxCount: 3,minSkill: 930, maxSkill: 1130, type: 'SCalProduct', subs: { 'Marble Spell Shard': { skill: 'Spellcraft', minCount: 5, maxCount: 5, minSkill: 930, maxSkill: 1130, type: 'SCalRefinedResource', subs: { 'Marble Brick': { skill: 'Spellcraft', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100, type: 'SCalRefinedResource', subs: { 'Marble Slab': { skill: 'Stoneworking', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100 } } } } }, 'Shining Essence Orb': { skill: 'Spellcraft', minCount: 9, maxCount: 18, minSkill: 930, maxSkill: 1130, type: 'SCalRefinedResource', subs: { 'Shining Essence': { skill: 'Essence Shaping', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100 } } } } }, 'Energy Strike V': { skill: 'Spellcraft', minCount: 1, maxCount: 3, minSkill: 850, maxSkill: 1050, type: 'SCalProduct', subs: { 'Marble Spell Shard': { skill: 'Spellcraft', minCount: 4, maxCount: 4, minSkill: 850, maxSkill: 1050, type: 'SCalRefinedResource', subs: { 'Marble Brick': { skill: 'Spellcraft', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100, type: 'SCalRefinedResource', subs: { 'Marble Slab': { skill: 'Stoneworking', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100 } } } } }, 'Shining Essence Orb': { skill: 'Spellcraft', minCount: 7, maxCount: 14, minSkill: 800, maxSkill: 1100, type: 'SCalRefinedResource', subs: { 'Shining Essence': { skill: 'Essence Shaping', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100 } } } } }, 'Ice Bomb V': { skill: 'Spellcraft', minCount: 1, maxCount: 3, minSkill: 920, maxSkill: 1120, type: 'SCalProduct', subs: { 'Marble Spell Shard': { skill: 'Spellcraft', minCount: 5, maxCount: 5, minSkill: 800, maxSkill: 1100, type: 'SCalRefinedResource', subs: { 'Marble Brick': { skill: 'Stoneworking', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100, type: 'SCalRefinedResource', subs: { 'Marble Slab': { skill: 'Stoneworking', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100 } } } } }, 'Shining Essence Orb': { skill: 'Spellcraft', minCount: 9, maxCount: 18, minSkill: 920, maxSkill: 1120, type: 'SCalRefinedResource', subs: { 'Shining Essence': { skill: 'Essence Shaping', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100 } } } } }, 'Fiery Strike V': { skill: 'Spellcraft', minCount: 1, maxCount: 3, minSkill: 980, maxSkill: 1180, type: 'SCalProduct', subs: { 'Marble Spell Shard': { skill: 'Spellcraft', minCount: 6, maxCount: 6, minSkill: 800, maxSkill: 1100, type: 'SCalRefinedResource', subs: { 'Marble Brick': { skill: 'Stoneworking', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100, type: 'SCalRefinedResource', subs: { 'Marble Slab': { skill: 'Stoneworking', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100 } } } } }, 'Shining Essence Orb': { skill: 'Spellcraft', minCount: 11, maxCount: 22, minSkill: 980, maxSkill: 1180, type: 'SCalRefinedResource', subs: { 'Shining Essence': { skill: 'Essence Shaping', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100 } } } } }, 'Gold Papyrus Sheet': { skill: 'Scribing', minCount: 2, maxCount: 5, minSkill: 1100, maxSkill: 1425, type: 'SCalRefinedResource', subs: { 'Gold Papyrus Stem': { skill: 'Papermaking', minCount: 2, maxCount: 5, minSkill: 1000, maxSkill: 1325 } } } } }, 'Hardened Adamantium-Mithril Bar': { skill: 'Tinkering', minCount: 2, maxCount: 5, minSkill: 1100, maxSkill: 1425, type: 'SCalRefinedResource', subs: { 'Solution of Majorita': { skill: 'Tinkering', minCount: 2, maxCount: 5, minSkill: 1100, maxSkill: 1425, type: 'SCalRefinedResource', subs: { 'Thornwood Bowl': { skill: 'Alchemy', minCount: 1, maxCount: 3, minSkill: 1100, maxSkill: 1425, type: 'SCalRefinedResource', subs: { 'Thornwood Sap': { skill: 'Fletching', minCount: 3, maxCount: 6, minSkill: 1100, maxSkill: 1425 } , 'Thornwood Board': { skill: 'Fletching', minCount: 5, maxCount: 10, minSkill: 1100, maxSkill: 1425, type: 'SCalRefinedResource', subs: { 'Thornwood Log': { skill: 'Lumbering', minCount: 2, maxCount: 5, minSkill: 1000, maxSkill: 1325 } } } } }, 'Crystallized Travertine Brick': { skill: 'Alchemy', minCount: 5, maxCount: 10, minSkill: 1000, maxSkill: 1325, type: 'SCalRefinedResource', subs: { 'Unfocused Violet Azulyte Crystal': { skill: 'Stoneworking', minCount: 1, maxCount: 5, minSkill: 1000, maxSkill: 1325 } , 'Travertine Slab': { skill: 'Stoneworking', minCount: 1, maxCount: 5, minSkill: 1000, maxSkill: 1325 } } }, 'Purified Radiant Essence Orb': { skill: 'Alchemy', minCount: 1, maxCount: 4, minSkill: 1100, maxSkill: 1425, type: 'SCalRefinedResource', subs: { 'Radiant Essence Orb': { skill: 'Alchemy', minCount: 1, maxCount: 4, minSkill: 1100, maxSkill: 1325, type: 'SCalRefinedResource', subs: { 'Radiant Essence': { skill: 'Essence Shaping', minCount: 2, maxCount: 5, minSkill: 1000, maxSkill: 1325 } } } } }, 'Water': { skill: 'Alchemy', minCount: 15, maxCount: 30, minSkill: 1100, maxSkill: 1425 } } }, 'Adamantium-Mithril Bar': { skill: 'Tinkering', minCount: 1, maxCount: 1, minSkill: 1100, maxSkill: 1425, type: 'SCalRefinedResource', subs: { 'Mithril Ore': { skill: 'Smelting', minCount: 3, maxCount: 6, minSkill: 1100, maxSkill: 1425 } , 'Adamantium Ore': { skill: 'Smelting', minCount: 3, maxCount: 6, minSkill: 1100, maxSkill: 1425 } } } } } } }, 'Skeleton Key Mold': { skill: 'Tinkering', minCount: 1, maxCount: 1, minSkill: 1100, maxSkill: 1425, type: 'SCalProduct', subs: { 'Skeleton Key Pattern': { skill: 'Earthencraft', minCount: 1, maxCount: 1, minSkill: 1100, maxSkill: 1425 } , 'Porcelain Clay Chunk': { skill: 'Earthencraft', minCount: 2, maxCount: 5, minSkill: 1100, maxSkill: 1425 } } } } } }; printHeader(); recursiveDetermineSkills(products); printSkillInputs(); $('#SCalMain').append('<center><table>' + '<tr valign="top">' + '<td id="SCalResourcesrow1"></td>' + '<td id="SCalResourcesrow2"></td>' + '</tr>' + '</table></center>' ); $('#SCalResourcesrow1').append('<div id="SCalResources"></div>'); if(validateInputs()) { // check if the input fields contain valid entries printLists(); } //FUNCTIONS: function printHeader() { var keyCount = getCookie('SCalCountInput'); if(!isRealInteger(keyCount)) keyCount = initialKeyCount; $('#SCalMain').append('<h1 id="SCalH1">The Calculator</h1>'); $('#SCalMain').append('<center><label for="SCalCountInput" id="SCalCountInputLbl">How many Skeleton Keys would you want to create?</label></center>'); $('#SCalMain').append('<center><input type="number" id="SCalCountInput" name="SCalCountInput" value="' + keyCount + '" size="6"></center>'); $('#SCalMain').append('<br />'); $('#SCalMain').append('<hr />'); $('#SCalMain').append('<center>Please enter your current skills in the fields below. Defaults to optimal skills.</center>'); $('#SCalMain').append('<center><input type="button" id="SCalMaxSkillsBtn" value="Reset to optimal skills"></center>'); $('#SCalMain').append('<center><div id="SCalSkills" style="column-count:3; width:fit-content; text-align:left"></div></center>'); $('#SCalMain').append('<br />'); $('#SCalMain').append('<center><input type="button" id="SCalCountBtn" value="Calculate now!"></center>'); $('#SCalMain').append('<div id="SCalErrorText"></div>'); $('#SCalMain').append('<hr />'); $('#SCalMaxSkillsBtn').click(function() { if(confirm('This will reset all of the skills! Are you really sure? ')) { for (var v of Object.values(skills)) { $('#' + v.id).val(v.maxSkill); $('#' + v.id).change(); }; } }); $('#SCalCountBtn').click(function(event) { if(validateInputs()) { printLists(); checkIntegerAndSetCookieById(event.target.id); } }); $('#SCalCountInput').keypress(function(event) { if (event.key === 'Enter' && validateInputs()) { printLists(); checkIntegerAndSetCookieById(event.target.id); } }); $('#SCalCountInput').change(function(event) { if(validateInputs()) { printLists(); checkIntegerAndSetCookieById(event.target.id); } }); } function printLists() { // (re-)initialize to be updated lists baseResources = {}; refinedResources = {}; recursiveCalculateNeededResources(products, parseInt($('#SCalCountInput').val())); $('#SCalResources').html(''); $('#SCalResources').append('<h2>Tree of needed products</h2>'); var html = recursivePrintTreeProduct(products); $('#SCalResources').append(html); printBaseResources(); printRefinedResources(); printNeededSkills(); mw.loader.using('jquery.tablesorter', function() { $('table.sortable').tablesorter({ sortList: [{ 0: 'asc' }] }) }); } function printNeededSkills() { $('#SCalResourcesrow2').append('<h2>Required skills</h2>'); $('#SCalResourcesrow2').append('<table id="SCalNeededSkillsTable" class="wikitable sortable"><thead>' + '<tr>' + '<th align="left">Skill</th>' + '<th align="left">Minimal</th>' + '<th align="left">Optimal</th>' + '</tr></thead>' ); var tablecontent = '<tbody>'; for(var [key, value] of Object.entries(skills).sort()) { tablecontent += '<tr>' + '<td><a href="' + mw.util.getUrl(key) + '">' + key + '</a></td>' + '<td>' + value.minSkill + '</td>' + '<td>' + value.maxSkill + '</td>' + '</tr>'; } tablecontent += '</tbody>'; tablecontent += '</table>'; $('#SCalNeededSkillsTable').append(tablecontent); } function printSkillInputs() { for (var [key, value] of Object.entries(skills)) { var id = value.id; var skill = getCookie(id); if(!isRealInteger(skill)) { // default to max value if cookie not correctly set skill = value.maxSkill; } $('#SCalSkills').append('<input type="number" id="' + id + '" name="' + id + '" size="6"><label for="' + id + '"> ' + key + '</label><br />'); $('#' + id).keypress(function(event) { if (event.key === 'Enter' && validateInputs()) { printLists(); checkIntegerAndSetCookieById(event.target.id); } }); $('#' + id).change(function(event) { if(validateInputs()) { printLists(); checkIntegerAndSetCookieById(event.target.id); } }); $('#' + id).val(skill); } } // Tests if the provided input field has a valid integer and sets a cookie for it function checkIntegerAndSetCookieById(id) { hashedId = '#' + id; if(isRealInteger($(hashedId).val())) setCookie(id, $(hashedId).val(), new Date(3030,1,4)); } // Adds skillnames, ids, minskill and maxskill to a skills list function recursiveDetermineSkills(currentproducts) { for (var product of Object.values(currentproducts)) { var skillName = product.skill; var newSkills = {}; // compare min and max skills and set accordingly newSkills.minSkill = product.minSkill; newSkills.maxSkill = product.maxSkill; if(skills.hasOwnProperty(skillName)) { if(skills[skillName].minSkill < newSkills.minSkill) { newSkills.minSkill = skills[skillName].minSkill; } if(skills[skillName].maxSkill > newSkills.maxSkill) { newSkills.maxSkill = skills[skillName].maxSkill; } } // set the id newSkills.id = 'SCalSkill' + skillName.replace(/\s/, '') + 'Input'; skills[skillName] = newSkills; if(product.hasOwnProperty('subs')) { recursiveDetermineSkills(product.subs); } } } function recursivePrintTreeProduct(product) { var html = ''; for(var [key, value] of Object.entries(product)) { html += '<ul>'; html += '<li>'; html += '<span class="' + value.type + '"><a href="' + mw.util.getUrl(key) + '">' + key + '</a>: ' + value.needed + '</span>'; if(value.hasOwnProperty('subs')) { html += recursivePrintTreeProduct(value.subs); } html += '</ul>'; html += '</li>' } return html; } // Adds needed resources to the dataset and counts up the base and refined resources function recursiveCalculateNeededResources(products, previousCount) { for(var [key, values] of Object.entries(products)) { var currentSkill = $('#' + skills[values.skill].id).val(); var percent = (currentSkill - values.minSkill) / (values.maxSkill - values.minSkill); var needEffective = values.maxCount - ((values.maxCount - values.minCount) * percent); needEffective = Math.ceil(needEffective); if (needEffective < values.minCount) needEffective = values.minCount; if (needEffective > values.maxCount) needEffective = values.maxCount; needEffective *= previousCount; // Process base resources // we assume that a product without subs is a base resource if(!values.hasOwnProperty('subs')) { if(baseResources.hasOwnProperty(key)) { baseResources[key] = needEffective + baseResources[key]; } else { baseResources[key] = needEffective; } } // Process refined resources if(values.type == 'SCalRefinedResource') { if(refinedResources.hasOwnProperty(key)) { refinedResources[key] = needEffective + refinedResources[key]; } else { refinedResources[key] = needEffective; } } values.needed = needEffective; products[key] = values; if(values.hasOwnProperty('subs')) { values.subs = recursiveCalculateNeededResources(values.subs, needEffective); } } return products; } function printRefinedResources() { $('#SCalResourcesrow2').append('<h2>Overview of refined resources</h2>'); $('#SCalResourcesrow2').append('<table id="SCalRefinedResourceTable" class="wikitable sortable"><thead>' + '<tr>' + '<th align="left">Resource</th>' + '<th align="left">Need</th>' + '</tr></thead>' ); var tablecontent = '<tbody>'; for(var [key, value] of Object.entries(refinedResources).sort()) { tablecontent += '<tr>' + '<td><a href="' + mw.util.getUrl(key) + '">' + key + '</a></td>' + '<td>' + value + '</td>' + '</tr>'; } tablecontent += '</tbody>'; tablecontent += '</table>'; $('#SCalRefinedResourceTable').append(tablecontent); } function printBaseResources() { $('#SCalResourcesrow2').html(''); $('#SCalResourcesrow2').append('<h2>Overview of base resources</h2>'); $('#SCalResourcesrow2').append('<table id="SCalBaseResourceTable" class="wikitable sortable"><thead>' + '<tr>' + '<th align="left">Resource</th>' + '<th align="left">Need</th>' + '</tr></thead>' ); var tablecontent = '<tbody>'; for (var [key, value] of Object.entries(baseResources).sort()) { tablecontent += '<tr>' + '<td><a href="' + mw.util.getUrl(key) + '">' + key + '</a></td>' + '<td>' + value + '</td>' + '</tr>'; } tablecontent += '</tbody>'; tablecontent += '</table>'; $('#SCalBaseResourceTable').append(tablecontent); } function isRealInteger(number) { return (!isNaN(number) && parseInt(Number(number)) == number && !isNaN(parseInt(number, 10))); } // check if the input fields contain valid entries function validateInputs() { var ready = true; //reset the error textfield $('#SCalErrorText').html(''); // check the keycounter value $('#SCalCountInput').removeClass('SCalErroreousInput'); var number = $('#SCalCountInput').val(); if (!isRealInteger(number)) { $('#SCalErrorText').append('<center>Amount of keys: this was not a number!</center>'); $('#SCalCountInput').addClass('SCalErroreousInput'); ready = false; } else { if (number < 1 || number > maxKeyCount) { $('#SCalErrorText').append('<center>Amount of keys: please provide a number between 1 and ' + maxKeyCount + '</center>'); $('#SCalCountInput').addClass('SCalErroreousInput'); ready = false; } } //check the skills counters for (var [skill, values] of Object.entries(skills)) { var inputObj = $('#' + values.id); inputObj.removeClass('SCalErroreousInput'); inputObj.removeClass('SCalOptimalInput'); number = inputObj.val(); if (!isRealInteger(number)) { $('#SCalErrorText').append('<center>' + skill + ': this was not a number!</center>'); inputObj.addClass('SCalErroreousInput'); ready = false; } else { if (number < 1 || number > maxSkillCount) { // exceeds the number range $('#SCalErrorText').append('<center>' + skill + ': please provide a number between 1 and ' + maxSkillCount + '</center>'); inputObj.addClass('SCalErroreousInput'); ready = false; } if(number < values.minSkill) { $('#SCalErrorText').append('<center>Skill ' + skill + ' is too low (have:' + number + ', need: ' + values.minSkill + ')</center>'); inputObj.addClass('SCalErroreousInput'); } if(!inputObj.hasClass('SCalErroreousInput')) { if(number >= values.maxSkill) inputObj.addClass('SCalOptimalInput'); } } } return ready; } function setCookie(name, value, date) { var expires = '; expires=' + date.toGMTString(); var cookie = name + '=' + value + expires + '; path=/; SameSite=Strict'; document.cookie = cookie; } function getCookie(name) { var nameEQ = name + '='; var ca = document.cookie.split(';'); for(var i=0;i < ca.length;i++) { var c = ca[i]; while (c.charAt(0)==' ') c = c.substring(1,c.length); if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length); } return null; } } });