shjeepergmail.com / WFTargettingScore

// ==UserScript==
// @name           WFTargettingScore
// @namespace      sk.seko
// @description    Computes targetting score for ship design.
// @include        http://*.war-facts.com/ship_designs.php*
// @grant          none
// @version        2.6
// ==/UserScript==

// Version 1.0 = grab params from displayed design, calculate targeting score and display it
// Version 2.0 = added support for "dynamic" display, i.e. during design creation
// Version 2.1 = fixed sliders and input fields for armor/shields
// Version 2.2 = fixed keyboard input
// Version 2.3 = fixed float vs. int speed issue, and fixed score display during ship design
// Version 2.4 = fixed formula for H5 (it has been changed, apparently!)
// Version 2.5 = fixed html/css changes in H6
// Version Screwup = Quick hack to work with new design - prosoft

// ----------------------------------------------------------------------------------------
// Note for v2.4:
// TS value calculated (and displayed) on View ship class screen is not accurate, i.e. real
// TS is probably lower. This is because formula is using 'Hull mass', not 'Total mass' and
// there is no way to find you what hull mass exactly is. This is only possible on Ship
// design screen, for wich TS displayed should be correct. Sorry for inconveniece!
//                      - Seko
// ----------------------------------------------------------------------------------------


function eval(s) {
  if (s) {return Math.round(parseFloat(s.replace(/[,]/g,'')));}
  return 0;
}

function evalNode(node) {
  if (node) {return eval(node.data.split(" ")[0]);}
  return 0.0;
}

// returns number formatted with commas, like 1234567 => "1,234,567"
function addCommas(nStr) {
    var x = nStr.split('.');
    var x1 = x[0];
    var x2 = x.length > 1 ? '.' + x[1] : '';
    var rgx = /(\d+)(\d{3})/;
    while (rgx.test(x1)) {
      x1 = x1.replace(rgx, '$1' + ',' + '$2');
    }
    return x1 + x2;
}

// calculate targeting score and return it as formatted string
function calculateAndFormatTS(firepower, base_armor, base_shield, hull_mass, speed) {
  // =====================================================================================
  // THIS is formula for targetting score (TS); it can change in the future instances :-(
  // =====================================================================================
  var ts = firepower * ((base_armor + base_shield + hull_mass - speed) / 2);
  //alert('fire=' + firepower + ', armor=' + base_armor + ', shield=' + base_shield + ', mass=' + hull_mass + ', speed=' + speed + ', ts=' + ts);
  return addCommas(String(ts));
}

/* I don't care about incorrect targetting scores, it just makes people compare the wrong shit.
// grab params and compute targeting score for existing design
window.grabAndCalculateStatic = function() {
  // GET SHIP DESIGN ATTRIBUTES
  var speed = evalNode(document.evaluate("//td[(child::text() = 'Cruise Speed:')]/following-sibling::node()/child::text()",
    document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue);
  var fireIter = document.evaluate("//td[(child::text() = 'Full Strike:')]/following-sibling::node()/child::text()",
    document, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
  var fire = 0.0;
  var fireVal = fireIter.iterateNext();
  while (fireVal) {
    if (fireVal.nodeValue && fireVal.nodeValue.replace(/\s/,'') != '') {
      fire += evalNode(fireVal);
    }
    fireVal = fireIter.iterateNext();
  }
  var shield = evalNode(document.evaluate("//td[(child::text() = 'Shield:')]/following-sibling::node()/child::text()",
    document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue);
  var armor = evalNode(document.evaluate("//td[(child::text() = 'Armor:')]/following-sibling::node()/child::text()",
    document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue);
  var mass = evalNode(document.evaluate("//td[(child::text() = 'Mass:')]/following-sibling::node()/child::text()",
    document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue);
  // CALCULATE TARGETING SCORE
  return calculateAndFormatTS(fire, armor, shield, mass, speed);
}
*/

