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.3
+
  * 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 requiredMinMaxSkills; // Collection of skills and their min/max skill values.
+
     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;
    let skills = new Map();// a list of all skills needed.
 
 
      
 
      
     // let's add some relevant information.
+
     // the dataset
     // needed amounts default to optimum skills
+
    // Note that the skill is NOT the actual skill you need to create the product.  
     let products = new Map();
+
     // It is the skill you need to create it's parent product. So if you created a Spell Shard which needs Spellcraft,
     products.set('Skeleton Key', { subs: new Map(), skill:'Tinkering', minCount: 1, maxCount: 1, minSkill: 1100, maxSkill: 1425, type: 'SCalProduct' });
+
     // the subcomponent (i.e. a Stone Brick, which would be Stoneworking) of it would be Spellcraft. The minXXX and maxXXX
    products.get('Skeleton Key').subs
+
     // parameters behave the same.
      .set('Enchanted Adamantium-Mithril Bar', { subs: new Map(), skill:'Tinkering', minCount: 3, maxCount: 6, minSkill: 1100, maxSkill: 1425, type: 'SCalProduct' });
+
    let products = {
    products.get('Skeleton Key').subs
+
      'Skeleton Key': { skill: 'Tinkering', minCount: 1, maxCount: 1, minSkill: 1100, maxSkill: 1425, type: 'SCalProduct', subs:
      .get('Enchanted Adamantium-Mithril Bar').subs
+
        {
        .set('Gozar\'s Blessing', { subs: new Map(), skill:'Tinkering', minCount: 2, maxCount: 4, minSkill: 1100, maxSkill: 1425, type: 'SCalProduct' });
+
          'Enchanted Adamantium-Mithril Bar': { skill: 'Tinkering', minCount: 3, maxCount: 6, minSkill: 1100, maxSkill: 1425, type: 'SCalProduct', subs:
    products.get('Skeleton Key').subs
+
            {
      .get('Enchanted Adamantium-Mithril Bar').subs
+
              'Gozar\'s Blessing': { skill: 'Tinkering', minCount: 2, maxCount: 4, minSkill: 1100, maxSkill: 1425, type: 'SCalProduct', subs:
        .get('Gozar\'s Blessing').subs
+
                {
          .set('Meltanis\' Prayer', { subs: new Map(), skill:'Scribing', minCount: 1, maxCount: 3, minSkill: 1100, maxSkill: 1425, type: 'SCalProduct' });
+
                  'Meltanis\' Prayer': { skill: 'Scribing', minCount: 1, maxCount: 3, minSkill: 1100, maxSkill: 1425, type: 'SCalProduct', subs:
    products.get('Skeleton Key').subs
+
                    {
      .get('Enchanted Adamantium-Mithril Bar').subs
+
                      'Travertine Spell Shard': { skill: 'Spellcraft', minCount: 1, maxCount: 5, minSkill: 1100, maxSkill: 1425, type: 'SCalRefinedResource', subs:
        .get('Gozar\'s Blessing').subs
+
                        {
          .get('Meltanis\' Prayer').subs
+
                          'Travertine Brick': { skill: 'Stoneworking', minCount: 2, maxCount: 5, minSkill: 1000, maxSkill: 1325, type: 'SCalRefinedResource', subs:
            .set('Travertine Spell Shard', { subs: new Map(), skill:'Spellcraft', minCount: 1, maxCount: 5, minSkill: 1100, maxSkill: 1425, type: 'SCalRefinedResource' });
+
                            {
    products.get('Skeleton Key').subs
+
                              'Travertine Slab': { skill: 'Stoneworking', minCount: 2, maxCount: 5, minSkill: 1000, maxSkill: 1325 }
      .get('Enchanted Adamantium-Mithril Bar').subs
+
                            }
        .get('Gozar\'s Blessing').subs
+
                          }
          .get('Meltanis\' Prayer').subs
+
                        }
            .get('Travertine Spell Shard').subs
+
                      }, 'Radiant Essence Orb': { skill: 'Spellcraft', minCount: 4, maxCount: 10, minSkill: 1100, maxSkill: 1425, type: 'SCalRefinedResource', subs:
              .set('Travertine Brick', { subs: new Map(), skill:'Stoneworking', minCount: 2, maxCount: 5, minSkill: 1000, maxSkill: 1325, type: 'SCalRefinedResource' });
+
                        {
    products.get('Skeleton Key').subs
+
                          'Radiant Essence': { skill: 'Essence Shaping', minCount: 2, maxCount: 5, minSkill: 1000, maxSkill: 1325 }
      .get('Enchanted Adamantium-Mithril Bar').subs
+
                        }
        .get('Gozar\'s Blessing').subs
+
                      }
          .get('Meltanis\' Prayer').subs
+
                    }
            .get('Travertine Spell Shard').subs
+
                  }, 'Primal Burst III': { skill: 'Spellcraft', minCount: 1, maxCount: 3,minSkill: 930, maxSkill: 1130, type: 'SCalProduct', subs:
              .get('Travertine Brick').subs
+
                    {
                .set('Travertine Slab', { skill:'Stoneworking', minCount: 2, maxCount: 5, minSkill: 1000, maxSkill: 1325 });
+
                      'Marble Spell Shard': { skill: 'Spellcraft', minCount: 5, maxCount: 5, minSkill: 930, maxSkill: 1130, type: 'SCalRefinedResource', subs:
    products.get('Skeleton Key').subs
+
                        {
      .get('Enchanted Adamantium-Mithril Bar').subs
+
                          'Marble Brick': { skill: 'Spellcraft', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100, type: 'SCalRefinedResource', subs:
        .get('Gozar\'s Blessing').subs
+
                            {
          .get('Meltanis\' Prayer').subs
+
                              'Marble Slab': { skill: 'Stoneworking', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100 }
            .set('Radiant Essence Orb', { subs: new Map(), skill:'Spellcraft', minCount: 4, maxCount: 10, minSkill: 1100, maxSkill: 1425, type: 'SCalRefinedResource'});
+
                            }
    products.get('Skeleton Key').subs
+
                          }
      .get('Enchanted Adamantium-Mithril Bar').subs
+
                        }
        .get('Gozar\'s Blessing').subs
+
                      }, 'Shining Essence Orb': { skill: 'Spellcraft', minCount: 9, maxCount: 18, minSkill: 930, maxSkill: 1130, type: 'SCalRefinedResource', subs:
          .get('Meltanis\' Prayer').subs
+
                        {
            .get('Radiant Essence Orb').subs
+
                          'Shining Essence': { skill: 'Essence Shaping', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100 }
              .set('Radiant Essence', { skill:'Essence Shaping', minCount: 2, maxCount: 5, minSkill: 1000, maxSkill: 1325});
+
                        }
    products.get('Skeleton Key').subs
+
                      }
      .get('Enchanted Adamantium-Mithril Bar').subs
+
                    }
        .get('Gozar\'s Blessing').subs
+
                  }, 'Energy Strike V': { skill: 'Spellcraft', minCount: 1, maxCount: 3, minSkill: 850, maxSkill: 1050, type: 'SCalProduct', subs:
          .set('Primal Burst III', { subs: new Map(), skill:'Spellcraft', minCount: 1, maxCount: 3, minSkill: 930, maxSkill: 1130, type: 'SCalProduct'});
+
                    {
    products.get('Skeleton Key').subs
+
                      'Marble Spell Shard': { skill: 'Spellcraft', minCount: 4, maxCount: 4, minSkill: 850, maxSkill: 1050, type: 'SCalRefinedResource', subs:
      .get('Enchanted Adamantium-Mithril Bar').subs
+
                        {
        .get('Gozar\'s Blessing').subs
+
                          'Marble Brick': { skill: 'Spellcraft', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100, type: 'SCalRefinedResource', subs:
          .get('Primal Burst III').subs
+
                            {
            .set('Marble Spell Shard', { subs: new Map(), skill:'Spellcraft', minCount: 5, maxCount: 5, minSkill: 930, maxSkill: 1130, type: 'SCalRefinedResource'});
+
                              'Marble Slab': { skill: 'Stoneworking', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100 }
    products.get('Skeleton Key').subs
+
                            }
      .get('Enchanted Adamantium-Mithril Bar').subs
+
                          }
        .get('Gozar\'s Blessing').subs
+
                        }
          .get('Primal Burst III').subs
+
                      }, 'Shining Essence Orb': { skill: 'Spellcraft', minCount: 7, maxCount: 14, minSkill: 800, maxSkill: 1100, type: 'SCalRefinedResource', subs:
            .get('Marble Spell Shard').subs
+
                        {
              .set('Marble Brick', { subs: new Map(), skill:'Spellcraft', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100, type: 'SCalRefinedResource'});
+
                          'Shining Essence': { skill: 'Essence Shaping', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100 }
    products.get('Skeleton Key').subs
+
                        }
      .get('Enchanted Adamantium-Mithril Bar').subs
+
                      }
        .get('Gozar\'s Blessing').subs
+
                    }
          .get('Primal Burst III').subs
+
                  }, 'Ice Bomb V': { skill: 'Spellcraft', minCount: 1, maxCount: 3, minSkill: 920, maxSkill: 1120, type: 'SCalProduct', subs:
            .get('Marble Spell Shard').subs
+
                    {
              .get('Marble Brick').subs
+
                      'Marble Spell Shard': { skill: 'Spellcraft', minCount: 5, maxCount: 5, minSkill: 800, maxSkill: 1100, type: 'SCalRefinedResource', subs:
                .set('Marble Slab', { skill:'Stoneworking', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100});
+
                        {
    products.get('Skeleton Key').subs
+
                          'Marble Brick': { skill: 'Stoneworking', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100, type: 'SCalRefinedResource', subs:
      .get('Enchanted Adamantium-Mithril Bar').subs
+
                            {
        .get('Gozar\'s Blessing').subs
+
                              'Marble Slab': { skill: 'Stoneworking', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100 }
          .get('Primal Burst III').subs
+
                            }
            .set('Shining Essence Orb', { subs: new Map(), skill:'Spellcraft', minCount: 9, maxCount: 18, minSkill: 930, maxSkill: 1130, type: 'SCalRefinedResource'});
+
                          }
    products.get('Skeleton Key').subs
+
                        }
      .get('Enchanted Adamantium-Mithril Bar').subs
+
                      }, 'Shining Essence Orb': { skill: 'Spellcraft', minCount: 9, maxCount: 18, minSkill: 920, maxSkill: 1120, type: 'SCalRefinedResource', subs:
        .get('Gozar\'s Blessing').subs
+
                        {
          .get('Primal Burst III').subs
+
                          'Shining Essence': { skill: 'Essence Shaping', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100 }
            .get('Shining Essence Orb').subs
+
                        }
              .set('Shining Essence', { skill:'Essence Shaping', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100});
+
                      }
    products.get('Skeleton Key').subs
+
                    }
      .get('Enchanted Adamantium-Mithril Bar').subs
+
                  }, 'Fiery Strike V': { skill: 'Spellcraft', minCount: 1, maxCount: 3, minSkill: 980, maxSkill: 1180, type: 'SCalProduct', subs:
        .get('Gozar\'s Blessing').subs
+
                    {
          .set('Energy Strike V', { subs: new Map(), skill:'Spellcraft', minCount: 1, maxCount: 3, minSkill: 850, maxSkill: 1050, type: 'SCalProduct'});
+
                      'Marble Spell Shard': { skill: 'Spellcraft', minCount: 6, maxCount: 6, minSkill: 800, maxSkill: 1100, type: 'SCalRefinedResource', subs:
    products.get('Skeleton Key').subs
+
                        {
      .get('Enchanted Adamantium-Mithril Bar').subs
+
                          'Marble Brick': { skill: 'Stoneworking', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100, type: 'SCalRefinedResource', subs:
        .get('Gozar\'s Blessing').subs
+
                            {
          .get('Energy Strike V').subs
+
                              'Marble Slab': { skill: 'Stoneworking', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100 }
            .set('Marble Spell Shard', { subs: new Map(), skill:'Spellcraft', minCount: 4, maxCount: 4, minSkill: 850, maxSkill: 1050, type: 'SCalRefinedResource'});
+
                            }
    products.get('Skeleton Key').subs
+
                          }
      .get('Enchanted Adamantium-Mithril Bar').subs
+
                        }
        .get('Gozar\'s Blessing').subs
+
                      }, 'Shining Essence Orb': { skill: 'Spellcraft', minCount: 11, maxCount: 22, minSkill: 980, maxSkill: 1180, type: 'SCalRefinedResource', subs:
          .get('Energy Strike V').subs
+
                        {
            .get('Marble Spell Shard').subs
+
                          'Shining Essence': { skill: 'Essence Shaping', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100 }
               .set('Marble Brick', { subs: new Map(), skill:'Spellcraft', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100, type: 'SCalRefinedResource'});
+
                        }
    products.get('Skeleton Key').subs
+
                      }
      .get('Enchanted Adamantium-Mithril Bar').subs
+
                    }
        .get('Gozar\'s Blessing').subs
+
                  }, 'Gold Papyrus Sheet': { skill: 'Scribing', minCount: 2, maxCount: 5, minSkill: 1100, maxSkill: 1425, type: 'SCalRefinedResource', subs:
          .get('Energy Strike V').subs
+
                    {
            .get('Marble Spell Shard').subs
+
                      'Gold Papyrus Stem': { skill: 'Papermaking', minCount: 2, maxCount: 5, minSkill: 1000, maxSkill: 1325 }
              .get('Marble Brick').subs
+
                    }
                .set('Marble Slab', { skill:'Stoneworking', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100});
+
                  }
    products.get('Skeleton Key').subs
+
                }
      .get('Enchanted Adamantium-Mithril Bar').subs
+
               }, 'Hardened Adamantium-Mithril Bar': { skill: 'Tinkering', minCount: 2, maxCount: 5, minSkill: 1100, maxSkill: 1425, type: 'SCalRefinedResource', subs:
        .get('Gozar\'s Blessing').subs
+
                {
          .get('Energy Strike V').subs
+
                  'Solution of Majorita': { skill: 'Tinkering', minCount: 2, maxCount: 5, minSkill: 1100, maxSkill: 1425, type: 'SCalRefinedResource', subs:
            .set('Shining Essence Orb', { subs: new Map(), skill:'Spellcraft', minCount: 7, maxCount: 14, minSkill: 800, maxSkill: 1100, type: 'SCalRefinedResource'});
+
                    {
    products.get('Skeleton Key').subs
+
                      'Thornwood Bowl': { skill: 'Alchemy', minCount: 1, maxCount: 3, minSkill: 1100, maxSkill: 1425, type: 'SCalRefinedResource', subs:
      .get('Enchanted Adamantium-Mithril Bar').subs
+
                        {
        .get('Gozar\'s Blessing').subs
+
                          'Thornwood Sap': { skill: 'Fletching', minCount: 3, maxCount: 6, minSkill: 1100, maxSkill: 1425 }
          .get('Energy Strike V').subs
+
                          , 'Thornwood Board': { skill: 'Fletching', minCount: 5, maxCount: 10, minSkill: 1100, maxSkill: 1425, type: 'SCalRefinedResource', subs:
            .get('Shining Essence Orb').subs
+
                            {
              .set('Shining Essence', { skill:'Essence Shaping', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100});
+
                              'Thornwood Log': { skill: 'Lumbering', minCount: 2, maxCount: 5, minSkill: 1000, maxSkill: 1325 }
    products.get('Skeleton Key').subs
+
                            }
      .get('Enchanted Adamantium-Mithril Bar').subs
+
                          }
        .get('Gozar\'s Blessing').subs
+
                        }
          .set('Ice Bomb V', { subs: new Map(), skill:'Spellcraft', minCount: 1, maxCount: 3, minSkill: 920, maxSkill: 1120, type: 'SCalProduct'});
+
                      }, 'Crystallized Travertine Brick': { skill: 'Alchemy', minCount: 5, maxCount: 10, minSkill: 1000, maxSkill: 1325, type: 'SCalRefinedResource', subs:
    products.get('Skeleton Key').subs
+
                        {
      .get('Enchanted Adamantium-Mithril Bar').subs
+
                          'Unfocused Violet Azulyte Crystal': { skill: 'Stoneworking', minCount: 1, maxCount: 5, minSkill: 1000, maxSkill: 1325 }
        .get('Gozar\'s Blessing').subs
+
                          , 'Travertine Slab': { skill: 'Stoneworking', minCount: 1, maxCount: 5, minSkill: 1000, maxSkill: 1325 }
          .get('Ice Bomb V').subs
+
                        }
            .set('Marble Spell Shard', { subs: new Map(), skill:'Spellcraft', minCount: 5, maxCount: 5, minSkill: 800, maxSkill: 1100, type: 'SCalRefinedResource'});
+
                      }, 'Purified Radiant Essence Orb': { skill: 'Alchemy', minCount: 1, maxCount: 4, minSkill: 1100, maxSkill: 1425, type: 'SCalRefinedResource', subs:
    products.get('Skeleton Key').subs
+
                        {
      .get('Enchanted Adamantium-Mithril Bar').subs
+
                          'Radiant Essence Orb': { skill: 'Alchemy', minCount: 1, maxCount: 4, minSkill: 1100, maxSkill: 1325, type: 'SCalRefinedResource', subs:
        .get('Gozar\'s Blessing').subs
+
                            {
          .get('Ice Bomb V').subs
+
                              'Radiant Essence': { skill: 'Essence Shaping', minCount: 2, maxCount: 5, minSkill: 1000, maxSkill: 1325 }
            .get('Marble Spell Shard').subs
+
                            }
              .set('Marble Brick', { subs: new Map(), skill:'Stoneworking', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100, type: 'SCalRefinedResource'});
+
                          }
    products.get('Skeleton Key').subs
+
                        }
      .get('Enchanted Adamantium-Mithril Bar').subs
+
                      }, 'Water': { skill: 'Alchemy', minCount: 15, maxCount: 30, minSkill: 1100, maxSkill: 1425 }
        .get('Gozar\'s Blessing').subs
+
                    }
          .get('Ice Bomb V').subs
+
                  }, 'Adamantium-Mithril Bar': { skill: 'Tinkering', minCount: 1, maxCount: 1, minSkill: 1100, maxSkill: 1425, type: 'SCalRefinedResource', subs:
            .get('Marble Spell Shard').subs
+
                    {
              .get('Marble Brick').subs
+
                      'Mithril Ore': { skill: 'Smelting', minCount: 3, maxCount: 6, minSkill: 1100, maxSkill: 1425 }
                .set('Marble Slab', { skill:'Stoneworking', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100});
+
                      , 'Adamantium Ore': { skill: 'Smelting', minCount: 3, maxCount: 6, minSkill: 1100, maxSkill: 1425 }
    products.get('Skeleton Key').subs
+
                    }
       .get('Enchanted Adamantium-Mithril Bar').subs
+
                  }
        .get('Gozar\'s Blessing').subs
+
                }
          .get('Ice Bomb V').subs
+
              }
            .set('Shining Essence Orb', { subs: new Map(), skill:'Spellcraft', minCount: 9, maxCount: 18, minSkill: 920, maxSkill: 1120, type: 'SCalRefinedResource'});
+
            }
    products.get('Skeleton Key').subs
+
          }, 'Skeleton Key Mold': { skill: 'Tinkering', minCount: 1, maxCount: 1, minSkill: 1100, maxSkill: 1425, type: 'SCalProduct', subs:
      .get('Enchanted Adamantium-Mithril Bar').subs
+
            {
        .get('Gozar\'s Blessing').subs
+
              'Skeleton Key Pattern': { skill: 'Earthencraft', minCount: 1, maxCount: 1, minSkill: 1100, maxSkill: 1425 }
          .get('Ice Bomb V').subs
+
              , 'Porcelain Clay Chunk': { skill: 'Earthencraft', minCount: 2, maxCount: 5, minSkill: 1100, maxSkill: 1425 }
            .get('Shining Essence Orb').subs
+
            }
              .set('Shining Essence', { skill:'Essence Shaping', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100});
+
          }
    products.get('Skeleton Key').subs
+
        }
      .get('Enchanted Adamantium-Mithril Bar').subs
+
       }
        .get('Gozar\'s Blessing').subs
+
     };
          .set('Fiery Strike V', { subs: new Map(), skill:'Spellcraft', minCount: 1, maxCount: 3, minSkill: 980, maxSkill: 1180, type: 'SCalProduct'});
 
    products.get('Skeleton Key').subs
 
      .get('Enchanted Adamantium-Mithril Bar').subs
 
        .get('Gozar\'s Blessing').subs
 
          .get('Fiery Strike V').subs
 
            .set('Marble Spell Shard', { subs: new Map(), skill:'Spellcraft', minCount: 6, maxCount: 6, minSkill: 800, maxSkill: 1100, type: 'SCalRefinedResource'});
 
    products.get('Skeleton Key').subs
 
      .get('Enchanted Adamantium-Mithril Bar').subs
 
        .get('Gozar\'s Blessing').subs
 
          .get('Fiery Strike V').subs
 
            .get('Marble Spell Shard').subs
 
              .set('Marble Brick', { subs: new Map(), skill:'Stoneworking', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100, type: 'SCalRefinedResource'});
 
    products.get('Skeleton Key').subs
 
      .get('Enchanted Adamantium-Mithril Bar').subs
 
        .get('Gozar\'s Blessing').subs
 
          .get('Fiery Strike V').subs
 
            .get('Marble Spell Shard').subs
 
              .get('Marble Brick').subs
 
                .set('Marble Slab', { skill:'Stoneworking', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100});
 
    products.get('Skeleton Key').subs
 
      .get('Enchanted Adamantium-Mithril Bar').subs
 
        .get('Gozar\'s Blessing').subs
 
          .get('Fiery Strike V').subs
 
            .set('Shining Essence Orb', { subs: new Map(), skill:'Spellcraft', minCount: 11, maxCount: 22, minSkill: 980, maxSkill: 1180, type: 'SCalRefinedResource'});
 
    products.get('Skeleton Key').subs
 
      .get('Enchanted Adamantium-Mithril Bar').subs
 
        .get('Gozar\'s Blessing').subs
 
          .get('Fiery Strike V').subs
 
            .get('Shining Essence Orb').subs
 
              .set('Shining Essence', { skill:'Essence Shaping', minCount: 2, maxCount: 5, minSkill: 800, maxSkill: 1100});
 
    products.get('Skeleton Key').subs
 
      .get('Enchanted Adamantium-Mithril Bar').subs
 
        .get('Gozar\'s Blessing').subs
 
          .set('Gold Papyrus Sheet', { subs: new Map(), skill:'Scribing', minCount: 2, maxCount: 5, minSkill: 1100, maxSkill: 1425, type: 'SCalRefinedResource'});
 
    products.get('Skeleton Key').subs
 
      .get('Enchanted Adamantium-Mithril Bar').subs
 
        .get('Gozar\'s Blessing').subs
 
          .get('Gold Papyrus Sheet').subs
 
            .set('Gold Papyrus Stem', { skill:'Papermaking', minCount: 2, maxCount: 5, minSkill: 1000, maxSkill: 1325});
 
    products.get('Skeleton Key').subs
 
      .get('Enchanted Adamantium-Mithril Bar').subs
 
        .set('Hardened Adamantium-Mithril Bar', { subs: new Map(), skill:'Tinkering', minCount: 2, maxCount: 5, minSkill: 1100, maxSkill: 1425, type: 'SCalRefinedResource'});
 
    products.get('Skeleton Key').subs
 
      .get('Enchanted Adamantium-Mithril Bar').subs
 
        .get('Hardened Adamantium-Mithril Bar').subs
 
          .set('Solution of Majorita', { subs: new Map(), skill:'Tinkering', minCount: 2, maxCount: 5, minSkill: 1100, maxSkill: 1425, type: 'SCalRefinedResource'});
 
    products.get('Skeleton Key').subs
 
      .get('Enchanted Adamantium-Mithril Bar').subs
 
        .get('Hardened Adamantium-Mithril Bar').subs
 
          .get('Solution of Majorita').subs
 
            .set('Thornwood Bowl', { subs: new Map(), skill:'Alchemy', minCount: 1, maxCount: 3, minSkill: 1100, maxSkill: 1425, type: 'SCalRefinedResource'});
 
    products.get('Skeleton Key').subs
 
      .get('Enchanted Adamantium-Mithril Bar').subs
 
        .get('Hardened Adamantium-Mithril Bar').subs
 
          .get('Solution of Majorita').subs
 
            .get('Thornwood Bowl').subs
 
              .set('Thornwood Sap', { skill:'Fletching', minCount: 3, maxCount: 6, minSkill: 1100, maxSkill: 1425});
 
    products.get('Skeleton Key').subs
 
      .get('Enchanted Adamantium-Mithril Bar').subs
 
        .get('Hardened Adamantium-Mithril Bar').subs
 
          .get('Solution of Majorita').subs
 
            .get('Thornwood Bowl').subs
 
              .set('Thornwood Board', { subs: new Map(), skill:'Fletching', minCount: 5, maxCount: 10, minSkill: 1100, maxSkill: 1425, type: 'SCalRefinedResource'});
 
    products.get('Skeleton Key').subs
 
      .get('Enchanted Adamantium-Mithril Bar').subs
 
        .get('Hardened Adamantium-Mithril Bar').subs
 
          .get('Solution of Majorita').subs
 
            .get('Thornwood Bowl').subs
 
              .get('Thornwood Board').subs
 
                .set('Thornwood Log', { skill:'Lumbering', minCount: 2, maxCount: 5, minSkill: 1000, maxSkill: 1325});
 
    products.get('Skeleton Key').subs
 
      .get('Enchanted Adamantium-Mithril Bar').subs
 
        .get('Hardened Adamantium-Mithril Bar').subs
 
          .get('Solution of Majorita').subs
 
            .set('Crystallized Travertine Brick', { subs: new Map(), skill:'Alchemy', minCount: 5, maxCount: 10, minSkill: 1000, maxSkill: 1325, type: 'SCalRefinedResource'});
 
    products.get('Skeleton Key').subs
 
      .get('Enchanted Adamantium-Mithril Bar').subs
 
        .get('Hardened Adamantium-Mithril Bar').subs
 
          .get('Solution of Majorita').subs
 
            .get('Crystallized Travertine Brick').subs
 
              .set('Unfocused Violet Azulyte Crystal', { skill:'Stoneworking', minCount: 1, maxCount: 5, minSkill: 1000, maxSkill: 1325});
 
    products.get('Skeleton Key').subs
 
      .get('Enchanted Adamantium-Mithril Bar').subs
 
        .get('Hardened Adamantium-Mithril Bar').subs
 
          .get('Solution of Majorita').subs
 
            .get('Crystallized Travertine Brick').subs
 
              .set('Travertine Slab', { skill:'Stoneworking', minCount: 1, maxCount: 5, minSkill: 1000, maxSkill: 1325});
 
    products.get('Skeleton Key').subs
 
      .get('Enchanted Adamantium-Mithril Bar').subs
 
        .get('Hardened Adamantium-Mithril Bar').subs
 
          .get('Solution of Majorita').subs
 
            .set('Purified Radiant Essence Orb', { subs: new Map(), skill:'Alchemy', minCount: 1, maxCount: 4, minSkill: 1100, maxSkill: 1425, type: 'SCalRefinedResource'});
 
    products.get('Skeleton Key').subs
 
      .get('Enchanted Adamantium-Mithril Bar').subs
 
        .get('Hardened Adamantium-Mithril Bar').subs
 
          .get('Solution of Majorita').subs
 
            .get('Purified Radiant Essence Orb').subs
 
              .set('Radiant Essence Orb', { subs: new Map(), skill:'Alchemy', minCount: 1, maxCount: 4, minSkill: 1100, maxSkill: 1325, type: 'SCalRefinedResource'});
 
    products.get('Skeleton Key').subs
 
      .get('Enchanted Adamantium-Mithril Bar').subs
 
        .get('Hardened Adamantium-Mithril Bar').subs
 
          .get('Solution of Majorita').subs
 
            .get('Purified Radiant Essence Orb').subs
 
              .get('Radiant Essence Orb').subs
 
                .set('Radiant Essence', { skill:'Essence Shaping', minCount: 2, maxCount: 5, minSkill: 1000, maxSkill: 1325});
 
    products.get('Skeleton Key').subs
 
      .get('Enchanted Adamantium-Mithril Bar').subs
 
        .get('Hardened Adamantium-Mithril Bar').subs
 
          .get('Solution of Majorita').subs
 
            .set('Water', { skill:'Alchemy', minCount: 15, maxCount: 30, minSkill: 1100, maxSkill: 1425});
 
    products.get('Skeleton Key').subs
 
      .get('Enchanted Adamantium-Mithril Bar').subs
 
        .get('Hardened Adamantium-Mithril Bar').subs
 
          .set('Adamantium-Mithril Bar', { subs: new Map(), skill:'Tinkering', minCount: 1, maxCount: 1, minSkill: 1100, maxSkill: 1425, type: 'SCalRefinedResource'});
 
    products.get('Skeleton Key').subs
 
      .get('Enchanted Adamantium-Mithril Bar').subs
 
        .get('Hardened Adamantium-Mithril Bar').subs
 
          .get('Adamantium-Mithril Bar').subs
 
            .set('Mithril Ore', { skill:'Smelting', minCount: 3, maxCount: 6, minSkill: 1100, maxSkill: 1425});
 
    products.get('Skeleton Key').subs
 
      .get('Enchanted Adamantium-Mithril Bar').subs
 
        .get('Hardened Adamantium-Mithril Bar').subs
 
          .get('Adamantium-Mithril Bar').subs
 
            .set('Adamantium Ore', { skill:'Smelting', minCount: 3, maxCount: 6, minSkill: 1100, maxSkill: 1425});
 
    products.get('Skeleton Key').subs
 
      .set('Skeleton Key Mold', { subs: new Map(), skill:'Tinkering', minCount: 1, maxCount: 1, minSkill: 1100, maxSkill: 1425, type: 'SCalProduct'});
 
    products.get('Skeleton Key').subs
 
      .get('Skeleton Key Mold').subs
 
        .set('Skeleton Key Pattern', { skill:'Earthencraft', minCount: 1, maxCount: 1, minSkill: 1100, maxSkill: 1425});
 
     products.get('Skeleton Key').subs
 
      .get('Skeleton Key Mold').subs
 
        .set('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="' + initialKeyCount + '" size="6"></center>');
