Difference between revisions of "MediaWiki:SCalScript.js"
From Istaria Lexica
(Big script import) |
(Big script import) |
||
Line 186: | Line 186: | ||
// css stylesheet | // css stylesheet | ||
− | if(hasMW) mw.loader.load( getURL('MediaWiki:SCalScript.css') + " | + | if(hasMW) mw.loader.load( getURL('MediaWiki:SCalScript.css') + "?action=raw&ctype=text/css", "text/css" ); |
// Let's start adding content | // Let's start adding content |
Revision as of 14:03, 28 June 2022
/** * Skeleton Key Calculator V 0.8 * Elteria Shadowhand */ $(document).ready(function() { if (document.getElementById('SCalMain')) { 'use strict'; let baseResources; // Collection of the needed base resources. To be filled. let refinedResources; // Collection of the needed refined resources. To be filled. let skillsOverview; // A list of all needed skills, their min/opt stats and an id let productsDetails = {}; // detailed dynamic information for each product let maxKeyCount = 5000; // Skeleton Key counter maximum value let maxSkillCount = 2000; // Skill input fields maximum value // Set to false for the script to not use the MediaWiki API (for local execution outside of wikis) // This invalidates all URLs and removes other mediawiki specific generated content, i.e. tablesorters and stylesheets let hasMW = true; let currentProductIdCount; // Dirty little helper for adding dynamic IDs to the products let cookieParameters = '; path=/; SameSite=Strict'; // 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 min and max // 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 } }; // dynamically generate input field IDs for skills for(var [key, values] of Object.entries(skillsOverview)) { values.id = 'SCal' + key.replace(/\s/, '') + 'Input'; } // css stylesheet if(hasMW) mw.loader.load( getURL('MediaWiki:SCalScript.css') + "?action=raw&ctype=text/css", "text/css" ); // Let's start adding content // top part of the gui. This is static. printHeader(); printSkillInputs(); printKeyCounter(); // Container for the 'Export Everything' feature $('#SCalMain').append('<div id="SCalExportEverything" style="text-align: center"></div>'); // Containers for the lists $('#SCalMain').append('<center><table>' + '<tr valign="top">' + '<td id="SCalResourcesrow1"></td>' + '<td id="SCalResourcesrow2"></td>' + '</tr>' + '</table></center>' ); // finally create the lists. printLists(); //FUNCTIONS: function printKeyCounter() { $('#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="1" size="6"></center>'); $('#SCalCountInput').change(function(event) { var value = event.target.value; if(!isRealInteger(value)) value = 1; if(value <= 0) value = 1; if(value > maxKeyCount) value = maxKeyCount; event.target.value = value; setCookieByInteger(event.target.id, value); printLists(); }); } function printHeader() { $('#SCalMain').append('<h1 id="SCalH1">The Calculator</h1>'); $('#SCalMain').append('<center>Please enter your current skills in the fields below. Defaults to optimal skills.</center>'); $('#SCalMain').append('<center><input type="button" class="SCal" 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('<hr />'); $('#SCalMaxSkillsBtn').click(function() { if(confirm('This will reset all of the skills to optimal! Are you really sure? ')) { for (var v of Object.values(skillsOverview)) { $('#' + v.id).val(v.max); $('#' + v.id).change(); } } }); } function generateExportLink(text, buttontext, id, mainId, mimetype, filename) { $('#' + id).remove(); $('#' + mainId).append('<a id="' + id + 'A"></a>'); $('#' + id + 'A').append('<input class="SCal" id="' + id + '" name="' + id + '" type="button" value="' + buttontext + '">'); $('#' + id).click(function() { var url = 'data:' + mimetype + ';charset=utf-8,' + encodeURIComponent(text); $('#' + id + 'A').attr('href', url); $('#' + id + 'A').attr('download', filename); }); } // Creates a simple products object, containing the needed resources function recursiveCreateProductTree(productsDetails) { var product = {}; for(var [key, values] of Object.entries(productsDetails)) { product[key] = { needed: values.needed }; if(values.hasOwnProperty('subs')) product[key].subs = recursiveCreateProductTree(values.subs); } return product; } function printExportEverythingLinks() { var JSONeverything = JSON.stringify({ 'Product Tree': recursiveCreateProductTree(productsDetails), 'Base Resources': baseResources, 'Refined Resources': refinedResources, 'Skills': generateSkillsAsJSON() }); generateExportLink(JSONeverything, 'Export everything as JSON', 'SCalExportEverythingAsJSON', 'SCalExportEverything', 'application/json', 'Skeleton Key - All.json'); var TEXTeverything = '--- Tree of needed Resources ---\n\n'; TEXTeverything += recursiveGenerateTreeAsTEXT(productsDetails, 0); TEXTeverything += '\n\n'; TEXTeverything += '--- Needed Base Resources ---\n\n'; TEXTeverything += generateResourcesAsTEXT(baseResources); TEXTeverything += '\n\n'; TEXTeverything += '--- Needed Refined Resources ---\n\n'; TEXTeverything += generateResourcesAsTEXT(refinedResources); TEXTeverything += '\n\n'; TEXTeverything += '--- Needed Skills ---\n\n'; TEXTeverything += generateSkillsAsTEXT(9,7); generateExportLink(TEXTeverything, 'Export everything as TEXT', 'SCalExportEverythingAsEXT', 'SCalExportEverything', 'text/plain', 'Skeleton Key - All.txt'); var XMLeverything = '<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>\n'; XMLeverything += '<ResourcesTree>\n'; XMLeverything += recursiveGenerateTreeAsXML(productsDetails, 2); XMLeverything += '</ResourcesTree>\n'; XMLeverything += generateResourcesAsXML(baseResources,'BaseResources', 0); XMLeverything += generateResourcesAsXML(refinedResources,'RefinedResources', 0); XMLeverything += generateSkillsAsXML(0); generateExportLink(XMLeverything, 'Export everything as XML', 'SCalExportEverythingAsXML', 'SCalExportEverything', 'application/xml', '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 recursiveGenerateTreeAsTEXT(productsDetails, indent) { var text = ''; for(var [key, value] of Object.entries(productsDetails)) { 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(productsDetails, indent) { var xml = ''; for(var [key, value] of Object.entries(productsDetails)) { 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; } // calculated the effective needed resources for the given product function calculateNeededResource(minSkill, maxSkill, minCount, maxCount, skill) { var currentSkill = $('#' + skillsOverview[skill].id).val(); var percent = (currentSkill - minSkill) / (maxSkill - minSkill); var needEffective = maxCount - ((maxCount - minCount) * percent); needEffective = Math.ceil(needEffective); if (needEffective < minCount) needEffective = minCount; if (needEffective > maxCount) needEffective = maxCount; return needEffective; } function recursiveCleanHaveCookies(details) { for(var values of Object.values(details)) { var id = values.id + 'Have'; deleteCookie(id); if(values.hasOwnProperty('subs')) recursiveCleanHaveCookies(values.subs); } } function printTree() { $('#SCalResourcesrow1').append('<h2>Tree of needed products</h2>'); generateExportLink(JSON.stringify(recursiveCreateProductTree(productsDetails)), 'Export as JSON', 'SCalExportTreeAsJSON', 'SCalResourcesrow1', 'application/json', 'Skeleton Key - Tree.json'); generateExportLink(recursiveGenerateTreeAsTEXT(productsDetails, 0), 'Export as TEXT', 'SCalExportTreeAsTEXT', 'SCalResourcesrow1', 'text/plain', 'Skeleton Key - Tree.txt'); var treeAsXML = '<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>\n' + recursiveGenerateTreeAsXML(productsDetails, 0); generateExportLink(treeAsXML, 'Export as XML', 'SCalExportTreeAsXML', 'SCalResourcesrow1', 'application/xml', 'Skeleton Key - Tree.xml'); $('#SCalResourcesrow1').append('<input class="SCal" type="button" id="SCalResetTree" value="Reset all have-fields">'); $('#SCalResetTree').click(function() { if(confirm('This will reset all have-fields to 0. Are you really sure?')) { recursiveCleanHaveCookies(productsDetails); printLists(); } }); $('#SCalResourcesrow1').append(recursivePrintTreeProduct(productsDetails)); recursiveAddHaveChangeEvents(productsDetails); } function recursiveAddHaveChangeEvents(details) { for(var values of Object.values(details)) { $('#' + values.id + 'Have').change(function(event) { var have = event.target.value; if(!isRealInteger(have)) have = 0; if(have < 0) have = 0; setCookieByInteger(event.target.id, have); printLists(); }); if(values.hasOwnProperty('subs')) recursiveAddHaveChangeEvents(values.subs); } } //Calulates the needed data for the lists and puts them into objects //for further processing function recursiveCalculateResourceData(products, previousNeeded) { var details = {}; for(var [key, values] of Object.entries(products)) { currentProductIdCount += 1; var id = 'SCalItem' + currentProductIdCount; var needed = calculateNeededResource(values.minSkill, values.maxSkill, values.minCount, values.maxCount, values.skill); needEffective = needed * previousNeeded; var have = getCookie(id + 'Have'); if(!isRealInteger(have)) have = 0; if(have < 0) have = 0; if(have > 0) needEffective = needEffective - have; if(needEffective < 0) needEffective = 0; //Process needed resources for this product //and set the input field ID and resource type details[key] = { id: id, needed: needEffective, type: values.type }; // Add to base resources // we assume that a product without subs is a base resource if(!values.hasOwnProperty('subs')) { if(baseResources.hasOwnProperty(key)) { baseResources[key] = details[key].needed + baseResources[key]; } else { baseResources[key] = details[key].needed; } } // Add to refined resources if(values.type == 'SCalRefinedResource') { if(refinedResources.hasOwnProperty(key)) { refinedResources[key] = details[key].needed + refinedResources[key]; } else { refinedResources[key] = details[key].needed; } } // recurse through the sub products if(values.hasOwnProperty('subs')) details[key].subs = recursiveCalculateResourceData(values.subs, details[key].needed); } return details; } function printLists() { if(validateSkillInputs()) { // reinitialize everything $('#SCalResourcesrow1').html(''); $('#SCalResourcesrow2').html(''); baseResources = {}; refinedResources = {}; currentProductIdCount = 0; var keysWanted = getCookie('SCalCountInput'); if(!isRealInteger(keysWanted)) keysWanted = 1; if(keysWanted < 0) keysWanted = 1; if(keysWanted > maxKeyCount) keysWanted = maxKeyCount; $('#SCalCountInput').val(keysWanted); // set the Skeleton Key count productsDetails = recursiveCalculateResourceData(products, keysWanted); printExportEverythingLinks(); printTree(); printResources(baseResources, 'Overview of Base Resources', 'Base'); printResources(refinedResources, 'Overview of Refined Resources', 'Refined'); printNeededSkills(); if(hasMW) { mw.loader.using('jquery.tablesorter', function() { // add the tablesorter to tables $('table.sortable').tablesorter({ sortList: [{ 0: 'asc' }] }) }); } return true; } return false; } // generates a simple object of skills and their min/max values 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 getURL(article) { if(hasMW) return mw.util.getUrl(article); return ''; } function printNeededSkills() { $('#SCalResourcesrow2').append('<h2>Required skills</h2>'); generateExportLink(JSON.stringify(generateExportSkills()), 'Export as JSON', 'SCalExportSkillsAsJSON', 'SCalResourcesrow2', 'application/json', 'Skeleton Key - Skills.json'); generateExportLink(generateSkillsAsTEXT(determineNeededDigitlengthSkills(9,7)), 'Export as TEXT', 'SCalExportSkillsAsTEXT', 'SCalResourcesrow2', 'text/plain', 'Skeleton Key - Skills.txt'); var skillsAsXML = '<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>\n' + generateSkillsAsXML(0); generateExportLink(skillsAsXML, 'Export as XML', 'SCalExportSkillsAsXML', 'SCalResourcesrow2', 'application/xml', '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="' + 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)) skill = value.max; // default to max value if cookie not correctly set $('#SCalSkills').append('<input type="number" id="' + id + '" name="' + id + '" size="6" value="' + skill + '"><label for="' + id + '"> ' + key + '</label><br />'); $('#' + id).change(function(event) { setCookieByInteger(event.target.id, event.target.value); printLists(); }); } } // Tests if the provided value has a valid integer and sets a cookie for it function setCookieByInteger(id, value) { if(isRealInteger(value)) setCookie(id, value, new Date(3030,1,4)); } function recursivePrintTreeProduct(details) { var html = ''; for(var [key, values] of Object.entries(details)) { html += ' <ul>'; html += ' <li>'; if(key != 'Skeleton Key') { var have = getCookie(values.id + 'Have'); if(!isRealInteger(have)) have = 0; if(have < 0) have = 0; var haveClass = ''; if(have > 0) haveClass = ' SCalGreenInput'; html += ' <span class="' + values.type + '"><a href="' + getURL(key) + '">' + key + '</a> (' + values.needed + ') </span>' + ' <label for="' + values.id + 'Have">have:</label><input class="SCalTreeHave' + haveClass + '" id="' + values.id + 'Have" name="' + values.id + 'Have" type="number" size="8" value="' + have + '">'; } else { html += ' <span class="' + values.type + '"><a href="' + getURL(key) + '">' + key + '</a> (' + values.needed + ')</span>'; } if(values.hasOwnProperty('subs')) { html += recursivePrintTreeProduct(values.subs); } html += ' </li>'; html += ' </ul>'; } return html; } function printResources(resources, headline, type) { $('#SCalResourcesrow2').append('<h2>' + headline + '</h2>'); generateExportLink(JSON.stringify(Object.fromEntries(Object.entries(resources).sort())), 'Export as JSON', 'SCalExport' + type + 'resourcesAsJSON', 'SCalResourcesrow2', 'application/json', 'Skeleton Key - ' + type + ' Resources.json'); generateExportLink(generateResourcesAsTEXT(resources), 'Export as TEXT', 'SCalExport' + type + 'resourcesAsTEXT', 'SCalResourcesrow2', 'text/plain', 'Skeleton Key - ' + type + ' Resources.txt'); var resourceXML = '<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>\n' + generateResourcesAsXML(resources, type, 0); generateExportLink(resourceXML, 'Export as XML', 'SCalExport' + type + 'resourcesAsXML', 'SCalResourcesrow2', 'application/xml', 'Skeleton Key - ' + type + ' Resources.xml'); $('#SCalResourcesrow2').append('<table id="SCal' + type + 'ResourceTable" 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(resources).sort()) { tablecontent += '<tr>' + '<td><a href="' + getURL(key) + '">' + key + '</a></td>' + '<td>' + value + '</td>' + '</tr>'; } tablecontent += '</tbody>'; tablecontent += '</table>'; $('#SCal' + type + 'ResourceTable').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(needLength, optLength) { 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 < needLength - values.min.toString().length; i++) { needIndent += ' '; } for(var i = 0;i < optLength - 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 skill's input fields contain valid entries function validateSkillInputs() { var ready = true; $('#SCalErrorText').html(''); 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 is not a number!</center>'); inputObj.addClass('SCalErroreousInput'); ready = false; } else { if (number < 1 || number > maxSkillCount) { $('#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 ' + 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 + cookieParameters; 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; } function deleteCookie(name) { var expires = '; expires=Thu, 01 Jan 1970 00:00:00 UTC'; var cookie = name + '=' + expires + cookieParameters; document.cookie = cookie; } } });