MediaWiki:Common.js: Difference between revisions

No edit summary
Automated page publish
Line 28: Line 28:
   };
   };
   Object.keys(GATHER).forEach(function(k){ GATHER[k].sort(function(a,b){ return a.xp-b.xp; }); });
   Object.keys(GATHER).forEach(function(k){ GATHER[k].sort(function(a,b){ return a.xp-b.xp; }); });
  // Smithing crafting tree, sourced from the game's own recipe data (not fan-site numbers).
  // Each entry: item name -> array of {name, count} ingredients needed to craft ONE of that item.
  // Items with no entry here are raw/gathered materials (chain terminates).
  var RECIPES = {
    'Iron Rod': [{name:'Iron Bar', count:1}],
    'Large Mithril Rod': [{name:'Mithril Rod', count:2}],
    'Mithril Rod': [{name:'Mithril Bar', count:2}],
    'Steel Rod': [{name:'Steel Bar', count:1}],
    'Iron Plate': [{name:'Iron Bar', count:2}],
    'Large Steel Rod': [{name:'Steel Rod', count:2}],
    'Silver Plate': [{name:'Silver Bar', count:7}],
    'Silver Foil': [{name:'Silver Plate', count:1}],
    'Gold Plate': [{name:'Gold Bar', count:8}],
    'Steel Plate': [{name:'Steel Bar', count:2}],
    'Large Steel Plate': [{name:'Steel Plate', count:2}],
    'Large Mithril Plate': [{name:'Mithril Plate', count:4}],
    'Mithril Plate': [{name:'Mithril Bar', count:4}],
    'Golden Shield Frame': [{name:'Gold Plate', count:5},{name:'Gold Bar', count:3},{name:'Steel Rod', count:2},{name:'Steel Bar', count:2}],
    'Small Ebony Rod': [{name:'Ebony Bar', count:2}],
    'Large Ebony Rod': [{name:'Ebony Rod', count:4},{name:'Ebony Bar', count:3}],
    'Ebony Rod': [{name:'Small Ebony Rod', count:4},{name:'Ebony Bar', count:3}],
    'Small Ebony Plate': [{name:'Ebony Bar', count:4}],
    'Ebony Plate': [{name:'Small Ebony Plate', count:4},{name:'Ebony Bar', count:3}],
    'Large Ebony Plate': [{name:'Ebony Plate', count:4},{name:'Ebony Bar', count:3}],
    'Duskknight Boot Left Sabaton': [{name:'Ebony Plate', count:1},{name:'Silver Foil', count:2}],
    'Duskknight Boot Right Sabaton': [{name:'Ebony Plate', count:1},{name:'Silver Foil', count:2}],
    'Duskknight Leg Tuille': [{name:'Ebony Plate', count:1},{name:'Silver Foil', count:1}],
    'Duskknight Leg Poleyn': [{name:'Ebony Plate', count:1},{name:'Silver Foil', count:1}],
    'Duskknight Body Pauldron': [{name:'Ebony Plate', count:1},{name:'Silver Foil', count:1}],
    'Duskknight Body Couter': [{name:'Ebony Plate', count:1},{name:'Silver Foil', count:1}],
    'Duskknight Body Rerebrace': [{name:'Ebony Plate', count:2},{name:'Silver Foil', count:2}],
    'Duskknight Body Vambrace': [{name:'Ebony Plate', count:2},{name:'Silver Foil', count:2}],
    'Duskknight Leg Tasset': [{name:'Ebony Plate', count:3},{name:'Silver Foil', count:3}],
    'Duskknight Boot Greave': [{name:'Large Ebony Plate', count:1},{name:'Silver Foil', count:2}],
    'Duskknight Leg Cuisses': [{name:'Large Ebony Plate', count:2},{name:'Silver Foil', count:2}],
    'Duskknight Helmet Face Plate': [{name:'Large Ebony Plate', count:1},{name:'Silver Foil', count:2}],
    'Duskknight Helmet Head Plate': [{name:'Large Ebony Plate', count:1},{name:'Silver Foil', count:2}],
    'Duskknight Helmet Spike': [{name:'Large Ebony Rod', count:1},{name:'Silver Foil', count:1}],
    'Duskknight Body Breastplate': [{name:'Large Ebony Plate', count:4},{name:'Silver Foil', count:8}],
    'Iron Bar': [{name:'Iron Ore', count:2}],
    'Steel Bar': [{name:'Iron Ore', count:1},{name:'Coal Ore', count:1}],
    'Mithril Bar': [{name:'Mithril Ore', count:1},{name:'Coal Ore', count:2}],
    'Gold Bar': [{name:'Gold Ore', count:8}],
    'Silver Bar': [{name:'Silver Ore', count:7}],
    'Ebony Bar': [{name:'Ebony Ore', count:7}]
  };
  // Walks RECIPES tier-by-tier from `qty` of `name`, merging same-name items within a tier.
  // Returns {tierLines: [string,...], totals: {rawItemName: qty,...}} or null if `name` has no recipe.
  function buildMaterialBreakdown(name, qty){
    if (!RECIPES[name]) return null;
    var tierLines = [];
    var totals = {};
    var currentTier = [{name:name, qty:qty}];
    tierLines.push(currentTier.map(function(e){ return fmt(e.qty) + ' ' + e.name; }).join(' & '));
    while (true){
      var nextMap = {};
      var expandedAny = false;
      currentTier.forEach(function(e){
        var recipe = RECIPES[e.name];
        if (!recipe){ totals[e.name] = (totals[e.name] || 0) + e.qty; return; }
        expandedAny = true;
        recipe.forEach(function(ing){ nextMap[ing.name] = (nextMap[ing.name] || 0) + e.qty * ing.count; });
      });
      if (!expandedAny) break;
      var nextTier = Object.keys(nextMap).map(function(n){ return {name:n, qty:nextMap[n]}; });
      tierLines.push(nextTier.map(function(e){ return fmt(e.qty) + ' ' + e.name; }).join(' & '));
      currentTier = nextTier;
    }
    return { tierLines: tierLines, totals: totals };
  }


   var MONSTERS = [
   var MONSTERS = [
Line 111: Line 183:
         '<div class="vl-xp-pair"><div class="vl-xp-box"><label>Current XP</label><div class="vl-num" id="vl-cur-xp">0</div></div><div class="vl-xp-box"><label>Target XP</label><div class="vl-num" id="vl-tgt-xp">0</div></div></div>' +
         '<div class="vl-xp-pair"><div class="vl-xp-box"><label>Current XP</label><div class="vl-num" id="vl-cur-xp">0</div></div><div class="vl-xp-box"><label>Target XP</label><div class="vl-num" id="vl-tgt-xp">0</div></div></div>' +
         '<div class="vl-result"><p class="vl-result-head">Reckoning</p><p class="vl-result-text" id="vl-gather-result">Pick a skill and an action to begin.</p><div class="vl-bar-track"><div class="vl-bar-fill" id="vl-gather-fill"></div></div></div>' +
         '<div class="vl-result"><p class="vl-result-head">Reckoning</p><p class="vl-result-text" id="vl-gather-result">Pick a skill and an action to begin.</p><div class="vl-bar-track"><div class="vl-bar-fill" id="vl-gather-fill"></div></div></div>' +
        '<div class="vl-result" id="vl-breakdown-section" style="display:none;"><p class="vl-result-head">Material Breakdown</p><p class="vl-result-text" id="vl-breakdown-text"></p></div>' +
       '</div>' +
       '</div>' +
       '<div id="vl-combat-view" style="display:none;">' +
       '<div id="vl-combat-view" style="display:none;">' +
Line 203: Line 276:
   var gatherResult = mount.querySelector('#vl-gather-result');
   var gatherResult = mount.querySelector('#vl-gather-result');
   var gatherFill = mount.querySelector('#vl-gather-fill');
   var gatherFill = mount.querySelector('#vl-gather-fill');
  var breakdownSection = mount.querySelector('#vl-breakdown-section');
  var breakdownText = mount.querySelector('#vl-breakdown-text');


   function populateActions(){
   function populateActions(){
Line 238: Line 313:
       gatherResult.textContent = 'Level ' + tgtLevel + ' calls for ' + fmt(tgtXp) + ' xp. You already have that at level ' + curLevel + ' (' + fmt(curXp) + ' xp). Nothing left to gather.';
       gatherResult.textContent = 'Level ' + tgtLevel + ' calls for ' + fmt(tgtXp) + ' xp. You already have that at level ' + curLevel + ' (' + fmt(curXp) + ' xp). Nothing left to gather.';
       gatherFill.style.width = '100%';
       gatherFill.style.width = '100%';
      breakdownSection.style.display = 'none';
       return;
       return;
     }
     }
Line 245: Line 321:
     gatherResult.textContent = 'Level ' + curLevel + ' -> Level ' + tgtLevel + '\nNeed ' + fmt(needed) + ' more xp\n= ' + fmt(actions) + ' x ' + entry.name;
     gatherResult.textContent = 'Level ' + curLevel + ' -> Level ' + tgtLevel + '\nNeed ' + fmt(needed) + ' more xp\n= ' + fmt(actions) + ' x ' + entry.name;
     gatherFill.style.width = '0%';
     gatherFill.style.width = '0%';
    var breakdown = state.tab === 'smithing' ? buildMaterialBreakdown(entry.name, actions) : null;
    if (!breakdown){
      breakdownSection.style.display = 'none';
    } else {
      breakdownSection.style.display = 'block';
      var text = breakdown.tierLines.join('\n-> ');
      var rawNames = Object.keys(breakdown.totals);
      if (rawNames.length){
        text += '\n\nTotal raw materials: ' + rawNames.map(function(n){ return fmt(breakdown.totals[n]) + ' ' + n; }).join(', ');
      }
      breakdownText.textContent = text;
    }
   }
   }