NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name Klanowicze online // @author Reskiezis // @version 1.0 // @match http://*.margonem.pl/ // @match http://*.margonem.com/ // @grant none // @license MIT // ==/UserScript== ((Engine, hero, $) => { 'use strict' const createStorage = () => { let storage = {} try { storage = JSON.parse( localStorage.getItem('klanowicze_online') ) } catch(error) {} //assigns object to storage const setStorage = object => { const modifiedStorage = { ...storage, ...object } storage = modifiedStorage localStorage.setItem( 'klanowicze_online', JSON.stringify(modifiedStorage) ) } const getStorage = () => ({ ...storage }) return { setStorage, getStorage } } const { setStorage, getStorage } = createStorage() let state = { wasMembersHidden: false, top: '10px', left: '200px', ...getStorage() } //assigns object to state const setState = object => { state = { ...state, ...object } } //assigns object to state and storage const updateMemory = object => { setState(object) setStorage(object) } //Start UI const appendCorners = element => { const cor1 = document.createElement('div') Object.assign(cor1.style, { background: 'url(img/tip-cor.png) no-repeat 0px 0px', position: 'absolute', top: '-6px', left: '-6px', width: '35px', height: '23px' }) const cor2 = document.createElement('div') Object.assign(cor2.style, { background: 'url(img/tip-cor.png) no-repeat -35px 0px', position: 'absolute', bottom: '-6px', right: '-6px', width: '35px', height: '23px' }) element.appendChild(cor1) element.appendChild(cor2) } const container = document.createElement('div') container.id = 'klanowicze-online' container.classList.add('default-cursor') Object.assign(container.style, { boxSizing: 'border-box', position: 'absolute', left: state.left, top: state.top, border: '3px gold double', color: '#eeeeee', width: '210px', backgroundColor: 'black', fontSize: '16px', zIndex: 500 }) const title = document.createElement('div') title.textContent = 'Klanowicze online' Object.assign(title.style, { fontSize: '1.1em', textAlign: 'center', fontWeight: 'bold', borderBottom: '1px solid gold', padding: '2px' }) container.appendChild(title) const membersTable = document.createElement('table') Object.assign(membersTable.style, { fontSize: '0.7em', width: '100%', borderCollapse: 'collapse', tableLayout: 'fixed' }) const membersTableWrapper = document.createElement('div') membersTableWrapper.hidden = state.areMembersHidden membersTableWrapper.style.padding = '1px' membersTableWrapper.appendChild(membersTable) container.appendChild(membersTableWrapper) const hideMembersButton = document.createElement('div') hideMembersButton.classList.add('do-action-cursor') hideMembersButton.textContent = state.areMembersHidden ? 'Rozwiń' : 'Zwiń' Object.assign(hideMembersButton.style, { fontSize: '0.8rem', textAlign: 'center', borderTop: '1px solid gold' }) container.appendChild(hideMembersButton) appendCorners(container) $(container).draggable({ cancel: 'table', //can't drag membersTable stop: function(){ const { top, left } = container.style updateMemory({ top, left }) } }) //style table rows and cells const tableStyle = document.createElement('style') tableStyle.textContent = ` .ko-row { border: solid; border-width: 1px 0; border-color: #5d5006; height: 1.6em; } .ko-row:hover { background: #3c3c16; } .ko-row:first-child { border-top: none; } .ko-row:last-child { border-bottom: none; } .ko-row > * { vertical-align: middle; } .ko-add-to-group-cell, .ko-nick-cell { user-select: none; } .ko-add-to-group-cell:hover, .ko-nick-cell:hover { color: #eaeb74; } .ko-add-to-group-cell { text-align: center; width: 12px; } .ko-map-cell { text-align: right; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } ` document.body.appendChild(tableStyle) //End UI const startWritingMessageTo = nick => { const chatInput = document.querySelector( 'div[data-section="chat"] .input-wrapper input' ) chatInput.value = `@${nick} ` chatInput.focus() } const chatWith = nick => () => startWritingMessageTo(nick) const addToGroup = id => () => window._g(`party&a=inv&id=${id}`) const fetchMembers = () => new Promise(resolve => { //super API bulwo const clan = Engine.clan ? { ...Engine.clan } //shallow copy : Engine.clan if(!clan) Engine.clan = { updateMembers(){} } _g(`clan&a=members`, ({ members2 }) => { Engine.clan = clan if(!members2){ resolve(null) return } resolve(members2) }) }) // [ id, nick, lvl, prof, map, x, y, ?, onlineStatus, icon ] const MEMBER_TUPLE_LENGTH = 10 const renderOnlineMembers = members => { if(members === null) return const membersTableBody = document.createElement('tbody') let onlineMembersCount = 0 let wasHeroCounted = false for(let i = 0; i <= members.length; i += MEMBER_TUPLE_LENGTH){ const onlineStatus = members[i+8] if(onlineStatus !== 'online') continue onlineMembersCount++ const nick = members[i+1] if(nick === hero.nick){ wasHeroCounted = true continue } const id = members[i] const lvl = members[i+2] const prof = members[i+3] const map = members[i+4] const x = members[i+5] const y = members[i+6] const row = membersTableBody.insertRow() row.classList.add('ko-row') const addToGroupCell = row.insertCell() addToGroupCell.textContent = '+' addToGroupCell.dataset.tip = 'Dodaj do grupy' addToGroupCell.classList.add('ko-add-to-group-cell', 'do-action-cursor') addToGroupCell.addEventListener('click', addToGroup(id)) const nickCell = row.insertCell() nickCell.textContent = `${nick} (${lvl}${prof})` nickCell.classList.add('ko-nick-cell', 'do-action-cursor') nickCell.addEventListener('click', chatWith(nick)) const mapCell = row.insertCell() mapCell.textContent = map mapCell.dataset.tip = `${map} (${x},${y})` mapCell.classList.add('ko-map-cell') } if(!wasHeroCounted) onlineMembersCount++ title.dataset.tip = onlineMembersCount === 1 ? 'Jesteś tylko ty' : `${onlineMembersCount} klanowiczów (łącznie z tobą)` if(membersTable.tBodies.length === 0){ membersTable.appendChild(membersTableBody) return } membersTable.replaceChild(membersTableBody, membersTable.tBodies[0]) } const fetchAndRenderOnlineMembers = () => fetchMembers().then(renderOnlineMembers) let fetchMembersInterval = null const startMembersFetching = () => { fetchAndRenderOnlineMembers() fetchMembersInterval = setInterval(fetchAndRenderOnlineMembers, 10000) } const stopMembersFetching = () => { clearInterval(fetchMembersInterval) } const handleHideMembersButtonClick = () => { const modifiedAreMembersHidden = !state.areMembersHidden membersTableWrapper.hidden = modifiedAreMembersHidden updateMemory({ areMembersHidden: modifiedAreMembersHidden }) if(modifiedAreMembersHidden){ stopMembersFetching() hideMembersButton.textContent = 'Rozwiń' return } startMembersFetching() hideMembersButton.textContent = 'Zwiń' } hideMembersButton.addEventListener('click', handleHideMembersButtonClick) const getDoggoImage = () => { const doggo = new Image doggo.src = 'https://i.imgur.com/jti8ksH.png' doggo.style.width = '100%' return doggo } const loadQueuePush = fn => { if(Engine.allInit){ fn() return } setTimeout(loadQueuePush, 2000, fn) } loadQueuePush(() => { if(!hero.clan) return if(state.areMembersHidden || startMembersFetching(), hero.clan.id === 13757 && Engine.worldName === 'hutena') container.replaceChild(getDoggoImage(), title) document.body.appendChild(container) }) })(window.Engine, window.Engine.hero.d, window.$)