Filter things out of the war base
// ==UserScript== // @name Warbase Filters // @namespace somenamespace // @version 0.5.1 // @description Filter things out of the war base // @author tos // @include *.torn.com/factions.php?step=your* // @grant GM_addStyle // ==/UserScript== animation_enabled = true animation_duration = 5 //minutes extended_desc_hide = true difficulty_colors = { 0: '#e0f2f2',//blue 1: '#e0f2e9', 2: '#e0f2e0',//green 3: '#e6f2e0', 4: '#ebf2e0', 5: '#f2f2e0',//yellow 6: '#f2ebe0', 7: '#f2e6e0', 8: '#f2e0e0',//red 9: '#f2d0d0', 10: '#f2c0c0', 11: 'rgb(255,0,0)', } GM_addStyle(` .wb_extended.f-war-list .descriptions { display: none; } .wb_extended.f-war-list .act { padding-bottom: 0 !important; border-radius: 5px !important; } #wb_filter_wrap .arrow-wrap {display: block;} #wb_filter_wrap i {margin: 8px 12px 0px 0px;} #wb_filter_wrap .active i {margin: 11px 12px 0px 0px;} #warbase_filters { display: flex;} #warbase_filters .wb_content_left { display: inline-flex; flex-direction: column; padding: 5px; width: 40%; vertical-align: top;} #warbase_filters .wb_content_middle { display: inline-flex; flex-direction: column; justify-content: center; padding: 5px; width: 30%;} #warbase_filters .wb_content_right { display: inline-flex; flex-direction: column; padding: 5px; width: 30%;} #warbase_filters .wb_content_right span{ justify-content: flex-end;} #warbase_filters .wb_content_right input{ margin-right: 0px !important; margin-left: 3px;} #warbase_filters .wbTotals_col_left{ display: inline-flex; flex-direction: column; font-size: 110%; font-weight: bold; width: auto;} #warbase_filters .wbTotals_col_right{ display: inline-flex; flex-direction: column; font-size: 110%; text-align: right; font-weight: normal; width: auto;} #warbase_filters .wbTotals_title{ padding: 1px 0px 1px 10px;} #warbase_filters .wbTotals { padding: 1px 0px;} #warbase_filters .filter-title { display: inline-flex; background-color: #BABABA; border-radius: 5px 0px 0px 5px; align-items: center; font-size: 150%; padding: 5px;} #warbase_filters .filter-content { display: inline-flex; flex-direction: column; background-color: #DBDBDB; border-radius: 0px 5px 5px 0px; padding: 3px 0px;} #warbase_filters .filter-row { display: flex; flex-wrap: wrap;} #warbase_filters span{ display: flex; flex-wrap: wrap; min-height: 3px; padding: 1px 10px;} #warbase_filters input[type="checkbox"] { margin-right: 3px;} #warbase_filters input[type="number"] { background: transparent; border-bottom: 1px solid black; text-align: center; width: 50px;} .f-chain {border-radius: 14px} @keyframes linkFade { 0% {color: #969;} 95% {color: #769;} 100% {color: #069;}} .animation_colorfade { animation-name: linkFade; animation-duration: ${animation_duration * 60}s;} @keyframes chainIconFade { from {background-color: #b2b2b2;} to {background-color: #f2f2f2;}} .animation_colorblind { animation-name: chainIconFade; animation-duration: ${animation_duration * 60}s;} #warbase_results { display: none;} #warbase_results .wbResults_placeholder { font-weight: bold; padding: 10px;} #wars_extended { margin-bottom:10px;} #wars_extended .descriptions-new { display: block; margin: 0; float: left; background-color: transparent; border-radius: 0; box-shadow: none; height: auto; width: 100%;} .wb_difficulty_DIV { float: right; vertical-align: middle; } .wb_difficulty_INPUT { background: white; border-radius: 3px; box-shadow: 0px 0px 2px #f2f2f2; text-align: center; float: right; height: 100%; width: 70%; margin: 12% 5%; padding: 3px 0px; } .wb_hide { overflow: hidden; height: 0;} `) const default_options = { fed: false, traveling: false, online: true, idle: true, offline: true, hosp: true, hosp_time: 0, level: false, level_min: 0, level_max: 100, extended: false, territories_inverted: false, colorblind: false, filters_collapse: false, } let filters = Object.assign(default_options, JSON.parse(localStorage.getItem('torn_wb_filters'))) //torn_warbase_filters const storeFilters = () => localStorage.setItem('torn_wb_filters', JSON.stringify(filters)) let enemy_difficulty = JSON.parse(localStorage.getItem('torn_enemy_difficulty')) || {} //torn_enemy_difficulties const difficulty_max = Object.keys(difficulty_colors).length - 1 let faction_nodes = {} let faction_totals = {} const count_enemies = (obj) => { let enemy_totals = {total:0, ok:0, hidden:0} for (const factionID of Object.keys(obj)) { enemy_totals.total += faction_totals[factionID].total enemy_totals.ok += faction_totals[factionID].ok enemy_totals.hidden += faction_totals[factionID].hidden } return enemy_totals } const run_filters = (node) => { const factionID = node.querySelector('.t-blue').href.split('&')[1].replace('=', '') let target_TOTALS = {total: 0, ok: 0, hidden: 0} faction_totals[factionID] = {} for (const enemy_LI of node.querySelector('.member-list').children) { target_TOTALS.total += 1 const status = enemy_LI.querySelector('.status').firstElementChild.textContent const online_status_icon = enemy_LI.querySelector('#icon1') || enemy_LI.querySelector('#icon2') || enemy_LI.querySelector('#icon62') const online_status = online_status_icon.title.replace('<b>', '').replace('</b>', '') //const bountied = enemy_LI.querySelector('#icon13') || false //if(bountied) enemy_LI.style.backgroundColor ='#F0D9D2'; let hosp_time = 0 if (enemy_LI.querySelector('#icon15')) { const time_string = enemy_LI.querySelector('#icon15').title.split('\'>')[1].split('</')[0] hosp_time = parseInt(time_string.split(':')[0]) * 3600 + parseInt(time_string.split(':')[1]) * 60 + parseInt(time_string.split(':')[2]) } let jail_time = 0 if (enemy_LI.querySelector('#icon16')) { const time_string = enemy_LI.querySelector('#icon16').title.split('\'>')[1].split('</')[0] jail_time = parseInt(time_string.split(':')[0]) * 3600 + parseInt(time_string.split(':')[1]) * 60 + parseInt(time_string.split(':')[2]) } const level = parseInt(enemy_LI.querySelector('.lvl .t-hide').nextSibling.textContent) const userID = enemy_LI.querySelector('.name').href.split('XID=')[1] const li_icon_wrap = enemy_LI.querySelector('.member-icons') if (!enemy_LI.querySelector('.wb_difficulty_DIV')) { const difficulty_DIV = document.createElement('DIV') difficulty_DIV.className = 'wb_difficulty_DIV' difficulty_DIV.innerHTML = `<input class="wb_difficulty_INPUT" type="number" min=0 max=${difficulty_max} data-userID="${userID}"></input>` li_icon_wrap.append(difficulty_DIV) const difficulty_INPUT = enemy_LI.querySelector('.wb_difficulty_INPUT') difficulty_INPUT.addEventListener('change', (event) => { if (difficulty_INPUT.value < 0) difficulty_INPUT.value = 0 if (difficulty_INPUT.value > difficulty_max) difficulty_INPUT.value = difficulty_max const difficulty = difficulty_INPUT.value if (difficulty === '') { if (enemy_difficulty['ID_'+ userID]) delete enemy_difficulty['ID_'+ userID] for (const this_user of document.querySelectorAll(`.wb_difficulty_INPUT[data-userID="${userID}"`)) { this_user.parentElement.parentElement.parentElement.style.backgroundColor = 'initial' this_user.value = difficulty } } else { enemy_difficulty['ID_'+ userID] = difficulty for (const this_user of document.querySelectorAll(`.wb_difficulty_INPUT[data-userID="${userID}"`)) { this_user.parentElement.parentElement.parentElement.style.backgroundColor = difficulty_colors[enemy_difficulty['ID_'+ userID]] this_user.value = difficulty } } localStorage.setItem('torn_enemy_difficulty', JSON.stringify(enemy_difficulty)) }) } if (enemy_difficulty['ID_'+ userID]) { enemy_LI.querySelector('.wb_difficulty_INPUT').value = enemy_difficulty['ID_'+ userID] enemy_LI.style.backgroundColor = difficulty_colors[enemy_difficulty['ID_'+ userID]] } if (status === 'Okay') target_TOTALS.ok +=1 const hide = (!filters.fed && status === 'Federal') || (!filters.traveling && status === 'Traveling') || (!filters.online && online_status === 'Online') || (!filters.idle && online_status === 'Idle') || (!filters.offline && online_status === 'Offline') || (filters.hosp && (filters.hosp_time * 60 < hosp_time || filters.hosp_time * 60 < jail_time)) || (filters.level && (filters.level_min > level || filters.level_max < level)) enemy_LI.style.display = hide ? 'none' : 'list-item' if (enemy_LI.style.display === 'none') target_TOTALS.hidden += 1 } faction_totals[factionID].total = target_TOTALS.total faction_totals[factionID].ok = target_TOTALS.ok faction_totals[factionID].hidden = target_TOTALS.total - target_TOTALS.hidden const warbase_totals = count_enemies(faction_totals) for (const totals_span of document.querySelectorAll('.wbTotals')) { const totals_controls = totals_span.className.split('wb_')[1] if (totals_controls === 'counted') totals_span.textContent = Object.keys(faction_totals).length +' / '+ totals_span.textContent.split('/')[1] else totals_span.textContent = warbase_totals[totals_controls] +' / '+ warbase_totals.total } } const observer = new MutationObserver((mutations) => { for (const mutation of mutations) { for (const node of mutation.addedNodes) { if (node.className && node.className === 'faction-respect-wars-wp' && !document.querySelector('#wb_filter_wrap')) { faction_nodes = {} faction_totals = {} const faction_main_wrap = document.querySelector('#faction-main') const respect_wars_wrap = document.querySelector('#faction-main .faction-respect-wars-wp') const wars_UL = respect_wars_wrap.querySelector('.f-war-list') const territory_wrap = document.querySelector('#faction-wars-wp') let fac_count_total = 0 for (const faction_tab of respect_wars_wrap.querySelector('.f-war-list').children) { if (faction_tab.className !== 'inactive' && faction_tab.className !== 'clear') fac_count_total += 1 } //Filter DIV------------------------------------------------------------------------------------------------------------------------------------- const filter_DIV = document.createElement('DIV') filter_DIV.id = 'wb_filter_wrap' filter_DIV.innerHTML = `<div class="title-black m-top10 ${filters.filters_collapse ? 'border-round': 'top-round active' }"> <div class="arrow-wrap"> <i class="accordion-header-arrow right"></i> </div> War Base Filters </div> <div class="cont-gray map-wrap bottom-round " id="warbase_filters"> <div class="wb_content_left"> <div class="filter-row"> <div class="filter-title">Show</div> <div class="filter-content"> <div class="filter-row"> <span><input type="checkbox" class="wbFilter wb_fed">Federal</span> <span><input type="checkbox" class="wbFilter wb_traveling">Traveling</span> </div> <div class="filter-row"> <span><input type="checkbox" class="wbFilter wb_online">Online</span> <span><input type="checkbox" class="wbFilter wb_idle">Idle</span> <span><input type="checkbox" class="wbFilter wb_offline">Offline</span> </div> <span></span> <span class="filter-row"><input type="checkbox" class="wbFilter wb_hosp">Hosp/Jail time < <input type="number" class="wbFilter wb_hosp_time" min="0"> minutes</span> <span class="filter-row"><input type="checkbox" class="wbFilter wb_level">Level<input type="number" min="0" max="100" class="wbFilter wb_level_min">to<input type="number" min="0" max="100" class="wbFilter wb_level_max"></span> </div> </div> </div> <div class="wb_content_middle"> <div class="filter_row"> <div class="wbTotals_col_left"> <span class="filter-row wbTotals_title">Factions Loaded: </span> <span class="filter-row wbTotals_title">Enemies Filtered: </span> <span class="filter-row wbTotals_title">Enemies Okay: </span> </div> <div class="wbTotals_col_right"> <span class="filter-row wbTotals wb_counted">0 / ${fac_count_total}</span> <span class="filter-row wbTotals wb_hidden">...</span> <span class="filter-row wbTotals wb_ok">...</span> </div> </div> </div> <div class="wb_content_right"> <span class="filter-row">Extended Warbase<input type="checkbox" class="wbFilter wb_extended"></span> <span class="filter-row">Territories on Top<input type="checkbox" class="wbFilter wb_territories_inverted"></span> <span class="filter-row">Color Blind Mode<input type="checkbox" class="wbFilter wb_colorblind"></span> </div> </div>` faction_main_wrap.insertBefore(filter_DIV, respect_wars_wrap) //Show/Hide button for respect wars------------------------------------------------------------------------------------------------------------------ const banner = respect_wars_wrap.querySelector('.f-msg') wars_UL.style.display = 'block' banner.onclick = () => wars_UL.classList.toggle('wb_hide') //War Base Extended DIV------------------------------------------------------------------------------------------------------------------------------ const warlist_DIV = document.createElement('DIV') warlist_DIV.id = 'warbase_results' warlist_DIV.innerHTML = `<div class="title-black m-top10 top-round">War Base Extended</div> <div class="cont-gray map-wrap bottom-round"> <div class="wbResults_placeholder">Updates on faction tab clicks...</div> <ul id="wars_extended" class="f-war-list war-old"> <li class="clear"></li> </ul> </div>` faction_main_wrap.insertBefore(warlist_DIV, territory_wrap) //Event Listeners for Filter DIV---------------------------------------------------------------------------------------------------------------------- const wb_filter_title = document.querySelector('#wb_filter_wrap .title-black') const wb_filter_content = document.querySelector('#warbase_filters') filters.filters_collapse ? wb_filter_content.style.display = 'none': wb_filter_content.style.display = 'flex' wb_filter_title.addEventListener('click', (event) => { if (filters.filters_collapse) { wb_filter_title.classList.add('top-round') wb_filter_title.classList.add('active') wb_filter_title.classList.remove('border-round') wb_filter_content.style.display = 'flex' filters.filters_collapse = false } else { wb_filter_title.classList.remove('top-round') wb_filter_title.classList.remove('active') wb_filter_title.classList.add('border-round') wb_filter_content.style.display = 'none' filters.filters_collapse = true } storeFilters() }) const filter_inputs = document.querySelectorAll('.wbFilter') for (const wbFilter of filter_inputs) { const filter_controls = wbFilter.className.split('wb_')[1] switch (wbFilter.type) { case 'checkbox': wbFilter.checked = filters[filter_controls] wbFilter.addEventListener('change', (event) => { filters[filter_controls] = event.target.checked storeFilters() switch (filter_controls) { case 'extended': if (event.target.checked) { document.querySelector('#warbase_results').style.display = 'block' wars_UL.classList.add('wb_extended') } else { document.querySelector('#warbase_results').style.display = 'none' wars_UL.classList.remove('wb_extended') } break case 'territories_inverted': if (event.target.checked) faction_main_wrap.insertBefore(territory_wrap, respect_wars_wrap) else { faction_main_wrap.insertBefore(respect_wars_wrap, territory_wrap) faction_main_wrap.insertBefore(document.querySelector('#warbase_results'), territory_wrap) } break case 'colorblind': break default: if (document.querySelector('#faction-main .faction-respect-wars-wp .descriptions')) { run_filters(document.querySelector('#faction-main .faction-respect-wars-wp .descriptions')) } if (Object.keys(faction_nodes).length > 0) { for (const facID of Object.keys(faction_nodes)) { run_filters(faction_nodes[facID]) } } break } }) break case 'number': wbFilter.value = filters[filter_controls] wbFilter.addEventListener('change', (event) => { filters[filter_controls] = event.target.value storeFilters() switch (filter_controls) { default: if (document.querySelector('#faction-main .faction-respect-wars-wp .descriptions')) { run_filters(document.querySelector('#faction-main .faction-respect-wars-wp .descriptions')) } if (Object.keys(faction_nodes).length > 0) { for (const facID of Object.keys(faction_nodes)) { run_filters(faction_nodes[facID]) } } break } }) break default: break } } //Set Extended and Territories inverted-------------------------------------------------------------------------------------------------------------------- if (filters.extended) { warlist_DIV.style.display = 'block' wars_UL.classList.add('wb_extended') } if (filters.territories_inverted) faction_main_wrap.insertBefore(territory_wrap, respect_wars_wrap) } //Observing for tabs opening-------------------------------------------------------------------------------------------------------------------------------- if (node.className && node.className === 'descriptions') { if (node.querySelector('.member-list')) { const factionID = node.querySelector('.t-blue').href.split('&')[1].replace('=', '') if (animation_enabled) { const faction_link = node.parentElement.querySelector('.act .name .t-blue') if (faction_link.className.includes('animation_colorfade')) { faction_link.classList.remove('animation_colorfade') void faction_link.offsetWidth } faction_link.classList.add('animation_colorfade') faction_link.addEventListener("animationend", (anim) => anim.target.classList.remove('animation_colorfade')) if (filters['colorblind']) { const chain_icon = node.parentElement.querySelector('.act .f-chain') if (chain_icon.className.includes('animation_colorblind')) { chain_icon.classList.remove('animation_colorblind') void chain_icon.offsetWidth } chain_icon.classList.add('animation_colorblind') chain_icon.addEventListener("animationend", (anim) => anim.target.classList.remove('animation_colorblind')) } } //clone node for extended war base const wars_extended = document.querySelector('#wars_extended') faction_nodes[factionID] = node.cloneNode(true) faction_nodes[factionID].id = factionID faction_nodes[factionID].className = 'descriptions-new' run_filters(faction_nodes[factionID]) if (!document.querySelector('#'+factionID)) { wars_extended.parentElement.querySelector('.wbResults_placeholder').style.display = 'none' wars_extended.insertBefore(faction_nodes[factionID], wars_extended.lastElementChild) } else { wars_extended.replaceChild(faction_nodes[factionID], document.querySelector('#'+factionID)) } run_filters(node) } } } } }); const wrapper = document.querySelector('#faction-main') observer.observe(wrapper, { subtree: true, childList: true })