|
|
(13 intermediate revisions by 2 users not shown) |
Line 1: |
Line 1: |
− | /**
| + | let SCalStateCheck = setInterval(() => { |
− | * Skeleton Key Calculator V 0.5
| + | 'use strict'; |
− | * Elteria Shadowhand
| + | if (document.readyState === 'complete') { |
− | */
| + | clearInterval(SCalStateCheck); |
− | $(document).ready(function() {
| + | let mainDivId = 'SCalMain'; // ID of the main content box. Can be a <div> or whatever. |
− | if (document.getElementById('SCalMain')) { | + | if (document.getElementById(mainDivId)) { |
− | 'use strict';
| + | var url = mw.util.getUrl('Product Calculator', { product: 'Skeleton Key' }); |
− | let baseResources; // Collection of the needed base resources. To be filled.
| + | window.location.href = url; |
− | let refinedResources; // Collection of the needed refined resources. To be filled.
| |
− | let productsSkills = {}; // A list of all product's skills needed, containing their names and their min/opt values.
| |
− | let skillsOverview; // A list of all needed skills, their min/opt stats and an id
| |
− | let resourcesTree = {}; // A tree of resources and needed counts. to be filled.
| |
− | 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.
| |
− | // the REAL needed skills are documented in the skillsOverview variable.
| |
− | 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 }
| |
− | }
| |
− | }
| |
− | }
| |
− | }
| |
− | };
| |
− | | |
− | // List of the skills you need to have for crafting everything, only used for the input fields
| |
− | skillsOverview = {
| |
− | 'Tinkering': { min: 1100, max: 1425 },
| |
− | 'Scribing': { min: 1100, max: 1425 },
| |
− | 'Spellcraft': { min: 1100, max: 1425 },
| |
− | 'Essence Shaping': { min: 1000, max: 1325 },
| |
− | 'Papermaking': { min: 1000, max: 1325 },
| |
− | 'Alchemy': { min: 1100, max: 1425 },
| |
− | 'Fletching': { min: 1100, max: 1425 },
| |
− | 'Enchanting': { min: 1100, max: 1425 },
| |
− | 'Stoneworking': { min: 1000, max: 1325 },
| |
− | 'Lumbering': { min: 1000, max: 1325 },
| |
− | 'Smelting': { min: 1100, max: 1425 },
| |
− | 'Earthencraft': { min: 1100, max: 1425 },
| |
− | };
| |
− |
| |
− | for(var [key, values] of Object.entries(skillsOverview)) {
| |
− | values.id = 'SCal' + key.replace(/\s/, '') + 'Input';
| |
− | }
| |
− | | |
− | printHeader();
| |
− | printSkillInputs();
| |
− | | |
− | $('#SCalMain').append('<div id="SCalExportEverything" style="text-align: center"></div>');
| |
− |
| |
− | // Details of the crafting
| |
− | $('#SCalMain').append('<center><table>'
| |
− | + '<tr valign="top">'
| |
− | + '<td id="SCalResourcesrow1"></td>'
| |
− | + '<td id="SCalResourcesrow2"></td>'
| |
− | + '</tr>'
| |
− | + '</table></center>'
| |
− | );
| |
− | | |
− | $('#SCalResourcesrow1').append('<div id="SCalResources"></div>');
| |
− | | |
− | recursiveDetermineProductsSkills(products);
| |
− | if(validateInputs()) {
| |
− | printLists();
| |
− | } | |
− | | |
− | // The 'print everything' feature
| |
− | resourcesTree = recursiveGenerateTree(products);
| |
− | printPrintEverythingLinks(); | |
− | | |
− | //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 /><center>A <font style="color: red"><b>red</b></font> box means there is an error.</center>');
| |
− | $('#SCalMain').append('<center>A <font style="color: green"><b>green</b></font> box means you\'re optimal for creating the items.</center>');
| |
− | $('#SCalMain').append('<div id="SCalErrorText"></div>');
| |
− | $('#SCalMain').append('<br />');
| |
− | $('#SCalMain').append('<center><input type="button" id="SCalCountBtn" value="Calculate now!"></center>');
| |
− | $('#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(skillsOverview)) {
| |
− | $('#' + v.id).val(v.max);
| |
− | $('#' + 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 printPrintEverythingLinks() {
| |
− | $('#SCalExportEverything').append('<a id="SCalExportEverythingAsJSONA"></a>');
| |
− | $('#SCalExportEverythingAsJSONA').append('<input id="SCalExportEverythingAsJSON" name="SCalExportEverythingAsJSON" type="button" value="Export everything as JSON">');
| |
− | $('#SCalExportEverythingAsJSON').click(function() {
| |
− | var JSONeverything = {
| |
− | 'Product Tree': resourcesTree,
| |
− | 'Base Resources': baseResources,
| |
− | 'Refined Resources': refinedResources,
| |
− | 'Skills': generateSkillsAsJSON()
| |
− | };
| |
− |
| |
− | var url = 'data:text/json;charset=utf-8,' + encodeURIComponent(JSON.stringify(JSONeverything));
| |
− | $('#SCalExportEverythingAsJSONA').attr('href', url);
| |
− | $('#SCalExportEverythingAsJSONA').attr('download', 'Skeleton Key - All.json');
| |
− | });
| |
− | $('#SCalExportEverything').append('<a id="SCalExportEverythingAsTEXTA"></a>');
| |
− | $('#SCalExportEverythingAsTEXTA').append('<input id="SCalExportEverythingAsTEXT" name="SCalExportEverythingAsTEXT" type="button" value="Export everything as TEXT">');
| |
− | $('#SCalExportEverythingAsTEXT').click(function() {
| |
− | var text = '--- Tree of needed Resources ---\n\n';
| |
− | text += recursiveGenerateTreeAsTEXT(resourcesTree, 0);
| |
− | text += '\n\n';
| |
− | text += '--- Needed Base Resources ---\n\n';
| |
− | text += generateResourcesAsTEXT(baseResources);
| |
− | text += '\n\n';
| |
− | text += '--- Needed Refined Resources ---\n\n';
| |
− | text += generateResourcesAsTEXT(refinedResources);
| |
− | text += '\n\n';
| |
− | text += '--- Needed Skills ---\n\n';
| |
− | text += generateSkillsAsTEXT([9,7]);
| |
− |
| |
− | var url = 'data:text/plain;charset=utf-8,' + encodeURIComponent(text);
| |
− | $('#SCalExportEverythingAsTEXTA').attr('href', url);
| |
− | $('#SCalExportEverythingAsTEXTA').attr('download', 'Skeleton Key - All.txt');
| |
− | });
| |
− | $('#SCalExportEverything').append('<a id="SCalExportEverythingAsXMLA"></a>');
| |
− | $('#SCalExportEverythingAsXMLA').append('<input id="SCalExportEverythingAsXML" name="SCalExportEverythingAsXML" type="button" value="Export everything as XML">');
| |
− | $('#SCalExportEverythingAsXML').click(function() {
| |
− | var text = '<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>\n';
| |
− | text += '<ResourcesTree>\n';
| |
− | text += recursiveGenerateTreeAsXML(resourcesTree, 2);
| |
− | text += '</ResourcesTree>\n';
| |
− | text += generateResourcesAsXML(baseResources,'BaseResources', 0);
| |
− | text += generateResourcesAsXML(refinedResources,'RefinedResources', 0);
| |
− | text += generateSkillsAsXML(0);
| |
− | var url = 'data:application/xml;charset=utf-8,' + encodeURIComponent(text);
| |
− | | |
− | $('#SCalExportEverythingAsXMLA').attr('href', url);
| |
− | $('#SCalExportEverythingAsXMLA').attr('download', 'Skeleton Key - All.xml');
| |
− | });
| |
− | }
| |
− |
| |
− | function generateSkillsAsJSON() {
| |
− | var json = {};
| |
− | for(var [key, values] of Object.entries(skillsOverview).sort()) {
| |
− | json[key] = {
| |
− | minimal: values.min,
| |
− | optimal: values.max
| |
− | }
| |
− | }
| |
− | return json;
| |
− | }
| |
− |
| |
− | function recursiveGenerateTree(product) {
| |
− | var tree = {};
| |
− | for(var [key, value] of Object.entries(product)) {
| |
− | tree[key] = { needed: value.needed };
| |
− |
| |
− | if(value.hasOwnProperty('subs')) {
| |
− | tree[key].subs = recursiveGenerateTree(value.subs);
| |
− | }
| |
− | }
| |
− | return tree;
| |
− | }
| |
− | | |
− | function recursiveGenerateTreeAsTEXT(tree, indent) {
| |
− | var text = '';
| |
− | for(var [key, value] of Object.entries(tree)) {
| |
− | for(var i=0; i<indent; i++) {
| |
− | text += ' ';
| |
− | }
| |
− |
| |
− | text += '|- ';
| |
− | text += key + ' ';
| |
− | text += value.needed;
| |
− | text += '\n';
| |
− | | |
− | if(value.hasOwnProperty('subs')) {
| |
− | text += recursiveGenerateTreeAsTEXT(value.subs, indent+2);
| |
− | }
| |
− | }
| |
− | return text;
| |
− | }
| |
− | | |
− | function recursiveGenerateTreeAsXML(tree, indent) {
| |
− | var xml = '';
| |
− | for(var [key, value] of Object.entries(tree)) {
| |
− | for(var i=0; i<indent; i++) {
| |
− | xml += ' ';
| |
− | }
| |
− |
| |
− | xml += '<item name="' + key +'" needed="' + value.needed + '">\n';
| |
− | | |
− | if(value.hasOwnProperty('subs')) {
| |
− | xml += recursiveGenerateTreeAsXML(value.subs, indent+2);
| |
− | }
| |
− | | |
− | for(var i=0; i<indent; i++) {
| |
− | xml += ' ';
| |
− | }
| |
− |
| |
− | xml +='</item>\n';
| |
− | }
| |
− | return xml;
| |
− | }
| |
− | | |
− | function determineNeededDigitlength(resources, length) {
| |
− | for(var value of Object.values(resources)) {
| |
− | if(value.toString().length > length) length = value.toString().length;
| |
− | }
| |
− | return length;
| |
− | }
| |
− | | |
− | function determineNeededDigitlengthSkills(length) {
| |
− | for(var key of Object.keys(skillsOverview)) {
| |
− | if(skillsOverview[key].min.toString().length > length) length[0] = skillsOverview[key].min.toString().length;
| |
− | if(skillsOverview[key].max.toString().length > length) length[1] = skillsOverview[key].max.toString().length;
| |
− | }
| |
− | return length;
| |
− | }
| |
− | | |
− | | |
− | 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>');
| |
− | $('#SCalResources').append('<a id="SCalExportTreeAsJSONA"></a>');
| |
− | $('#SCalExportTreeAsJSONA').append('<input id="SCalExportTreeAsJSON" name="SCalExportTreeAsJSON" type="button" value="Export as JSON">');
| |
− | $('#SCalExportTreeAsJSON').click(function() {
| |
− | var url = 'data:text/json;charset=utf-8,' + encodeURIComponent(JSON.stringify(resourcesTree));
| |
− | $('#SCalExportTreeAsJSONA').attr('href', url);
| |
− | $('#SCalExportTreeAsJSONA').attr('download', 'Skeleton Key - Tree.json');
| |
− | }); | |
− | $('#SCalResources').append('<a id="SCalExportTreeAsTEXTA"></a>');
| |
− | $('#SCalExportTreeAsTEXTA').append('<input id="SCalExportTreeAsTEXT" name="SCalExportTreeAsTEXT" type="button" value="Export as TEXT">');
| |
− | $('#SCalExportTreeAsTEXT').click(function() {
| |
− | var url = 'data:text/plain;charset=utf-8,' + encodeURIComponent(recursiveGenerateTreeAsTEXT(resourcesTree, 0));
| |
− | $('#SCalExportTreeAsTEXTA').attr('href', url);
| |
− | $('#SCalExportTreeAsTEXTA').attr('download', 'Skeleton Key - Tree.txt');
| |
− | });
| |
− | $('#SCalResources').append('<a id="SCalExportTreeAsXMLA"></a>');
| |
− | $('#SCalExportTreeAsXMLA').append('<input id="SCalExportTreeAsXML" name="SCalExportTreeAsXML" type="button" value="Export as XML">');
| |
− | $('#SCalExportTreeAsXML').click(function() {
| |
− | var url = 'data:application/xml;charset=utf-8,' + encodeURIComponent(
| |
− | '<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>\n'
| |
− | + recursiveGenerateTreeAsXML(resourcesTree, 0));
| |
− | $('#SCalExportTreeAsXMLA').attr('href', url);
| |
− | $('#SCalExportTreeAsXMLA').attr('download', 'Skeleton Key - Tree.xml');
| |
− | });
| |
− |
| |
− | var html = recursivePrintTreeProduct(products);
| |
− | $('#SCalResources').append(html);
| |
− | | |
− | printBaseResources();
| |
− | printRefinedResources();
| |
− | printNeededSkills();
| |
− | | |
− | // mw.loader.using('jquery.tablesorter', function() {
| |
− | // $('table.sortable').tablesorter({ sortList: [{ 0: 'asc' }] })
| |
− | // });
| |
− | }
| |
− | | |
− | function generateExportSkills() {
| |
− | var skills = {};
| |
− | for(var [key, value] of Object.entries(skillsOverview).sort()) {
| |
− | skills[key] = {
| |
− | 'minimal skill': value.min,
| |
− | 'optimal skill': value.max
| |
− | }
| |
− | }
| |
− | return skills;
| |
− | }
| |
− | | |
− | function printNeededSkills() {
| |
− | $('#SCalResourcesrow2').append('<h2>Required skills</h2>');
| |
− | | |
− | $('#SCalResourcesrow2').append('<a id="SCalExportSkillsAsJSONA"></a>');
| |
− | $('#SCalExportSkillsAsJSONA').append('<input id="SCalExportSkillsAsJSON" name="SCalExportSkillsAsJSON" type="button" value="Export as JSON">');
| |
− | $('#SCalExportSkillsAsJSON').click(function() {
| |
− | var url = 'data:text/json;charset=utf-8,' + encodeURIComponent(JSON.stringify(generateExportSkills()));
| |
− | $('#SCalExportSkillsAsJSONA').attr('href', url);
| |
− | $('#SCalExportSkillsAsJSONA').attr('download', 'Skeleton Key - Skills.json');
| |
− | });
| |
− | | |
− | $('#SCalResourcesrow2').append('<a id="SCalExportSkillsAsTEXTA"></a>');
| |
− | $('#SCalExportSkillsAsTEXTA').append('<input id="SCalExportSkillsAsTEXT" name="SCalExportSkillsAsTEXT" type="button" value="Export as TEXT">');
| |
− | $('#SCalExportSkillsAsTEXT').click(function() {
| |
− | var text = generateSkillsAsTEXT(determineNeededDigitlengthSkills([9,7]));
| |
− | var url = 'data:text/plain;charset=utf-8,' + encodeURIComponent(text);
| |
− | $('#SCalExportSkillsAsTEXTA').attr('href', url);
| |
− | $('#SCalExportSkillsAsTEXTA').attr('download', 'Skeleton Key - Skills.txt');
| |
− | });
| |
− | | |
− | $('#SCalResourcesrow2').append('<a id="SCalExportSkillsAsXMLA"></a>');
| |
− | $('#SCalExportSkillsAsXMLA').append('<input id="SCalExportSkillsAsXML" name="SCalExportSkillsAsXML" type="button" value="Export as XML">');
| |
− | $('#SCalExportSkillsAsXML').click(function() {
| |
− | var text = '<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>\n'
| |
− | + generateSkillsAsXML(0);
| |
− | var url = 'data:application/xml;charset=utf-8,' + encodeURIComponent(text);
| |
− | $('#SCalExportSkillsAsXMLA').attr('href', url);
| |
− | $('#SCalExportSkillsAsXMLA').attr('download', 'Skeleton Key - Skills.xml');
| |
− | });
| |
− | | |
− | | |
− | $('#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(skillsOverview).sort()) {
| |
− | tablecontent += '<tr>'
| |
− | + '<td><a href="' /*+ mw.util.getUrl(key)*/ + '">' + key + '</a></td>'
| |
− | + '<td>' + value.min + '</td>'
| |
− | + '<td>' + value.max + '</td>'
| |
− | + '</tr>';
| |
− | }
| |
− | | |
− | tablecontent += '</tbody>';
| |
− | tablecontent += '</table>';
| |
− | $('#SCalNeededSkillsTable').append(tablecontent);
| |
− | }
| |
− |
| |
− | function printSkillInputs() {
| |
− | for (var [key, value] of Object.entries(skillsOverview)) {
| |
− | var id = value.id;
| |
− | var skill = getCookie(id);
| |
− | if(!isRealInteger(skill)) { // default to max value if cookie not correctly set
| |
− | skill = value.max;
| |
− | }
| |
− | | |
− | $('#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 recursiveDetermineProductsSkills(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(productsSkills.hasOwnProperty(skillName)) {
| |
− | if(productsSkills[skillName].minSkill < newSkills.minSkill) {
| |
− | newSkills.minSkill = productsSkills[skillName].minSkill;
| |
− | }
| |
− |
| |
− | if(productsSkills[skillName].maxSkill > newSkills.maxSkill) {
| |
− | newSkills.maxSkill = productsSkills[skillName].maxSkill;
| |
− | }
| |
− | }
| |
− |
| |
− | productsSkills[skillName] = newSkills;
| |
− |
| |
− | if(product.hasOwnProperty('subs')) {
| |
− | recursiveDetermineProductsSkills(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(product, previousCount) {
| |
− | for(var [key, values] of Object.entries(product)) {
| |
− | var currentSkill = $('#' + skillsOverview[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;
| |
− | product[key] = values;
| |
− | | |
− | if(values.hasOwnProperty('subs')) {
| |
− | values.subs = recursiveCalculateNeededResources(values.subs, needEffective);
| |
− | }
| |
− | }
| |
− | return product;
| |
− | }
| |
− | | |
− | function printRefinedResources() {
| |
− | $('#SCalResourcesrow2').append('<h2>Overview of refined resources</h2>');
| |
− |
| |
− | $('#SCalResourcesrow2').append('<a id="SCalExportRefinedresourcesAsJSONA"></a>');
| |
− | $('#SCalExportRefinedresourcesAsJSONA').append('<input id="SCalExportRefinedresourceAsJSON" name="SCalExportRefinedresourceAsJSON" type="button" value="Export as JSON">');
| |
− | $('#SCalExportRefinedresourceAsJSON').click(function() {
| |
− | var url = 'data:text/json;charset=utf-8,' + encodeURIComponent(JSON.stringify(Object.fromEntries(Object.entries(refinedResources).sort())));
| |
− | $('#SCalExportRefinedresourcesAsJSONA').attr('href', url);
| |
− | $('#SCalExportRefinedresourcesAsJSONA').attr('download', 'Skeleton Key - Refined Resources.json');
| |
− | });
| |
− | | |
− | $('#SCalResourcesrow2').append('<a id="SCalExportRefinedresourcesAsTEXTA"></a>');
| |
− | $('#SCalExportRefinedresourcesAsTEXTA').append('<input id="SCalExportRefinedresourceAsTEXT" name="SCalExportRefinedresourceAsTEXT" type="button" value="Export as TEXT">');
| |
− | $('#SCalExportRefinedresourceAsTEXT').click(function() {
| |
− | var url = 'data:application/xml;charset=utf-8,' + encodeURIComponent(generateResourcesAsTEXT(baseResources));
| |
− | $('#SCalExportRefinedresourcesAsTEXTA').attr('href', url);
| |
− | $('#SCalExportRefinedresourcesAsTEXTA').attr('download', 'Skeleton Key - Refined Resouces.txt');
| |
− | });
| |
− | | |
− | $('#SCalResourcesrow2').append('<a id="SCalExportRefinedresourcesAsXMLA"></a>');
| |
− | $('#SCalExportRefinedresourcesAsXMLA').append('<input id="SCalExportRefinedresourceAsXML" name="SCalExportRefinedresourceAsXML" type="button" value="Export as XML">');
| |
− | $('#SCalExportRefinedresourceAsXML').click(function() {
| |
− | var url = 'data:application/xml;charset=utf-8,' + encodeURIComponent(
| |
− | '<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>\n'
| |
− | + generateResourcesAsXML(refinedResources,'RefinedResources', 0));
| |
− | $('#SCalExportRefinedresourcesAsXMLA').attr('href', url);
| |
− | $('#SCalExportRefinedresourcesAsXMLA').attr('download', 'Skeleton Key - Refined Resources.xml');
| |
− | });
| |
− | | |
− | $('#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('<a id="SCalExportBaseresourcesAsJSONA"></a>');
| |
− | $('#SCalExportBaseresourcesAsJSONA').append('<input id="SCalExportBaseresourceAsJSON" name="SCalExportBaseresourceAsJSON" type="button" value="Export as JSON">');
| |
− | $('#SCalExportBaseresourceAsJSON').click(function() {
| |
− | var url = 'data:text/json;charset=utf-8,' + encodeURIComponent(JSON.stringify(Object.fromEntries(Object.entries(baseResources).sort())));
| |
− | $('#SCalExportBaseresourcesAsJSONA').attr('href', url);
| |
− | $('#SCalExportBaseresourcesAsJSONA').attr('download', 'Skeleton Key - Base Resources.json');
| |
− | });
| |
− | | |
− | $('#SCalResourcesrow2').append('<a id="SCalExportBaseresourcesAsTEXTA"></a>');
| |
− | $('#SCalExportBaseresourcesAsTEXTA').append('<input id="SCalExportBaseresourceAsTEXT" name="SCalExportBaseresourceAsTEXT" type="button" value="Export as TEXT">');
| |
− | $('#SCalExportBaseresourceAsTEXT').click(function() {
| |
− | var url = 'data:application/xml;charset=utf-8,' + encodeURIComponent(generateResourcesAsTEXT(baseResources));
| |
− | $('#SCalExportBaseresourcesAsTEXTA').attr('href', url);
| |
− | $('#SCalExportBaseresourcesAsTEXTA').attr('download', 'Skeleton Key - Base Resouces.txt');
| |
− | });
| |
− | | |
− | $('#SCalResourcesrow2').append('<a id="SCalExportBaseresourcesAsXMLA"></a>');
| |
− | $('#SCalExportBaseresourcesAsXMLA').append('<input id="SCalExportBaseresourceAsXML" name="SCalExportBaseresourceAsXML" type="button" value="Export as XML">');
| |
− | $('#SCalExportBaseresourceAsXML').click(function() {
| |
− | var url = 'data:application/xml;charset=utf-8,' + encodeURIComponent(
| |
− | '<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>\n'
| |
− | + generateResourcesAsXML(baseResources,'BaseResources', 0));
| |
− | $('#SCalExportBaseresourcesAsXMLA').attr('href', url);
| |
− | $('#SCalExportBaseresourcesAsXMLA').attr('download', 'Skeleton Key - Base Resources.xml');
| |
− | });
| |
− |
| |
− | $('#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 generateResourcesAsTEXT(resources) {
| |
− | var text = '';
| |
− | var length = determineNeededDigitlength(resources, 0);
| |
− | for(var [key, count] of Object.entries(resources).sort()) {
| |
− | var indent = '';
| |
− | for(var i = 0;i < length - count.toString().length; i++) {
| |
− | indent += ' ';
| |
− | }
| |
− |
| |
− | text += count + indent + ' ' + key + '\n';
| |
− | }
| |
− | return text;
| |
− | }
| |
− |
| |
− | function generateSkillsAsXML(indent) {
| |
− | indentation = '';
| |
− | for(var i = 0; i < indent; i++) {
| |
− | indentation += ' ';
| |
− | }
| |
− |
| |
− | var xml = indentation + '<Skills>\n';
| |
− | for(var [key, values] of Object.entries(skillsOverview).sort()) {
| |
− | xml += indentation + ' <skill minimal="' + values.min + '" optimal="' + values.max + '">' + key + '</item>\n';
| |
− | }
| |
− | xml += indentation + '</Skills>'
| |
− | return xml;
| |
− | }
| |
− |
| |
− | function generateSkillsAsTEXT(lengths) {
| |
− | var text = 'Minimal Optimal Skillname\n';
| |
− | text += '--------------------------------------------------------\n';
| |
− | | |
− | for(var [key, values] of Object.entries(skillsOverview).sort()) {
| |
− | var needIndent = '';
| |
− | var optIndent = '';
| |
− | for(var i = 0;i < lengths[0] - values.min.toString().length; i++) {
| |
− | needIndent += ' ';
| |
− | }
| |
− | | |
− | for(var i = 0;i < lengths[1] - values.max.toString().length; i++) {
| |
− | optIndent += ' ';
| |
− | }
| |
− |
| |
− | text += values.min + needIndent + values.max + optIndent + ' ' + key + '\n';
| |
− | }
| |
− | return text;
| |
− | }
| |
− | | |
− | function generateResourcesAsXML(resources, tag, indent) {
| |
− | var indentation = '';
| |
− | for(var i = 0; i < indent; i++) {
| |
− | indentation += ' ';
| |
− | }
| |
− | var xml = indentation + '<' + tag + '>\n';
| |
− |
| |
− | for(var [key, count] of Object.entries(resources).sort()) {
| |
− | xml += indentation + ' <item needed="' + count + '">' + key + '</item>\n';
| |
− | }
| |
− | xml += '</' + tag + '>\n';
| |
− | return xml;
| |
− | }
| |
− | | |
− | 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(skillsOverview)) {
| |
− | 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.min) {
| |
− | $('#SCalErrorText').append('<center>Skill ' + skill + ' is too low (have:' + number + ', need: ' + values.min + ')</center>');
| |
− | inputObj.addClass('SCalErroreousInput');
| |
− | }
| |
− | if(!inputObj.hasClass('SCalErroreousInput')) {
| |
− | if(number >= values.max) 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;
| |
| } | | } |
| } | | } |
− | }); | + | }, 50); |