// ==UserScript==
// @name StarRepublik Tools
// @name:bg StarRepublik Инструменти
// @name:ro Unelte StarRepublik
// @description Various enhancements and tools for StarRepublik
// @description:bg Различни подобрения и инструменти за StarRepublik
// @description:ro Diverse îmbunătățiri și unelte pentru StarRepublik
// @namespace http://www.linuxmint.ro/
// @version 1.4
// @license CC BY 4.0
// @author Nicolae Crefelean
// @include https://www.starrepublik.com/*
// @grant none
// ==/UserScript==
$(function() {
// add custom styles
$('head').append('<style></style>');
$('style')
.append('#srtools { font-size: 13px; padding: 5px; background-color: #121925; border-radius: 2px; margin-top: 5px; margin-bottom: 10px }')
.append('.srtselect { width: 200px; height: 30px; background-color: #121925; color: #cecece; border: 1px solid #595959; border-radius: 2px; padding: 2px }');
var srtversion = '1.4',
letters = ['α', 'β', 'γ', 'Δ', 'Ω'],
effectDelay = 150,
locale = {
bg: {
name: 'Български',
medalsStr: 'Медали',
starshipPartsPointsStr: 'Изисквани Седмични турнирни точки',
baseDamage: 'Bаза щети',
battles: 'Битките',
move: 'Ход',
building: 'Cграда',
myLocation: 'Моето място'
},
en: {
name: 'English',
medalStr: 'Medals',
starshipPartsPointsStr: 'Weekly tournament points required',
baseDamage: 'Base damage',
battles: 'Battles',
move: 'Move',
building: 'Building',
myLocation: 'My location'
},
es: {
name: 'Español',
medalStr: 'Medallas',
starshipPartsPointsStr: 'Puntos de torneo semanal necesaria',
baseDamage: 'Daño base',
battles: 'Batallas',
move: 'Moverse',
building: 'Edificio',
myLocation: 'Mi ubicación'
},
it: {
name: 'Italiano',
medalStr: 'Medaglie',
starshipPartsPointsStr: 'Punti Torneo Settimanale richiesti',
baseDamage: 'Danno base',
battles: 'Battaglie',
move: 'Spostati',
building: 'Costruzione',
myLocation: 'La mia posizione'
},
ro: {
name: 'Română',
medalStr: 'Medalii',
starshipPartsPointsStr: 'Puncte necesare în turneul săptămânal',
baseDamage: 'Daune de bază',
battles: 'Bătălii',
move: 'Mutare',
building: 'Clădire',
myLocation: 'Locația mea'
},
sr: {
name: 'Srpski',
medalStr: 'Medalje',
starshipPartsPointsStr: 'Delovi zvezdane krstarice',
baseDamage: 'Bazna steta',
battles: 'Bitke',
move: 'Predji na',
building: 'Zgrada',
myLocation: 'Moja lokacija'
}
},
defaultLang = getLocale();
// adds the StarRepublik Tools settings box on the sidebar
if ($('.stardate').length > 0) {
$('.stardate').after('<div class="row-fluid" id="srtools"></div>');
$('#srtools')
.html('<div class="text-center">StarRepublik Tools v' + srtversion + '</div>')
.append('<select class="center-block srtselect"></select>');
$.each(locale, function(i, v) {
$('.srtselect').append('<option value="' + i + '"' + (i === defaultLang ? ' selected' : '') + '>' + v.name + '</option>');
});
}
// Adds links to the Battles and the Change location pages.
$('.dropdown:eq(0) > .dropdown-menu')
.append('<li><a href="/battles/">' + getString('battles') + '</a></li>')
.append('<li><a href="/change-location/">' + getString('move') + '</a></li>');
// Set the default language as English, or if the browser requests
// a language available in the script, it will choose it automatically.
// The language can also be changed by the user. Refresh required.
function setLocale(lang) {
if (localStorage.locale === undefined) {
var langList = navigator.languages,
language = 'en',
found = false;
for (i=0; !found; i++) {
if (locale[langList[i]] !== undefined) {
language = langList[i];
found = true;
}
}
localStorage.locale = language;
return;
}
if (lang !== undefined && lang in locale) {
localStorage.locale = lang;
}
}
// Returns the default locale and sets one if not available.
function getLocale() {
if (localStorage.locale === undefined) {
setLocale();
}
return localStorage.locale;
}
// Returns a string based on its identifier. Defaults to English if missing.
function getString(id) {
lang = getLocale();
var str = locale[lang][id] === undefined ? (locale.en[id] === undefined ? id : locale.en[id]) : locale[lang][id];
return str;
}
// Event handler for the language switcher.
$('.srtselect').change(function() {
setLocale(this.value);
});
// Returns the user ID.
function getUserId() {
return $("#main-menu a:eq(1)").attr('href').split('/')[2];
}
// Returns the user profile link.
function getUserProfileLink() {
return $("#main-menu a:eq(1)").attr('href');
}
// Return the base damage.
function getBaseDamage(skill, rank) {
return Math.round(Math.pow(10 * skill * (1 + rank / 20), 0.8));
}
// Add the base damage data to the military wings on the user profile page.
function getBaseDamageStats() {
$.get('/api/profile/' + getUserId() + '/', function(data) {
var d = data.user.military,
baseDamage = {
interceptor: 0,
bomber: 0,
fighter: 0
};
baseDamage.interceptor = getBaseDamage(d.skills.interceptor, d.rank),
baseDamage.bomber = getBaseDamage(d.skills.bomber, d.rank),
baseDamage.fighter = getBaseDamage(d.skills.fighter, d.rank);
$('#baseI').html(getString('baseDamage') + ': ' + baseDamage.interceptor + '<br>+20% = ' + Math.round(baseDamage.interceptor * 1.2));
$('#baseB').html(getString('baseDamage') + ': ' + baseDamage.bomber + '<br>+20% = ' + Math.round(baseDamage.bomber * 1.2));
$('#baseF').html(getString('baseDamage') + ': ' + baseDamage.fighter + '<br>+20% = ' + Math.round(baseDamage.fighter * 1.2));
});
}
// Creates the HTML/CSS/JS foundation for the base damage tooltips in the user profile.
function addBaseDamageTooltips() {
$('style')
.append('.skill-desc > .description { position: absolute; z-index: 10; margin-top: -132px; margin-left: -15px; width: 100%; background-color: #070d15; border: 1px solid #101924; padding: 10px; border-radius: 3px }');
$('.skills:eq(1) .skill:eq(2)').addClass('description-container skill-desc')
.append('<div style="display: none;" class="description"><div class="row-fluid" id="baseI"></div></div>');
$('.skills:eq(1) .skill:eq(3)').addClass('description-container skill-desc')
.append('<div style="display: none;" class="description"><div class="row-fluid" id="baseB"></div></div>');
$('.skills:eq(1) .skill:eq(4)').addClass('description-container skill-desc')
.append('<div style="display: none;" class="description"><div class="row-fluid" id="baseF"></div></div>');
$('.skills:eq(1) .skill').slice(2, 5).hover(function() {
$(this).find(".description").toggle();
});
}
// Displays the number of medals and total Credits earned (in the user profile).
function calcCredits() {
var rewards = {
hard_worker: 5,
expert: 5,
political_activist: 5,
congress_member: 10,
country_leader: 20,
prosperous_journalist: 3,
media_mogul: 5,
society_builder: 50,
weekly_runner: 100,
hunter: 3,
wing_commander: 2,
battle_hero: 5,
deft_shooter: 3,
ace: 10,
rebellion_hero: 10,
juggernaut: 20,
patriot: 5,
faithfull_ally: 5,
super_soldier: 5
},
medal_count = 0,
earned_credits = 0,
medal_name,
medal_counter;
$('.medals-list li').each(function() {
medal_name = $(this).find('img').attr('src').split('/').pop().split('.')[0];
medal_counter = Number($(this).find('.medal-quantity').text().trim());
if (medal_name in rewards) {
earned_credits += rewards[medal_name] * medal_counter;
medal_count += medal_counter;
}
});
$('.achievements').last().append(' (' + medal_count + ': ' + earned_credits + ' Cr)');
}
// Code executed while viewing a user profile.
if (/^\/profile\/[0-9]+\/$/.test(document.location.pathname)) {
addBaseDamageTooltips();
getBaseDamageStats();
calcCredits();
}
// Reset the medals data (on the battlefield).
function clearTopMedals() {
var medals = ['.defender-ds', '.attacker-ds', '.defender-bh', '.attacker-bh', '.defender-ace', '.attacker-ace'],
medal;
for (i = 0; i < 7; i++) {
medal = medals[i];
$(medal + ' a').removeAttr('href');
$(medal + ' a img').removeAttr('src');
$(medal + ' div.username').text('');
$(medal + ' span.damage').text('');
$(medal + ' span.shoots').text('');
}
}
// Build and place the squadron switcher next to the stats Close button (on the battlefield).
function addSquadronSwitcher() {
var squads = [],
sclass;
$('.close-statistics:eq(1)').attr('class',$('.close-statistics:eq(1)').attr('class').replace(/4/g, '1'));
for (i = 1; i < 6; i++) {
sclass = 'squadSwitch' + ($('.statistics:eq(1)').data('squadron') == i ? ' btn-primary' : '');
squads.push("<a role='button' class='btn " + sclass + "'>" + letters[i - 1] + "</a>");
}
$('.close-statistics:eq(1)').before("<div class='col-lg-3 col-md-3 col-sm-3 col-xs-3'>" + squads.join('') + "</div>");
}
// Set the width of the statistics overlay to the same width as the battlefield.
if (/^\/military\/battle\//.test(document.location.pathname)) {
$('.battle-statistics').css('width', '100%');
addSquadronSwitcher();
}
// Event handler for clicking the squadron switcher buttons (on the battlefield).
$('.squadSwitch').on("click", function() {
var squad = letters.indexOf($(this).text());
clearTopMedals();
$('.squadSwitch').removeClass('btn-primary');
$('.squadSwitch:eq(' + squad + ')').addClass('btn-primary');
$('.statistics:eq(1)').data('squadron', squad + 1).click();
});
// Counts the number of sectors owned by a country and adds it to the section header.
function getCountryDetails() {
var sectors = $('.country-content .society-list:eq(1) li').length;
$('.country-content .society-list:eq(1) > div').append(' (' + sectors + ')');
}
// Code executed while viewing the Society page of a country.
if (/^\/country\/society\//.test(document.location.pathname)) {
getCountryDetails();
}
// Code executed while viewing the Congress candidature proposal page.
if (/^\/politics\/congress-proposal\/$/.test(document.location.pathname)) {
$('#id_sector').addClass('srtselect');
getCandidatesBySector();
}
// Returns the country ID of the displayed country on the Congress candidature proposal page.
function getCountryFromCongressProposal() {
return $(".inline-country-flag").parent().attr("href").split('/')[3];
}
// Calculates the number of candidates per sector and adds them in the sector selector.
function getCandidatesBySector() {
$.get('https://www.starrepublik.com/politics/congress-candidates/' + getCountryFromCongressProposal() + '/', function(data) {
if ($(data).find('.citizens-list li').length > 0) {
var sectors = {},
sector;
$(data).find('.citizens-list li').each(function() {
sector = $(this).find('.sector').text().trim();
if (sector in sectors) {
sectors[sector] += 1;
} else {
sectors[sector] = 1;
}
});
$('#id_sector option').each(function() {
if (this.value !== '') {
current = this.innerHTML;
this.innerHTML += " (" + (sectors[current] > 4 ? '!!! ' : '') + (current in sectors ? sectors[current] : 0) + "/5)";
}
});
}
});
}
// Code executed while viewing the storage.
if (/^\/storage\/$/.test(document.location.pathname)) {
var minParts = Math.min(
itemsCount('ion_ammo'),
itemsCount('ion_stock'),
itemsCount('ion_chip')
);
setCannonPartBalance(minParts);
setWeaponBalance(minParts);
addStarshipPartsRequirements();
}
// Returns the number of items by image name (in the storage).
function itemsCount(img) {
return Number($('.storage-list:eq(0) li img[src="/media/images/products/' + img + '.jpg"]').parent().next().text().trim()) || 0;
}
// Add the positive/negative sign to non-zero balances (for storage items).
function setBalance(num) {
return (num === 0 ? '' : (num > 0 ? '-' : '+')) + Math.abs(num).toString();
}
// Add the balance to each weapon type (in the storage).
function setWeaponBalance(cannons) {
var weaponMultiplier = {'q1': 10, 'q2': 8, 'q3': 6, 'q4': 4, 'q5': 2},
quality,
balance;
for (i = 1; i < 6; i++) {
quality = 'q' + i.toString();
balance = setBalance(cannons * weaponMultiplier[quality] - itemsCount('weapon_' + quality));
$('.item-creation-list li img[src="/media/images/products/weapon_' + quality + '.jpg"]').attr('alt', quality).parent().next().text(balance);
}
}
// Add the balance to each cannon part (in the storage).
function setCannonPartBalance(count) {
var cannonParts = {1: 'ammo', 2: 'stock', 3: 'chip'},
balance;
$('.item-creation-list:eq(1) .item-to-create .quantity').text(count).prev().find('img').attr('alt', 'cannons');
for (i = 1; i < 4; i++) {
balance = setBalance(count - itemsCount('ion_' + cannonParts[i]));
$('.item-creation-list:eq(1) img[src="/media/images/products/ion_' + cannonParts[i] + '.jpg"]').attr('alt', cannonParts[i]).parent().next().text(balance);
}
}
// Adds the Starship parts requirements in the user storage.
function addStarshipPartsRequirements() {
var req = [1500, 2000, 2500, 2750, 5000],
reqText = getString('starshipPartsPointsStr');
$('.item-details').css('z-index', '1');
$('.storage-list:eq(1) li').each(function(i, v) {
item = $(v).find('.item-name').append('<div class="details">' + reqText + ': ' + req[i] + '</div>');
});
}
// Code executed while viewing the congress candidates page.
if (/^\/politics\/congress-candidates\//.test(document.location.pathname)) {
buildCongressCandidatesArticle();
}
// Build the congress candidates list in BB-code format.
function getCongressCandidatesList() {
if ($('.citizens-list li').length > 0) {
var congressCandidatesList = {},
cit;
$('.citizens-list li').each(function() {
cit = {};
cit.cname = $(this).find('.name').text().trim();
cit.curl = $(this).find('.name a').attr('href').trim();
cit.sector = '[b]' + $(this).find('.sector').text().trim() + '[/b]';
cit.pname = $(this).find('.party').text().trim();
cit.purl = $(this).find('.party a').attr('href').trim();
if (!(cit.sector in congressCandidatesList)) {
congressCandidatesList[cit.sector] = {};
}
cit.bbcit = '[url=https://www.starrepublik.com' + cit.curl + ']' + cit.cname + '[/url]';
cit.bbprt = '[url=https://www.starrepublik.com' + cit.purl + ']' + cit.pname + '[/url]';
congressCandidatesList[cit.sector][cit.bbcit] = cit.bbprt;
});
return congressCandidatesList;
}
}
// Build the congress candidates text area and populate it with data.
function buildCongressCandidatesArticle() {
var congressCandidatesArticle = '',
list = getCongressCandidatesList();
if (list) {
$.each(list, function(index, value) {
congressCandidatesArticle += "\n" + index + "\n";
$.each(value, function(idx, val) {
congressCandidatesArticle += idx + ' - ' + val + "\n";
});
});
congressCandidatesArticle = "[center]" + congressCandidatesArticle.trim() + "[/center]";
$('.party-content > .section-header.politics').append(' [<span id="toggleArticle" style="cursor: pointer">+</span>]');
$('.citizens-list').before("<div id='congressCandidatesArticle' class='col-md-12' style='display: none'><p><textarea class='form-control' style='resize: vertical'>" + congressCandidatesArticle + "</textarea></p></div>");
}
}
// Event handler for clicking the congress candidates list button.
$('#toggleArticle').click(function () {
if ($('#congressCandidatesArticle').css('display') === 'none') {
$('#congressCandidatesArticle').show(effectDelay);
$('#toggleArticle').html('—');
} else {
$('#congressCandidatesArticle').hide(effectDelay);
$('#toggleArticle').html('+');
}
});
// Remove the existing building information from the sector information panel.
function removeBuildings() {
$('.sector-info .buildings').remove();
}
// Get the list of buildings for a given sector id.
function getRegionBuildings(id) {
removeBuildings();
$.get('/country/sector/' + id + '/', function(data) {
var btype,
bquality,
owner = $(data).find('.country-header div:eq(1) a').attr('href');
$('.sector-info .owner div:eq(1)').wrapInner('<a href="' + owner + '"></a>');
if ($(data).find('.building').length) {
removeBuildings();
$('.sector-info').append('<div class="row buildings"></div>');
$(data).find('.building').each(function() {
btype = $(this).find('.header').text().trim();
bquality = $(this).find('.quality').text().trim();
$('.sector-info .buildings').append('<div class="col-lg-6 col-md-6 col-sm-6 col-xs-6">Building:</div><div class="col-lg-6 col-md-6 col-sm-6 col-xs-6 value">' + btype + " " + bquality + '</div>');
});
} else {
removeBuildings();
}
});
}
// Add the user's location panel in the side panel.
function addMyLocationToMap(location) {
$('style').append('.location-info { margin-top: 10px; padding: 0; border: 1px solid #101924; background-color: #02060b; border-radius: 5px; line-height: 25px }');
$('style').append('.location-info .row { padding-bottom: 7px }');
$('.sidebar div.row:eq(0)').after('<div class="location-info" id="srtlocinfo"></div>');
$('#srtlocinfo').append('<div class="section-header social">My location</div>');
$('#srtlocinfo').append('<div class="row"><div class="col-lg-12 col-md-12 col-sm-12 col-xs-12 text-center">' + location + '</div></div>');
}
// Event handlers for sector mouse-over and clicking.
function addMapEventHandlers() {
$('image').on('click', function() {
getRegionBuildings($(this).data('sector'));
});
$('.svg-map image').mouseenter(function() {
var sector = '#' + $(this).data('sector');
$('#srtcurrsector').html(' [' + $(sector).data('x') + ':' + $(sector).data('y') + ']');
});
$('g path, .svg-map image').mouseleave(function() {
$('#srtcurrsector').html('');
});
$('g path').mouseenter(function() {
$('#srtcurrsector').html(' [' + $(this).data('x') + ':' + $(this).data('y') + ']');
});
}
// Code executed on the Galaxy map page.
if (/^\/galaxy-map\/$/.test(document.location.pathname)) {
var countries = {},
t,
region,
bulidings;
$('style').append('.srtmapdef { border: 1px solid #1e81b1 !important; box-shadow: 0 0 5px #1e81b1 }');
$('#owners').addClass('srtmapdef');
$('.section-header:eq(1)').append('<span id="srtcurrsector"></span>');
$.get('/api' + getUserProfileLink(), function(data) {
addMyLocationToMap(data.user.location.label);
});
addMapEventHandlers();
$('#original, #owners, #resources, #battles').click(function() {
$('#original, #owners, #resources, #battles').removeClass('srtmapdef');
$(this).addClass('srtmapdef');
setTimeout(addMapEventHandlers, 1000);
});
}
// Get the comment count for a given article id.
function getComments(selector) {
$(selector === 'main' ? '.news-list li' : '.articles-list li').each(function() {
var target = (selector === 'main' ? $(this).find('.article-newspaper') : $(this).find('.publication-date')),
link = $(this).find(selector === 'main' ? '.article-title a' : '.title a').attr('href'),
commimg = '<img src="/media/images/main/comments.png">',
comments;
$.get(link, function(data) {
comments = '• ' + commimg + ' ' + $(data).find('.commentator').length + (selector === 'main' ? ' •' : '');
if (selector === 'main') {
$(target).after('<span class="artcomments">' + comments + '</span>');
} else {
$(target).append('<span class="artcomments">' + comments + '</span>');
}
});
});
}
// Add the comment count for the articles on the main page and the newspaper page.
if ($('.news-list').length || $('.newspaper-content').length) {
$('style')
.append('.artcomments { margin-left: 5px }')
.append('.artcomments img { height: 10px; margin-top: -2px }');
getComments($('.news-list').length ? 'main' : 'newspaper');
}
// Code executed while viewing an article - adds endorsement count and Credits amount, plus comment count.
if (/\/newspaper\/article\/[0-9]+/.test(document.location.pathname)) {
if ($('.endorsers').length) {
var blue = $('.endorsers .blue').length,
green = $('.endorsers .green').length,
red = $('.endorsers .red').length,
total = blue + green + red,
credits = blue * 1 + green * 0.5 + red * 0.25;
$('.endorsers').prev().append(' (' + total + ': ' + credits + ' Cr)');
}
if ($('.commentator').length) {
$('.comments-list div.social').append(' (' + $('.commentator').length + ')');
}
}
// Event handler for clicking the national/international news feeds.
$('.news-selector').on('click', function() {
setTimeout(getComments, 1500, 'main');
});
});