// ==UserScript==
// @name War Base Extended - Haka
// @namespace ashkill94.warBaseExtended
// @author AshKill94 [1850991]
// @description Brings back the old war base layout, adds a filter to the war base, enables enemy tagging
// @include *.torn.com/factions.php?step=your*
// @version 2.3.2
// @require http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js
// @grant GM_addStyle
// ==/UserScript==
'use strict';
this.$ = this.jQuery = jQuery.noConflict(true);
// global CSS
GM_addStyle(
'#ashkill94-extendedWarBasePanel { line-height: 2em }' +
'#ashkill94-extendedWarBasePanel label { background-color: rgba(200, 195, 195, 1); padding: 2px; border: 1px solid #fff; border-radius: 5px }' +
'#ashkill94-extendedWarBasePanel input { margin-right: 5px; vertical-align: text-bottom }' +
'#ashkill94-extendedWarBasePanel input[type="number"] { vertical-align: baseline; line-height: 1.3em }' +
'#ashkill94-extendedWarBasePanel { padding: 4px; }'
);
var $MAIN = $('#faction-main');
// ============================================================================
// --- FEATURE: War Base Layout
// ============================================================================
function enableWarBaseLayout() {
var fragment = document.createDocumentFragment();
$('.f-war-list .desc-wrap').each(function() {
var row = document.createElement('li');
row.classList.add('descriptions');
$(this.children).each(function() {
row.appendChild(this);
});
fragment.appendChild(row);
});
$('.f-war-list li:not(.clear)').remove();
$('.f-war-list').prepend(fragment);
$('.f-msg').css('margin-bottom', '10px');
GM_addStyle(
'.f-war-list .descriptions { margin-top: 10px !important; border-radius: 5px !important }' +
'.f-war-list .descriptions .status-desc { border-radius: 5px 5px 0 0 !important }' +
'.f-war-list #icon6, .f-war-list #icon8, .f-war-list #icon23, .f-war-list #icon10, .f-war-list #icon26, .f-war-list #icon9, .f-war-list #icon35, .f-war-list #icon4, .f-war-list #icon7 { display: none !important }'
);
}
// ============================================================================
// --- FEATURE: War base filter
// ============================================================================
var warBaseFilter;
var $filterStatusElement;
/**
* Adds the filter panel to the war base extended main panel
* @param {jQuery-Object} $panel Main panel
*/
function addWarBaseFilter($panel) {
var $warList = $('.f-war-list');
var $statusElement = $('<p>', {text: 'The war base is currently hidden. Click the bar above to show it.', style: 'text-align: center; margin-top: 4px; font-weight: bold'}).hide();
$('.f-msg')
.css('cursor', 'pointer')
.on('click', function() {
if (shouldHideWarBase()) {
localStorage.vinkuunHideWarBase = false;
$warList.show();
$statusElement.hide();
} else {
localStorage.vinkuunHideWarBase = true;
$warList.hide();
$statusElement.show();
}})
.attr('title', 'Click to show/hide the war base')
.after($statusElement);
if (shouldHideWarBase()) {
$warList.hide();
$statusElement.show();
}
// load saved war base filter settings
warBaseFilter = JSON.parse(localStorage.vinkuunWarBaseFilter || '{}');
warBaseFilter.status = warBaseFilter.status || {};
$filterStatusElement = $('<span>', {text: 0});
addFilterPanel($panel);
applyFilter();
}
// returns true if the layout is enabled, false if not
function shouldHideWarBase() {
return JSON.parse(localStorage.vinkuunHideWarBase || 'false');
}
/**
* Applys the filter to the war base
*
* @param {jquery-Object} $list
* @param {Object} filter
*/
function applyFilter() {
var $list = $MAIN.find('ul.f-war-list');
// show all members
$list.find('li').show();
var countFiltered = 0;
var items;
if (warBaseFilter.status.okay) {
items = $list.find('span:contains("Okay")');
countFiltered += items.length;
items.parent().parent().hide();
}
if (warBaseFilter.status.offline) {
items = $list.find(icon2);
countFiltered += items.length;
items.parent().parent().parent().hide();
}
if (warBaseFilter.status.traveling) {
items = $list.find('span:contains("Traveling")');
countFiltered += items.length;
items.parent().parent().hide();
}
if (warBaseFilter.status.federal) {
items = $list.find('span:contains("Federal")');
countFiltered += items.length;
items.parent().parent().hide();
}
if (warBaseFilter.status.hospital) {
$list.find('span:contains("Hospital")').each(function() {
var $this = $(this);
var $li = $this.parent().parent();
var hospitalTimeLeft = remainingHospitalTime($li.find('.member-icons #icon15').attr('title'));
if (hospitalTimeLeft > warBaseFilter.status.hospital) {
countFiltered++;
$li.hide();
}
});
}
// update the number of hidden members
$filterStatusElement.text(countFiltered);
}
/**
* Panel to configure the filter - will be added to the main panel
*/
function addFilterPanel($panel) {
$panel.append("Hide enemies who are ");
// status: traveling filter
var $travelingCheckbox = $('<input>', {type: 'checkbox'})
.on('change', function() {
reapplyFilter({status: {traveling: this.checked}});
});
var $travelingElement = $('<label>', {text: 'traveling'}).prepend($travelingCheckbox);
$panel.append($travelingElement).append(', ');
// status: okay filter
var $okayCheckbox = $('<input>', {type: 'checkbox'})
.on('change', function() {
reapplyFilter({status: {okay: this.checked}});
});
var $okayElement = $('<label>', {text: 'okay'}).prepend($okayCheckbox);
$panel.append($okayElement).append(', ');
// status: offline filter
var $offlineCheckbox = $('<input>', {type: 'checkbox'})
.on('change', function() {
reapplyFilter({status: {offline: this.checked}});
});
var $offlineElement = $('<label>', {text: 'offline'}).prepend($offlineCheckbox);
$panel.append($offlineElement).append(', ');
// status: federal filter
var $federalCheckbox = $('<input>', {type: 'checkbox'})
.on('change', function() {
reapplyFilter({status: {federal: this.checked}});
});
var $federalElement = $('<label>', {text: 'in federal prison'}).prepend($federalCheckbox);
$panel.append($federalElement).append(', ');
// status: hospital filter
var $hospitalTextfield = $('<input>', {type: 'number', style: 'width: 50px'})
.on('change', function() {
if (isNaN(this.value)) {
reapplyFilter({status: {hospital: false}});
} else {
reapplyFilter({status: {hospital: parseInt(this.value, 10)}});
}
});
var $hospitalElement = $('<label>', {text: 'in hospital for more than '})
.append($hospitalTextfield)
.append(' minutes');
$panel.append($hospitalElement);
$panel.append(' (').append($filterStatusElement).append(' enemies are hidden by the filter.)');
// set the states of the elements according to the saved filter
$travelingCheckbox[0].checked = warBaseFilter.status.traveling || false;
$okayCheckbox[0].checked = warBaseFilter.status.okay || false;
$offlineCheckbox[0].checked = warBaseFilter.status.offline || false;
$federalCheckbox[0].checked = warBaseFilter.status.federal || false;
$hospitalTextfield.val(warBaseFilter.status.hospital || '');
}
/**
* Reapplies the war base filter - current settings will be merged with the new filter settings
* @param {Object} newFilter new filter settings
*/
function reapplyFilter(newFilter) {
$.extend(true, warBaseFilter, newFilter);
localStorage.vinkuunWarBaseFilter = JSON.stringify(warBaseFilter);
applyFilter(warBaseFilter);
}
/**
* Returns the remaining hospital time in minutes
*
* @param {String} text The tooltip text of the hospital icon
* @return {Integer} time in minutes
*/
function remainingHospitalTime(text) {
var match = text.match(/data-time='(\d+)'/);
return match[1] / 60;
}
// ============================================================================
// --- FEATURE: Enemy tagging
// ============================================================================
var TAGS = {
tbd: {
text: 'Difficulty',
color: 'inherit'
},
possible: {
text: 'Possible Target',
color: 'rgba(240, 255, 240, 1)'
},
tooeasy: {
text: 'Too easy, leave',
color: 'rgba(176, 141, 162, 1)'
},
easy: {
text: 'Xanax CD, No Dmg',
color: 'rgba(161, 248, 161, 1)'
},
easy1: {
text: 'Xanax CD, Low to Med Dmg',
color: 'rgba(192, 255, 062, 1)'
},
easy2: {
text: 'Xanax CD, Med-High Dmg',
color: 'rgba(255, 69, 0, 1)'
},
medium: {
text: 'No Drug CD, No Dmg',
color: 'rgba(161, 248, 161, 1)'
},
medium1: {
text: 'No Drug CD, Low-Med Dmg',
color: 'rgba(192, 255, 062, 1)'
},
medium2: {
text: 'No Drug CD, Med-High Dmg',
color: 'rgba(255, 69, 0, 1)'
},
hard: {
text: 'Vicodin CD, No Dmg',
color: 'rgba(161, 248, 161, 1)'
},
impossible2: {
text: 'Vicodin CD, Low-Med Dmg',
color: 'rgba(192, 255, 062, 1)'
},
hard2: {
text: 'Vicodin CD, Med-High Dmg',
color: 'rgba(255, 69, 0, 1)'
},
holders: {
text: 'Level holder to Spank!',
color: 'rgba(065, 105, 225, 1)'
},
stalemate: {
text: 'Avoid - Stalemate!',
color: 'rgba(139, 026, 026, 1)'
},
impossible5: {
text: 'Impossible, maybe Dec-2015?',
color: 'rgba(205, 055, 000, 1)'
},
impossible6: {
text: 'Impossible, maybe 2016?',
color: 'rgba(139, 026, 026, 1)'
},
impossible7: {
text: 'Impossible, maybe 2017?',
color: 'rgba(139, 026, 026, 1)'
}
};
var enemyTags = JSON.parse(localStorage.vinkuunEnemyTags || '{}');
function addEnemyTagging() {
GM_addStyle(
'select.vinkuun-enemeyDifficulty { font-size: 12px; vertical-align: text-bottom }' +
'.member-list li div.status, .member-list li div.act-cont { font-weight: bold }'
);
var $list = $MAIN.find('.member-list > li').each(function() {
var $this = $(this);
var id = $this.find('.user.name').eq(0).attr('href').match(/XID=(\d+)/)[1];
$this.find('.member-icons').prepend(createDropdown($this, id));
});
}
function createDropdown($li, id) {
var $dropdown = $('<select>', {'class': 'vinkuun-enemeyDifficulty'}).on('change', function() {
enemyTags[id] = $(this).val();
localStorage.vinkuunEnemyTags = JSON.stringify(enemyTags);
updateColor($li, id);
});
$.each(TAGS, function(key, value) {
var $el = $('<option>', {value: key, text: value.text});
if (enemyTags[id] && key === enemyTags[id]) {
$el.attr('selected', 'selected');
}
$dropdown.append($el);
});
updateColor($li, id);
return $dropdown;
}
function updateColor($li, id) {
if (enemyTags[id]) {
$li.css('background-color', TAGS[enemyTags[id]].color);
}
}
// ============================================================================
// --- MAIN
// ============================================================================
/**
* Shows/Hides the control panel according to the current tab
* @param {jQuery-Object} $element control panel
*/
function addUrlChangeCallback($element) {
var urlChangeCallback = function () {
if (window.location.hash === '#/tab=main' || window.location.hash === '') {
$element.show();
} else {
$element.hide();
}
};
// call it one time to show/hide the panel after the page has been loaded
urlChangeCallback();
// listen to a hash change
window.onhashchange = urlChangeCallback;
}
/**
* Initialises the script's features
*/
function init() {
var $warBaseExtendedPanel = $('#vinkuun-extendedWarBasePanel');
if ($warBaseExtendedPanel.length !== 0) {
$warBaseExtendedPanel.empty();
} else {
$warBaseExtendedPanel = $('<div>', { id:'vinkuun-extendedWarBasePanel' });
$MAIN.before($warBaseExtendedPanel);
}
var $title = $('<div>', { 'class': 'title-black m-top10 title-toggle tablet active top-round', text: 'War Base Extended' });
$MAIN.before($title);
var $panel = $('<div>', { 'class': 'cont-gray10 bottom-round cont-toggle' });
$MAIN.before($panel);
$warBaseExtendedPanel.append($title).append($panel);
enableWarBaseLayout();
addWarBaseFilter($panel);
addEnemyTagging();
addUrlChangeCallback($warBaseExtendedPanel);
}
try {
// observer used to apply the filter after the war base was loaded via ajax
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
// The main content is being added to the div
if (mutation.addedNodes.length === 19) {
init();
}
});
});
// start listening for changes
var observerTarget = $MAIN[0];
var observerConfig = { attributes: false, childList: true, characterData: false };
observer.observe(observerTarget, observerConfig);
} catch (err) {
console.log(err);
}