// ==UserScript== // @name TimeNpc // @namespace https://github.com/MyRequiem/comfortablePlayingInGW // @description На главной странице выводит время, оставшееся до взятия квеста и сcылку на NPC, у которого в последний раз брали квест. Звуковое оповещение. Умеет выводить список NPC с информацией о них для каждого острова. // @id comfortablePlayingInGW@MyRequiem // @updateURL https://raw.githubusercontent.com/MyRequiem/comfortablePlayingInGW/master/separatedScripts/TimeNpc/timeNpc.meta.js // @downloadURL https://raw.githubusercontent.com/MyRequiem/comfortablePlayingInGW/master/separatedScripts/TimeNpc/timeNpc.user.js // @include https://*gwars*/me.php* // @include https://*gwars*/me/* // @include https://*gwars*/npc.php?id=* // @grant none // @license MIT // @version 2.37-140522 // @author MyRequiem [https://www.gwars.io/info.php?id=2095458] // ==/UserScript== /*global unsafeWindow */ /*jslint browser: true, maxlen: 80, vars: true, nomen: true, plusplus: true, devel: true, regexp: true */ /*eslint-env browser */ /*eslint no-useless-escape: 'warn', linebreak-style: ['error', 'unix'], quotes: ['error', 'single'], semi: ['error', 'always'], eqeqeq: 'error', curly: 'error' */ /*jscs:disable requireMultipleVarDecl, requireVarDeclFirst */ /*jscs:disable disallowKeywords, disallowDanglingUnderscores */ /*jscs:disable validateIndentation */ (function () { 'use strict'; // ================= НАСТРОЙКИ ========================== var soundNPC = 17; // номер звука, когда пора делать квест (0 - без звука) // ============== КОНЕЦ НАСТРОЕК ======================== /** * @class General * @constructor */ var General = function () { /** * @property root * @type {Object} */ this.root = this.getRoot(); /** * @property doc * @type {Object} */ this.doc = this.root.document; /** * @property loc * @type {String} */ this.loc = this.root.location.href; /** * @property st * @type {Object} */ this.st = this.root.localStorage; /** * @property STNAME * @type {String} */ this.STNAME = 'timeNpc'; /** * @property imgPath * @type {String} */ this.imgPath = 'https://raw.githubusercontent.com/MyRequiem/' + 'comfortablePlayingInGW/master/imgs/'; /** * @property domain * @type {String} */ this.domain = this.doc.domain; }; /** * @lends General.prototype */ General.prototype = { /** * @method getRoot * @return {Object} */ getRoot: function () { var rt = typeof unsafeWindow; return rt !== 'undefined' ? unsafeWindow : window; }, /** * @method setData * @param {Array} data */ setData: function (data) { this.st.setItem(this.STNAME, data.join('|')); }, /** * @method getData * @return {Array} */ getData: function () { var stData = this.st.getItem(this.STNAME); if (stData) { return stData.split('|'); } stData = ['1', '', '']; this.setData(stData); return stData; }, /** * @method $ * @param {string} id * @return {HTMLElement|null} */ $: function (id) { return this.doc.querySelector('#' + id); } }; var general = new General(); /** * @class AjaxQuery * @constructor */ var AjaxQuery = function () { /** * @method init * @param {String} url * @param {Function} onsuccess * @param {Function} onfailure */ this.init = function (url, onsuccess, onfailure) { var xmlHttpRequest = new XMLHttpRequest(); if (!xmlHttpRequest) { general.root.console.log('Error create xmlHttpRequest !!!'); return; } xmlHttpRequest.open('GET', url, true); xmlHttpRequest.send(null); var timeout = general.root.setTimeout(function () { xmlHttpRequest.abort(); }, 10000); xmlHttpRequest.onreadystatechange = function () { if (xmlHttpRequest.readyState === 4) { clearTimeout(timeout); if (xmlHttpRequest.status === 200) { onsuccess(xmlHttpRequest); } else { onfailure(); } } }; }; }; /** * @class PlaySound * @constructor */ var PlaySound = function () { /** * @method init * @param {int|String} sound */ this.init = function (sound) { if (sound && sound !== '0') { var audio = general.$('cpingw_audio'); if (!audio) { audio = general.doc.createElement('audio'); audio.setAttribute('id', 'cpingw_audio'); var divAudio = general.doc.createElement('div'); divAudio.setAttribute('style', 'display: none;'); divAudio.appendChild(audio); general.doc.body.appendChild(divAudio); } audio.volume = 0.3; audio.src = 'https://raw.githubusercontent.com/MyRequiem/' + 'comfortablePlayingInGW/master/sounds/' + sound + '.ogg'; // noinspection JSIgnoredPromiseFromCall audio.play(); } }; }; /** * @class TimeNpc * @constructor */ var TimeNpc = function () { /** * @property imgPath * @type {String} */ this.imgPath = general.imgPath + 'TimeNpc/'; /** * @property npc * @type {Object} */ this.npc = { g: ['2', '3', '6', '8', '10', '12'], z: ['1', '4', '5', '7', '9', '11'], p: ['16', '17', '18', '19', '20'] }; /** * @property tm * @type {int} */ this.tm = 1000; /** * @method clearNPCData */ this.clearNPCData = function () { general.$('dataNPC').innerHTML = ''; }; /** * @method setCloseButton */ this.setCloseButton = function () { general.$('dataNPC').innerHTML += ''; general.$('npsDataClose'). addEventListener('click', this.clearNPCData, false); general.$('imgSoundNPC').removeAttribute('checkscan'); }; /** * @method scanNPC * @param {int} ind * @param {Array} npcs */ this.scanNPC = function (ind, npcs) { if (!ind) { if (general.$('imgSoundNPC').getAttribute('checkscan')) { return; } this.clearNPCData(); general.$('imgSoundNPC').setAttribute('checkscan', 'yes'); } var url = 'https://' + general.domain + '/npc.php?id=' + npcs[ind], _this = this, tr, td; tr = general.doc.createElement('tr'); td = general.doc.createElement('td'); td.setAttribute('style', 'text-align: center;'); td.setAttribute('colspan', '3'); td.innerHTML = 'Загрузка...'; tr.appendChild(td); general.$('dataNPC').appendChild(tr); new AjaxQuery().init(url, function (xml) { var spanContent = general.doc.createElement('span'); spanContent.innerHTML = xml.responseText; if (/Вы находитесь в пути/.test(spanContent.innerHTML)) { general.$('dataNPC').lastElementChild.innerHTML = 'Вы в пути. Данные NPC не ' + 'доступны.'; _this.setCloseButton(); return; } var cssSelector1 = 'td[class="wb"][colspan="3"]' + '[bgcolor="#f0fff0"]', cssSelector2 = 'a[href*="/syndicate.php?id="]', cssSelector3 = 'td[class="wb"][align="left" ]' + '[width="100%"]>b', syndLink = spanContent.querySelector(cssSelector1). querySelector(cssSelector2), nameNPC = spanContent.querySelector(cssSelector3).innerHTML; general.$('dataNPC').lastElementChild.innerHTML = '' + '' + nameNPC + '' + '' + syndLink.nextSibling.nodeValue.replace(/^\s*/, '') + ''; ind++; if (npcs[ind]) { general.root.setTimeout(function () { _this.scanNPC(ind, npcs); }, _this.tm); return; } _this.setCloseButton(); }, function () { general.root.setTimeout(function () { if (!ind) { general.$('imgSoundNPC').removeAttribute('checkscan'); } _this.scanNPC(ind, npcs); }, _this.tm); }); }; /** * @method getTimeNow * @return {int} */ this.getTimeNow = function () { return new Date().getTime(); }; /** * @method goQuest */ this.goQuest = function () { var stData = general.getData(); general.$('timerNPC').innerHTML = '' + 'Взять квест'; if (stData[0]) { new PlaySound().init(soundNPC); } }; /** * @method showTimerNPC * @param {int} sec */ this.showTimerNPC = function (sec) { var timer = general.$('spanTimer'); // при переходе на личного NPC таймера не будет if (timer) { var s = sec, h = Math.floor(s / 3600); s -= h * 3600; var min = Math.floor(s / 60); s -= min * 60; h = h < 10 ? '0' + h : h; min = min < 10 ? '0' + min : min; s = s < 10 ? '0' + s : s; general.$('spanTimer').innerHTML = h + ':' + min + ':' + s; sec -= 1; var _this = this; if (sec > -1) { general.root.setTimeout(function () { _this.showTimerNPC(sec); }, 1000); } else { this.goQuest(); } } }; /** * @method init */ this.init = function () { // на главной странице личного NPC if (/\?nid=\d+/.test(general.loc)) { return; } /** * localStorage * [0] - звук вкл/выкл * [1] - ID NPC, у которого последний раз брали квест * [2] - время */ var stData = general.getData(); if (/gwars.*\/me(\/|\.php)/.test(general.loc)) { var mainDiv = general.doc.createElement('div'), target = general.doc.querySelector('td[rowspan="3"]' + '[valign="top"][bgcolor="#e9ffe9"]>' + 'div[style="padding-left:5px"]>' + 'a[href$="/home.friends.php"]').previousElementSibling, onoff = stData[0] ? 'On' : 'Off'; mainDiv.setAttribute('style', 'font-size: 8pt; ' + 'padding-left: 16px;'); target.parentNode.insertBefore(mainDiv, target); mainDiv.innerHTML = '[Z][G][P] Sound ' + onoff +
                    '' + '
