// ==UserScript==
// @name Atlantis GameData hyperlinks
// @namespace http://atlantis-pbem.com/data
// @version 0.010
// @description Add hyperlinks to GameData
// @author Anton
// @match http://atlantis-pbem.com/data
// @match http://atlantis-pbem.com/times*
// @grant GM_addStyle
// ==/UserScript==
(function() {
'use strict';
let scriptName = "Atlantis GameData hyperlinks:";
let GMAddStyle = (typeof GM_addStyle == 'function') ? GM_addStyle : function (aCss) {
'use strict';
let head = document.getElementsByTagName('head')[0];
if (head) {
let style = document.createElement('style');
style.setAttribute('type', 'text/css');
style.textContent = aCss;
head.appendChild(style);
return style;
}
return null;
};
GMAddStyle(`
.gameDataMenu {
position: fixed;
right: 0;
top: 100px;
width: 350px;
border-top: 1px solid #CCC;
border-left: 1px solid #CCC;
border-bottom: 1px solid #CCC;
border-top-left-radius: 8px;
border-bottom-left-radius: 8px;
padding: 8px;
background: rgba(255,255,255,0.75);
}
.gameDataMenu > a {
display: block;
}
.gameDataLink, pre > a.mainlink {
position: relative;
top: -80px;
}
#skills-ph, #items-ph, #objects-ph, #infopanel {
padding-left: 8px;
font-size: 70%;
}
#filtr {
margin-left: 8px;
padding: 1px;
border: 1px solid #CCC;
}
.gameDataHidden {
display: none;
}
`);
let shipTable =
`Ship Capacity Speed Cost/skill Crew Mages Defence
Longship 150 4 10/1 4 - -
Raft 450 2 10/1 2 - -
Cog 750 4 25/2 6 - -
Galleon 2700 4 75/3 15 1 -
Galley 1200 4 50/3 IRWD 12 2 2 (120 men)
Corsair 1500 5 50/4 15 - -
Balloon 100 4/fly 20/4 FLOA 3 1 -
Airship 800 4/fly 60+60/5 FLOA 10 2 -
Cloudship 1500 4/fly 75 IRWD+FLOA 15 5 3 (140 men)`.split("\n");
let isData = window.location.pathname.toLowerCase().replace('/','') == "data";
let isTimes = window.location.pathname.toLowerCase().replace('/','').indexOf("times") == 0;
let body = document.querySelector('body');
let controlPanel = document.createElement('div');
controlPanel.className = 'gameDataMenu';
body.append(controlPanel);
let timesControllerInit = () => {
controlPanel.innerHTML = `
<div><label for="filtr">Search: </label><input id="filtr" type="text"></div>
<a href="#top-agdhl">Top</a>
<a href="#quests">Quests</a>
<a href="#articles">Articles</a>
<a href="#rumors">Rumors</a>
<div id="infopanel"></div>
`;
let container = document.querySelector('div.container.my-5');
container.style.paddingRight = '350px';
let paragraphs = container.querySelectorAll('h2');
// Add links to paragraphs
if (paragraphs.length == 4) {
let addLinkToParapgraph = (pp, idx, linkName) => {
pp[idx].outerHTML = '<a class="gameDataLink" name="' + linkName + '"></a>' + pp[idx].outerHTML
};
addLinkToParapgraph(paragraphs, 0, 'top-agdhl');
addLinkToParapgraph(paragraphs, 1, 'quests');
addLinkToParapgraph(paragraphs, 2, 'articles');
addLinkToParapgraph(paragraphs, 3, 'rumors');
} else {
console.log(scriptName, "Paragraphs not found!");
}
// Fix events
let events = container.querySelector('pre').parentNode;
events.style.fontSize = '14px';
let messages = container.querySelectorAll('.jumbotron');
// fill info panel
let infopanel = document.getElementById('infopanel');
for (let i = 0; i < messages.length; i++) {
let txt = messages[i].innerText.toLowerCase();
if (txt.indexOf('players have visited') != -1 && txt.indexOf('of all inhabited regions') != -1) {
let percentInfo = txt.split(' ').filter(e => e.indexOf('%') != -1);
if (percentInfo.length > 0) percentInfo = percentInfo[0];
infopanel.innerHTML += 'Map: ' + percentInfo + '<br/>';
}
}
let allMessagesIncludingParagraph = container.querySelectorAll('div.jumbotron,h2');
let questsCount = -2;
for (let i = 0; i < allMessagesIncludingParagraph.length; i++) {
if (questsCount < 0 && allMessagesIncludingParagraph[i].tagName == 'H2') questsCount++;
else if (questsCount >= 0) {
if (allMessagesIncludingParagraph[i].tagName == 'H2') break; else questsCount++;
}
}
infopanel.innerHTML += 'Quests: ' + questsCount + '<br/>';
let updateLists = (s) => {
s = s.toLowerCase().trim();
for (let i = 0; i < messages.length; i++) {
let txt = messages[i].innerText.toLowerCase();
messages[i].classList.toggle('gameDataHidden', txt.indexOf(s) == -1);
}
events.classList.toggle('gameDataHidden', s != '');
};
let inp = document.querySelector('#filtr');
inp.onkeyup = (e) => {
updateLists(String(inp.value).toUpperCase());
};
};
let dataControllerInit = () => {
let container = document.querySelector('pre');
let data = container.innerHTML;
let dataLines = data.split(/\r?\n/);
let shipbuilding1Line = dataLines.findIndex(e => e.indexOf('shipbuilding [SHIP] 2') != -1);
let skillReportLine = dataLines.indexOf("Skill reports:");
let itemReportLine = dataLines.indexOf("Item reports:");
let objectReportLine = dataLines.indexOf("Object reports:");
controlPanel.innerHTML = `
<div><label for="filtr">Search: </label><input id="filtr" type="text"></div>
<a href="#skills">Skills</a>
<div id="skills-ph"></div>
<a href="#items">Items</a>
<div id="items-ph"></div>
<a href="#objects">Objects</a>
<div id="objects-ph"></div>
`;
body.append(controlPanel);
let skillsArray = [];
let itemsArray = [];
let objectsArray = [];
let skillsDescription = {};
let itemsDescription = {};
let objectsDescription = {};
let skillsDesc = {};
let itemsDesc = {};
let objectsDesc = {}; // inside: {name, desc}
let addToArray = (arr, key, item) => {
if (arr != '' && key != '') {
if (!arr[key]) arr[key] = [];
if (arr[key].indexOf(item) == -1) arr[key].push(item);
}
};
let analyzePart = (s, run, prevSkill, prevItem, prevObject) => {
let parts = s.match(/(.*)(\[(.{3,5})\])(.*)/);
if (parts && parts.length > 0) {
let skillAddon = (skillsArray.indexOf(parts[3] + '1') != -1) ? '1' : '';
addToArray(skillsDescription, prevSkill, parts[3] + skillAddon);
addToArray(itemsDescription, prevItem, parts[3]);
addToArray(objectsDescription, prevObject, parts[3]);
return analyzePart(parts[1], run, prevSkill, prevItem, prevObject) +
'<a href="#' + parts[3] + skillAddon + '">' + parts[2] + '</a>' + analyzePart(parts[4], run, prevSkill, prevItem, prevObject);
}
return s;
};
let clearName = (s) => {
return s.replaceAll(' ', '_').replaceAll("'", '');
};
for (let run = 0; run < 2; run++) {
let prevLine = '';
let prevSkill = '';
let prevItem = '';
let prevObject = '';
for (let i = 0; i < dataLines.length; i++) {
let str = dataLines[i];
// mining [MINI] 3: A unit with this skill may PRODUCE mithril [MITH] at
let searchForName = str.match(/(\S.*)(\[(.{3,5})\].(\d)):(.*)/);
if (searchForName && searchForName.length > 0 && prevLine.trim() == '') {
let firstPart = searchForName[1]; // mining
let linkText = searchForName[2]; // [MINI] 3
let name = searchForName[3]; // MINI
let level = parseInt(searchForName[4]); // 3
let lastPart = searchForName[5]; // A unit with this skill may PRODUCE mithril [MITH] at
let linkName = name + level;
prevSkill = name + '1';
prevItem = '';
prevObject = '';
if (skillsArray.indexOf(linkName) == -1) {
skillsArray.push(linkName);
lastPart = analyzePart(lastPart, run, prevSkill, prevItem, prevObject);
dataLines[i] = firstPart + '<a class="mainlink" name="' + linkName + '"></a>' + linkText + ':' + lastPart;
}
} else {
// winged horse [WING], weight 50, walking capacity 20, riding capacity
searchForName = str.match(/(\S.*)(\[(.{3,5})\])[,\.](.*)/);
if (searchForName && searchForName.length > 0 && prevLine.trim() == '') {
let firstPart = searchForName[1]; // winged horse
let linkText = searchForName[2]; // [WING]
let name = searchForName[3]; // WING
let lastPart = searchForName[4]; // weight 50, walking capacity 20, riding capacity
let linkName = name;
prevSkill = '';
prevItem = name;
prevObject = '';
if (itemsArray.indexOf(linkName) == -1) {
itemsArray.push(linkName);
lastPart = analyzePart(lastPart, run, prevSkill, prevItem, prevObject);
dataLines[i] = firstPart + '<a class="mainlink" name="' + linkName + '"></a>' + linkText + ',' + lastPart;
}
} else {
// Magician's Tower: This is a building. Monsters can potentially lair in
searchForName = str.match(/^(.+):(.+)/);
if (searchForName && searchForName.length > 0 && prevLine.trim() == '' && run == 0) {
let name = searchForName[1]; // Magician's Tower
let lastPart = searchForName[2]; // This is a building. Monsters can potentially lair in
let linkName = clearName(name);
prevSkill = '';
prevItem = '';
prevObject = name;
if (objectsArray.indexOf(linkName) == -1) {
objectsArray.push(linkName);
lastPart = analyzePart(lastPart, run, prevSkill, prevItem, prevObject);
dataLines[i] = '<a class="mainlink" name="' + linkName + '"></a>' + name + ':' + lastPart;
}
} else {
if (run == 1) dataLines[i] = analyzePart(str, run, prevSkill, prevItem, prevObject);
}
}
}
if (str.trim() == '') {
prevSkill = '';
prevItem = '';
} else if (prevSkill != '' && run == 0) {
if (!skillsDesc[prevSkill]) skillsDesc[prevSkill] = str.trim().toUpperCase();
else skillsDesc[prevSkill] += ' ' + str.trim().toUpperCase();
} else if (prevItem != '' && run == 0) {
if (!itemsDesc[prevItem]) itemsDesc[prevItem] = str.trim().toUpperCase();
else itemsDesc[prevItem] += ' ' + str.trim().toUpperCase();
} else if (prevObject != '' && run == 0) {
let obj_id = clearName(prevObject);
if (!objectsDesc[obj_id]) objectsDesc[obj_id] = {desc: str.trim().toUpperCase(), name: prevObject};
else objectsDesc[obj_id].desc += ' ' + str.trim().toUpperCase();
}
prevLine = str;
}
}
dataLines[skillReportLine] = '<a name="skills" class="gameDataLink"></a>Skill reports:';
dataLines[itemReportLine] = '<a name="items" class="gameDataLink"></a>Item reports:';
dataLines[objectReportLine] = '<a name="objects" class="gameDataLink"></a>Object reports:';
// add shipbuilding description of possible ships
dataLines.splice(shipbuilding1Line, 0, "");
for (let i = 0; i < shipTable.length; i++) {
dataLines.splice(shipbuilding1Line, 0, shipTable[shipTable.length - i - 1]);
}
container.innerHTML = dataLines.join("\n");
let skillHasObject = (skil, filterValue) => {
let found = skillsDescription[skil] && !!(skillsDescription[skil].find(o => o.indexOf(filterValue) != -1));
let foundInDesc = skillsDesc[skil] && skillsDesc[skil].indexOf(filterValue) != -1;
return found || foundInDesc;
};
let objectHasSkill = (ob, filterValue) => {
let found = itemsDescription[ob] && !!(itemsDescription[ob].find(o => o.indexOf(filterValue) != -1));
let foundInDesc = itemsDesc[ob] && itemsDesc[ob].indexOf(filterValue) != -1;
return found || foundInDesc;
};
let objectHasDescription = (ob, filterValue) => {
let foundInDesc = objectsDesc[ob].desc && objectsDesc[ob].desc.indexOf(filterValue) != -1;
return foundInDesc;
};
let skillsPH = document.querySelector('#skills-ph');
let itemsPH = document.querySelector('#items-ph');
let objectsPH = document.querySelector('#objects-ph');
let updateLists = (filterValue) => {
skillsPH.innerHTML = skillsArray
.filter(e => e[e.length - 1] == 1)
.filter(e => e.indexOf(filterValue) != -1 || skillHasObject(e, filterValue))
.map(e => e.substr(0, e.length - 1))
.map(e => '<a href="#' + e + '1">' + e + '</a>')
.join(', ');
itemsPH.innerHTML = itemsArray
.filter(e => e.indexOf(filterValue) != -1 || objectHasSkill(e, filterValue))
.map(e => '<a href="#' + e + '">' + e + '</a>')
.join(', ');
if (filterValue.trim() == '') objectsPH.innerHTML = '';
else {
objectsPH.innerHTML = objectsArray
.filter(e => objectHasDescription(e, filterValue))
.map(e => '<a href="#' + clearName(e) + '">' + objectsDesc[e].name + '</a>')
.join(', ');
}
}
updateLists('');
let inp = document.querySelector('#filtr');
inp.onkeyup = (e) => {
updateLists(String(inp.value).toUpperCase());
};
};
if (isData) dataControllerInit();
if (isTimes) timesControllerInit();
console.log(scriptName, 'hello.');
})();