// ==UserScript== // @name MouseHunt GM // @namespace http://userscripts.org/users/295901 // @description Automatically sounds the hunter's horn and notifies about various events in the background. Displays desktop notifications when used with Autohotkey script. // @version 1.2.1 // @author Camarean // @license Creative Commons BY-NC-SA 3.0 // @include http://www.mousehuntgame.com/* // @include http://apps.facebook.com/mousehunt/* // @exclude http://www.mousehuntgame.com/ads/* // @exclude http://www.mousehuntgame.com/canvas/* // @downloadURL https://update.greasyfork.icu/scripts/2244/MouseHunt%20GM.user.js // @updateURL https://update.greasyfork.icu/scripts/2244/MouseHunt%20GM.meta.js // ==/UserScript== String.prototype.contains = function(str) { return this.indexOf(str) != -1; }; String.prototype.regexMatch = function(regex) { return regex.test(this); }; var browser = identifyBrowser(); var settings = loadSettings(); var currentVersion = '1.2.1'; var latestVersion = getValue('MouseHuntGM_LatestVersion', currentVersion); var newVersionAvailable = false; var nowTimeFull = new Date(); var nowTimeInMS = nowTimeFull.getTime(); var hud, sidebar; /* -------------------------------------------------------------------------------------------------------------------- Main -------------------------------------------------------------------------------------------------------------------- */ function initBot() { var pageHtml = document.getElementsByTagName('html')[0].innerHTML; if (pageHtml.contains('Lightning struck our server')) { document.title = 'Having server issues. Reloading in a few seconds. | MouseHunt'; window.setTimeout(function() { window.location.reload(); }, 10000); } else if (pageHtml.contains('Login to see your account')) { document.title = 'Not logged in | MouseHunt'; } else if (pageHtml.contains('MouseHunt will return shortly')) { document.title = 'Under maintenance | MouseHunt'; window.setTimeout(function() { window.location.reload(); }, 180000); } else { var hornTimeRemaining = parseInt(getBetween(pageHtml, '"next_activeturn_seconds":', ',')); var trapCheckTimeRemaining = calculateTrapCheck(settings.trapCheckTime, nowTimeFull); var cheeseRemaining = parseInt(getBetween(pageHtml, '"bait_quantity":', ',')); var rewardPending = pageHtml.contains('"has_puzzle":true'); var titlePercentage = getBetween(pageHtml, '"title_percentage":', ','); var currentHuntLocation = getBetween(pageHtml, '"location":"', '",'); var fixedHuntLocation = getValue('fixedHuntLocation', ''); var hornDelay = randomise(settings.minHornDelay, settings.maxHornDelay); var trapCheckDelay = randomise(settings.minTrapCheckDelay, settings.maxTrapCheckDelay); var nextHornTime = calculateNextTime(hornTimeRemaining + hornDelay, nowTimeInMS); var nextTrapCheckTime = calculateNextTime(trapCheckTimeRemaining + trapCheckDelay, nowTimeInMS); var hunterStatus = getHunterStatus(); var trapCheckInactive = true; var hornAttempts = 0; writeHudEnhancements(currentHuntLocation); preCountdownUpdates(); if (window.location.href == 'http://www.mousehuntgame.com/' || window.location.href == 'http://www.mousehuntgame.com/index.php' || window.location.href == 'http://www.mousehuntgame.com/turn.php' || window.location.href == 'http://www.mousehuntgame.com/journal.php') { var allowActivity = true; if (hornTimeRemaining == 0 && hunterStatus == 'Normal') { window.setTimeout(soundTheHorn, 5000); } else { initCountdown('HuntersCamp'); } } else { var allowActivity = false; if (window.location.href.contains('profile.php?snuid=')) { initCountdown('HuntersProfile'); } else { initCountdown('InactivePage'); } } } pageHtml = null; function initCountdown(mhPage) { switch (hunterStatus) { case 'Normal': switch (mhPage) { case 'HuntersCamp': if (trapCheckTimeRemaining < hornTimeRemaining && settings.trapCheckEnabled) { updateStatus('Waiting for next trap check time...'); } else { updateStatus('Waiting for next horn time...'); } break; case 'InactivePage': updateStatus('Autohunting has been disabled. Return to the \ Hunter\'s Camp to resume script activity.'); break; case 'HuntersProfile': var hpIntervalRemaining = randomise(settings.minHpInterval, settings.maxHpInterval) * 60; var nextHpRefresh = calculateNextTime(hpIntervalRemaining, nowTimeInMS); var titleMessage = 'Hunter\'s Profile'; updateStatus('Autohunting has been disabled. Return to the \ Hunter\'s Camp to resume script activity.'); countdownHuntersProfile(); break; } break; case 'KingsReward': document.getElementsByName('puzzle_answer')[0].focus(); var krTimeRemaining = randomise(settings.minKrInterval, settings.maxKrInterval) * 60; var nextKrRefresh = calculateNextTime(krTimeRemaining, nowTimeInMS); if (settings.krAlertEnabled) { var soundAlert = document.createElement('div'); soundAlert.innerHTML = '\ '; getPageElement('fb-root').appendChild(soundAlert); } var titleMessage = 'King\'s Reward is pending.'; updateStatus('Autohunting has been disabled. King\'s reward is pending.'); allowActivity = false; kingsRewardWatcher(); countdownKingsReward(); break; case 'InvalidLocation': var titleMessage = 'Invalid location'; updateStatus('Autohunting has been disabled. Thrown out of predefined hunting location.'); allowActivity = false; break; case 'NoCheese': var titleMessage = 'Out of cheese'; updateStatus('Autohunting has been disabled. You are out of cheese.'); allowActivity = false; break; } countdownHorn(); if (trapCheckInactive) { countdownTrapCheck(); trapCheckInactive = false; } function countdownHorn() { hornTimeRemaining = nextHornTime - (new Date()).getTime(); if (hornTimeRemaining >= 0) { document.title = formatTimer(parseInt(hornTimeRemaining / 1000)) + (titleMessage == undefined ? '' : ' | ' + titleMessage) + ' | MouseHunt'; updateHornTimer(formatTimer(parseInt(hornTimeRemaining / 1000))); window.setTimeout(countdownHorn, 1000); } else { if (allowActivity) { soundTheHorn(); } else { document.title = 'Horn Ready' + (titleMessage == undefined ? '' : ' | ' + titleMessage) + ' | MouseHunt'; } } } function countdownHuntersProfile() { hpTimeRemaining = nextHpRefresh - (new Date()).getTime(); if (hpTimeRemaining >= 0) { updateStatus('Autohunting has been disabled. Reloading hunter\'s profile in ' + formatTimerLong(parseInt(hpTimeRemaining / 1000))); window.setTimeout(countdownHuntersProfile, 1000); } else { window.location.reload(); } } function countdownKingsReward() { krTimeRemaining = nextKrRefresh - (new Date()).getTime(); if (krTimeRemaining >= 0) { updateStatus('Autohunting has been disabled. King\'s reward is pending. (Refreshing in ' + formatTimerLong(parseInt(krTimeRemaining / 1000)) + ')'); window.setTimeout(countdownKingsReward, 1000); } else { window.location.assign('http://www.mousehuntgame.com/'); } } function countdownTrapCheck() { trapCheckTimeRemaining = nextTrapCheckTime - (new Date()).getTime(); if (trapCheckTimeRemaining >= 0) { updateTrapCheckTimer(formatTimerLong(parseInt(trapCheckTimeRemaining / 1000))); window.setTimeout(countdownTrapCheck, 1000); } else { if (allowActivity && settings.trapCheckEnabled) { updateTrapCheckTimer('Now!'); updateStatus('Checking trap...'); window.location.assign('http://www.mousehuntgame.com/'); } else { updateTrapCheckTimer('Now!'); } } } } function extractData() { switch (browser) { case 'Firefox': case 'Opera': hornTimeRemaining = unsafeWindow.user.next_activeturn_seconds; cheeseRemaining = unsafeWindow.user.bait_quantity; rewardPending = unsafeWindow.user.has_puzzle; titlePercentage = unsafeWindow.user.title_percentage; currentHuntLocation = unsafeWindow.user.location; break; case 'Chrome': hornTimeRemaining = parseInt(getPageVariable('user.next_activeturn_seconds')); cheeseRemaining = parseInt(getPageVariable('user.bait_quantity')); rewardPending = getPageVariable('user.has_puzzle').toString() == 'true'; titlePercentage = getPageVariable('user.title_percentage'); currentHuntLocation = getPageVariable('user.location'); break; } nowTimeInMS = (new Date()).getTime(); hornDelay = randomise(settings.minHornDelay, settings.maxHornDelay); nextHornTime = calculateNextTime(hornTimeRemaining + hornDelay, nowTimeInMS); hunterStatus = getHunterStatus(); preCountdownUpdates(); initCountdown('HuntersCamp'); } function getHunterStatus() { if (rewardPending) return 'KingsReward'; else if (settings.locationLockEnabled && currentHuntLocation != fixedHuntLocation) return 'InvalidLocation'; else if (cheeseRemaining == 0) return 'NoCheese'; else return 'Normal'; } function kingsRewardWatcher() { var puzzleContainer = getPageElement('puzzleContainer'); if (puzzleContainer.innerHTML.contains('resume_hunting_blue')) { window.location.assign('http://www.mousehuntgame.com/'); } else { window.setTimeout(kingsRewardWatcher, 1000); } } function soundTheHorn() { var hornStatus = getPageElement('header').getAttribute('class'); if (hornStatus.contains('ready') || settings.forceHornEnabled) { document.title = 'Sounding the horn'; updateStatus('Sounding the horn...'); hornAttempts += 1; fireEvent(document.getElementsByClassName('hornbutton')[0].firstChild, 'click'); window.setTimeout(postHornEvent, 3000); } else { document.title = 'Updating timer data'; updateHornTimer('Updating...') updateStatus('Timers out of sync. Updating timer data...'); window.location.reload(); } function postHornEvent() { hornStatus = getPageElement('header').getAttribute('class'); if (hornStatus.contains('sounding')) { window.setTimeout(postHornEvent, 1000); } else if (hornStatus.contains('sounded')) { if (getPageElement('hornTitle').firstChild.firstChild.innerHTML.contains('reward')) { window.location.replace('http://www.mousehuntgame.com/'); } else { window.setTimeout(postHornEvent, 1000); } } else if (hornStatus.contains('ready')) { if (hornAttempts > 3 && trapCheckInactive) { document.title = 'Unable to sound the horn.'; updateStatus('Unable to sound the horn. Reloading...'); window.location.reload(); } else { soundTheHorn(); } } else { document.title = 'Updating timer data'; updateHornTimer('Updating...'); updateStatus('Updating timer data...'); hornAttempts = 0; window.setTimeout(extractData, 400); } } } function preCountdownUpdates() { hud.titlePercentage.innerHTML = titlePercentage; if (settings.locationLockEnabled) { updateLocation(currentHuntLocation == fixedHuntLocation ? fixedHuntLocation : '' + fixedHuntLocation + ''); } } } function getPage() { if (window.location.href.contains('apps.facebook.com/mousehunt')) return 'fb'; else if (window.location.href.contains('www.mousehuntgame.com')) return 'mhg'; } function loadSettings() { return { minHornDelay: getValue('minHornDelay', 20), maxHornDelay: getValue('maxHornDelay', 60), minTrapCheckDelay: getValue('minTrapCheckDelay', 20), maxTrapCheckDelay: getValue('maxTrapCheckDelay', 90), minKrInterval: getValue('minKrInterval', 15), maxKrInterval: getValue('maxKrInterval', 20), minHpInterval: getValue('minHpInterval', 15), maxHpInterval: getValue('maxHpInterval', 20), trapCheckEnabled: getValue('trapCheckEnabled', true), autoRedirectEnabled: getValue('autoRedirectEnabled', false), forceHornEnabled: getValue('forceHornEnabled', false), krAlertEnabled: getValue('krAlertEnabled', false), locationLockEnabled: getValue('locationLockEnabled', false), trapCheckTime: getValue('trapCheckTime', 0), updateSchedule: getValue('updateSchedule', 3) }; } function calculateNextTime(timeRemaining, now) { return now + (timeRemaining * 1000); } function calculateTrapCheck(setting, now) { var minute = now.getMinutes(); var second = now.getSeconds(); var tcTime = (setting * 60) - ((minute * 60) + second); return (minute >= setting) ? tcTime + 3600 : tcTime; } function checkForUpdates(version, timestamp) { GM_xmlhttpRequest({ method: 'GET', url: 'http://userscripts.org/scripts/source/97586.meta.js', onload: function(response) { if (response.status == 200) { setValue('MouseHuntGM_LastUpdateCheck', timestamp); var metaArray = response.responseText.split('\n'); for (var line in metaArray) { var meta = trimString(metaArray[line].substring(3)); if (meta.contains('UserScript==')) continue; if (meta.contains('@version')) { var metaVersion = trimString(meta.substring(8)); if (version != metaVersion) { setValue('MouseHuntGM_LatestVersion', metaVersion); } } } } } }); } function formatTimer(time) { var seconds = time % 60; return parseInt(time / 60) + (seconds < 10 ? ':0' : ':') + seconds; } function formatTimerLong(time) { var minutes = parseInt(time / 60); var seconds = time % 60; return minutes + (minutes == 1 ? ' minute' : ' minutes') + ' and ' + seconds + ' seconds'; } // writeCorrections function contributed by userscripts.org user "bartsim". function writeCorrections() { function correct(event) { switch (event.target.id) { case 'componentCategories': event.target.style.paddingLeft = '14px'; event.target.style.width = '521px'; break; case 'availableComponentsContainer': event.target.style.marginLeft = '6px'; event.target.style.width = '536px'; break; case 'selectedComponentsContainer': event.target.style.marginLeft = '545px'; break; } } if (navigator.platform.contains('Linux') && browser == 'Firefox') { var rootNode = document.getElementsByTagName('html')[0]; rootNode.addEventListener('DOMNodeInserted', correct, false); var leftCol = document.getElementsByClassName('campLeft'); if (leftCol.length > 0) { leftCol[0].style.width = '370px'; getPageElement('trapSelector').style.width = '370px'; getPageElement('trapSelectorBrowserControls').style.backgroundRepeat = 'repeat-x'; getPageElement('trapSelectorBrowser').style.width = '364px'; getPageElement('trapSelectorStats').style.backgroundRepeat = 'repeat-x'; } var styleSheets = document.styleSheets; StyleLoop: for (var i = 0; i < styleSheets.length; i++) { if (styleSheets[i].href != null && styleSheets[i].href.contains('camp.css')) { var currSheetRules = styleSheets[i].cssRules; for (var j = 0; j < currSheetRules.length; j++) { if (currSheetRules[j].selectorText == '#trapSelectorStats .stat .help') { currSheetRules[j].style.setProperty('width', '354px', null); break StyleLoop; } } } } var hudelems = document.getElementsByClassName('hudstatlist'); for (var i = 0; i < hudelems.length; i++) { hudelems[i].style.marginLeft = '2px'; hudelems[i].style.marginRight = '2px'; } getPageElement('cheeseped').style.width = '155px'; } } function writeHudEnhancements(location) { if (settings.locationLockEnabled) { hud.huntLocation.innerHTML += ' [Unlock]'; getPageElement('lockSwitch').addEventListener('click', function() { setValue('locationLockEnabled', false); removeValue('fixedHuntLocation'); }, false); } else { hud.huntLocation.innerHTML += ' [Lock]'; getPageElement('lockSwitch').addEventListener('click', function() { setValue('locationLockEnabled', true); setValue('fixedHuntLocation', escape(location)); }, false); } var hudRealHorn = document.getElementById('huntTimer'); hudRealHorn.style.display = 'none'; hud.hornTimer.className = 'hunttimer'; hudRealHorn.parentNode.insertBefore(hud.hornTimer, hudRealHorn); document.getElementsByClassName('version')[0].innerHTML += ' [with MouseHunt GM v' + currentVersion + ']'; } function writeSidebar(page) { var sidebarReferenceNode = document.getElementsByClassName(page == 'mhg' ? 'hgSideBar' : 'UIStandardFrame_SidebarAds')[0]; var sidebarContainer = document.createElement('div'); sidebarContainer.id = 'sidebarContainer'; sidebarContainer.style.marginLeft = '775px'; sidebarContainer.style.paddingTop = '10px'; sidebarContainer.style.paddingBottom = '20px'; sidebarReferenceNode.parentNode.insertBefore(sidebarContainer, sidebarReferenceNode); var sidebarHeader = document.createElement('div'); sidebarHeader.innerHTML = 'MouseHunt GM [version ' + currentVersion + ']