'; var _this = this; general.$('imgSoundNPC').addEventListener('click', function () { var data = general.getData(), d = data[0], s = d ? 'Sound Off' : 'Sound On', img = this; img.src = _this.imgPath + (d ? 'soundOff.png' : 'soundOn.png'); img.setAttribute('title', s); img.setAttribute('alt', s); data[0] = d ? '' : '1'; general.setData(data); }, false); general.$('buttonNPC_Z').addEventListener('click', function () { _this.scanNPC(0, _this.npc.z); }, false); general.$('buttonNPC_G').addEventListener('click', function () { _this.scanNPC(0, _this.npc.g); }, false); general.$('buttonNPC_P').addEventListener('click', function () { _this.scanNPC(0, _this.npc.p); }, false); if (!stData[2]) { // время не установлено general.$('timerNPC').innerHTML = '' + 'Поговорите с NPC'; } else { if (this.getTimeNow() >= stData[2]) { // пора делать квест this.goQuest(); } else { // ждем general.$('timerNPC').innerHTML = 'NPC: ' + '[]'; var sec = Math. ceil((+stData[2] - this.getTimeNow()) / 1000); this.showTimerNPC(sec); } } return; } var talkNPC = general.doc. querySelector('td[class="wb"][valign="top"]'), talk = /\?id=(\d+)&talk=1/.exec(general.loc); // если id у NPC больше 20, то это не наш NPC if (talkNPC && talk && +talk[1] < 21) { stData[1] = talk[1]; // говорим с NPC, но время квеста еще не пришло var timer = /\[подождите (\d+) мин/.exec(talkNPC.innerHTML); if (timer) { stData[2] = +timer[1] * 60 * 1000 + this.getTimeNow(); general.setData(stData); return; } // если берем или отказываемся от квеста, // то стираем время из хранилища if (/Ваш ответ:/.test(talkNPC.innerHTML)) { stData[2] = ''; general.setData(stData); } } }; }; new TimeNpc().init(); }());