// ==UserScript==
// @name Sensor Net Manager
// @namespace github.com/odahviing/warfacts
// @version 0.5
// @description Next Generation Sensor Net
// @author Odahviing
// @match http://www.war-facts.com/sensorArray.php
// @grant GM_getValue
// @grant GM_setValue
// ==/UserScript==
// TODO:
// -- Add Bookmark all option
// -- Add Raw muiltiple fleets name + send
(function() {
'use strict';
loadData();
})();
// Loading Functions
function loadData() {
buildPage(0);
let currentList = GM_getValue('sensor-list');
if (!currentList) return;
let allNetworks = currentList.split('&');
for (let i = 0; i < allNetworks.length; i++) {
let currentNetwork = readString(GM_getValue(allNetworks[i]));
buildPage(i+1, currentNetwork.Name, currentNetwork.Scanner, currentNetwork.Cords, currentNetwork.Range);
}
document.getElementsByClassName('padding5 dark shadow')[0].outerHTML = `<div id='data-holder'></div>` + document.getElementsByClassName('padding5 dark shadow')[0].outerHTML;
}
function buildPage(id, name = "", sensor = "", cords = "", range = "") {
var afterTitle = document.getElementsByTagName('h1')[0];
afterTitle.outerHTML = afterTitle.outerHTML + htmlIframe(id, name, sensor, cords, range);
document.getElementById(`buttonUpdate${id}`).addEventListener("click", update);
document.getElementById(`buttonView${id}`).addEventListener("click", view);
document.getElementById(`buttonDelete${id}`).addEventListener("click", del);
}
// End Loading Functions
// User Action Functions
function readInputs(_this) {
var objTable = _this.parentElement.parentElement.parentElement;
var allInputs = objTable.getElementsByTagName('input');
var networkName = allInputs[0].value;
var scannerLevel = allInputs[1].value;
var coreCords = Cords(allInputs[2].value, allInputs[3].value, allInputs[4].value);
var range = Range(allInputs[5].value,allInputs[6].value,allInputs[7].value,allInputs[8].value);
var networkData = Network(networkName, scannerLevel, coreCords, range);
return networkData;
}
function update(){
var networkData = readInputs(this);
if (networkData.Name == "") return;
saveNode(networkData);
alert('Added / Updated');
}
function del() {
var networkData = readInputs(this);
removeMainList(networkData.Name);
this.parentElement.parentElement.parentElement.parentElement.remove();
}
function view(){
var networkData = readInputs(this);
var allPoints = getAllCords(networkData.Cords, networkData.Scanner, networkData.Range);
let newData = "";
for (let i = 0; i < allPoints.length; i++) {
newData = newData + newRaw(i+1, allPoints[i]);
}
document.getElementById('data-holder').innerHTML = addHeader() + newData;
document.getElementById('verify-all').addEventListener("click", verifyAll);
for (let i = 1; i <= allPoints.length; i++) {
document.getElementById(`sendButton${i}`).addEventListener("click", sendFleet);
document.getElementById(`bookmark${i}`).addEventListener("click", bookmarkFleet);
}
}
function verifyAll() {
var allActive = [];
getFleetList().then(function(fleetList) {
var allListening = document.getElementsByClassName('padding5 dark shadow')[0].getElementsByTagName('tr');
for (let i = 1; i < allListening.length; i++) {
let aHold = allListening[i].getElementsByTagName('a')[0];
if (aHold) {
let href = aHold.href;
allActive.push(href.substring(href.indexOf('?') + 7));
}
}
var allLines = document.getElementById('data-holder').getElementsByTagName('tbody')[0].getElementsByTagName('tr');
for (let i = 0; i < allLines.length; i++) {
var allTds = allLines[i].getElementsByTagName('td');
let lineCord = allTds[1].innerHTML.split(', ');
let theCords = Cords(lineCord[0],lineCord[1],lineCord[2]);
let exists = fleetList.findIndex(x => isEqual(x.Cords, theCords));
if (exists == -1) {
allTds[4].innerHTML = 'Missing';
allTds[4].style.color = "red"
}
else {
allTds[4].innerHTML = allActive.findIndex(fleetList[exists].Id) >= 0 ? 'Listening' : 'In-Place';
allTds[5].value = fleetList[exists].Id;
}
}
});
}
function getFleetList() {
var fleetLists = [];
return new Promise(function (fulfill, reject){
divAjaxRequest("GET", 'http://www.war-facts.com/overview.php?view=2', true, true, null).then(function(newDiv) {
let fleetTable = newDiv.getElementsByTagName('table')[0];
let allRows = newDiv.getElementsByTagName('tr');
for (let i = 1 ; i < allRows.length; i++) {
if (allRows[i].innerHTML.indexOf('Single Vessels') >= 0) break;
var allAs = allRows[i].getElementsByTagName('a');
let fleetId = allAs[0].href.substring(allAs[0].href.indexOf('?') + 7);
let cordsObj = allAs[1].innerHTML.split('');
fleetLists.push(Fleet(fleetId, Cords(cordsObj[0],cordsObj[1],cordsObj[2]), false));
}
return fulfill(fleetLists);
});
});
}
function sendFleet() {
var row = this.parentElement.parentElement;
var allColumns = row.getElementsByTagName('td');
let value = allColumns[5].getElementsByTagName('input')[0].value;
if (value == "") return;
let lineCord = allColumns[2].innerHTML.split(', ');
let theCords = Cords(lineCord[0],lineCord[1],lineCord[2]);
window.open(`http://www.war-facts.com/fleet.php?tpos=global&x=${lineCord[0]}&y=${lineCord[1]}&z=${lineCord[2]}&fleet=${value}`, '_blank');
return;
}
function bookmarkFleet() {
var row = this.parentElement.parentElement;
var allColumns = row.getElementsByTagName('td');
let value = allColumns[1].getElementsByTagName('input')[0].value;
if (value == "") return;
let lineCord = allColumns[2].innerHTML.split(', ');
let theCords = Cords(lineCord[0],lineCord[1],lineCord[2]);
window.open(`http://www.war-facts.com/empire_rally_points.php?x=${lineCord[0]}&y=${lineCord[1]}&z=${lineCord[2]}&rallyname=${value}`, '_blank');
return;
}
// End User Action Functions
// Sensors Grid Functions - Logic
function getAllCords(cords, level, fuel) {
let scanPoints = sTc(level);
let scanRange = cTr(scanPoints);
let westCount = Math.ceil(fuel.West / (scanRange * 2), 1);
let northCount = Math.ceil(fuel.North / (scanRange * 2), 1);
let eastCount = Math.ceil(fuel.East / (scanRange * 2), 1);
let southCount = Math.ceil(fuel.South / (scanRange * 2), 1);
var allCords = [];
allCords = allCords.concat(mainCords(cords, scanPoints));
allCords = allCords.concat(generateRows(clone(cords), -2 * scanPoints, 0, westCount, fuel.West, scanPoints));
allCords = allCords.concat(generateRows(clone(cords), 0, 2 * scanPoints, northCount, fuel.North, scanPoints));
allCords = allCords.concat(generateRows(clone(cords), 2 * scanPoints, 0, eastCount, fuel.East, scanPoints));
allCords = allCords.concat(generateRows(clone(cords), 0, -2 * scanPoints, southCount, fuel.South, scanPoints));
const uniqueCords = [];
const map = new Map();
for (const cord of allCords) {
let sign = cord.Cords.X+""+cord.Cords.Y+""+cord.Cords.Z;
if(!map.has(sign)){
map.set(sign, true); // set any value to Map
uniqueCords.push(cord);
}
}
return uniqueCords;
}
function generateRows(cords, x, y, count, topRange, scanPoints) {
let allCords = [];
for (let i = 1; i < count; i++) {
allCords = allCords.concat(
buildRow(add(clone(cords), x * i, y * i, 0), scanPoints, topRange, cords));
}
return allCords;
}
function buildRow(cords, range, topRange, baseCords) {
console.log(cords);
var thisLists = [];
// Right, Left, Top, Bottom
thisLists.push(add(clone(cords), range, 0, 0));
thisLists.push(add(clone(cords), -range, 0, 0));
thisLists.push(add(clone(cords), 0, range, 0));
thisLists.push(add(clone(cords), 0, -range, 0));
// Above - Right, Left, Top, Bottom
thisLists.push(add(clone(cords), range, 0, range));
thisLists.push(add(clone(cords), range, 0, -range));
thisLists.push(add(clone(cords), 0, range, range));
thisLists.push(add(clone(cords), 0, range, -range));
// Below - Right, Left, Top, Bottom
thisLists.push(add(clone(cords), -range, 0, range));
thisLists.push(add(clone(cords), -range, 0, -range));
thisLists.push(add(clone(cords), 0, -range, range));
thisLists.push(add(clone(cords), 0, -range, -range));
const rangeCords = [];
const map = new Map();
for (const cord of thisLists) {
let sign = cord.X+""+cord.Y+""+cord.Z;
if(!map.has(sign)){
map.set(sign, true); // set any value to Map
let dis = getDistance(cord, baseCords);
if (dis <= topRange)
rangeCords.push({Cords: cord, Distance: dis});
}
}
return rangeCords;
}
function mainCords(cords, range) {
var thisLists = [];
thisLists.push({Cords: add(clone(cords), 0, 0, 0), Distance: 0});
let topCords = add(clone(cords), 0, 0, range);
let dis = getDistance(cords, topCords);
thisLists.push({Cords: topCords, Distance: dis});
let bottomCords = add(clone(cords), 0, 0, -range);
dis = getDistance(cords, bottomCords);
thisLists.push({Cords: bottomCords, Distance: dis});
return thisLists;
}
function sTc(level) {return level * 50 * 2;}
function cTr(cords) {return cords * 4000};
// End Sensors Grid Functions - Logic
// Saving Functions
function Network(name, level, cords, range) {
return {
Name: name,
Scanner: level,
Cords: cords,
Range: range
}
}
function createString(networkObject) {
return `${networkObject.Name}&${networkObject.Scanner}&${networkObject.Cords.X}&${networkObject.Cords.Y}&${networkObject.Cords.Z}&${networkObject.Range.West}&${networkObject.Range.North}&${networkObject.Range.East}&${networkObject.Range.South}`;
}
function readString(networkString) {
let parts = networkString.split('&');
return Network(parts[0], parts[1], Cords(parts[2], parts[3], parts[4]), Range(parts[5], parts[6], parts[7], parts[8]));
}
function saveNode(network) {
GM_setValue(network.Name, createString(network));
updateMainList(network.Name);
}
function updateMainList(networkName) {
let currentList = GM_getValue('sensor-list');
var allNetworks = [];
if (!currentList) {
allNetworks.push(networkName);
}
else {
allNetworks = currentList.split('&');
let index = allNetworks.findIndex(x => x == networkName);
if (index == -1) {
allNetworks.push(networkName);
}
}
currentList = allNetworks.join('&');
GM_setValue('sensor-list', currentList);
}
function removeMainList(networkName) {
let currentList = GM_getValue('sensor-list');
let allNetworks = currentList.split('&');
let index = allNetworks.findIndex(x => x == networkName);
if (index != -1) {
allNetworks = allNetworks.filter(x => x != networkName);
currentList = allNetworks.join('&');
GM_setValue('sensor-list', currentList);
}
}
// End Saving Functions
// Cords Class
function Cords(x,y,z) {
return {X : parseInt(x), Y: parseInt(y), Z: parseInt(z)}
}
function clone(cords) {
return {X : cords.X, Y: cords.Y, Z: cords.Z}
}
function add(cords, x, y, z) {
cords.X = cords.X + x;
cords.Y = cords.Y + y;
cords.Z = cords.Z + z;
return cords;
}
function toCords(cords) {
return `${cords.X}, ${cords.Y}, ${cords.Z}`;
}
function getDistance(cordsA, cordsB) {
let X = Math.pow(cordsA.X - cordsB.X, 2);
let Y = Math.pow(cordsA.Y - cordsB.Y, 2);
let Z = Math.pow(cordsA.Z - cordsB.Z, 2);
let f = Math.sqrt(X + Y + Z);
return 4000 * f;
}
function isEqual(cordsA, cordsB) {
return (cordsA.X == cordsB.X && cordsA.Y == cordsB.Y && cordsA.Z == cordsB.Z);
}
// End Cords Class
// Range Class
function Range(l,t,r,b) {
return {West: l, North: t, East: r, South: b};
}
// Fleet Class
function Fleet(id, cords, status) {
return {Id: id, Cords: cords, Status: status};
}
// End Fleet Class
// HTML Painting Functions
function htmlIframe(id, name, sensor, cords, range) {
if (!cords) cords = {X:"",Y:"",Z:""};
if (!range) range = Range('','','','');
return `
<div id="manage-data${id}">
<div id="header-data${id}">
<table id="table-header${id}" style="width:100%">
<tr class="dark tbborder">
<td class="padding5">Grid Name:</td>
<td class="padding5">
<input type="text" class="darkinput" id="grid-name${id}" value='${name}' />
</td>
</tr>
<tr class="dark tbborder">
<td class="padding5">Scanner Level:</td>
<td class="padding5">
<input type="text" class="darkinput" id="scanner-level${id}" value='${sensor}' />
</td>
</tr>
<tr class="dark tbborder">
<td class="padding5">Core Point (X Y Z):</td>
<td class="padding5">
X:<input type="text" class="darkinput" id="core-pointX${id}" value='${cords.X}' />
Y:<input type="text" class="darkinput" id="core-pointY${id}" value='${cords.Y}' />
Z:<input type="text" class="darkinput" id="core-pointZ${id}" value='${cords.Z}' />
</td>
</tr>
<tr class="dark tbborder">
<td class="padding5">Range:</td>
<td class="padding5">
West:<input type="text" class="darkinput" id="rangeL${id}" value='${range.West}' />
North:<input type="text" class="darkinput" id="rangeT${id}" value='${range.North}' />
East:<input type="text" class="darkinput" id="rangeR${id}" value='${range.East}' />
South:<input type="text" class="darkinput" id="rangeB${id}" value='${range.South}' />
</td>
</tr>
<tr class="dark tbborder">
<td>
<input type="button" id='buttonUpdate${id}' value="${id == 0 ? 'Add' : 'Update'}" class="darkbutton dangerbutton" />
<input type='button' id='buttonDelete${id}' class='darkbutton dangerbutton' value='Delete' />
<input type="button" id='buttonView${id}' class="darkbutton dangerbutton" value="View" />
</td>
</tr>
</table>
</div>
</div>`;
}
function addHeader() {
return `
<div id="body-data">
<table id="table-data" style="width:100%">
<thead class="dark tbborder">
<td class="padding5" align="center">Id</td>
<td class="padding5" align="center">Name</td>
<td class="padding5" align="center">Cords</td>
<td class="padding5" align="center">Distance</td>
<td class="padding5" align="center">Sensor Status</td>
<td class="padding5" align="center">Fleet</td>
<td>
<input id='verify-all' type='button' value='Verify All' class="darkbutton dangerbutton" />
</td>
</thead>
</div>`
}
function newRaw(index, cords) {
return `
<tr class="dark tbborder">
<td align="center">${index}</td>
<td align="center"><input type="text" class="darkinput" placeholder="Bookmark Name" value="" /></td>
<td align="center">${toCords(cords.Cords)}</td>
<td align="center">${toNumber(cords.Distance)} km</td>
<td align="center">Check</td>
<td align="center"><input type="text" class="darkinput" placeholder="Add Fleet Number" value="" /></td>
<td>
<input type="text" class="darkbutton" value="Send" id="sendButton${index}" />
<input type="text" class="darkbutton" value="Bookmark" id="bookmark${index}" />
</td>
</tr>`
}
// End HTML Painting Functions
// Utilities Functions
function sendAjaxRequest(type, link, async, withResponse, params) {
return new Promise(function (fulfill, reject){
var xhttp = new XMLHttpRequest();
xhttp.open(type, link , true);
xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhttp.send(params);
xhttp.onreadystatechange = function () {
if(xhttp.readyState === 4 && xhttp.status === 200) {
if (withResponse == true)
fulfill(xhttp.responseText);
else
fulfill();
}
};
});
}
function divAjaxRequest(type, link, async, withResponse, params) {
return new Promise(function (fulfill, reject){
sendAjaxRequest(type, link, async, withResponse, params).then(function(html){
var div = document.createElement('div');
div.innerHTML = html;
return fulfill(div);
});
});
}
function toNumber(num) {
num = Math.floor(num, 2);
return num.toString().replace(/(\d)(?=(\d{3})+$)/g, '$1,');
}
// End Utilities Functions