// compute targeting score for ship being designed
window.grabAndCalculateDynamic = function() {
  // GET SHIP DESIGN ATTRIBUTES
  var speed = evalNode(document.evaluate("//span[@id='drivespeed']/child::text()",
    document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue);
  var firegun = evalNode(document.evaluate("//span[@id='vgunAstrike']/child::text()",
    document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue);
  var firecannon = evalNode(document.evaluate("//span[@id='vcannonAstrike']/child::text()",
    document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue);
  var shield = evalNode(document.evaluate("//span[@id='veffshield']/child::text()",
    document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue);
  var armor = evalNode(document.evaluate("//span[@id='veffarmor']/child::text()",
    document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue);
  var mass = eval(document.evaluate("//div[text()[contains(.,'Hull Mass')]]",
    document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue.innerHTML.split(" ")[2]);
  // CALCULATE TARGETING SCORE
  var fire = (firecannon ? firecannon : 0.0) + (firegun ? firegun : 0.0);
  document.getElementById("massused").innerHTML = mass;
  document.getElementById("speedused").innerHTML = speed;
  document.getElementById("fireused").innerHTML = fire;
  document.getElementById("armorused").innerHTML = armor;
  document.getElementById("shieldused").innerHTML = shield;
  return calculateAndFormatTS(fire, armor, shield, mass, speed);
}

// compute and display targeting score for ship being designed
window.processDynamic = function() {
  var ts = grabAndCalculateDynamic();
  document.getElementById("targetingscore").innerHTML = ts
}

function insertAfter(newNode, referenceNode) {
    referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
}


/*
// displays targeting score as a table row
window.displayTS = function(tablerow, ts) {
    var ncol1 = document.createElement('td');
    ncol1.setAttribute("class","strong");
    ncol1.appendChild(document.createTextNode('Targeting Score:'));
    var ncol2 = document.createElement('td');
    ncol2.setAttribute("colspan", "3");
    var scoreElem = document.createTextNode(ts);
    ncol2.appendChild(scoreElem);
    var nrow = document.createElement('tr');
    nrow.appendChild(ncol1);
    nrow.appendChild(ncol2);
    tablerow.parentNode.insertBefore(nrow, tablerow);
    return scoreElem;
}



// compute and display targeting score for existing design
window.processStatic = function() {
  // check if this is design is displayed
  //var tablerow = document.evaluate("//center/table/tbody/tr[2]",
  var check = document.evaluate("//input[@value='Delete Design']",
    document, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null).iterateNext();
  if (!check) {
    return; // design is not displayed, just quit
  }
  var tablerow = document.evaluate("//center/table/tbody/tr[2]",
    document, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null).iterateNext();
  if (!tablerow) {
    return; // something wrong, just quit
  }
  // calculate targeting score
  var ts = grabAndCalculateStatic();
  // DISPLAY TARGETING SCORE
  displayTS(tablerow, 'less than ' + ts);
}

// adds 'processDynamic' callback to all elements matching elements event
window.registerDynamicElements = function(xpath, attr) {
  var it = document.evaluate(xpath, document, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
  if (it) {
    var b = it.iterateNext();
    var elems = [];
    while (b) {
      elems.push(b);
      b = it.iterateNext();
    }
    for (x in elems) {
      elems[x].setAttribute(attr,elems[x].getAttribute(attr) + ";setTimeout(\"processDynamic()\", 100);");
    }
  }
}

*/
// compute and display targeting score for existing design
window.initializeScript = function() {
    var massdiv = document.createElement("div");
    massdiv.className = "padding5 light tbborder";
    massdiv.innerHTML = 'Mass Used: <span id="massused"></span>';
    
    var speeddiv = document.createElement("div");
    speeddiv.className = "padding5 light tbborder";
    speeddiv.innerHTML = 'Speed Used: <span id="speedused"></span>';
    
    var firediv = document.createElement("div");
    firediv.className = "padding5 light tbborder";
    firediv.innerHTML = 'Fire Used: <span id="fireused"></span>';
    
    var shielddiv = document.createElement("div");
    shielddiv.className = "padding5 light tbborder";
    shielddiv.innerHTML = 'Shield Used: <span id="shieldused"></span>';
    
    var armordiv = document.createElement("div");
    armordiv.className = "padding5 light tbborder";
    armordiv.innerHTML = 'Armor Used: <span id="armorused"></span>';

    insertAfter(shielddiv, document.getElementById("targetingscore").parentNode);
    insertAfter(armordiv, document.getElementById("targetingscore").parentNode);
    insertAfter(firediv, document.getElementById("targetingscore").parentNode);
    insertAfter(speeddiv, document.getElementById("targetingscore").parentNode);
    insertAfter(massdiv, document.getElementById("targetingscore").parentNode);
}

document.onclick = function(){
    if(evalNode(document.evaluate("//span[@id='drivespeed']/child::text()",
                                  document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue) != 0) {
        processDynamic();
    }
}

//document.getElementById("targetingscore").insertAdjacentHTML( 'beforeBegin', '<input type="button" value="Update Score" onclick="processDynamic();">' );
if( document.location.href.indexOf('designid') == -1 ) {
    initializeScript();
}
//window.addEventListener("load", initializeScript, false);