BvS_Daily

Assist in daily tasks

目前为 2015-11-07 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name BvS_Daily
  3. // @namespace SirDuck36
  4. // @description Assist in daily tasks
  5. // @version 2015.11.07
  6. // @include http://*animecubed.com/billy/bvs*
  7. // @grant GM_log
  8. // @grant GM_addStyle
  9. // ==/UserScript==
  10.  
  11.  
  12. // 4.14.2011 Initial version by SirDuck36
  13. // 4.19.2011 Major overhaul of the API by SirDuck36
  14. // 4.20.2011 Minor updates and bug fixes from North
  15. // 4.20.2011 Updated ChangeSequence to include a task number
  16. // 4.20.2011 Bug fix for GoPage('glowslinging');
  17. // 4.21.2011 Added several new options for gopage function
  18. // 4.23.2011 Added sequences link -- suggested by WolfX
  19. // 4.23.2011 Add hotkeylock to left and right arrow hotkeys -- suggested by Skarn22
  20. // 4.23.2011 Added support for //@SequenceCode before first task -- suggested by North
  21. // 4.23.2011 Fixed editor window hide to remove lingering select box -- SirDuck36
  22. // 4.23.2011 Added functionality to hide daily window on desired pages -- SirDuck36
  23. // 6.12.2011 Bug fix for ChangeSequence function -- Skarn22
  24. // 6.19.2011 Add newline to ShowMsg and add pizzawitch to GoPage function -- SirDuck36
  25. // 9.28.2014 Added grant permissions -- Channel28
  26. // 11.7.2015 Fix a bug with flags when changing sequences. Thanks to Terrec -- Channel28
  27.  
  28.  
  29. ////////////////////////////////////////////////////////////////////////
  30. /////////// LIBRARY CODE /////////////////
  31. ////////////////////////////////////////////////////////////////////////
  32.  
  33. /*
  34. DOM Storage wrapper class (credits: http://userscripts.org/users/dtkarlsson)
  35. Constructor:
  36. var store = new DOMStorage({"session"|"local"}, [<namespace>]);
  37. Set item:
  38. store.setItem(<key>, <value>);
  39. Get item:
  40. store.getItem(<key>[, <default value>]);
  41. Remove item:
  42. store.removeItem(<key>);
  43. Get all keys in namespace as array:
  44. var array = store.keys();
  45. */
  46.  
  47. function DOMStorage(type, namespace) {
  48. var my = this;
  49.  
  50. if (typeof(type) != "string")
  51. type = "session";
  52. switch (type) {
  53. case "local": my.storage = localStorage; break;
  54. case "session": my.storage = sessionStorage; break;
  55. default: my.storage = sessionStorage;
  56. }
  57.  
  58. if (!namespace || typeof(namespace) != "string")
  59. namespace = "Greasemonkey";
  60.  
  61. my.ns = namespace + ".";
  62. my.setItem = function(key, val) {
  63. try {
  64. my.storage.setItem(escape(my.ns + key), val);
  65. }
  66. catch (e) {
  67. GM_log(e);
  68. }
  69. },
  70. my.getItem = function(key, def) {
  71. try {
  72. var val = my.storage.getItem(escape(my.ns + key));
  73. if (val)
  74. return val;
  75. else
  76. return def;
  77. }
  78. catch (e) {
  79. return def;
  80. }
  81. }
  82. // Kludge, avoid Firefox crash
  83. my.removeItem = function(key) {
  84. try {
  85. my.storage.setItem(escape(my.ns + key), null);
  86. }
  87. catch (e) {
  88. GM_log(e);
  89. }
  90. }
  91. // Return array of all keys in this namespace
  92. my.keys = function() {
  93. var arr = [];
  94. var i = 0;
  95. do {
  96. try {
  97. var key = unescape(my.storage.key(i));
  98. if (key.indexOf(my.ns) == 0 && my.storage.getItem(key))
  99. arr.push(key.slice(my.ns.length));
  100. }
  101. catch (e) {
  102. break;
  103. }
  104. i++;
  105. } while (true);
  106. return arr;
  107. }
  108. }
  109. // End DOM Storage Wrapper class
  110.  
  111. // UI (credits: http://userscripts.org/users/dtkarlsson)
  112. function Window(id, storage)
  113. {
  114. var my = this;
  115. my.id = id;
  116. my.offsetX = 0;
  117. my.offsetY = 0;
  118. my.moving = false;
  119.  
  120. // Window dragging events
  121. my.drag = function(event) {
  122. if (my.moving) {
  123. my.element.style.left = (event.clientX - my.offsetX)+'px';
  124. my.element.style.top = (event.clientY - my.offsetY)+'px';
  125. event.preventDefault();
  126. }
  127. }
  128. my.stopDrag = function(event) {
  129. if (my.moving) {
  130. my.moving = false;
  131. var x = parseInt(my.element.style.left);
  132. var y = parseInt(my.element.style.top);
  133. if(x < 0) x = 0;
  134. if(y < 0) y = 0;
  135. storage.setItem(my.id + ".coord.x", x);
  136. storage.setItem(my.id + ".coord.y", y);
  137. my.element.style.opacity = 1;
  138. window.removeEventListener('mouseup', my.stopDrag, true);
  139. window.removeEventListener('mousemove', my.drag, true);
  140. }
  141. }
  142. my.startDrag = function(event) {
  143. if (event.button != 0) {
  144. my.moving = false;
  145. return;
  146. }
  147. my.offsetX = event.clientX - parseInt(my.element.style.left);
  148. my.offsetY = event.clientY - parseInt(my.element.style.top);
  149. if (my.offsetY > 27)
  150. return;
  151.  
  152. my.moving = true;
  153. my.element.style.opacity = 0.75;
  154. event.preventDefault();
  155. window.addEventListener('mouseup', my.stopDrag, true);
  156. window.addEventListener('mousemove', my.drag, true);
  157. }
  158.  
  159. my.show = function()
  160. {
  161. this.element.style.visibility = 'visible';
  162. }
  163.  
  164. my.hide = function()
  165. {
  166. this.element.style.visibility = 'hidden';
  167. }
  168.  
  169. my.reset = function()
  170. {
  171. storage.setItem(my.id + ".coord.x", 6);
  172. storage.setItem(my.id + ".coord.y", 6);
  173. my.element.style.left = "6px";
  174. my.element.style.top = "6px";
  175. }
  176.  
  177.  
  178. my.element = document.createElement("div");
  179. my.element.id = id;
  180. document.body.appendChild(my.element);
  181. my.element.addEventListener('mousedown', my.startDrag, true);
  182.  
  183. if (storage.getItem(my.id + ".coord.x"))
  184. my.element.style.left = storage.getItem(my.id + ".coord.x") + "px";
  185. else
  186. my.element.style.left = "6px";
  187. if (storage.getItem(my.id + ".coord.y"))
  188. my.element.style.top = storage.getItem(my.id + ".coord.y") + "px";
  189. else
  190. my.element.style.top = "6px";
  191. }
  192. // End UI Window implementation
  193.  
  194.  
  195.  
  196. // Make infinite alerts less miserable
  197. var displayAlerts = true;
  198. function alert(msg) {
  199. if (displayAlerts) {
  200. if (!confirm(msg)) {
  201. displayAlerts = false;
  202. }
  203. }
  204. }
  205.  
  206. ////////////////////////////////////////////////////////////////////////
  207. /////////// DATA STRUCTURES /////////////////
  208. ////////////////////////////////////////////////////////////////////////
  209.  
  210.  
  211. function dailyData()
  212. {
  213. // Save the storage object
  214. this.storage = new DOMStorage("local", "BvSDaily");
  215. this.namePlayer = document.evaluate("//input[@name='player' and @type='hidden']", document, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue.value;
  216.  
  217. // List of all sequences stored in memory
  218. this.sequenceList = "";
  219.  
  220. // List of all pages on which the daily window is hidden
  221. this.hidePageList = "";
  222.  
  223. // Name and task number of current sequence
  224. this.sequenceName = "";
  225. this.taskNum = 0;
  226.  
  227. // Actual tasklist for this sequence
  228. this.taskList = new Array();
  229.  
  230. // Array of string flags to save information... a flag is set if contained in the array
  231. // Crude but simple
  232. this.flagStr = "|";
  233.  
  234. // Helper function to set a flag
  235. this.SetFlag = function(flagtext)
  236. {
  237. if (!this.TestFlag(flagtext))
  238. this.flagStr += flagtext + "|";
  239. }
  240.  
  241. // Helper function to test for a flag
  242. this.TestFlag = function(flagtext)
  243. {
  244. if (this.flagStr.indexOf("|" + flagtext + "|") > -1)
  245. return true;
  246. else
  247. return false;
  248. }
  249.  
  250. // Check whether a page is in the hidePageList
  251. this.TestHidePage = function(pageName)
  252. {
  253. for (var i=0; i < this.hidePageList.length; i++)
  254. if (this.hidePageList[i] === pageName)
  255. return true;
  256. return false;
  257. }
  258.  
  259. // Add a page to the hidePageList
  260. this.AddHidePage = function(pageName)
  261. {
  262. if (!this.TestHidePage(pageName))
  263. this.hidePageList.push(pageName);
  264. this.SaveState();
  265. }
  266.  
  267. // Remove a page from the hidePageList
  268. this.RemoveHidePage = function(pageName)
  269. {
  270. for (var i=0; i < this.hidePageList.length; i++)
  271. if (this.hidePageList[i] === pageName)
  272. {
  273. this.hidePageList.splice(i,1);
  274. break;
  275. }
  276. this.SaveState();
  277. }
  278.  
  279. // Check whether a sequence name is in the sequence list
  280. this.TestSequence = function(sequenceName)
  281. {
  282. for (var i=0; i < this.sequenceList.length; i++)
  283. if (this.sequenceList[i] === sequenceName)
  284. return true;
  285. return false;
  286. }
  287.  
  288. // Remove a sequence
  289. this.RemoveSequence = function(sequenceName)
  290. {
  291. // Remove sequence from sequence list
  292. for (var i=0; i<this.sequenceList.length; i++)
  293. if (this.sequenceList[i] === sequenceName)
  294. {
  295. // Remove this element from sequencelist
  296. this.sequenceList.splice(i,1);
  297. break;
  298. }
  299.  
  300. this.SaveState();
  301.  
  302. this.storage.removeItem("Daily_Sequence_" + sequenceName);
  303. }
  304.  
  305. // Store a new or modified sequence
  306. this.SaveSequence = function(sequenceName, sequenceCode)
  307. {
  308. if (!this.TestSequence(sequenceName))
  309. {
  310. // Add sequenceName to sequenceList and save
  311. this.sequenceList.push(sequenceName);
  312. this.SaveState();
  313. }
  314. // Save the sequence code
  315. this.storage.setItem("Daily_Sequence_" + sequenceName, sequenceCode);
  316.  
  317. // Update the daily window
  318. floatingDaily.Draw();
  319. }
  320.  
  321. // Load and parse a given new sequence name
  322. this.LoadSequence = function(newSequenceName)
  323. {
  324. // Set the current sequence name and reinitialize taskList
  325.  
  326. this.flagStr = this.storage.getItem(this.namePlayer + "_Daily_" + this.newSequenceName + "_Flags", "|");
  327.  
  328. if (!(this.sequenceName === newSequenceName))
  329. {
  330. // Only reset the sequencename and tasknum if this is not the current sequence in use
  331. this.sequenceName = newSequenceName;
  332. this.taskNum = 1;
  333. }
  334. // Initialize empty tasklist
  335. this.taskList = new Array();
  336.  
  337. // Load newSequenceName from memory and parse into this.taskList
  338. var strSequenceData = this.storage.getItem("Daily_Sequence_" + newSequenceName, "");
  339. if (!strSequenceData)
  340. return; // no sequence data to be loaded
  341.  
  342. var sequenceData = strSequenceData.split("@NewTask");
  343.  
  344. // Implementation of sequence code goes into task 0
  345. if (sequenceData[0].indexOf("@SequenceCode") > -1)
  346. this.taskList.push(new Task("SequenceCode", sequenceData[0]));
  347. else
  348. this.taskList.push(null);
  349.  
  350. // Input the various tasks to be performed
  351. for (i=1; i < sequenceData.length; i++)
  352. {
  353. // Default taskname from a line such as "//@TaskName: Example Task Name"
  354. var taskname;
  355. var res = /@TaskName: (.+)(?=\r|\n)/.exec(sequenceData[i]);
  356.  
  357. if (res)
  358. taskname = res[1];
  359. else
  360. taskname = "task " + i; // default taskname
  361.  
  362. this.taskList.push(new Task(taskname, sequenceData[i]) );
  363. }
  364.  
  365. // Add a final ending task which does nothing
  366. this.taskList.push(new Task("Done", "ShowMsg(\"Sequence Complete!\")"));
  367. }
  368.  
  369. this.SaveState = function()
  370. {
  371. // Save the current state of this script (sequence name, task number, flags in use)
  372.  
  373. this.storage.setItem("Daily_SequenceList", this.sequenceList.join("|") );
  374. this.storage.setItem("Daily_HidePageList", this.hidePageList.join("|") );
  375. this.storage.setItem(this.namePlayer + "_DailyTaskNum", this.taskNum);
  376. this.storage.setItem(this.namePlayer + "_Daily_" + this.sequenceName + "_Flags", this.flagStr );
  377. this.storage.setItem(this.namePlayer + "_DailySequenceName", this.sequenceName);
  378. }
  379.  
  380. this.LoadState = function()
  381. {
  382. // Load the previous state of this script (sequence name, task number, flags in use)
  383.  
  384. this.sequenceList = this.storage.getItem("Daily_SequenceList", this.sequenceList ).split("|");
  385. this.hidePageList = this.storage.getItem("Daily_HidePageList", this.hidePageList ).split("|");
  386. this.sequenceName = this.storage.getItem(this.namePlayer + "_DailySequenceName", "");
  387.  
  388. if (this.sequenceName)
  389. {
  390. this.taskNum = parseInt( this.storage.getItem(this.namePlayer + "_DailyTaskNum", "0") );
  391. this.flagStr = this.storage.getItem(this.namePlayer + "_Daily_" + this.sequenceName + "_Flags", "|" );
  392. }
  393.  
  394. // remove leading empty sequence strings
  395. // problem only occurs intially (I think)
  396. if (this.sequenceList[0] === "")
  397. {
  398. this.sequenceList.splice(0,1);
  399. this.SaveState();
  400. }
  401.  
  402. if (this.hidePageList[0] === "")
  403. {
  404. this.hidePageList.splice(0,1);
  405. this.SaveState();
  406. }
  407. }
  408. // Load the current state
  409. this.LoadState();
  410.  
  411. // Load the sequence corresponding to the current state
  412. this.LoadSequence(this.sequenceName);
  413. }
  414.  
  415.  
  416.  
  417. // task object has a description to be shown and a function that gets called
  418. function Task(taskname, taskfun)
  419. {
  420. this.taskname = taskname;
  421. this.taskfun = taskfun;
  422. }
  423.  
  424. function Jutsu(name, code)
  425. {
  426. this.name = name;
  427. this.code = code;
  428. }
  429.  
  430. function Mission(name, jutsu, allyget, type, diff, succ)
  431. {
  432. this.name = name;
  433. this.jutsu = jutsu;
  434. this.type = type;
  435. this.diff = diff;
  436. this.succ = succ;
  437. this.allyget = allyget;
  438. }
  439.  
  440. function Quest(name, code, numsteps, flag)
  441. {
  442. this.name = name;
  443. this.code = code;
  444. this.numsteps = numsteps;
  445. this.flag = flag;
  446. }
  447.  
  448.  
  449. ////////////////////////////////////////////////////////////////////////
  450. /////////// FLOATING WINDOWS ///////////////
  451. ////////////////////////////////////////////////////////////////////////
  452.  
  453.  
  454. function FloatingDaily()
  455. {
  456.  
  457. this.window = new Window("floatingDaily", data.storage);
  458. // Add css style for report window
  459. GM_addStyle("#floatingDaily {border: 2px solid #000000; position: fixed; z-index: 100; " +
  460. "color: #000000; background-color: #FFFFFF; padding: 5; text-align: left; " +
  461. "overflow-y: auto; overflow-x: auto; width: 200; height: 500; " +
  462. "background: none repeat scroll 0% 0% rgb(216, 216, 216);}");
  463.  
  464. this.Draw = function()
  465. {
  466. // Test whether the daily window should be drawn on this page
  467. if (data.TestHidePage(location.href))
  468. {
  469. this.Hide();
  470. return;
  471. }
  472.  
  473. // Show the window if not already
  474. this.window.show();
  475.  
  476. // Helper array to build the HTML
  477. var arr = new Array();
  478. arr.push('<table width="200"><tr><td align="left">Daily Helper</td>',
  479. '<td align="right"><p style="margin: 0pt; text-align: right;">',
  480. '<a href="javascript:void(0)" id="DailyHidePageButton">',
  481. '(Hide)</a></p></td></tr></table><br>');
  482.  
  483. arr.push("Sequence: <b>" + data.sequenceName + "</b><br><br>");
  484. arr.push('<table width="200"><tr><td align="left">',
  485. '<a href="javascript:void(0)" id="DailyBackTaskButton">',
  486. '&lt;-----</a></td>');
  487.  
  488. arr.push('<td align="center"><b>' + data.taskNum + '</b> / ' + (data.taskList.length-1) + '</td>');
  489.  
  490. arr.push('<td align="right"><a href="javascript:void(0)" id="DailySkipTaskButton">',
  491. '-----&gt;</a></td></tr></table><br>');
  492. if (data.taskNum > 0 && data.taskNum < data.taskList.length)
  493. arr.push('Task: <b>' + data.taskList[data.taskNum].taskname + '</b>');
  494. else
  495. arr.push('Task: Undefined Task');
  496.  
  497. arr.push('<br><br><div id="DailyMsgDiv"></div><br><br>');
  498.  
  499. arr.push('Your sequences:');
  500. // Generate list of sequence options to choose from
  501. for (var i=0; i<data.sequenceList.length; i++)
  502. {
  503. var sequenceName = data.sequenceList[i];
  504.  
  505. arr.push('<p style="margin: 0pt; text-align: right;">',
  506. '<a href="javascript:void(0)" val="' + sequenceName,
  507. '" id="ChooseSequenceButton_' + sequenceName + '">',
  508. sequenceName + ' &gt;</a></p>');
  509. }
  510.  
  511. arr.push('<br><p style="margin: 0pt; text-align: left;">',
  512. '<a href="javascript:void(0)" id="DailySequenceEditorButton">',
  513. '&lt; Open Sequence Editor</a></p>');
  514.  
  515. arr.push('<br><p style="margin: 0pt; text-align: left;">',
  516. '<a href="https://docs.google.com/leaf?id=0B10D12_4U2KiNzYxZjY0YTEtYzU1Mi00Y2YzLTg5NGYtYWZlNGQzMDQyNDE0&hl=en" id="MoreSequencesButton" target="_blank">',
  517. '&lt; Get More Sequences</a></p>');
  518.  
  519. // arr.push("<b>Flags</b>:");
  520. // arr.push(data.flagStr.replace(/\|/g, "<br>"));
  521. // Concatenate everything in the array to form the html
  522. this.window.element.innerHTML = arr.join("");
  523.  
  524. // Event handlers for sequenceList items
  525. for (var i=0; i<data.sequenceList.length; i++)
  526. {
  527. var sequenceName = data.sequenceList[i];
  528.  
  529. var elem = document.getElementById("ChooseSequenceButton_" + sequenceName);
  530. elem.addEventListener("click", function() { data.LoadSequence(this.id.split("_")[1]); data.SaveState(); floatingDaily.Draw(); }, false);
  531. }
  532.  
  533. document.getElementById("DailyHidePageButton").addEventListener("click", floatingDaily.HidePage, true);
  534. // document.getElementById("DailyResetDataButton").addEventListener("click", floatingDaily.ResetData, true);
  535. document.getElementById("DailySkipTaskButton").addEventListener("click", floatingDaily.SkipTask, true);
  536. document.getElementById("DailyBackTaskButton").addEventListener("click", floatingDaily.BackTask, true);
  537. document.getElementById("DailySequenceEditorButton").addEventListener("click", floatingDaily.OpenSequenceEditor, true);
  538. }
  539.  
  540. // Hide the window (and remove the interior)
  541. this.Hide = function()
  542. {
  543. this.window.element.innerHTML = "";
  544. this.window.hide();
  545. }
  546.  
  547. this.showErr = function(err)
  548. {
  549. document.getElementById("DailyMsgDiv").innerHTML += err.message;
  550. }
  551.  
  552. this.HidePage = function()
  553. {
  554. data.AddHidePage(location.href);
  555. floatingDaily.Hide();
  556. }
  557.  
  558. this.ResetData = function()
  559. {
  560. data.taskNum = 1;
  561. data.flagStr = "|";
  562. data.SaveState();
  563. floatingDaily.Draw();
  564. }
  565.  
  566. this.SkipTask = function()
  567. {
  568. IncrementTask();
  569. }
  570.  
  571. this.BackTask = function()
  572. {
  573. // Temporary for debugging
  574. if (data.taskNum > 1)
  575. data.taskNum--;
  576. data.SaveState();
  577. floatingDaily.Draw();
  578. }
  579.  
  580. this.OpenSequenceEditor = function()
  581. {
  582. // Disable hotkeys
  583. hotkeyLock = true;
  584.  
  585. // Initialize the Editor window if not already
  586. floatingEditor.Draw();
  587.  
  588. // Load the current sequence if it exists
  589. if (data.TestSequence(data.sequenceName))
  590. floatingEditor.LoadSequence(data.sequenceName);
  591.  
  592. // Show the editor window
  593. floatingEditor.window.show();
  594. }
  595. }
  596.  
  597.  
  598.  
  599.  
  600. function FloatingEditor()
  601. {
  602.  
  603. this.window = new Window("floatingEditor", data.storage);
  604.  
  605. // Add css style for report window
  606. GM_addStyle("#floatingEditor {border: 2px solid #000000; position: fixed; z-index: 100; " +
  607. "color: #000000; background-color: #FFFFFF; padding: 5; text-align: left; " +
  608. "overflow-y: auto; overflow-x: auto; width=600; height: 620; " +
  609. "background: none repeat scroll 0% 0% rgb(216, 216, 216);}");
  610.  
  611. this.Draw = function()
  612. {
  613. // Helper array to build the HTML
  614. var arr = new Array();
  615. arr.push("Sequence Editor<br><br>");
  616.  
  617. // Drop down box for things in the sequence list
  618. arr.push('Choose an existing sequence to edit: ');
  619. arr.push('<select id="sequenceSelect">');
  620. for (var i=0; i < data.sequenceList.length; i++)
  621. arr.push('<option value="' + data.sequenceList[i] + '">' + data.sequenceList[i] + '</option>');
  622. arr.push('</select>&nbsp&nbsp');
  623.  
  624. arr.push('<a href="javascript:void(0)" id="EditorLoadSequenceButton">',
  625. 'Load Sequence &gt;</a><br>');
  626.  
  627. arr.push('<br><br>');
  628.  
  629. // Textbox for sequence code
  630. arr.push('<textarea id="sequenceCode" rows="30" cols="76"></textarea><br>');
  631.  
  632. // Remove button
  633. arr.push('<p style="margin: 0pt; text-align: left;">',
  634. '<a href="javascript:void(0)" id="EditorDeleteSequenceButton">',
  635. '&lt; Delete Sequence</a></p>');
  636.  
  637. // Save button
  638. arr.push('<p style="margin: 0pt; text-align: right;">',
  639. '<a href="javascript:void(0)" id="EditorSaveSequenceButton">',
  640. 'Save Sequence &gt;</a></p><br>');
  641.  
  642.  
  643. // Concatenate everything in the array to form the html
  644. this.window.element.innerHTML = arr.join("");
  645.  
  646. floatingEditor.LoadSequence(data.sequenceName);
  647. document.getElementById("EditorSaveSequenceButton").addEventListener("click", floatingEditor.SaveSequence, true);
  648. document.getElementById("EditorDeleteSequenceButton").addEventListener("click", floatingEditor.DeleteSequence, true);
  649. document.getElementById("EditorLoadSequenceButton").addEventListener("click", floatingEditor.LoadSelectedSequence, true);
  650.  
  651. // Load the textarea with a sample sequence
  652. var sequenceStr =
  653. "//@SequenceName: Default\n\n\n" +
  654. "//------------------------------------------\n" +
  655. "//@NewTask\n" +
  656. "//@TaskName: Example Task 1\n\n" +
  657. "ShowMsg(\"Example task 1 only shows this message\");\n\n\n" +
  658. "//------------------------------------------\n" +
  659. "//@NewTask\n" +
  660. "//@TaskName: Example Task 2\n\n" +
  661. "ShowMsg(\"Example task 2 is almost the same\");";
  662.  
  663. document.getElementById("sequenceCode").value = sequenceStr;
  664. }
  665.  
  666. // Hide the window (and remove the interior)
  667. this.Hide = function()
  668. {
  669. this.window.element.innerHTML = "";
  670. this.window.hide();
  671. }
  672.  
  673. this.SaveSequence = function()
  674. {
  675. // Extract the sequence string
  676. var sequenceCode = document.getElementById("sequenceCode").value;
  677. var sequenceName;
  678.  
  679. // Get the sequence name and verify correct input formatting
  680. try
  681. {
  682. sequenceName = /@SequenceName: (.+)(?=\r|\n)/.exec(sequenceCode)[1];
  683. }
  684. catch(err)
  685. {
  686. alert("Please enter a sequence name on the first line with format:\n" +
  687. "//@SequenceName: Example Sequence Name");
  688. return;
  689. }
  690. // Clean the string for only alphanumeric characters and spaces
  691. if ( !(sequenceName === sequenceName.replace(/[^a-zA-Z 0-9]+/g,'')) )
  692. {
  693. alert("Alphanumeric characters and spaces only in sequence names");
  694. return;
  695. }
  696.  
  697. data.SaveSequence(sequenceName, sequenceCode);
  698. data.LoadSequence(sequenceName);
  699.  
  700. // floatingEditor.Draw();
  701. // document.getElementById("sequenceCode").value = sequenceCode;
  702. }
  703.  
  704. this.LoadSelectedSequence = function()
  705. {
  706. var elem = document.getElementById("sequenceSelect");
  707. var sequenceName = elem.options[elem.selectedIndex].value;
  708. floatingEditor.LoadSequence(sequenceName);
  709. }
  710.  
  711. this.DeleteSequence = function()
  712. {
  713. // Extract the sequence string
  714. var sequenceCode = document.getElementById("sequenceCode").value;
  715. var sequenceName;
  716.  
  717. // Get the sequence name and verify correct input formatting
  718. try
  719. {
  720. sequenceName = /@SequenceName: (.+)(?=\r|\n)/.exec(sequenceCode)[1];
  721. }
  722. catch(err)
  723. {
  724. alert("Please enter a sequence name on the first line with format:\n" +
  725. "//@SequenceName: Example Sequence Name");
  726. return;
  727. }
  728. // Clean the string for only alphanumeric characters and spaces
  729. if ( !(sequenceName === sequenceName.replace(/[^a-zA-Z 0-9]+/g,'')) )
  730. {
  731. alert("Alphanumeric characters and spaces only in sequence names");
  732. return;
  733. }
  734.  
  735. // Make sure the user really wants to do this
  736. if (!confirm("Are you sure you want to delete the sequence: \'" + sequenceName + "\'?"))
  737. return;
  738.  
  739. // Remove the sequence and reload the editor
  740. data.RemoveSequence(sequenceName);
  741. data.LoadSequence("");
  742. floatingEditor.LoadSequence("");
  743. floatingEditor.Draw();
  744. floatingDaily.Draw();
  745. }
  746.  
  747. this.LoadSequence = function(sequenceName)
  748. {
  749. // If sequenceName is null do nothing
  750. if (!sequenceName)
  751. return;
  752.  
  753. // sequenceName is assumed to exist... error if not
  754. var sequenceStr = data.storage.getItem("Daily_Sequence_" + sequenceName, "");
  755.  
  756. if (!sequenceStr)
  757. {
  758. alert("Sequence " + sequenceName + " does not exist\nThis is an error that should be reported.");
  759. return;
  760. }
  761.  
  762. // Otherwise, load up the sequence text
  763. document.getElementById("sequenceCode").value = sequenceStr;
  764.  
  765. // Also load up this sequence in browser cache
  766. data.LoadSequence(sequenceName);
  767. floatingDaily.Draw();
  768. }
  769.  
  770. // hide the window by default
  771. this.window.hide();
  772. }
  773.  
  774.  
  775.  
  776.  
  777.  
  778. ////////////////////////////////////////////////////////////////////////
  779. /////////// USER API FUNCTIONS ///////////////
  780. ////////////////////////////////////////////////////////////////////////
  781.  
  782. //////////////// API Functions which halt task execution //////////////////
  783.  
  784. // Put up a message in the floating daily window
  785. // This function halts script execution
  786. function ShowMsg(strMsg)
  787. {
  788. if (!strMsg)
  789. strMsg = "";
  790. else
  791. strMsg += '<br>';
  792. throw new Error(strMsg);
  793. }
  794.  
  795. // Submit a form with name strName and display message strMsg on success
  796. // This function always halts task execution
  797. function FormSubmit(strName, strMsg)
  798. {
  799. if (!strMsg)
  800. strMsg = 'Submitting Form: ' + strName;
  801.  
  802. if (FormTest(strName))
  803. {
  804. // Success, submit the form and display the desired message
  805. document.forms.namedItem(strName).submit();
  806. ShowMsg(strMsg);
  807. }
  808. else
  809. {
  810. // Display error message for user to see
  811. ShowMsg('Form ' + strName + ' does not exist');
  812. }
  813. }
  814.  
  815. // Move to the next task if possible
  816. // This function always halts task execution
  817. function IncrementTask(strMsg)
  818. {
  819. if (data.taskNum < data.taskList.length-1)
  820. data.taskNum++;
  821. data.SaveState();
  822. floatingDaily.Draw();
  823.  
  824. ShowMsg(strMsg);
  825. }
  826.  
  827. // Move to the next task if possible
  828. // This function does NOT halt task execution
  829. function IncrementTaskNonBlock()
  830. {
  831. if (data.taskNum < data.taskList.length-1)
  832. data.taskNum++;
  833. data.SaveState();
  834. floatingDaily.Draw();
  835. }
  836.  
  837. // Move to next task if condition is true
  838. // This function halts task execution if condition is true
  839. function IncrementTaskIf(cond, strMsg)
  840. {
  841. if (cond)
  842. IncrementTask(strMsg);
  843. }
  844.  
  845. // Change to new sequence (useful for chaining together separate sequences)
  846. function ChangeSequence(strSequenceName, newTaskName)
  847. {
  848. // Search for strSequenceName in sequence list
  849. for (var i=0; i < data.sequenceList.length; i++)
  850. if (data.sequenceList[i] === strSequenceName)
  851. {
  852. // Load the sequence and set the task number if desired
  853. data.LoadSequence(strSequenceName);
  854.  
  855. if (newTaskName)
  856. {
  857. for (var j=1; j < data.taskList.length; j++)
  858. if (data.taskList[j].taskname === newTaskName)
  859. data.taskNum = j;
  860.  
  861. }
  862.  
  863. // Save state
  864. data.SaveState();
  865.  
  866. // Redraw the window
  867. floatingDaily.Draw();
  868.  
  869. // Done
  870. ShowMsg('Loaded Sequence: ' + strSequenceName);
  871. }
  872.  
  873. // If code reaches this point, sequence does not exist
  874. ShowMsg('Sequence ' + strSequenceName + ' does not exist');
  875. }
  876.  
  877.  
  878. //////////////// API Functions which test the page for information //////////////////
  879.  
  880. // Test the document body HTML for the given text
  881. function DocTest(strText)
  882. {
  883. return (document.body.innerHTML.indexOf(strText) > -1);
  884. }
  885.  
  886. // Test the href location for the given text
  887. function LocationTest(strText)
  888. {
  889. return (location.href.indexOf(strText) > -1);
  890. }
  891.  
  892. // Test for the existence of a form with name = strName
  893. function FormTest(strName)
  894. {
  895. return (document.forms.namedItem(strName) ? true : false);
  896. }
  897.  
  898. // Test whether a form input is already checked
  899. function FormCheckTest(strFormName, strInputName, strInputValue)
  900. {
  901. var strXPath = "";
  902.  
  903. // Form name is optional, include it if necessary
  904. if (strFormName)
  905. strXPath += '//form[@name=\'' + strFormName + '\']';
  906.  
  907. // Input name is mandatory (else we cannot find the input box...)
  908. strXPath += '//input[@name=\'' + strInputName + '\'';
  909.  
  910. // Input value is also optional
  911. if (strInputValue)
  912. strXPath += ' and @value=\'' + strInputValue + '\'';
  913. strXPath += ']';
  914.  
  915. var elem = document.evaluate(strXPath, document, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue;
  916.  
  917. // Element does not exist
  918. if (!elem)
  919. return false;
  920.  
  921. // Otherwise return checked state
  922. return elem.checked;
  923. }
  924.  
  925.  
  926.  
  927. /////////////// API Functions to manipulate forms on the page //////////////
  928.  
  929. // Check a checkbox on a form
  930. // Returns false if element does not exist, or is disabled
  931. function FormCheck(strFormName, strInputName, strInputValue)
  932. {
  933. var strXPath = "";
  934.  
  935. // Form name is optional, include it if necessary
  936. if (strFormName)
  937. strXPath += '//form[@name=\'' + strFormName + '\']';
  938.  
  939. // Input name is mandatory (else we cannot find the input box...)
  940. strXPath += '//input[@name=\'' + strInputName + '\'';
  941.  
  942. // Input value is also optional
  943. if (strInputValue)
  944. strXPath += ' and @value=\'' + strInputValue + '\'';
  945. strXPath += ']';
  946.  
  947. var elem = document.evaluate(strXPath, document, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue;
  948.  
  949. // Return without action if element does not exist or is disabled
  950. if (!elem || elem.disabled)
  951. return false;
  952.  
  953. // Otherwise check the box and return true
  954. elem.checked = "checked";
  955. return true;
  956. }
  957.  
  958. // Select an option form a drop down box
  959. function FormSelect(strFormName, strSelectName, strOptionValue, strOptionText)
  960. {
  961. // First get the select object
  962. var strXPath = "";
  963.  
  964. // Form name is optional, include it if necessary
  965. if (strFormName)
  966. strXPath += '//form[@name=\'' + strFormName + '\']';
  967.  
  968. // Input name is mandatory (else we cannot find the input box...)
  969. strXPath += '//select[@name=\'' + strSelectName + '\']';
  970.  
  971. var elem = document.evaluate(strXPath, document, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue;
  972.  
  973. // Element does not exist
  974. if (!elem || elem.disabled)
  975. return false;
  976.  
  977. // loop through options and select any if found
  978. for (var i=0; i<elem.options.length; i++)
  979. {
  980. if ( (!strOptionValue || elem.options[i].value == strOptionValue) &&
  981. (!strOptionText || elem.options[i].text == strOptionText) )
  982. {
  983. elem.selectedIndex = i;
  984. return true;
  985. }
  986. }
  987.  
  988. // If the code reaches this point, we did not find the option to select
  989. return false;
  990. }
  991.  
  992. // Set .value field of an Input object
  993. function FormSetValue(strFormName, strInputName, newValue)
  994. {
  995. var strXPath = "";
  996.  
  997. // Form name is optional, include it if necessary
  998. if (strFormName)
  999. strXPath += '//form[@name=\'' + strFormName + '\']';
  1000.  
  1001. // Input name is mandatory (else we cannot find the input box...)
  1002. strXPath += '//input[@name=\'' + strInputName + '\']';
  1003.  
  1004. var elem = document.evaluate(strXPath, document, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue;
  1005.  
  1006. // Return without action if element does not exist or is disabled
  1007. if (!elem || elem.disabled)
  1008. return false;
  1009.  
  1010. // Otherwise check the box and return true
  1011. elem.value = newValue;
  1012. return true;
  1013. }
  1014.  
  1015. // Get .value field of an Input object
  1016. function FormGetValue(strFormName, strInputName)
  1017. {
  1018. var strXPath = "";
  1019.  
  1020. // Form name is optional, include it if necessary
  1021. if (strFormName)
  1022. strXPath += '//form[@name=\'' + strFormName + '\']';
  1023.  
  1024. // Input name is mandatory (else we cannot find the input box...)
  1025. strXPath += '//input[@name=\'' + strInputName + '\']';
  1026.  
  1027. var elem = document.evaluate(strXPath, document, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue;
  1028.  
  1029. // Return without action if element does not exist or is disabled
  1030. if (!elem)
  1031. return false;
  1032.  
  1033. // Otherwise check the box and return true
  1034. return elem.value;
  1035. }
  1036.  
  1037.  
  1038.  
  1039.  
  1040. ////////////// API Functions which navigate around the BvS world //////////////
  1041.  
  1042. // Helper function to interact with BvS menus
  1043. function GoMenuPage(strMenuItem)
  1044. {
  1045. var menucell = document.evaluate('//a[text()="' + strMenuItem + '"]', document, null,
  1046. XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue;
  1047. FormSubmit(menucell.href.split(":")[1].split(".")[1], 'Moving to page: ' + strMenuItem);
  1048. };
  1049.  
  1050. // General function to go to any (or at least most) bvs page
  1051. function GoPage(strPageName)
  1052. {
  1053. // Class to define how to get to a specific page
  1054. // funLoad is a function which loads the desired page (starting on the prereq page)
  1055. // strPrereq indicates whether we should start from a simpler page
  1056. // funTest is a function which determines whether we are already on the correct page
  1057.  
  1058. function objPage(funLoad, strPrereq, funTest)
  1059. {
  1060. this.funLoad = funLoad;
  1061. this.strPrereq = strPrereq;
  1062. this.funTest = funTest;
  1063. };
  1064.  
  1065. // Create the list of page objects
  1066. var pageList = {
  1067. // Main menu items
  1068. main: new objPage(function(){GoMenuPage('Main');}, null, function(){return LocationTest('/bvs/pages/main.html');} ),
  1069. village: new objPage(function(){GoMenuPage('Village');}, null, function(){return LocationTest('/bvs/village.html');} ),
  1070. partyhouse: new objPage(function(){GoMenuPage('Party House');}, null, function(){return LocationTest('/bvs/partyhouse.html');} ),
  1071. shop: new objPage(function(){GoMenuPage('Shop');}, null, function(){return LocationTest('/bvs/shop.html');} ),
  1072. consumables: new objPage(function(){GoMenuPage('Consumables');}, null, function(){return LocationTest('/bvs/oneuseitems.html');} ),
  1073. worldkaiju: new objPage(function(){GoMenuPage('WorldKaiju');}, null, function(){return LocationTest('/bvs/worldkaiju.html');} ),
  1074. missions: new objPage(function(){GoMenuPage('Missions');}, null, function(){return LocationTest('/bvs/missionstart.html') || LocationTest('/bvs/missions');} ),
  1075. quests: new objPage(function(){GoMenuPage('Quests');}, null, function(){return LocationTest('/bvs/quests.html') || LocationTest('/bvs/questattempt.html') || LocationTest('/bvs/chuninexam.html');} ),
  1076. spar: new objPage(function(){GoMenuPage('Spar');}, null, function(){return LocationTest('/bvs/spar.html');} ),
  1077. arena: new objPage(function(){GoMenuPage('Arena');}, null, function(){return LocationTest('/bvs/arena.html');} ),
  1078. team: new objPage(function(){GoMenuPage('Team');}, null, function(){return LocationTest('/bvs/team.html');} ),
  1079. jutsu: new objPage(function(){GoMenuPage('Jutsu');}, null, function(){return LocationTest('/bvs/jutsu.html');} ),
  1080. summons: new objPage(function(){GoMenuPage('Summons');}, null, function(){return LocationTest('/bvs/summon.html');} ),
  1081. bucket: new objPage(function(){GoMenuPage('Bucket');}, null, function(){return LocationTest('/bvs/bucket.html');} ),
  1082.  
  1083. // Party house menu items
  1084. ph_tipline: new objPage(function(){GoMenuPage('Tip Line');}, 'partyhouse', function(){return FormTest('tipline');} ),
  1085. ph_juicebar: new objPage(function(){GoMenuPage('\'Juice\' Bar');}, 'partyhouse', function(){return FormTest('br');} ),
  1086. 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).');} ),
  1087. ph_wheel: new objPage(function(){GoMenuPage('Wheel');}, 'partyhouse', function(){return FormTest('raf');} ),
  1088. ph_jackpot: new objPage(function(){GoMenuPage('Jackpot');}, 'partyhouse', function(){return FormTest('ninrou');} ),
  1089. ph_lottery: new objPage(function(){GoMenuPage('Lottery');}, 'partyhouse', function(){return FormTest('el');} ),
  1090. ph_tsukiball: new objPage(function(){GoMenuPage('Tsukiball');}, 'partyhouse', function(){return FormTest('skib');} ),
  1091. ph_bigboard: new objPage(function(){GoMenuPage('Big Board');}, 'partyhouse', function(){return DocTest('<b>The Big Board</b>');} ),
  1092. ph_scratchies: new objPage(function(){GoMenuPage('Scratchies');}, 'partyhouse', function(){return FormTest('scratch') || FormTest('mainform2');} ),
  1093. ph_darts: new objPage(function(){GoMenuPage('Darts');}, 'partyhouse', function(){return FormTest('dgame');} ),
  1094. ph_partyroom: new objPage(function(){GoMenuPage('Party Room');}, 'partyhouse', function(){return FormTest('pr');} ),
  1095. ph_crane: new objPage(function(){GoMenuPage('Crane');}, 'partyhouse', function(){return FormTest('cgame');} ),
  1096. ph_over11k: new objPage(function(){GoMenuPage('Over 11K');}, 'partyhouse', function(){return FormTest('over11');} ),
  1097. ph_snakeman: new objPage(function(){GoMenuPage('SNAKEMAN');}, 'partyhouse', function(){return FormTest('newsnake');} ),
  1098. ph_roulette: new objPage(function(){GoMenuPage('Roulette');}, 'partyhouse', function(){return LocationTest('/bvs/partyhouse-roulette.html');} ),
  1099. ph_mahjong: new objPage(function(){GoMenuPage('Mahjong');}, 'partyhouse', function(){return LocationTest('/bvs/partyhouse-mahjong.html');} ),
  1100. ph_superfail: new objPage(function(){GoMenuPage('SUPERFAIL');}, 'partyhouse', function(){return LocationTest('/bvs/partyhouse-superfail.html');} ),
  1101. ph_pigeons: new objPage(function(){GoMenuPage('Pigeons');}, 'partyhouse', function(){return LocationTest('/bvs/partyhouse-keno.html');} ),
  1102. ph_flowerwars: new objPage(function(){GoMenuPage('Flower Wars');}, 'partyhouse', function(){return LocationTest('/bvs/partyhouse-hanafuda.html');} ),
  1103. ph_pachinko: new objPage(function(){GoMenuPage('Pachinko');}, 'partyhouse', function(){return LocationTest('/bvs/partyhouse-pachinko.html');} ),
  1104.  
  1105.  
  1106. // Linked from village
  1107. fields: new objPage(function(){FormSubmit('fieldmenu');}, 'village', function(){return LocationTest('/bvs/villagefields.html');} ),
  1108. phases: new objPage(function(){FormSubmit('phases');}, 'village', function(){return LocationTest('/bvs/villagephases.html') || LocationTest('/bvs/villager00t.html');} ),
  1109. bingo: new objPage(function(){FormSubmit('bbook');}, 'village', function(){return LocationTest('/bvs/bingo');} ),
  1110. jutsuenhance: new objPage(function(){FormSubmit('jenhance');}, 'village', function(){return LocationTest('/bvs/villagejenhance.html');} ),
  1111. billycon: new objPage(function(){FormSubmit('concenter');}, 'village', function(){return LocationTest('/bvs/billycon-register.html');} ),
  1112. robofighto: new objPage(function(){FormSubmit('robofighto');}, 'village', function(){return LocationTest('/bvs/villagerobofighto.html');} ),
  1113. zrewards: new objPage(function(){FormSubmit('zrt');}, 'village', function(){return LocationTest('/bvs/zombjarewards.html');} ),
  1114. kaiju: new objPage(function(){FormSubmit('kat');}, 'village', function(){return LocationTest('/bvs/villagemonsterfight');} ),
  1115. pizzawitch: new objPage(function(){FormSubmit('pizzamenu');}, 'village', function(){return LocationTest('/bvs/pizzawitch.html') || LocationTest('/bvs/pizzawitchgarage.html');} ),
  1116.  
  1117. // Linked from billycon
  1118. glowslinging: new objPage(function(){FormSubmit('glowsling');}, 'billycon', function(){return LocationTest('/bvs/billycon-glowslinging.html') || LocationTest('/billycon-glowslingfight.html');} ),
  1119.  
  1120. // Linked from main page
  1121. themes: new objPage(function(){FormSubmit('theme');}, 'main', function(){return LocationTest('/bvs/themesdifficulty.html');} ),
  1122. tinybeevault: new objPage(function(){FormSubmit('tinybee');}, 'main', function(){return LocationTest('/bvs/tinybees.html');} ),
  1123. sponsoritem: new objPage(function(){FormSubmit('sponsor');}, 'main', function(){return LocationTest('/bvs/sponsoritems.html');} ),
  1124. favors: new objPage(function(){FormSubmit('sandstorm');}, 'main', function(){return LocationTest('/bvs/sandstorm.html');} ),
  1125. reaperblood: new objPage(function(){FormSubmit('reaper');}, 'main', function(){return LocationTest('/bvs/reaper.html');} ),
  1126. driftstyle: new objPage(function(){FormSubmit('drifter');}, 'main', function(){return LocationTest('/bvs/drifter.html');} ),
  1127. avatar: new objPage(function(){FormSubmit('avatar');}, 'main', function(){return LocationTest('/bvs/avatar.html');} ),
  1128.  
  1129.  
  1130. blank: new objPage(null,null,null)
  1131. };
  1132.  
  1133. // Extract the page from the pageList object
  1134. var page = pageList[strPageName];
  1135. if (!page)
  1136. throw new Error('Page list object: ' + strPageName + ' does not exist');
  1137. // Test whether we are already on the correct page
  1138. if (page.funTest())
  1139. return; // Early return, on a good page
  1140.  
  1141. // If a prerequisite page is listed, go to it first
  1142. if (page.strPrereq)
  1143. GoPage(page.strPrereq);
  1144.  
  1145. // Finally, move to the desired page
  1146. page.funLoad();
  1147. ShowMsg('Moving to page: ' + strPageName);
  1148. }
  1149.  
  1150. // Get a mission of a given rank
  1151. function GetMission(rank)
  1152. {
  1153. GoPage('missions');
  1154.  
  1155. if ( !LocationTest("/bvs/missionstart.html") )
  1156. return;
  1157.  
  1158. objMissionLookup = {
  1159. D: "d",
  1160. genD: "gd",
  1161. ninD: "nd",
  1162. taiD: "td",
  1163.  
  1164. C: "c",
  1165. genC: "gc",
  1166. ninC: "nc",
  1167. taiC: "tc",
  1168.  
  1169. B: "b",
  1170. genB: "gb",
  1171. ninB: "nb",
  1172. taiB: "tb",
  1173.  
  1174. A: "a",
  1175. genA: "ga",
  1176. ninA: "na",
  1177. taiA: "ta",
  1178.  
  1179. AA: "aa",
  1180. genAA: "gaa",
  1181. ninAA: "naa",
  1182. taiAA: "taa",
  1183.  
  1184. Reaper: "reaper",
  1185. genReaper: "greaper",
  1186. ninReaper: "nreaper",
  1187. taiReaper: "treaper",
  1188.  
  1189. Monochrome: "monochrome",
  1190. genMonochrome: "gmonochrome",
  1191. ninMonochrome: "nmonochrome",
  1192. taiMonochrome: "tmonochrome",
  1193.  
  1194. Outskirts: "outskirts",
  1195. Wasteland: "wasteland",
  1196. Burgerninja: "burger",
  1197. Pizzawitch: "pizza",
  1198. Witchinghour: "witch",
  1199. S: "s",
  1200.  
  1201. Blank: ""
  1202. };
  1203. FormSubmit("misform" + objMissionLookup[rank], 'Getting ' + rank + ' rank mission');
  1204. }
  1205.  
  1206. // Set the r00t field keys
  1207. function SetField(key1, key2, key3)
  1208. {
  1209. GoPage('fields');
  1210.  
  1211. // See whether we are on the right field
  1212. if ( key1 && key2 && key3 &&
  1213. (!DocTest("<b>"+key1+"</b></td>") ||
  1214. !DocTest("<b>"+key2+"</b></td>") ||
  1215. !DocTest("<b>"+key3+"</b></td>")) )
  1216. {
  1217. // Go to the right field if possible
  1218. if ( FormSelect(null, 'key_1', null, key1) &&
  1219. FormSelect(null, 'key_2', null, key2) &&
  1220. FormSelect(null, 'key_3', null, key3) )
  1221. {
  1222. FormSubmit('field', 'Changing to: ' + key1 + ' ' + key2 + ' ' + key3);
  1223. }
  1224. }
  1225. }
  1226.  
  1227.  
  1228.  
  1229.  
  1230.  
  1231. //////////////// API Functions for running missions //////////////////
  1232.  
  1233. // Enable megamissions -- this function might go away
  1234. function EnableMegamissions()
  1235. {
  1236. GoPage('missions');
  1237. IncrementTaskIf(DocTest("<i>MegaMissions Active!</i>"));
  1238. FormSubmit('megamis', 'Enabling megamissions');
  1239. }
  1240.  
  1241. // Simple attempt for current mission with given jutsu... does not return, always throws exception
  1242. function MissionAttempt(jutsu)
  1243. {
  1244. if (!jutsu)
  1245. {
  1246. jutsu = { code: -1, name: '' };
  1247. }
  1248.  
  1249. // Blindly attempt the mission using the given jutsu
  1250. if (FormTest('domission'))
  1251. FormSubmit('domission');
  1252.  
  1253. if (FormTest('attempt'))
  1254. {
  1255. if (jutsu.code > -1)
  1256. FormCheck(null, 'usejutsu', "" + jutsu.code);
  1257. FormSubmit('attempt', 'Attempting mission with jutsu: ' + jutsu.name);
  1258. }
  1259.  
  1260. // Show message
  1261. ShowMsg("Attempting mission with jutsu: " + jutsu.name);
  1262. }
  1263.  
  1264. // Complex attempt for current mission stack
  1265. // Script defaults to given jutsu if not found in the stack
  1266. function MissionStackAttempt(stack, defaultjutsu)
  1267. {
  1268. // Get the mission name cell
  1269. var missioncell = document.evaluate('//div[@class="miscontainer"]/div/div/div/center/font/b', document, null,
  1270. XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue;
  1271. var strMissionName = missioncell.innerHTML;
  1272.  
  1273. // stack is an array of Mission objects
  1274. for (var i in stack)
  1275. if (stack[i].name == strMissionName)
  1276. {
  1277. if (stack[i].allyget)
  1278. CheckAllyGet(stack[i].allyget);
  1279. MissionAttempt(stack[i].jutsu);
  1280. }
  1281.  
  1282. // This point is not reached unless mission is not in the stack
  1283.  
  1284. // Default jutsu
  1285. MissionAttempt(defaultjutsu);
  1286. }
  1287.  
  1288. // Function to attempt a mission based on difficulty and success (before crank) in addition to name and mission type
  1289. function MissionDetailedStackAttempt(stack, defaultjutsu)
  1290. {
  1291. /*
  1292. <div class="miscontainer"><div class="misshadow"><div class="miscontent_g"><div class="miscontent2" align="left">
  1293. <div class="misstat_g">Genjutsu</div><center>
  1294. <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>
  1295. <i><font style="font-size: 12px;"><br>(+27 Diff, +27 Succ, +135% Ryo)</font></i><font style="font-size: 12px;"></font><br><br>
  1296. <div class="misonestat_g"><table class="misonetable"><tbody><tr><td align="right">Difficulty 40&nbsp;&nbsp;&nbsp;Successes 36&nbsp;</td></tr></tbody></table></div>
  1297. */
  1298.  
  1299. // Get the mission name
  1300. var missioncell = document.evaluate('//div[@class="miscontainer"]/div/div/div/center/font/b', document, null,
  1301. XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue;
  1302. var strMissionName = missioncell.innerHTML;
  1303.  
  1304. // Get mission type
  1305. missioncell = document.evaluate('//div[@class="miscontainer"]/div/div/div/div', document, null,
  1306. XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue;
  1307. var strMissionType = missioncell.innerHTML;
  1308.  
  1309. // Get crank
  1310. var numMissionCrank;
  1311. if (DocTest('Crank Level'))
  1312. {
  1313. missioncell = document.evaluate('//div[@class="miscontainer"]/div/div/div/center', document, null,
  1314. XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue;
  1315. numMissionCrank = parseInt(/Crank Level: (\d+)</.exec(missioncell.innerHTML)[1], 10);
  1316. }
  1317. else
  1318. numMissionCrank = 0;
  1319.  
  1320. // Get difficulty and successes
  1321. missioncell = document.evaluate('//div[@class="miscontainer"]/div/div/div/center/div/table/tbody/tr/td', document, null,
  1322. XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue;
  1323.  
  1324. // Difficulty 40&nbsp;&nbsp;&nbsp;Successes 36&nbsp;
  1325. var numMissionDiff = parseInt(/Difficulty (\d+)&/.exec(missioncell.innerHTML)[1], 10) - numMissionCrank;
  1326. var numMissionSucc = parseInt(/Successes (\d+)&/.exec(missioncell.innerHTML)[1], 10) - numMissionCrank;
  1327.  
  1328. // stack is an array of Mission objects
  1329. for (var i in stack)
  1330. if (stack[i].name == strMissionName &&
  1331. stack[i].type == strMissionType &&
  1332. stack[i].diff == numMissionDiff &&
  1333. stack[i].succ == numMissionSucc)
  1334. {
  1335. if (stack[i].allyget)
  1336. CheckAllyGet(stack[i].allyget);
  1337.  
  1338. MissionAttempt(stack[i].jutsu);
  1339. }
  1340.  
  1341. // This point is not reached unless mission is not in the stack
  1342.  
  1343. // Default jutsu
  1344. MissionAttempt(defaultjutsu);
  1345. }
  1346.  
  1347.  
  1348.  
  1349. ///////////// API Functions for doing quests ///////////////////
  1350.  
  1351. // Generic function to perform quest steps -- jutsu selection is currently broken
  1352. function DoGenericQuest(quest, endstep, jutsu)
  1353. {
  1354. // Ensure that we are on the quest page or go there
  1355. // This function also continues a quest in progress
  1356. GoPage('quests');
  1357.  
  1358. if (FormTest('questcontinue'))
  1359. FormSubmit('questcontinue');
  1360.  
  1361. // safeguard against bad code for eval statement
  1362. if (typeof(quest.code) != "number")
  1363. ShowMsg("quest.code must be a number");
  1364.  
  1365. // Sanity check to make sure that we are on the correct page
  1366. if (!DocTest(quest.name))
  1367. ShowMsg("We are on the wrong quest?!?");
  1368.  
  1369. // Select the desired quest to start
  1370. if (FormTest('quest' + quest.code))
  1371. FormSubmit("quest" + quest.code);
  1372.  
  1373. // Check termination conditions
  1374. if ( (endstep == -1 && DocTest("--Epilogue--")) ||
  1375. DocTest("--Part " + endstep + " of " + quest.numsteps + "--") )
  1376. {
  1377. if (quest.flag)
  1378. {
  1379. data.SetFlag(quest.flag);
  1380. data.SaveState();
  1381. }
  1382.  
  1383. // Manually increment the task without halting execution
  1384. if (data.taskNum < data.taskList.length-1)
  1385. data.taskNum++;
  1386. data.SaveState();
  1387. floatingDaily.Draw();
  1388.  
  1389. GoMenuPage('Quests');
  1390. return;
  1391. }
  1392.  
  1393. // Set the requested jutsu
  1394. if (jutsu && FormTest('attack'))
  1395. FormCheck(null, 'usejutsu', '' + jutsu.code);
  1396.  
  1397. // document.getElementById(jutsu.code).checked = "checked";
  1398.  
  1399. // Blindly attempt the quest if we get this far
  1400.  
  1401. if (FormTest('attack'))
  1402. FormSubmit('attack');
  1403.  
  1404. if (FormTest('goquest'))
  1405. FormSubmit('goquest');
  1406. }
  1407.  
  1408.  
  1409. ////////////// API Functions primarily for convenience / miscellaneous /////////////
  1410.  
  1411. // Generic function to set flags based on an ally we might get on this page
  1412. // ally is an object of type Ally
  1413. function CheckAllyGet(strAllyName)
  1414. {
  1415. // Somewhat better version of CheckStuffGet()
  1416. if (DocTest("You got an Ally!<br><b>" + strAllyName + "!</b>") ||
  1417. DocTest("<b>" + strAllyName + " joins you!</b>") ||
  1418. DocTest("<b>" + strAllyName + " joins your party!</b>") ||
  1419. DocTest("<b>" + strAllyName + " joined your party!</b>") ||
  1420. DocTest("You got <b>" + strAllyName + "!</b>") )
  1421. {
  1422. data.SetFlag(strAllyName);
  1423. data.SaveState();
  1424. ShowMsg("Got ally:" + strAllyName);
  1425. }
  1426.  
  1427. // Ally Level 2
  1428. if (DocTest("Level Up!<br><b>" + strAllyName + "</b> is now <b>" + strAllyName + " Lvl. 2!</b>"))
  1429. {
  1430. data.SetFlag(strAllyName + " Lvl. 2");
  1431. data.SaveState();
  1432. ShowMsg("Got " + strAllyName + " Lvl. 2");
  1433. }
  1434.  
  1435. // Ally Level 3
  1436. if (DocTest("<b>" + strAllyName + " is now Lvl. 3!</b>")) // specific to stalker3 for now
  1437. {
  1438. data.SetFlag(strAllyName + " Lvl. 3");
  1439. data.SaveState();
  1440. ShowMsg("Got " + strAllyName + " Lvl. 3");
  1441. }
  1442. }
  1443.  
  1444. // Set themes
  1445. function SetThemes(theme1, theme2, theme3, theme4)
  1446. {
  1447. GoPage('themes');
  1448.  
  1449. if (theme1 && !FormCheckTest('themes1', 'theme_entry_1', theme1))
  1450. {
  1451. FormCheck('themes1', 'theme_entry_1', theme1);
  1452. FormSubmit('themes1');
  1453. ShowMsg("Setting Opening Theme");
  1454. }
  1455. if (theme2 && !FormCheckTest('themes2', 'theme_entry_2', theme2))
  1456. {
  1457. FormCheck('themes2', 'theme_entry_2', theme2);
  1458. FormSubmit('themes2');
  1459. ShowMsg("Setting Battle Theme");
  1460. }
  1461. if (theme3 && !FormCheckTest('themes3', 'theme_entry_3', theme3))
  1462. {
  1463. FormCheck('themes3', 'theme_entry_3', theme3);
  1464. FormSubmit('themes3');
  1465. ShowMsg("Setting Ending Theme");
  1466. }
  1467. if (theme4 && !FormCheckTest('themes4', 'theme_entry_4', theme4))
  1468. {
  1469. FormCheck('themes4', 'theme_entry_4', theme4);
  1470. FormSubmit('themes4');
  1471. ShowMsg("Setting Overworld Theme");
  1472. }
  1473. }
  1474.  
  1475.  
  1476.  
  1477. // Change teams -- exact text strings for ally names required
  1478. function TeamChange(strAllyName1, strAllyName2, strAllyName3)
  1479. {
  1480. GoPage('team');
  1481.  
  1482. // Confirm teams without thinking
  1483. if (FormTest('conteam'))
  1484. FormSubmit('conteam');
  1485.  
  1486. // Check whether the task is already complete
  1487. var indstart = document.body.innerHTML.indexOf("<b>-Current Team-</b>");
  1488. var ind1 = document.body.innerHTML.indexOf("<b>" + strAllyName1, indstart);
  1489. var ind2 = document.body.innerHTML.indexOf("<b>" + strAllyName2, indstart);
  1490. var ind3 = document.body.innerHTML.indexOf("<b>" + strAllyName3, indstart);
  1491. var indend = document.body.innerHTML.indexOf("Save current team as Quickteam:");
  1492.  
  1493. IncrementTaskIf(ind1 < indend && ind2 < indend && ind3 < indend);
  1494.  
  1495. // Helper function to test each element against the ally name
  1496. function AllyTest(strFor, strText)
  1497. {
  1498. return (strFor.indexOf('id_') > -1 &&
  1499. ( strText.indexOf('<b>' + strAllyName1) > -1 ||
  1500. strText.indexOf('<b>' + strAllyName2) > -1 ||
  1501. strText.indexOf('<b>' + strAllyName3) > -1 ) );
  1502. };
  1503.  
  1504.  
  1505. // Get a snapshot for each message in the village chat
  1506. var snapMessageList = document.evaluate("//label", document, null,
  1507. XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  1508.  
  1509. // Examine each snapshot
  1510. for (var i=0; i<snapMessageList.snapshotLength; i++)
  1511. {
  1512. var snap = snapMessageList.snapshotItem(i);
  1513.  
  1514. if (AllyTest(snap.htmlFor, snap.innerHTML))
  1515. document.getElementById(snap.htmlFor).checked = "checked";
  1516. }
  1517.  
  1518. // Submit the form
  1519. FormSubmit('maketeam');
  1520. }
  1521.  
  1522.  
  1523.  
  1524. ////////////////////////////////////////////////////////////////////////
  1525. /////////// DAILY CODE /////////////
  1526. ////////////////////////////////////////////////////////////////////////
  1527.  
  1528. function DailyStep()
  1529. {
  1530. // Perform a single step of daily
  1531. try
  1532. {
  1533. // Execute SequenceCode if it exists, stored in task 0
  1534. if (data.taskList[0])
  1535. eval(data.taskList[0].taskfun);
  1536.  
  1537. // Call the next function in the tasklist
  1538. eval(data.taskList[data.taskNum].taskfun);
  1539. }
  1540. catch(err)
  1541. {
  1542. // Report the error or message on the floating window
  1543. floatingDaily.showErr(err);
  1544. }
  1545. }
  1546.  
  1547.  
  1548.  
  1549. ////////////////////////////////////////////////////////////////////////
  1550. /////////// HOTKEY CODE /////////////
  1551. ////////////////////////////////////////////////////////////////////////
  1552.  
  1553. var hotkeyLock = false;
  1554. var keyDailyCheckRecentEscape = false;
  1555.  
  1556. function KeyCheck(event)
  1557. {
  1558. var KeyID = event.keyCode;
  1559.  
  1560. // Lock hotkeys if daily window is hidden
  1561. if (data.TestHidePage(location.href))
  1562. hotkeyLock = true;
  1563. if ( (KeyID == 252 || KeyID == 61) && !hotkeyLock) // backquote key or equals: ` or =
  1564. {
  1565. // Lock hotkey usage to protect from button spamming
  1566. hotkeyLock = true;
  1567.  
  1568. // Perform one daily step
  1569. DailyStep();
  1570.  
  1571. // Unlock hotkey usage
  1572. hotkeyLock = false;
  1573. }
  1574.  
  1575. if (KeyID == 27) // escape key
  1576. {
  1577. // Close editor window if not already and unlock hotkeys
  1578. floatingEditor.Hide();
  1579. hotkeyLock = false;
  1580.  
  1581. // Unhide daily window if hidden
  1582. if (data.TestHidePage(location.href))
  1583. {
  1584. data.RemoveHidePage(location.href);
  1585. floatingDaily.Draw();
  1586. }
  1587. // If escape is pressed twice in succession, reset the window positions
  1588. if (keyDailyCheckRecentEscape)
  1589. {
  1590. floatingEditor.window.reset();
  1591. floatingDaily.window.reset();
  1592. }
  1593. else
  1594. {
  1595. keyDailyCheckRecentEscape = true;
  1596. setTimeout(function(){keyDailyCheckRecentEscape = false;}, 1000);
  1597. }
  1598. }
  1599.  
  1600. if (KeyID == 37 && !hotkeyLock) // left arrow
  1601. floatingDaily.BackTask();
  1602.  
  1603. if (KeyID == 39 && !hotkeyLock) // right arrow
  1604. floatingDaily.SkipTask();
  1605. }
  1606.  
  1607. document.documentElement.addEventListener("keyup", KeyCheck, true);
  1608.  
  1609.  
  1610.  
  1611.  
  1612. ////////////////////////////////////////////////////////////////////////
  1613. /////////// PAGE LOAD RUNTIME ///////////////
  1614. ////////////////////////////////////////////////////////////////////////
  1615.  
  1616.  
  1617. // Initialize the jutsus object
  1618. var jutsus = {
  1619. // Jutsu(name, code)
  1620. SRS: new Jutsu("Soul Reaper Style: Lunch, SandySword!", 499),
  1621. MBST: new Jutsu("Mind Body Switch Technique", 393),
  1622. PWK: new Jutsu("Projectile Weapons: Kunai", 373),
  1623. Redeye: new Jutsu("RedEye", 500),
  1624. Clone: new Jutsu("Clone Jutsu", 368),
  1625. Disguise: new Jutsu("Disguise Jutsu", 370),
  1626. ETA: new Jutsu("Exploding Tags: Activate", 371),
  1627. PWS: new Jutsu("Projectile Weapons: Shuriken", 372),
  1628. Escape: new Jutsu("Escape Jutsu", 374),
  1629. FSFJ: new Jutsu("Fire Style: Fireball Jutsu", 376),
  1630. OI: new Jutsu("Obsessive Insight", 466),
  1631.  
  1632. PSPDP: new Jutsu("Pinky Style: Pervert-Destroying Punch", 416),
  1633. AOTNS: new Jutsu("Attack on the Nervous System", 429),
  1634. FOS: new Jutsu("Flock of Seagulls", 419),
  1635.  
  1636. EDUT: new Jutsu("Epic Dog Urination Technique", 421),
  1637. KICHC: new Jutsu("Kido: I can has cheeseburger", 484),
  1638. INT: new Jutsu("I Need This", 497),
  1639.  
  1640. FGTT: new Jutsu("Flying Thunder God Technique", 448),
  1641. BSTIS: new Jutsu("Billy Style: This is Sparta", 444),
  1642.  
  1643. SSFLB: new Jutsu("Stalker Style: Freaking Laser Beams", 418),
  1644.  
  1645. SRSIN: new Jutsu("Soul Reaper Style: Imperishable Night", 480),
  1646.  
  1647. Diagnosis: new Jutsu("Diagnosis", 485),
  1648.  
  1649. Blank: new Jutsu("", -1)
  1650. };
  1651.  
  1652. // Initialize the quests object
  1653. var quests = {
  1654. // Quest(name, code, numsteps, flag)
  1655. ShowWatchin: new Quest("Watchin' Your Shows", 8, 1),
  1656.  
  1657. Blank: new Quest("", -1, -1, "")
  1658. }
  1659.  
  1660.  
  1661. // Create global instance of daily data object
  1662. var data = new dailyData();
  1663. // Create the floating window objects
  1664. var floatingDaily = new FloatingDaily();
  1665. var floatingEditor = new FloatingEditor();
  1666.  
  1667. floatingDaily.Draw();