您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Assist in daily tasks
// ==UserScript== // @name BvS_Daily // @namespace SirDuck36 // @description Assist in daily tasks // @version 2019.05.25 // @include http*://*animecubedgaming.com/billy/bvs* // @include http*://*animecubed.com/billy/bvs* // @grant GM_log // @grant GM_addStyle // ==/UserScript== // ** NOTE ** - This version uses ES6 features. For the non-ES6 script please visit // https://greasyfork.org/en/scripts/383503-bvs-daily-non-es6 // 4.14.2011 Initial version by SirDuck36 // 4.19.2011 Major overhaul of the API by SirDuck36 // 4.20.2011 Minor updates and bug fixes from North // 4.20.2011 Updated ChangeSequence to include a task number // 4.20.2011 Bug fix for GoPage('glowslinging'); // 4.21.2011 Added several new options for gopage function // 4.23.2011 Added sequences link -- suggested by WolfX // 4.23.2011 Add hotkeylock to left and right arrow hotkeys -- suggested by Skarn22 // 4.23.2011 Added support for //@SequenceCode before first task -- suggested by North // 4.23.2011 Fixed editor window hide to remove lingering select box -- SirDuck36 // 4.23.2011 Added functionality to hide daily window on desired pages -- SirDuck36 // 6.12.2011 Bug fix for ChangeSequence function -- Skarn22 // 6.19.2011 Add newline to ShowMsg and add pizzawitch to GoPage function -- SirDuck36 // 9.28.2014 Added grant permissions -- Channel28 // 11.7.2015 Fix a bug with flags when changing sequences. Thanks to Terrec -- Channel28 // 11.8.2015 Small fix. Thanks to Terrec -- Channel28 // 12.30.2015 Small fix regarding which key is to be pressed (Thanks to DTC) -- Channel28 // 5.19.2017 Now https compatible -- Channel28 // 2.04.2018 Now compatible with GreaseMonkey v4 (Thanks to Takumi) -- Channel28 // 5.25.2019 Added GoPage destinations for Breakfast, Marketplace & Tattoo Parlor. Hiding/unhiding // of the window is remembered globally. This can be turned off by changing the // OptGlobalHide below. True to show and false to hide (Thanks to Chrobot) -- Channel28 // Options // GlobalHide: if set, window's hidden/unhidden state is remembered globally // instead of per page. const OptGlobalHide = true; //////////////////////////////////////////////////////////////////////// /////////// LIBRARY CODE ///////////////// //////////////////////////////////////////////////////////////////////// /* DOM Storage wrapper class (credits: http://userscripts.org/users/dtkarlsson) Constructor: var store = new DOMStorage({"session"|"local"}, [<namespace>]); Set item: store.setItem(<key>, <value>); Get item: store.getItem(<key>[, <default value>]); Remove item: store.removeItem(<key>); Get all keys in namespace as array: var array = store.keys(); */ function DOMStorage(type, namespace) { var my = this; if (typeof(type) != "string") type = "session"; switch (type) { case "local": my.storage = localStorage; break; case "session": my.storage = sessionStorage; break; default: my.storage = sessionStorage; } if (!namespace || typeof(namespace) != "string") namespace = "Greasemonkey"; my.ns = namespace + "."; my.setItem = function(key, val) { try { my.storage.setItem(escape(my.ns + key), val); } catch (e) { GM_log(e); } }, my.getItem = function(key, def) { try { var val = my.storage.getItem(escape(my.ns + key)); if (val) return val; else return def; } catch (e) { return def; } } // Kludge, avoid Firefox crash my.removeItem = function(key) { try { my.storage.setItem(escape(my.ns + key), null); } catch (e) { GM_log(e); } } // Return array of all keys in this namespace my.keys = function() { var arr = []; var i = 0; do { try { var key = unescape(my.storage.key(i)); if (key.indexOf(my.ns) == 0 && my.storage.getItem(key)) arr.push(key.slice(my.ns.length)); } catch (e) { break; } i++; } while (true); return arr; } } // End DOM Storage Wrapper class // UI (credits: http://userscripts.org/users/dtkarlsson) function Window(id, storage) { var my = this; my.id = id; my.offsetX = 0; my.offsetY = 0; my.moving = false; // Window dragging events my.drag = function(event) { if (my.moving) { my.element.style.left = (event.clientX - my.offsetX)+'px'; my.element.style.top = (event.clientY - my.offsetY)+'px'; event.preventDefault(); } } my.stopDrag = function(event) { if (my.moving) { my.moving = false; var x = parseInt(my.element.style.left); var y = parseInt(my.element.style.top); if(x < 0) x = 0; if(y < 0) y = 0; storage.setItem(my.id + ".coord.x", x); storage.setItem(my.id + ".coord.y", y); my.element.style.opacity = 1; window.removeEventListener('mouseup', my.stopDrag, true); window.removeEventListener('mousemove', my.drag, true); } } my.startDrag = function(event) { if (event.button != 0) { my.moving = false; return; } my.offsetX = event.clientX - parseInt(my.element.style.left); my.offsetY = event.clientY - parseInt(my.element.style.top); if (my.offsetY > 27) return; my.moving = true; my.element.style.opacity = 0.75; event.preventDefault(); window.addEventListener('mouseup', my.stopDrag, true); window.addEventListener('mousemove', my.drag, true); } my.show = function() { this.element.style.visibility = 'visible'; } my.hide = function() { this.element.style.visibility = 'hidden'; } my.reset = function() { storage.setItem(my.id + ".coord.x", 6); storage.setItem(my.id + ".coord.y", 6); my.element.style.left = "6px"; my.element.style.top = "6px"; } my.element = document.createElement("div"); my.element.id = id; document.body.appendChild(my.element); my.element.addEventListener('mousedown', my.startDrag, true); if (storage.getItem(my.id + ".coord.x")) my.element.style.left = storage.getItem(my.id + ".coord.x") + "px"; else my.element.style.left = "6px"; if (storage.getItem(my.id + ".coord.y")) my.element.style.top = storage.getItem(my.id + ".coord.y") + "px"; else my.element.style.top = "6px"; } // End UI Window implementation // Make infinite alerts less miserable var displayAlerts = true; function alert(msg) { if (displayAlerts) { if (!confirm(msg)) { displayAlerts = false; } } } //////////////////////////////////////////////////////////////////////// /////////// DATA STRUCTURES ///////////////// //////////////////////////////////////////////////////////////////////// function dailyData() { // Save the storage object this.storage = new DOMStorage("local", "BvSDaily"); this.namePlayer = document.evaluate("//input[@name='player' and @type='hidden']", document, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue.value; // List of all sequences stored in memory this.sequenceList = ""; // List of all pages on which the daily window is hidden this.hidePageList = ""; // Global hide flag this.globalHide = false; // Name and task number of current sequence this.sequenceName = ""; this.taskNum = 0; // Actual tasklist for this sequence this.taskList = new Array(); // Array of string flags to save information... a flag is set if contained in the array // Crude but simple this.flagStr = "|"; // Helper function to set a flag this.SetFlag = function(flagtext) { if (!this.TestFlag(flagtext)) this.flagStr += flagtext + "|"; } // Helper function to test for a flag this.TestFlag = function(flagtext) { if (this.flagStr.indexOf("|" + flagtext + "|") > -1) return true; else return false; } // Check whether a page is in the hidePageList this.TestHidePage = function(pageName) { if (OptGlobalHide) return this.globalHide; for (var i=0; i < this.hidePageList.length; i++) if (this.hidePageList[i] === pageName) return true; return false; } // Add a page to the hidePageList this.AddHidePage = function(pageName) { if (!this.TestHidePage(pageName)) this.hidePageList.push(pageName); if (OptGlobalHide) this.globalHide = true; this.SaveState(); } // Remove a page from the hidePageList this.RemoveHidePage = function(pageName) { this.globalHide = false; for (var i=0; i < this.hidePageList.length; i++) if (this.hidePageList[i] === pageName) { this.hidePageList.splice(i,1); break; } this.SaveState(); } // Check whether a sequence name is in the sequence list this.TestSequence = function(sequenceName) { for (var i=0; i < this.sequenceList.length; i++) if (this.sequenceList[i] === sequenceName) return true; return false; } // Remove a sequence this.RemoveSequence = function(sequenceName) { // Remove sequence from sequence list for (var i=0; i<this.sequenceList.length; i++) if (this.sequenceList[i] === sequenceName) { // Remove this element from sequencelist this.sequenceList.splice(i,1); break; } this.SaveState(); this.storage.removeItem("Daily_Sequence_" + sequenceName); } // Store a new or modified sequence this.SaveSequence = function(sequenceName, sequenceCode) { if (!this.TestSequence(sequenceName)) { // Add sequenceName to sequenceList and save this.sequenceList.push(sequenceName); this.SaveState(); } // Save the sequence code this.storage.setItem("Daily_Sequence_" + sequenceName, sequenceCode); // Update the daily window floatingDaily.Draw(); } // Load and parse a given new sequence name this.LoadSequence = function(newSequenceName) { // Set the current sequence name and reinitialize taskList this.flagStr = this.storage.getItem(this.namePlayer + "_Daily_" + newSequenceName + "_Flags", "|"); if (!(this.sequenceName === newSequenceName)) { // Only reset the sequencename and tasknum if this is not the current sequence in use this.sequenceName = newSequenceName; this.taskNum = 1; } // Initialize empty tasklist this.taskList = new Array(); // Load newSequenceName from memory and parse into this.taskList var strSequenceData = this.storage.getItem("Daily_Sequence_" + newSequenceName, ""); if (!strSequenceData) return; // no sequence data to be loaded var sequenceData = strSequenceData.split("@NewTask"); // Implementation of sequence code goes into task 0 if (sequenceData[0].indexOf("@SequenceCode") > -1) this.taskList.push(new Task("SequenceCode", sequenceData[0])); else this.taskList.push(null); // Input the various tasks to be performed for (i=1; i < sequenceData.length; i++) { // Default taskname from a line such as "//@TaskName: Example Task Name" var taskname; var res = /@TaskName: (.+)(?=\r|\n)/.exec(sequenceData[i]); if (res) taskname = res[1]; else taskname = "task " + i; // default taskname this.taskList.push(new Task(taskname, sequenceData[i]) ); } // Add a final ending task which does nothing this.taskList.push(new Task("Done", "ShowMsg(\"Sequence Complete!\")")); } this.SaveState = function() { // Save the current state of this script (sequence name, task number, flags in use) this.storage.setItem("Daily_SequenceList", this.sequenceList.join("|") ); this.storage.setItem("Daily_HidePageList", this.hidePageList.join("|") ); this.storage.setItem("Daily_GlobalHide", this.globalHide); this.storage.setItem(this.namePlayer + "_DailyTaskNum", this.taskNum); this.storage.setItem(this.namePlayer + "_Daily_" + this.sequenceName + "_Flags", this.flagStr ); this.storage.setItem(this.namePlayer + "_DailySequenceName", this.sequenceName); } this.LoadState = function() { // Load the previous state of this script (sequence name, task number, flags in use) this.sequenceList = this.storage.getItem("Daily_SequenceList", this.sequenceList ).split("|"); this.hidePageList = this.storage.getItem("Daily_HidePageList", this.hidePageList ).split("|"); this.globalHide = ('true' === this.storage.getItem("Daily_GlobalHide", 'false')); this.sequenceName = this.storage.getItem(this.namePlayer + "_DailySequenceName", ""); if (this.sequenceName) { this.taskNum = parseInt( this.storage.getItem(this.namePlayer + "_DailyTaskNum", "0") ); this.flagStr = this.storage.getItem(this.namePlayer + "_Daily_" + this.sequenceName + "_Flags", "|" ); } // remove leading empty sequence strings // problem only occurs intially (I think) if (this.sequenceList[0] === "") { this.sequenceList.splice(0,1); this.SaveState(); } if (this.hidePageList[0] === "") { this.hidePageList.splice(0,1); this.SaveState(); } } // Load the current state this.LoadState(); // Load the sequence corresponding to the current state this.LoadSequence(this.sequenceName); } // task object has a description to be shown and a function that gets called function Task(taskname, taskfun) { this.taskname = taskname; this.taskfun = taskfun; } function Jutsu(name, code) { this.name = name; this.code = code; } function Mission(name, jutsu, allyget, type, diff, succ) { this.name = name; this.jutsu = jutsu; this.type = type; this.diff = diff; this.succ = succ; this.allyget = allyget; } function Quest(name, code, numsteps, flag) { this.name = name; this.code = code; this.numsteps = numsteps; this.flag = flag; } //////////////////////////////////////////////////////////////////////// /////////// FLOATING WINDOWS /////////////// //////////////////////////////////////////////////////////////////////// function FloatingDaily() { this.window = new Window("floatingDaily", data.storage); // Add css style for report window this.window.element.style.border = "2px solid #000000"; this.window.element.style.position = "fixed"; this.window.element.style.zIndex = "100"; this.window.element.style.color = "#000000"; this.window.element.style.padding = "5"; this.window.element.style.textAlign = "left"; this.window.element.style.overflowX = "auto"; this.window.element.style.overflowY = "auto"; this.window.element.style.width = "200px"; this.window.element.style.height = "500px"; this.window.element.style.background = "none repeat scroll 0% 0% rgb(216, 216, 216)"; this.Draw = function() { // Test whether the daily window should be drawn on this page if (data.TestHidePage(location.href)) { this.Hide(); return; } // Show the window if not already this.window.show(); // Helper array to build the HTML var arr = new Array(); arr.push('<table width="200"><tr><td align="left">Daily Helper</td>', '<td align="right"><p style="margin: 0pt; text-align: right;">', '<a href="javascript:void(0)" id="DailyHidePageButton">', '(Hide)</a></p></td></tr></table><br>'); arr.push("Sequence: <b>" + data.sequenceName + "</b><br><br>"); arr.push('<table width="200"><tr><td align="left">', '<a href="javascript:void(0)" id="DailyBackTaskButton">', '<-----</a></td>'); arr.push('<td align="center"><b>' + data.taskNum + '</b> / ' + (data.taskList.length-1) + '</td>'); arr.push('<td align="right"><a href="javascript:void(0)" id="DailySkipTaskButton">', '-----></a></td></tr></table><br>'); if (data.taskNum > 0 && data.taskNum < data.taskList.length) arr.push('Task: <b>' + data.taskList[data.taskNum].taskname + '</b>'); else arr.push('Task: Undefined Task'); arr.push('<br><br><div id="DailyMsgDiv"></div><br><br>'); arr.push('Your sequences:'); // Generate list of sequence options to choose from for (var i=0; i<data.sequenceList.length; i++) { var sequenceName = data.sequenceList[i]; arr.push('<p style="margin: 0pt; text-align: right;">', '<a href="javascript:void(0)" val="' + sequenceName, '" id="ChooseSequenceButton_' + sequenceName + '">', sequenceName + ' ></a></p>'); } arr.push('<br><p style="margin: 0pt; text-align: left;">', '<a href="javascript:void(0)" id="DailySequenceEditorButton">', '< Open Sequence Editor</a></p>'); arr.push('<br><p style="margin: 0pt; text-align: left;">', '<a href="https://docs.google.com/leaf?id=0B10D12_4U2KiNzYxZjY0YTEtYzU1Mi00Y2YzLTg5NGYtYWZlNGQzMDQyNDE0&hl=en" id="MoreSequencesButton" target="_blank">', '< Get More Sequences</a></p>'); // arr.push("<b>Flags</b>:"); // arr.push(data.flagStr.replace(/\|/g, "<br>")); // Concatenate everything in the array to form the html this.window.element.innerHTML = arr.join(""); // Event handlers for sequenceList items for (var i=0; i<data.sequenceList.length; i++) { var sequenceName = data.sequenceList[i]; var elem = document.getElementById("ChooseSequenceButton_" + sequenceName); elem.addEventListener("click", function() { data.LoadSequence(this.id.split("_")[1]); data.SaveState(); floatingDaily.Draw(); }, false); } document.getElementById("DailyHidePageButton").addEventListener("click", floatingDaily.HidePage, true); // document.getElementById("DailyResetDataButton").addEventListener("click", floatingDaily.ResetData, true); document.getElementById("DailySkipTaskButton").addEventListener("click", floatingDaily.SkipTask, true); document.getElementById("DailyBackTaskButton").addEventListener("click", floatingDaily.BackTask, true); document.getElementById("DailySequenceEditorButton").addEventListener("click", floatingDaily.OpenSequenceEditor, true); } // Hide the window (and remove the interior) this.Hide = function() { this.window.element.innerHTML = ""; this.window.hide(); } this.showErr = function(err) { document.getElementById("DailyMsgDiv").innerHTML += err.message; } this.HidePage = function() { data.AddHidePage(location.href); floatingDaily.Hide(); } this.ResetData = function() { data.taskNum = 1; data.flagStr = "|"; data.SaveState(); floatingDaily.Draw(); } this.SkipTask = function() { IncrementTask(); } this.BackTask = function() { // Temporary for debugging if (data.taskNum > 1) data.taskNum--; data.SaveState(); floatingDaily.Draw(); } this.OpenSequenceEditor = function() { // Disable hotkeys hotkeyLock = true; // Initialize the Editor window if not already floatingEditor.Draw(); // Load the current sequence if it exists if (data.TestSequence(data.sequenceName)) floatingEditor.LoadSequence(data.sequenceName); // Show the editor window floatingEditor.window.show(); } } function FloatingEditor() { this.window = new Window("floatingEditor", data.storage); // Add css style for report window this.window.element.style.border = "2px solid #000000"; this.window.element.style.position = "fixed"; this.window.element.style.zIndex = "100"; this.window.element.style.color = "#000000"; this.window.element.style.padding = "5"; this.window.element.style.textAlign = "left"; this.window.element.style.overflowX = "auto"; this.window.element.style.overflowY = "auto"; this.window.element.style.width = "600px"; this.window.element.style.height = "620px"; this.window.element.style.background = "none repeat scroll 0% 0% rgb(216, 216, 216)"; this.Draw = function() { // Helper array to build the HTML var arr = new Array(); arr.push("Sequence Editor<br><br>"); // Drop down box for things in the sequence list arr.push('Choose an existing sequence to edit: '); arr.push('<select id="sequenceSelect">'); for (var i=0; i < data.sequenceList.length; i++) arr.push('<option value="' + data.sequenceList[i] + '">' + data.sequenceList[i] + '</option>'); arr.push('</select>  '); arr.push('<a href="javascript:void(0)" id="EditorLoadSequenceButton">', 'Load Sequence ></a><br>'); arr.push('<br><br>'); // Textbox for sequence code arr.push('<textarea id="sequenceCode" rows="30" cols="76"></textarea><br>'); // Remove button arr.push('<p style="margin: 0pt; text-align: left;">', '<a href="javascript:void(0)" id="EditorDeleteSequenceButton">', '< Delete Sequence</a></p>'); // Save button arr.push('<p style="margin: 0pt; text-align: right;">', '<a href="javascript:void(0)" id="EditorSaveSequenceButton">', 'Save Sequence ></a></p><br>'); // Concatenate everything in the array to form the html this.window.element.innerHTML = arr.join(""); floatingEditor.LoadSequence(data.sequenceName); document.getElementById("EditorSaveSequenceButton").addEventListener("click", floatingEditor.SaveSequence, true); document.getElementById("EditorDeleteSequenceButton").addEventListener("click", floatingEditor.DeleteSequence, true); document.getElementById("EditorLoadSequenceButton").addEventListener("click", floatingEditor.LoadSelectedSequence, true); // Load the textarea with a sample sequence var sequenceStr = "//@SequenceName: Default\n\n\n" + "//------------------------------------------\n" + "//@NewTask\n" + "//@TaskName: Example Task 1\n\n" + "ShowMsg(\"Example task 1 only shows this message\");\n\n\n" + "//------------------------------------------\n" + "//@NewTask\n" + "//@TaskName: Example Task 2\n\n" + "ShowMsg(\"Example task 2 is almost the same\");"; document.getElementById("sequenceCode").value = sequenceStr; } // Hide the window (and remove the interior) this.Hide = function() { this.window.element.innerHTML = ""; this.window.hide(); } this.SaveSequence = function() { // Extract the sequence string var sequenceCode = document.getElementById("sequenceCode").value; var sequenceName; // Get the sequence name and verify correct input formatting try { sequenceName = /@SequenceName: (.+)(?=\r|\n)/.exec(sequenceCode)[1]; } catch(err) { alert("Please enter a sequence name on the first line with format:\n" + "//@SequenceName: Example Sequence Name"); return; } // Clean the string for only alphanumeric characters and spaces if ( !(sequenceName === sequenceName.replace(/[^a-zA-Z 0-9]+/g,'')) ) { alert("Alphanumeric characters and spaces only in sequence names"); return; } data.SaveSequence(sequenceName, sequenceCode); data.LoadSequence(sequenceName); // floatingEditor.Draw(); // document.getElementById("sequenceCode").value = sequenceCode; } this.LoadSelectedSequence = function() { var elem = document.getElementById("sequenceSelect"); var sequenceName = elem.options[elem.selectedIndex].value; floatingEditor.LoadSequence(sequenceName); } this.DeleteSequence = function() { // Extract the sequence string var sequenceCode = document.getElementById("sequenceCode").value; var sequenceName; // Get the sequence name and verify correct input formatting try { sequenceName = /@SequenceName: (.+)(?=\r|\n)/.exec(sequenceCode)[1]; } catch(err) { alert("Please enter a sequence name on the first line with format:\n" + "//@SequenceName: Example Sequence Name"); return; } // Clean the string for only alphanumeric characters and spaces if ( !(sequenceName === sequenceName.replace(/[^a-zA-Z 0-9]+/g,'')) ) { alert("Alphanumeric characters and spaces only in sequence names"); return; } // Make sure the user really wants to do this if (!confirm("Are you sure you want to delete the sequence: \'" + sequenceName + "\'?")) return; // Remove the sequence and reload the editor data.RemoveSequence(sequenceName); data.LoadSequence(""); floatingEditor.LoadSequence(""); floatingEditor.Draw(); floatingDaily.Draw(); } this.LoadSequence = function(sequenceName) { // If sequenceName is null do nothing if (!sequenceName) return; // sequenceName is assumed to exist... error if not var sequenceStr = data.storage.getItem("Daily_Sequence_" + sequenceName, ""); if (!sequenceStr) { alert("Sequence " + sequenceName + " does not exist\nThis is an error that should be reported."); return; } // Otherwise, load up the sequence text document.getElementById("sequenceCode").value = sequenceStr; // Also load up this sequence in browser cache data.LoadSequence(sequenceName); floatingDaily.Draw(); } // hide the window by default this.window.hide(); } //////////////////////////////////////////////////////////////////////// /////////// USER API FUNCTIONS /////////////// //////////////////////////////////////////////////////////////////////// //////////////// API Functions which halt task execution ////////////////// // Put up a message in the floating daily window // This function halts script execution function ShowMsg(strMsg) { if (!strMsg) strMsg = ""; else strMsg += '<br>'; throw new Error(strMsg); } // Submit a form with name strName and display message strMsg on success // This function always halts task execution function FormSubmit(strName, strMsg) { if (!strMsg) strMsg = 'Submitting Form: ' + strName; if (FormTest(strName)) { // Success, submit the form and display the desired message document.forms.namedItem(strName).submit(); ShowMsg(strMsg); } else { // Display error message for user to see ShowMsg('Form ' + strName + ' does not exist'); } } // Move to the next task if possible // This function always halts task execution function IncrementTask(strMsg) { if (data.taskNum < data.taskList.length-1) data.taskNum++; data.SaveState(); floatingDaily.Draw(); ShowMsg(strMsg); } // Move to the next task if possible // This function does NOT halt task execution function IncrementTaskNonBlock() { if (data.taskNum < data.taskList.length-1) data.taskNum++; data.SaveState(); floatingDaily.Draw(); } // Move to next task if condition is true // This function halts task execution if condition is true function IncrementTaskIf(cond, strMsg) { if (cond) IncrementTask(strMsg); } // Change to new sequence (useful for chaining together separate sequences) function ChangeSequence(strSequenceName, newTaskName) { // Search for strSequenceName in sequence list for (var i=0; i < data.sequenceList.length; i++) if (data.sequenceList[i] === strSequenceName) { // Load the sequence and set the task number if desired data.LoadSequence(strSequenceName); if (newTaskName) { for (var j=1; j < data.taskList.length; j++) if (data.taskList[j].taskname === newTaskName) data.taskNum = j; } // Save state data.SaveState(); // Redraw the window floatingDaily.Draw(); // Done ShowMsg('Loaded Sequence: ' + strSequenceName); } // If code reaches this point, sequence does not exist ShowMsg('Sequence ' + strSequenceName + ' does not exist'); } //////////////// API Functions which test the page for information ////////////////// // Test the document body HTML for the given text function DocTest(strText) { return (document.body.innerHTML.indexOf(strText) > -1); } // Test the href location for the given text function LocationTest(strText) { return (location.href.indexOf(strText) > -1); } // Test for the existence of a form with name = strName function FormTest(strName) { return (document.forms.namedItem(strName) ? true : false); } // Test whether a form input is already checked function FormCheckTest(strFormName, strInputName, strInputValue) { var strXPath = ""; // Form name is optional, include it if necessary if (strFormName) strXPath += '//form[@name=\'' + strFormName + '\']'; // Input name is mandatory (else we cannot find the input box...) strXPath += '//input[@name=\'' + strInputName + '\''; // Input value is also optional if (strInputValue) strXPath += ' and @value=\'' + strInputValue + '\''; strXPath += ']'; var elem = document.evaluate(strXPath, document, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue; // Element does not exist if (!elem) return false; // Otherwise return checked state return elem.checked; } /////////////// API Functions to manipulate forms on the page ////////////// // Check a checkbox on a form // Returns false if element does not exist, or is disabled function FormCheck(strFormName, strInputName, strInputValue) { var strXPath = ""; // Form name is optional, include it if necessary if (strFormName) strXPath += '//form[@name=\'' + strFormName + '\']'; // Input name is mandatory (else we cannot find the input box...) strXPath += '//input[@name=\'' + strInputName + '\''; // Input value is also optional if (strInputValue) strXPath += ' and @value=\'' + strInputValue + '\''; strXPath += ']'; var elem = document.evaluate(strXPath, document, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue; // Return without action if element does not exist or is disabled if (!elem || elem.disabled) return false; // Otherwise check the box and return true elem.checked = "checked"; return true; } // Select an option form a drop down box function FormSelect(strFormName, strSelectName, strOptionValue, strOptionText) { // First get the select object var strXPath = ""; // Form name is optional, include it if necessary if (strFormName) strXPath += '//form[@name=\'' + strFormName + '\']'; // Input name is mandatory (else we cannot find the input box...) strXPath += '//select[@name=\'' + strSelectName + '\']'; var elem = document.evaluate(strXPath, document, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue; // Element does not exist if (!elem || elem.disabled) return false; // loop through options and select any if found for (var i=0; i<elem.options.length; i++) { if ( (!strOptionValue || elem.options[i].value == strOptionValue) && (!strOptionText || elem.options[i].text == strOptionText) ) { elem.selectedIndex = i; return true; } } // If the code reaches this point, we did not find the option to select return false; } // Set .value field of an Input object function FormSetValue(strFormName, strInputName, newValue) { var strXPath = ""; // Form name is optional, include it if necessary if (strFormName) strXPath += '//form[@name=\'' + strFormName + '\']'; // Input name is mandatory (else we cannot find the input box...) strXPath += '//input[@name=\'' + strInputName + '\']'; var elem = document.evaluate(strXPath, document, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue; // Return without action if element does not exist or is disabled if (!elem || elem.disabled) return false; // Otherwise check the box and return true elem.value = newValue; return true; } // Get .value field of an Input object function FormGetValue(strFormName, strInputName) { var strXPath = ""; // Form name is optional, include it if necessary if (strFormName) strXPath += '//form[@name=\'' + strFormName + '\']'; // Input name is mandatory (else we cannot find the input box...) strXPath += '//input[@name=\'' + strInputName + '\']'; var elem = document.evaluate(strXPath, document, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue; // Return without action if element does not exist or is disabled if (!elem) return false; // Otherwise check the box and return true return elem.value; } ////////////// API Functions which navigate around the BvS world ////////////// // Helper function to interact with BvS menus function GoMenuPage(strMenuItem) { var menucell = document.evaluate('//a[text()="' + strMenuItem + '"]', document, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue; FormSubmit(menucell.href.split(":")[1].split(".")[1], 'Moving to page: ' + strMenuItem); }; // General function to go to any (or at least most) bvs page function GoPage(strPageName) { // Class to define how to get to a specific page // funLoad is a function which loads the desired page (starting on the prereq page) // strPrereq indicates whether we should start from a simpler page // funTest is a function which determines whether we are already on the correct page function objPage(funLoad, strPrereq, funTest) { this.funLoad = funLoad; this.strPrereq = strPrereq; this.funTest = funTest; }; // Create the list of page objects var pageList = { // Main menu items main: new objPage(function(){GoMenuPage('Main');}, null, function(){return LocationTest('/bvs/pages/main.html');} ), village: new objPage(function(){GoMenuPage('Village');}, null, function(){return LocationTest('/bvs/village.html');} ), partyhouse: new objPage(function(){GoMenuPage('Party House');}, null, function(){return LocationTest('/bvs/partyhouse.html');} ), shop: new objPage(function(){GoMenuPage('Shop');}, null, function(){return LocationTest('/bvs/shop.html');} ), consumables: new objPage(function(){GoMenuPage('Consumables');}, null, function(){return LocationTest('/bvs/oneuseitems.html');} ), worldkaiju: new objPage(function(){GoMenuPage('WorldKaiju');}, null, function(){return LocationTest('/bvs/worldkaiju.html');} ), missions: new objPage(function(){GoMenuPage('Missions');}, null, function(){return LocationTest('/bvs/missionstart.html') || LocationTest('/bvs/missions');} ), quests: new objPage(function(){GoMenuPage('Quests');}, null, function(){return LocationTest('/bvs/quests.html') || LocationTest('/bvs/questattempt.html') || LocationTest('/bvs/chuninexam.html');} ), spar: new objPage(function(){GoMenuPage('Spar');}, null, function(){return LocationTest('/bvs/spar.html');} ), arena: new objPage(function(){GoMenuPage('Arena');}, null, function(){return LocationTest('/bvs/arena.html');} ), team: new objPage(function(){GoMenuPage('Team');}, null, function(){return LocationTest('/bvs/team.html');} ), jutsu: new objPage(function(){GoMenuPage('Jutsu');}, null, function(){return LocationTest('/bvs/jutsu.html');} ), summons: new objPage(function(){GoMenuPage('Summons');}, null, function(){return LocationTest('/bvs/summon.html');} ), bucket: new objPage(function(){GoMenuPage('Bucket');}, null, function(){return LocationTest('/bvs/bucket.html');} ), // Party house menu items ph_tipline: new objPage(function(){GoMenuPage('Tip Line');}, 'partyhouse', function(){return FormTest('tipline');} ), ph_juicebar: new objPage(function(){GoMenuPage('\'Juice\' Bar');}, 'partyhouse', function(){return FormTest('br');} ), ph_firstloser: new objPage(function(){GoMenuPage('First Loser');}, 'partyhouse', function(){return DocTest('Four times a day a new First Loser contest begins (and the old one finishes).');} ), ph_wheel: new objPage(function(){GoMenuPage('Wheel');}, 'partyhouse', function(){return FormTest('raf');} ), ph_jackpot: new objPage(function(){GoMenuPage('Jackpot');}, 'partyhouse', function(){return FormTest('ninrou');} ), ph_lottery: new objPage(function(){GoMenuPage('Lottery');}, 'partyhouse', function(){return FormTest('el');} ), ph_tsukiball: new objPage(function(){GoMenuPage('Tsukiball');}, 'partyhouse', function(){return FormTest('skib');} ), ph_bigboard: new objPage(function(){GoMenuPage('Big Board');}, 'partyhouse', function(){return DocTest('<b>The Big Board</b>');} ), ph_scratchies: new objPage(function(){GoMenuPage('Scratchies');}, 'partyhouse', function(){return FormTest('scratch') || FormTest('mainform2');} ), ph_darts: new objPage(function(){GoMenuPage('Darts');}, 'partyhouse', function(){return FormTest('dgame');} ), ph_partyroom: new objPage(function(){GoMenuPage('Party Room');}, 'partyhouse', function(){return FormTest('pr');} ), ph_crane: new objPage(function(){GoMenuPage('Crane');}, 'partyhouse', function(){return FormTest('cgame');} ), ph_over11k: new objPage(function(){GoMenuPage('Over 11K');}, 'partyhouse', function(){return FormTest('over11');} ), ph_snakeman: new objPage(function(){GoMenuPage('SNAKEMAN');}, 'partyhouse', function(){return FormTest('newsnake');} ), ph_roulette: new objPage(function(){GoMenuPage('Roulette');}, 'partyhouse', function(){return LocationTest('/bvs/partyhouse-roulette.html');} ), ph_mahjong: new objPage(function(){GoMenuPage('Mahjong');}, 'partyhouse', function(){return LocationTest('/bvs/partyhouse-mahjong.html');} ), ph_superfail: new objPage(function(){GoMenuPage('SUPERFAIL');}, 'partyhouse', function(){return LocationTest('/bvs/partyhouse-superfail.html');} ), ph_pigeons: new objPage(function(){GoMenuPage('Pigeons');}, 'partyhouse', function(){return LocationTest('/bvs/partyhouse-keno.html');} ), ph_flowerwars: new objPage(function(){GoMenuPage('Flower Wars');}, 'partyhouse', function(){return LocationTest('/bvs/partyhouse-hanafuda.html');} ), ph_pachinko: new objPage(function(){GoMenuPage('Pachinko');}, 'partyhouse', function(){return LocationTest('/bvs/partyhouse-pachinko.html');} ), // Linked from village breakfast: new objPage(() => FormSubmit('dobreakfast'), 'main', () => LocationTest('/bvs/breakfast.html')), marketplace: new objPage(() => FormSubmit('market'), 'village', () => LocationTest('/bvs/villagemarketplace.html')), tattoo: new objPage(() => FormSubmit('tatstime'), 'village', () => LocationTest('/bvs/villagetattoo.html')), fields: new objPage(function(){FormSubmit('fieldmenu');}, 'village', function(){return LocationTest('/bvs/villagefields.html');} ), phases: new objPage(function(){FormSubmit('phases');}, 'village', function(){return LocationTest('/bvs/villagephases.html') || LocationTest('/bvs/villager00t.html');} ), bingo: new objPage(function(){FormSubmit('bbook');}, 'village', function(){return LocationTest('/bvs/bingo');} ), jutsuenhance: new objPage(function(){FormSubmit('jenhance');}, 'village', function(){return LocationTest('/bvs/villagejenhance.html');} ), billycon: new objPage(function(){FormSubmit('concenter');}, 'village', function(){return LocationTest('/bvs/billycon-register.html');} ), robofighto: new objPage(function(){FormSubmit('robofighto');}, 'village', function(){return LocationTest('/bvs/villagerobofighto.html');} ), zrewards: new objPage(function(){FormSubmit('zrt');}, 'village', function(){return LocationTest('/bvs/zombjarewards.html');} ), kaiju: new objPage(function(){FormSubmit('kat');}, 'village', function(){return LocationTest('/bvs/villagemonsterfight');} ), pizzawitch: new objPage(function(){FormSubmit('pizzamenu');}, 'village', function(){return LocationTest('/bvs/pizzawitch.html') || LocationTest('/bvs/pizzawitchgarage.html');} ), // Linked from billycon glowslinging: new objPage(function(){FormSubmit('glowsling');}, 'billycon', function(){return LocationTest('/bvs/billycon-glowslinging.html') || LocationTest('/billycon-glowslingfight.html');} ), // Linked from main page themes: new objPage(function(){FormSubmit('theme');}, 'main', function(){return LocationTest('/bvs/themesdifficulty.html');} ), tinybeevault: new objPage(function(){FormSubmit('tinybee');}, 'main', function(){return LocationTest('/bvs/tinybees.html');} ), sponsoritem: new objPage(function(){FormSubmit('sponsor');}, 'main', function(){return LocationTest('/bvs/sponsoritems.html');} ), favors: new objPage(function(){FormSubmit('sandstorm');}, 'main', function(){return LocationTest('/bvs/sandstorm.html');} ), reaperblood: new objPage(function(){FormSubmit('reaper');}, 'main', function(){return LocationTest('/bvs/reaper.html');} ), driftstyle: new objPage(function(){FormSubmit('drifter');}, 'main', function(){return LocationTest('/bvs/drifter.html');} ), avatar: new objPage(function(){FormSubmit('avatar');}, 'main', function(){return LocationTest('/bvs/avatar.html');} ), blank: new objPage(null,null,null) }; // Extract the page from the pageList object var page = pageList[strPageName]; if (!page) throw new Error('Page list object: ' + strPageName + ' does not exist'); // Test whether we are already on the correct page if (page.funTest()) return; // Early return, on a good page // If a prerequisite page is listed, go to it first if (page.strPrereq) GoPage(page.strPrereq); // Finally, move to the desired page page.funLoad(); ShowMsg('Moving to page: ' + strPageName); } // Get a mission of a given rank function GetMission(rank) { GoPage('missions'); if ( !LocationTest("/bvs/missionstart.html") ) return; objMissionLookup = { D: "d", genD: "gd", ninD: "nd", taiD: "td", C: "c", genC: "gc", ninC: "nc", taiC: "tc", B: "b", genB: "gb", ninB: "nb", taiB: "tb", A: "a", genA: "ga", ninA: "na", taiA: "ta", AA: "aa", genAA: "gaa", ninAA: "naa", taiAA: "taa", Reaper: "reaper", genReaper: "greaper", ninReaper: "nreaper", taiReaper: "treaper", Monochrome: "monochrome", genMonochrome: "gmonochrome", ninMonochrome: "nmonochrome", taiMonochrome: "tmonochrome", Outskirts: "outskirts", Wasteland: "wasteland", Burgerninja: "burger", Pizzawitch: "pizza", Witchinghour: "witch", S: "s", Blank: "" }; FormSubmit("misform" + objMissionLookup[rank], 'Getting ' + rank + ' rank mission'); } // Set the r00t field keys function SetField(key1, key2, key3) { GoPage('fields'); // See whether we are on the right field if ( key1 && key2 && key3 && (!DocTest("<b>"+key1+"</b></td>") || !DocTest("<b>"+key2+"</b></td>") || !DocTest("<b>"+key3+"</b></td>")) ) { // Go to the right field if possible if ( FormSelect(null, 'key_1', null, key1) && FormSelect(null, 'key_2', null, key2) && FormSelect(null, 'key_3', null, key3) ) { FormSubmit('field', 'Changing to: ' + key1 + ' ' + key2 + ' ' + key3); } } } //////////////// API Functions for running missions ////////////////// // Enable megamissions -- this function might go away function EnableMegamissions() { GoPage('missions'); IncrementTaskIf(DocTest("<i>MegaMissions Active!</i>")); FormSubmit('megamis', 'Enabling megamissions'); } // Simple attempt for current mission with given jutsu... does not return, always throws exception function MissionAttempt(jutsu) { if (!jutsu) { jutsu = { code: -1, name: '' }; } // Blindly attempt the mission using the given jutsu if (FormTest('domission')) FormSubmit('domission'); if (FormTest('attempt')) { if (jutsu.code > -1) FormCheck(null, 'usejutsu', "" + jutsu.code); FormSubmit('attempt', 'Attempting mission with jutsu: ' + jutsu.name); } // Show message ShowMsg("Attempting mission with jutsu: " + jutsu.name); } // Complex attempt for current mission stack // Script defaults to given jutsu if not found in the stack function MissionStackAttempt(stack, defaultjutsu) { // Get the mission name cell var missioncell = document.evaluate('//div[@class="miscontainer"]/div/div/div/center/font/b', document, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue; var strMissionName = missioncell.innerHTML; // stack is an array of Mission objects for (var i in stack) if (stack[i].name == strMissionName) { if (stack[i].allyget) CheckAllyGet(stack[i].allyget); MissionAttempt(stack[i].jutsu); } // This point is not reached unless mission is not in the stack // Default jutsu MissionAttempt(defaultjutsu); } // Function to attempt a mission based on difficulty and success (before crank) in addition to name and mission type function MissionDetailedStackAttempt(stack, defaultjutsu) { /* <div class="miscontainer"><div class="misshadow"><div class="miscontent_g"><div class="miscontent2" align="left"> <div class="misstat_g">Genjutsu</div><center> <font style="font-size: 18px;"><b>Wander the Sands</b></font><br>The Wasteland is endless..<br><b><i><font style="font-size: 16px;">Crank Level: 27</font></i></b> <i><font style="font-size: 12px;"><br>(+27 Diff, +27 Succ, +135% Ryo)</font></i><font style="font-size: 12px;"></font><br><br> <div class="misonestat_g"><table class="misonetable"><tbody><tr><td align="right">Difficulty 40 Successes 36 </td></tr></tbody></table></div> */ // Get the mission name var missioncell = document.evaluate('//div[@class="miscontainer"]/div/div/div/center/font/b', document, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue; var strMissionName = missioncell.innerHTML; // Get mission type missioncell = document.evaluate('//div[@class="miscontainer"]/div/div/div/div', document, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue; var strMissionType = missioncell.innerHTML; // Get crank var numMissionCrank; if (DocTest('Crank Level')) { missioncell = document.evaluate('//div[@class="miscontainer"]/div/div/div/center', document, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue; numMissionCrank = parseInt(/Crank Level: (\d+)</.exec(missioncell.innerHTML)[1], 10); } else numMissionCrank = 0; // Get difficulty and successes missioncell = document.evaluate('//div[@class="miscontainer"]/div/div/div/center/div/table/tbody/tr/td', document, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue; // Difficulty 40 Successes 36 var numMissionDiff = parseInt(/Difficulty (\d+)&/.exec(missioncell.innerHTML)[1], 10) - numMissionCrank; var numMissionSucc = parseInt(/Successes (\d+)&/.exec(missioncell.innerHTML)[1], 10) - numMissionCrank; // stack is an array of Mission objects for (var i in stack) if (stack[i].name == strMissionName && stack[i].type == strMissionType && stack[i].diff == numMissionDiff && stack[i].succ == numMissionSucc) { if (stack[i].allyget) CheckAllyGet(stack[i].allyget); MissionAttempt(stack[i].jutsu); } // This point is not reached unless mission is not in the stack // Default jutsu MissionAttempt(defaultjutsu); } ///////////// API Functions for doing quests /////////////////// // Generic function to perform quest steps -- jutsu selection is currently broken function DoGenericQuest(quest, endstep, jutsu) { // Ensure that we are on the quest page or go there // This function also continues a quest in progress GoPage('quests'); if (FormTest('questcontinue')) FormSubmit('questcontinue'); // safeguard against bad code for eval statement if (typeof(quest.code) != "number") ShowMsg("quest.code must be a number"); // Sanity check to make sure that we are on the correct page if (!DocTest(quest.name)) ShowMsg("We are on the wrong quest?!?"); // Select the desired quest to start if (FormTest('quest' + quest.code)) FormSubmit("quest" + quest.code); // Check termination conditions if ( (endstep == -1 && DocTest("--Epilogue--")) || DocTest("--Part " + endstep + " of " + quest.numsteps + "--") ) { if (quest.flag) { data.SetFlag(quest.flag); data.SaveState(); } // Manually increment the task without halting execution if (data.taskNum < data.taskList.length-1) data.taskNum++; data.SaveState(); floatingDaily.Draw(); GoMenuPage('Quests'); return; } // Set the requested jutsu if (jutsu && FormTest('attack')) FormCheck(null, 'usejutsu', '' + jutsu.code); // document.getElementById(jutsu.code).checked = "checked"; // Blindly attempt the quest if we get this far if (FormTest('attack')) FormSubmit('attack'); if (FormTest('goquest')) FormSubmit('goquest'); } ////////////// API Functions primarily for convenience / miscellaneous ///////////// // Generic function to set flags based on an ally we might get on this page // ally is an object of type Ally function CheckAllyGet(strAllyName) { // Somewhat better version of CheckStuffGet() if (DocTest("You got an Ally!<br><b>" + strAllyName + "!</b>") || DocTest("<b>" + strAllyName + " joins you!</b>") || DocTest("<b>" + strAllyName + " joins your party!</b>") || DocTest("<b>" + strAllyName + " joined your party!</b>") || DocTest("You got <b>" + strAllyName + "!</b>") ) { data.SetFlag(strAllyName); data.SaveState(); ShowMsg("Got ally:" + strAllyName); } // Ally Level 2 if (DocTest("Level Up!<br><b>" + strAllyName + "</b> is now <b>" + strAllyName + " Lvl. 2!</b>")) { data.SetFlag(strAllyName + " Lvl. 2"); data.SaveState(); ShowMsg("Got " + strAllyName + " Lvl. 2"); } // Ally Level 3 if (DocTest("<b>" + strAllyName + " is now Lvl. 3!</b>")) // specific to stalker3 for now { data.SetFlag(strAllyName + " Lvl. 3"); data.SaveState(); ShowMsg("Got " + strAllyName + " Lvl. 3"); } } // Set themes function SetThemes(theme1, theme2, theme3, theme4) { GoPage('themes'); if (theme1 && !FormCheckTest('themes1', 'theme_entry_1', theme1)) { FormCheck('themes1', 'theme_entry_1', theme1); FormSubmit('themes1'); ShowMsg("Setting Opening Theme"); } if (theme2 && !FormCheckTest('themes2', 'theme_entry_2', theme2)) { FormCheck('themes2', 'theme_entry_2', theme2); FormSubmit('themes2'); ShowMsg("Setting Battle Theme"); } if (theme3 && !FormCheckTest('themes3', 'theme_entry_3', theme3)) { FormCheck('themes3', 'theme_entry_3', theme3); FormSubmit('themes3'); ShowMsg("Setting Ending Theme"); } if (theme4 && !FormCheckTest('themes4', 'theme_entry_4', theme4)) { FormCheck('themes4', 'theme_entry_4', theme4); FormSubmit('themes4'); ShowMsg("Setting Overworld Theme"); } } // Change teams -- exact text strings for ally names required function TeamChange(strAllyName1, strAllyName2, strAllyName3) { GoPage('team'); // Confirm teams without thinking if (FormTest('conteam')) FormSubmit('conteam'); // Check whether the task is already complete var indstart = document.body.innerHTML.indexOf("<b>-Current Team-</b>"); var ind1 = document.body.innerHTML.indexOf("<b>" + strAllyName1, indstart); var ind2 = document.body.innerHTML.indexOf("<b>" + strAllyName2, indstart); var ind3 = document.body.innerHTML.indexOf("<b>" + strAllyName3, indstart); var indend = document.body.innerHTML.indexOf("Save current team as Quickteam:"); IncrementTaskIf(ind1 < indend && ind2 < indend && ind3 < indend); // Helper function to test each element against the ally name function AllyTest(strFor, strText) { return (strFor.indexOf('id_') > -1 && ( strText.indexOf('<b>' + strAllyName1) > -1 || strText.indexOf('<b>' + strAllyName2) > -1 || strText.indexOf('<b>' + strAllyName3) > -1 ) ); }; // Get a snapshot for each message in the village chat var snapMessageList = document.evaluate("//label", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); // Examine each snapshot for (var i=0; i<snapMessageList.snapshotLength; i++) { var snap = snapMessageList.snapshotItem(i); if (AllyTest(snap.htmlFor, snap.innerHTML)) document.getElementById(snap.htmlFor).checked = "checked"; } // Submit the form FormSubmit('maketeam'); } //////////////////////////////////////////////////////////////////////// /////////// DAILY CODE ///////////// //////////////////////////////////////////////////////////////////////// function DailyStep() { // Perform a single step of daily try { // Execute SequenceCode if it exists, stored in task 0 if (data.taskList[0]) eval(data.taskList[0].taskfun); // Call the next function in the tasklist eval(data.taskList[data.taskNum].taskfun); } catch(err) { // Report the error or message on the floating window floatingDaily.showErr(err); } } //////////////////////////////////////////////////////////////////////// /////////// HOTKEY CODE ///////////// //////////////////////////////////////////////////////////////////////// var hotkeyLock = false; var keyDailyCheckRecentEscape = false; function KeyCheck(event) { var KeyID = event.keyCode; // Lock hotkeys if daily window is hidden if (data.TestHidePage(location.href)) hotkeyLock = true; if ( (KeyID == 192 || KeyID == 61 || KeyID == 187) && !hotkeyLock) // backquote key (` - code 192) or equals (= - code 61 in FireFox & code 187 in Chrome, etc) { // Lock hotkey usage to protect from button spamming hotkeyLock = true; // Perform one daily step DailyStep(); // Unlock hotkey usage hotkeyLock = false; } if (KeyID == 27) // escape key { // Close editor window if not already and unlock hotkeys floatingEditor.Hide(); hotkeyLock = false; // Unhide daily window if hidden if (data.TestHidePage(location.href)) { data.RemoveHidePage(location.href); floatingDaily.Draw(); } // If escape is pressed twice in succession, reset the window positions if (keyDailyCheckRecentEscape) { floatingEditor.window.reset(); floatingDaily.window.reset(); } else { keyDailyCheckRecentEscape = true; setTimeout(function(){keyDailyCheckRecentEscape = false;}, 1000); } } if (KeyID == 37 && !hotkeyLock) // left arrow floatingDaily.BackTask(); if (KeyID == 39 && !hotkeyLock) // right arrow floatingDaily.SkipTask(); } document.documentElement.addEventListener("keyup", KeyCheck, true); //////////////////////////////////////////////////////////////////////// /////////// PAGE LOAD RUNTIME /////////////// //////////////////////////////////////////////////////////////////////// // Initialize the jutsus object var jutsus = { // Jutsu(name, code) SRS: new Jutsu("Soul Reaper Style: Lunch, SandySword!", 499), MBST: new Jutsu("Mind Body Switch Technique", 393), PWK: new Jutsu("Projectile Weapons: Kunai", 373), Redeye: new Jutsu("RedEye", 500), Clone: new Jutsu("Clone Jutsu", 368), Disguise: new Jutsu("Disguise Jutsu", 370), ETA: new Jutsu("Exploding Tags: Activate", 371), PWS: new Jutsu("Projectile Weapons: Shuriken", 372), Escape: new Jutsu("Escape Jutsu", 374), FSFJ: new Jutsu("Fire Style: Fireball Jutsu", 376), OI: new Jutsu("Obsessive Insight", 466), PSPDP: new Jutsu("Pinky Style: Pervert-Destroying Punch", 416), AOTNS: new Jutsu("Attack on the Nervous System", 429), FOS: new Jutsu("Flock of Seagulls", 419), EDUT: new Jutsu("Epic Dog Urination Technique", 421), KICHC: new Jutsu("Kido: I can has cheeseburger", 484), INT: new Jutsu("I Need This", 497), FGTT: new Jutsu("Flying Thunder God Technique", 448), BSTIS: new Jutsu("Billy Style: This is Sparta", 444), SSFLB: new Jutsu("Stalker Style: Freaking Laser Beams", 418), SRSIN: new Jutsu("Soul Reaper Style: Imperishable Night", 480), Diagnosis: new Jutsu("Diagnosis", 485), Blank: new Jutsu("", -1) }; // Initialize the quests object var quests = { // Quest(name, code, numsteps, flag) ShowWatchin: new Quest("Watchin' Your Shows", 8, 1), Blank: new Quest("", -1, -1, "") } // Create global instance of daily data object var data = new dailyData(); // Create the floating window objects var floatingDaily = new FloatingDaily(); var floatingEditor = new FloatingEditor(); floatingDaily.Draw();