+
       $('#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 skills.values()) {
+
           for (var v of Object.values(skills)) {
             $('#SCalSkill' + v + 'Input').val(maxSkillCount);
+
             $('#' + v.id).val(v.maxSkill);
             $('#SCalSkill' + v + 'Input').change();
+
             $('#' + 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);
 +
        }
 
       });
 
       });
 
      printSkillInputs();
 
 
     }
 
     }
  
 
     function printLists() {
 
     function printLists() {
       baseResources = new Map();
+
       // (re-)initialize to be updated lists
       refinedResources = new Map();
+
       baseResources = {};
       requiredMinMaxSkills = new Map();
+
       refinedResources = {};
     
 
      recursiveCalculateNeededSkills(products);
 
 
        
 
        
       if(validateInputs()) { // check if the input fields contain valid entries
+
       recursiveCalculateNeededResources(products, parseInt($('#SCalCountInput').val()));
        $('#SCalResources').html('');
+
      $('#SCalResources').html('');
        $('#SCalResources').append('<h2>Tree of needed products</h2>');
+
      $('#SCalResources').append('<h2>Tree of needed products</h2>');
        products = recursiveCalculateNeedEffectives(products, parseInt($('#SCalCountInput').val()));
+
      var html = recursivePrintTreeProduct(products);
        var html = recursivePrintTreeProduct(products);
+
      $('#SCalResources').append(html);
        $('#SCalResources').append(html);
 
 
 
 
 
        printBaseResources();
 
        printRefinedResources();
 
        printNeededSkills();
 
 
 
        mw.loader.using('jquery.tablesorter', function() {
 
          $('table.sortable').tablesorter({ sortList: [{ 0: 'asc' }] })
 
        });
 
      }
 
    }
 
 
 
    function recursiveCalculateNeededSkills(product) {
 
      for (var value of product.values()) {
 
        var newSkills = [];
 
        var skillName = value.skill;
 
       
 
        newSkills[0] = value.minSkill;
 
        newSkills[1] = value.maxSkill;
 
       
 
        if(requiredMinMaxSkills.has(skillName)) {
 
          if(requiredMinMaxSkills.get(skillName)[0] < newSkills[0]) {
 
            newSkills[0] = requiredMinMaxSkills.get(skillName)[0];
 
          }
 
         
 
          if(requiredMinMaxSkills.get(skillName)[1] > newSkills[1]) {
 
            newSkills[1] = requiredMinMaxSkills.get(skillName)[1]
 
          }
 
        }
 
  
        requiredMinMaxSkills.set(skillName, newSkills);       
+
      printBaseResources();
 +
      printRefinedResources();
 +
       printNeededSkills();
  
        if(value.subs instanceof Map) {
+
      mw.loader.using('jquery.tablesorter', function() {
          recursiveCalculateNeededSkills(value.subs);
+
        $('table.sortable').tablesorter({ sortList: [{ 0: 'asc' }] })
        }
+
       });
       }
 
 
     }
 
     }
  
 
     function printNeededSkills() {
 
     function printNeededSkills() {
      requiredMinMaxSkills = new Map([...requiredMinMaxSkills.entries()].sort());
 
 
 
       $('#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>';
  
       requiredMinMaxSkills.forEach(function(value, key) {
+
       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[0] + '</td>'
+
           + '<td>' + value.minSkill + '</td>'
           + '<td>' + value[1] + '</td>'
+
           + '<td>' + value.maxSkill + '</td>'
 
           + '</tr>';
 
           + '</tr>';
       });
+
       }
  
 
       tablecontent += '</tbody>';
 
       tablecontent += '</tbody>';
Line 422: Line 269:
 
      
 
      
 
     function printSkillInputs() {
 
     function printSkillInputs() {
      recursiveDetermineSkills(products);
+
       for (var [key, value] of Object.entries(skills)) {
       for (var [key, value] of skills.entries()) {
+
         var id = value.id;
         var id = 'SCalSkill' + value;
+
         var skill = getCookie(id);
         var skill = getCookie(id + 'Input');
+
         if(!isRealInteger(skill)) { // default to max value if cookie not correctly set
 
+
           skill = value.maxSkill;
         if(!isRealInteger(skill)) {
 
           skill = maxSkillCount;
 
 
         }  
 
         }  
  
         $('#SCalSkills').append('<input type="number" id="' + id + 'Input" name="' + id + '" size="6"><label for="' + id + '">&nbsp;&nbsp;' + key + '</label><br />');
+
         $('#SCalSkills').append('<input type="number" id="' + id + '" name="' + id + '" size="6"><label for="' + id + '">&nbsp;&nbsp;' + key + '</label><br />');
         $('#' + id + 'Input').keypress(function(event) {
+
       
           if (event.key === 'Enter') {
+
         $('#' + id).keypress(function(event) {
 +
           if (event.key === 'Enter' && validateInputs()) {
 
             printLists();
 
             printLists();
             setCookie(id, skill, new Date(3030,1,4));
+
             checkIntegerAndSetCookieById(event.target.id);
 
           }
 
           }
 
         });
 
         });
         $('#' + id + 'Input').change(function(event) {
+
       
           printLists();
+
         $('#' + id).change(function(event) {
          setCookie(event.target.id, $('#' + event.target.id).val(), new Date(3030,1,4));
+
           if(validateInputs()) {
 +
            printLists();
 +
            checkIntegerAndSetCookieById(event.target.id);
 +
          }
 
         });
 
         });
         $('#SCalSkill' + value + 'Input').val(skill);
+
       
 +
         $('#' + id).val(skill);
 
       }
 
       }
 
     }
 
     }
  
     function recursiveDetermineSkills(product) {
+
    // Tests if the provided input field has a valid integer and sets a cookie for it
       product.forEach((obj) => {
+
    function checkIntegerAndSetCookieById(id) {
         if(typeof obj.skill != 'undefined') {
+
      hashedId = '#' + id;
           skills.set(obj.skill, obj.skill.replace(/\s/, ''));
+
      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(obj.subs instanceof Map) {
+
        // set the id
           recursiveDetermineSkills(obj.subs);
+
        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 = '';
       product.forEach((obj, value) => {
+
       for(var [key, value] of Object.entries(product)) {
 
         html += '<ul>';
 
         html += '<ul>';
 
         html += '<li>';
 
         html += '<li>';
         html += '<span class="' + obj.type + '"><a href="' + mw.util.getUrl(value) + '">' + value + '</a>: ' + obj.neededCount + '</span>';
+
         html += '<span class="' + value.type + '"><a href="' + mw.util.getUrl(key) + '">' + key + '</a>: ' + value.needed + '</span>';
         if(obj.subs instanceof Map) {
+
         if(value.hasOwnProperty('subs')) {
           html += recursivePrintTreeProduct(obj.subs);
+
           html += recursivePrintTreeProduct(value.subs);
 
         }
 
         }
 
         html += '</ul>';
 
         html += '</ul>';
 
         html += '</li>'
 
         html += '</li>'
       });
+
       }
 
       return html;
 
       return html;
 
     }
 
     }
  
     function recursiveCalculateNeedEffectives(product, previousCount) {
+
    // Adds needed resources to the dataset and counts up the base and refined resources
       product.forEach((value,key) => {
+
     function recursiveCalculateNeededResources(products, previousCount) {
         var currentSkill;
+
       for(var [key, values] of Object.entries(products)) {
        if(typeof value.skill != 'undefined') { // if we found a skill, use the value of the input field
+
         var currentSkill = $('#' + skills[values.skill].id).val();
          currentSkill = $('#SCalSkill' + skills.get(value.skill) + 'Input').val();
+
          
         } else {
+
         var percent = (currentSkill - values.minSkill) / (values.maxSkill - values.minSkill);
          currentSkill = maxSkillCount;
+
         var needEffective = values.maxCount - ((values.maxCount - values.minCount) * percent);
        }
 
         var percent = (currentSkill - value.minSkill) / (value.maxSkill - value.minSkill);
 
         var needEffective = value.maxCount - ((value.maxCount - value.minCount) * percent);
 
 
         needEffective = Math.ceil(needEffective);
 
         needEffective = Math.ceil(needEffective);
 
    
 
    
         if (needEffective < value.minCount) needEffective = value.minCount;
+
         if (needEffective < values.minCount) needEffective = values.minCount;
         if (needEffective > value.maxCount) needEffective = value.maxCount;
+
         if (needEffective > values.maxCount) needEffective = values.maxCount;
 
          
 
          
         value.neededCount = needEffective * previousCount;
+
         needEffective *= previousCount;
  
         if(!(value.subs instanceof Map)) { // we assume that a product without subs is a base resource
+
         // Process base resources
           if(baseResources.has(key)) {
+
        // we assume that a product without subs is a base resource
             baseResources.set(key, value.neededCount + baseResources.get(key));
+
        if(!values.hasOwnProperty('subs')) {
 +
           if(baseResources.hasOwnProperty(key)) {
 +
             baseResources[key] = needEffective + baseResources[key];
 
           } else {
 
           } else {
             baseResources.set(key, value.neededCount);
+
             baseResources[key] = needEffective;
 
           }
 
           }
 
         }
 
         }
  
         if(value.type == 'SCalRefinedResource') {  
+
        // Process refined resources
           if(refinedResources.has(key)) {
+
         if(values.type == 'SCalRefinedResource') {  
             refinedResources.set(key, value.neededCount + refinedResources.get(key));
+
           if(refinedResources.hasOwnProperty(key)) {
 +
             refinedResources[key] = needEffective + refinedResources[key];
 
           } else {
 
           } else {
             refinedResources.set(key, value.neededCount);
+
             refinedResources[key] = needEffective;
 
           }
 
           }
 
         }
 
         }
 +
       
 +
        values.needed = needEffective;
 +
        products[key] = values;
  
         if(value.subs instanceof Map) {
+
         if(values.hasOwnProperty('subs')) {
           recursiveCalculateNeedEffectives(value.subs, value.neededCount);
+
           values.subs = recursiveCalculateNeededResources(values.subs, needEffective);
 
         }
 
         }
       });
+
       }
 
+
       return products;
       return product;
 
 
     }
 
     }
  
 
     function printRefinedResources() {
 
     function printRefinedResources() {
      refinedResources = new Map([...refinedResources.entries()].sort());
 
 
 
       $('#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.forEach(function(value, key) {
+
       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() {
      baseResources = new Map([...baseResources.entries()].sort());
 
 
 
       $('#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.forEach(function(value, key) {
+
       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, id] of skills) {
+
       for (var [skill, values] of Object.entries(skills)) {
         var inputObj = $('#SCalSkill' + id + 'Input');
+
         var inputObj = $('#' + values.id);
        var currentSkills = requiredMinMaxSkills.get(skill);
 
 
          
 
          
 
         inputObj.removeClass('SCalErroreousInput');
 
         inputObj.removeClass('SCalErroreousInput');
Line 611: Line 485:
 
           }
 
           }
 
            
 
            
           if(number < currentSkills[0]) {
+
           if(number < values.minSkill) {
             $('#SCalErrorText').append('<center>Skill ' + skill + ' is too low (have:' + number + ', need: ' + currentSkills[0] + ')</center>');
+
             $('#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 >= currentSkills[1]) inputObj.addClass('SCalOptimalInput');
+
             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 + '">&nbsp;&nbsp;' + 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;
    }
  }
});