Guest User

Multi-Char Profession Bot

a guest
Jan 29th, 2014
1,168
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ==UserScript==
  2. // @name           Neverwinter Gateway - Professions Robot
  3. // @description    Automatically selects tasks from professions for empty slots
  4. // @namespace      blabla
  5. // @include        https://gateway.playneverwinter.com
  6. // @include        https://gateway.playneverwinter.com/*
  7. // @include        https://gatewaysitedown.playneverwinter.com
  8. // @include        https://gatewaysitedown.playneverwinter.com/*
  9. // @include        http://gateway.playneverwinter.com
  10. // @include        http://gateway.playneverwinter.com/*
  11. // @include        http://gatewaysitedown.playneverwinter.com
  12. // @include        http://gatewaysitedown.playneverwinter.com/*
  13. // @originalAuthor Mustex&Bunta
  14. // @modifiedBy     Insignis
  15. // @version        0.2.1.4.0
  16. // @license        http://creativecommons.org/licenses/by-nc-nd/3.0/us/
  17. // @grant          GM_getValue
  18. // @grant          GM_setValue
  19. // ==/UserScript==
  20.  
  21. /* RELEASE NOTES
  22. 0.2.1.4.0
  23.     - Added automatic refine diamonds on each character change with option in menu to disable it
  24.         * If switched on after character selection script will go to inventory and try to refine diamonds
  25.         * After that will go to professions and do its normal thing
  26. 0.2.1.3.0
  27.     - Multiple Character Support tweaked a bit.
  28.         * Now when switching characters processing won't stop on the current character
  29.         * Instead of reloading the gateway to switch, the character selection page is loaded directly
  30.         * This change sponsored by Jaytime
  31. 0.2.1.2.0
  32.     - Changed whole code responsible for handling multiple characters to be fully dynamic (method of reloging on each char change didn't change)
  33.         * You just open settings, change number of character, reload the page - and you can now set up the char name, and number of tasks per profession per that character
  34. 0.2.1.1.1
  35.     - Added few missing mass/deep ingredient task skipping conditions useful mainly for alchemy (or other proffesions if someone will revert back to buntas task lists)
  36.     - Added engine that cycles trough multiple characters by disconnecting after each one (uses longDelay, and works good)
  37.         * it uses static setup of options (in other words you need to edit this script to add more characters - adding slightly changed copies of already existing options: nw_charname and <taskname>)
  38.         * code that creates settings menu is a bit messy - you need to manualy add few copy&slightly_change lines/parts of already existing code
  39.         * both of above are planned to be changed into fully dinamic and dependant on just one option (which if possible will be in the settings menu, instead of a static editable only in this script)
  40.     - Added missing professions in function selecting least rank optional bronze (white) assets (buntas TO-DO done ^_^)
  41.     - Modified SearchForTaskByName function so that it takes profession level into account
  42.         * atm it helps only with empowered aqua task: if alchemy is set to show higher level first then old code stops working trying to run empowered aqua task, but now instead of skipping it entirely it does it only if alchemy is below 8-th level (empowered task is more efficent so its not good to skip it)
  43.     - Few other minor changes/polishes (connected with multiple characters upgrades, or just debug/info - mainly debug output to console allerts)
  44. 0.2.0.1.6
  45.     - Add configurable option for excluding rare tasks
  46. 0.2.0.1.5
  47.     - Add ability to specify specific level for tasks and configure same named artificing resource tasks to request correct level of task
  48.     - Remove purchase notification that never times out
  49. 0.2.0.1.4
  50.     - Added functionality to purchase required resources from gateway shop
  51. 0.2.0.1.3
  52.     - Add Artificing and Weaponsmithing to Robot
  53.       (Artificing will not work properly yet as all three tiers of gather and craft tasks have the same task name)
  54. 0.2.0.1.2
  55.     - Update reload process
  56.     - Fix optional asset selector with gateway update
  57. 0.2.0.1.1
  58.     - Simplify asset selection after they fixed bug in previous gateway update
  59.     - Update level 20 leadership tasks
  60.     - Update with changes in Mustex's script (version 15)
  61.         * Added a secondary timer that will reload the gateway every few hours. This should help with disconnects from the server
  62.         * Implemented tooltips for settings panel
  63. 0.1.9.1.15
  64.     - Repeat task reordering for +2 armor
  65. 0.1.9.1.14
  66.     - Fix selection of assets after gateway update
  67.     - Skip intensive gather tasks added after gateway update
  68. 0.1.9.1.13
  69.     - Change ordering of tasks and ingredient checks
  70.       The purpose of this is to allow crafting of +4 armors if you have +2 ingredients in your inv but to not create them if you don't.
  71.       Creating the ingredients for them is less efficient than crafting ingredients for pants but is more efficient if you already have the ingredients from earlier tasks.
  72. 0.1.9.1.12
  73.     - Optimise crafting tasks for highest exp/min gains due to ingredient requirements
  74. 0.1.9.1.11
  75.     - Add extra craft tasks for when residuum runs out
  76. 0.1.9.1.10
  77.     - Only allow rare tasks to be selected for Leadership
  78.       This avoids craft loops where higher quality rare crafts require ingredients with the same name
  79. 0.1.9.1.9
  80.     - Alter craft tasks to favour armor to optimise inventory space
  81. 0.1.9.1.8
  82.     - Fix script restart bug when no tasks found
  83. 0.1.9.1.7
  84.     - Update search string for Potions (After the task names for elxiirs have been changed)
  85.     - Remove logon error skips to avoid logons sometimes failing on first load (ensure logon details are correct!)
  86. 0.1.9.1.6
  87.     - Update tasks for all professions
  88.     - Update ingredient search lists for all professions
  89. 0.1.9.1.5
  90.     - Fix regular expression used in potion ingredient search
  91. 0.1.9.1.4
  92.     - Alter default timeouts (makes script a lot more stable and less prone to errors)
  93.     - Remove unused variable
  94.     - Add extra logging for task ingredient searches
  95. 0.1.9.1.3
  96.     - Fix bug with required resource checks getting stuck on non craftable resources
  97. 0.1.9.1.2
  98.     - Added method to check for required task ingredients and choose tasks to create them
  99.       Method is currently hard coded to specify certain search strings for ingredient types
  100.       Currently working for all Alchemy tasks
  101.       There is a current problem that if you have the required potion ingredient but it is in your belt slots
  102.       the task is uncraftable but the ingredients show as available and it will not craft a new one
  103. 0.1.9.1
  104.     - Update with changes in Mustex's script (version 12)
  105.         * Added tasks for Platesmithing, Leatherworking, Tailoring
  106.         * Added detection for the gateway being down
  107. 0.1.8.3.8
  108.     - Update asset selection to avoid using coloured assets in junk slots for leadership
  109. 0.1.8.3.7
  110.     - Update leadership tasks table due to task reward/duration alterations
  111. 0.1.8.3.6
  112.     - Add option to enable/disable automation process
  113.     - Update alchemy tasks some more
  114. 0.1.8.3.5
  115.     - Add ability to select from multiple tasks with same name (eg Alchemical Research)
  116.     - Add craft options for alchemy potions (need to be manually switched since they use the same ingredients)
  117. 0.1.8.3.4
  118.     - Add alchemy tasks up to level 20
  119. 0.1.8.3.3
  120.     - Change task slot selection to be user configurable options in settings window
  121.     - Add level 1 alchemical research
  122. 0.1.8.3.2
  123.     - Added ability to specify how many tasks of each profession to train multiple professions at once
  124.     - Updated mailsmithing level 0 tasks
  125. 0.1.8.3.1
  126.     - Changed asset selection to only update Junk assets
  127.     - Leadership asset selection for bronze tier picks lowest asset first
  128.     - Modified Leadership tasks
  129. 0.1.8.3
  130.     - Tweaked Leadership tasks grid
  131.     - Added task grid for Alchemy (Partial)
  132. 0.1.8.2
  133.     - onsave handlers for settings are now called before the settings values are saved
  134.     - Added onsave handler for console to enable/disable using the window console
  135. 0.1.8.1
  136.     - Added checking for errors (using the window title) and will navigate back to the main login page if autologin is enabled
  137. 0.1.8
  138.     - Added popup for altering settings
  139.     - Settings are saved to script cache
  140.     - Added mailsmithing tasks to task grid
  141. 0.1.7
  142.     - Added lower level leadership tasks to grid
  143.     - Added hiring tasks to leadership task
  144.     - Uses saved values to determine which profession type to level (Defaults to Leadership, currently no way to change it)
  145.  
  146. 0.1.5
  147.     - Is now able to recover from missing assets
  148.     - Uses a configurable grid to determine what the next task is to complete
  149.  
  150. 0.1.0
  151.     - Is now able to select some hard coded leadership tasks
  152.     - Can now collect from any completed slot
  153. */
  154.  
  155. /* REQUESTED FEATURES
  156.  * - Add settings to restrict types of optional assets selected
  157.  * - Add logic to determine when to 'hire' more assets (Depends on number of open slots, profession level, and current assets of the correct level)
  158.  * - Add logic to determine when a task is running (like alchemy research) so to be able to do different tasks based on it (like run task in preparation for next level experimentation, instead of doing useless experimentation on actuall level)
  159.  * - Add settings for defining a minimum amount of resources to attempt to keep in stock (When the rare tasks come up we will need to have some resources available)
  160.  */
  161. /* PLANNED FEATURES
  162.  * - Possible upgrade to code so to allow of multiple account handling (as the multiple character handling uses relogging - it I think is fully possible without to much of a hassle)
  163.  * - Add logic with a checkbox in menu, to open inventory tab and try reforging ADs if checkbox is marked (possibly make it do it with a counter - once per few full character changing loops)
  164.  */
  165.  
  166. // Make sure it's running on the main page, no frames
  167. if(window.self !== window.top) {
  168.     throw "";
  169. }
  170.  
  171. // If "loading" take longer than 1 minute, reload page (maybe a javascript error)
  172. (function(){
  173.   var $                  = unsafeWindow.$;
  174.   var loading_crash      = 0;
  175.   var loading_crash_time = 20;
  176.   var timer              = setInterval(function(){
  177.     if( $("div.loading-image:visible").length ){
  178.       if( loading_crash > loading_crash_time ){
  179.         location.reload();
  180.       }
  181.       else{
  182.         loading_crash++;
  183.         console.log("Loading ... " + loading_crash + "s" );
  184.       }
  185.     }
  186.     else{
  187.       loading_crash = 0;
  188.     }
  189. },1000);
  190.  
  191. })();
  192.  
  193. (function() {
  194.  
  195.     /**
  196.      * Add a string of CSS to the main page
  197.      *
  198.      * @param {String} cssString The CSS to add to the main page
  199.      */
  200.     function AddCss(cssString) {
  201.         var head = document.getElementsByTagName('head')[0];
  202.         if(!head)
  203.             return;
  204.         var newCss = document.createElement('style');
  205.         newCss.type = "text/css";
  206.         newCss.innerHTML = cssString;
  207.         head.appendChild(newCss);
  208.     }
  209.     function countLeadingSpaces(str) {
  210.         return str.match(/^(\s*)/)[1].length;
  211.     }
  212.  
  213.     var image_pause = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAY" +
  214.         "AAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2" +
  215.         "ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AUkSYqIQkQSoghodkVUcERRUUEG" +
  216.         "8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuja9a89+bN/rXXPues852zzwfACAyWSDNR" +
  217.         "NYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMBAPh+PDwrIsAHvgABeNMLCADATZvAMBy" +
  218.         "H/w/qQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAtAGAnf+bTAI" +
  219.         "Cd+Jl7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3AMDOE" +
  220.         "AuyAAgMADBRiIUpAAR7AGDIIyN4AISZABRG8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dX" +
  221.         "Lh4ozkkXKxQ2YQJhmkAuwnmZGTKBNA/g88wAAKCRFRHgg/P9eM4Ors7ONo62Dl8t6r8G/yJ" +
  222.         "iYuP+5c+rcEAAAOF0ftH+LC+zGoA7BoBt/qIl7gRoXgugdfeLZrIPQLUAoOnaV/Nw+H48PE" +
  223.         "WhkLnZ2eXk5NhKxEJbYcpXff5nwl/AV/1s+X48/Pf14L7iJIEyXYFHBPjgwsz0TKUcz5IJh" +
  224.         "GLc5o9H/LcL//wd0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcUl0v9k4t8s+wM+3zUAsGo+" +
  225.         "AXuRLahdYwP2SycQWHTA4vcAAPK7b8HUKAgDgGiD4c93/+8//UegJQCAZkmScQAAXkQkLlT" +
  226.         "Ksz/HCAAARKCBKrBBG/TBGCzABhzBBdzBC/xgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKm" +
  227.         "Av1EAdNMBRaIaTcA4uwlW4Dj1wD/phCJ7BKLyBCQRByAgTYSHaiAFiilgjjggXmYX4IcFIB" +
  228.         "BKLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5h1xGupE7yAAygvyGvEcxlIGyUT3UDLVDuag3" +
  229.         "GoRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8+Q8cwwOgYBzPEbDAuxsNCsTgsCZNjy7E" +
  230.         "irAyrxhqwVqwDu4n1Y8+xdwQSgUXACTYEd0IgYR5BSFhMWE7YSKggHCQ0EdoJNwkDhFHCJy" +
  231.         "KTqEu0JroR+cQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQAkmxpFTSEtJG0m5SI+ksq" +
  232.         "Zs0SBojk8naZGuyBzmULCAryIXkneTD5DPkG+Qh8lsKnWJAcaT4U+IoUspqShnlEOU05QZl" +
  233.         "mDJBVaOaUt2ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdpr+h0uhHdlR5" +
  234.         "Ol9BX0svpR+iX6AP0dwwNhhWDx4hnKBmbGAcYZxl3GK+YTKYZ04sZx1QwNzHrmOeZD5lvVV" +
  235.         "gqtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI+pXlN9rkZVM1PjqQnUlqtVqp1Q61MbU" +
  236.         "2epO6iHqmeob1Q/pH5Z/YkGWcNMw09DpFGgsV/jvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2" +
  237.         "KruY/R27iz2qqaE5QzNKM1ezUvOUZj8H45hx+Jx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVx" +
  238.         "rqpaXllirSKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4/OBZ3nU9lT3acKpxZNPTr1ri" +
  239.         "6qa6UbobtEd79up+6Ynr5egJ5Mb6feeb3n+hx9L/1U/W36p/VHDFgGswwkBtsMzhg8xTVxb" +
  240.         "zwdL8fb8VFDXcNAQ6VhlWGX4YSRudE8o9VGjUYPjGnGXOMk423GbcajJgYmISZLTepN7ppS" +
  241.         "TbmmKaY7TDtMx83MzaLN1pk1mz0x1zLnm+eb15vft2BaeFostqi2uGVJsuRaplnutrxuhVo" +
  242.         "5WaVYVVpds0atna0l1rutu6cRp7lOk06rntZnw7Dxtsm2qbcZsOXYBtuutm22fWFnYhdnt8" +
  243.         "Wuw+6TvZN9un2N/T0HDYfZDqsdWh1+c7RyFDpWOt6azpzuP33F9JbpL2dYzxDP2DPjthPLK" +
  244.         "cRpnVOb00dnF2e5c4PziIuJS4LLLpc+Lpsbxt3IveRKdPVxXeF60vWdm7Obwu2o26/uNu5p" +
  245.         "7ofcn8w0nymeWTNz0MPIQ+BR5dE/C5+VMGvfrH5PQ0+BZ7XnIy9jL5FXrdewt6V3qvdh7xc" +
  246.         "+9j5yn+M+4zw33jLeWV/MN8C3yLfLT8Nvnl+F30N/I/9k/3r/0QCngCUBZwOJgUGBWwL7+H" +
  247.         "p8Ib+OPzrbZfay2e1BjKC5QRVBj4KtguXBrSFoyOyQrSH355jOkc5pDoVQfujW0Adh5mGLw" +
  248.         "34MJ4WHhVeGP45wiFga0TGXNXfR3ENz30T6RJZE3ptnMU85ry1KNSo+qi5qPNo3ujS6P8Yu" +
  249.         "ZlnM1VidWElsSxw5LiquNm5svt/87fOH4p3iC+N7F5gvyF1weaHOwvSFpxapLhIsOpZATIh" +
  250.         "OOJTwQRAqqBaMJfITdyWOCnnCHcJnIi/RNtGI2ENcKh5O8kgqTXqS7JG8NXkkxTOlLOW5hC" +
  251.         "epkLxMDUzdmzqeFpp2IG0yPTq9MYOSkZBxQqohTZO2Z+pn5mZ2y6xlhbL+xW6Lty8elQfJa" +
  252.         "7OQrAVZLQq2QqboVFoo1yoHsmdlV2a/zYnKOZarnivN7cyzytuQN5zvn//tEsIS4ZK2pYZL" +
  253.         "Vy0dWOa9rGo5sjxxedsK4xUFK4ZWBqw8uIq2Km3VT6vtV5eufr0mek1rgV7ByoLBtQFr6wt" +
  254.         "VCuWFfevc1+1dT1gvWd+1YfqGnRs+FYmKrhTbF5cVf9go3HjlG4dvyr+Z3JS0qavEuWTPZt" +
  255.         "Jm6ebeLZ5bDpaql+aXDm4N2dq0Dd9WtO319kXbL5fNKNu7g7ZDuaO/PLi8ZafJzs07P1SkV" +
  256.         "PRU+lQ27tLdtWHX+G7R7ht7vPY07NXbW7z3/T7JvttVAVVN1WbVZftJ+7P3P66Jqun4lvtt" +
  257.         "Xa1ObXHtxwPSA/0HIw6217nU1R3SPVRSj9Yr60cOxx++/p3vdy0NNg1VjZzG4iNwRHnk6fc" +
  258.         "J3/ceDTradox7rOEH0x92HWcdL2pCmvKaRptTmvtbYlu6T8w+0dbq3nr8R9sfD5w0PFl5Sv" +
  259.         "NUyWna6YLTk2fyz4ydlZ19fi753GDborZ752PO32oPb++6EHTh0kX/i+c7vDvOXPK4dPKy2" +
  260.         "+UTV7hXmq86X23qdOo8/pPTT8e7nLuarrlca7nuer21e2b36RueN87d9L158Rb/1tWeOT3d" +
  261.         "vfN6b/fF9/XfFt1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v+3Njv3H9qwHeg89HcR/c" +
  262.         "GhYPP/pH1jw9DBY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i/suuFxYvfvjV69fO0Z" +
  263.         "jRoZfyl5O/bXyl/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8IH8o/2j5sfVT0" +
  264.         "Kf7kxmTk/8EA5jz/GMzLdsAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgA" +
  265.         "ABdvkl/FRgAAAZ9JREFUeNqU0z+LE2EQBvDfvsuZ3IkoFzSJiuCfeAkWFmJnkz5wjVjlK4i" +
  266.         "tnR9BrP0E4uewE/bQwKko2CjR88+BuSMhycbm3RjjNk41z7szz8w8O5Motzqu4iwW+Ir3+L" +
  267.         "YemKzh07iLGziJPL4HjPAKz3FcRnAJD3AKXzBb+b7ABhr4jscYQhoDzuBhrDQsIU9iNz9j7" +
  268.         "G28wLQg6OMyhrVaLd3Z2dFoNBwdHdna2tJut9XrdZPJJIzH4xHOo4rXAU3cjJXTfr8vyzJZ" +
  269.         "lul2u3q9nizL7O3t2d3dLbr+jFvYDuiggjlMp9Nl3/P53Gw2W+IVfxZFbgecw7SYOc/zZUK" +
  270.         "e5//gNU22QxRu4f9tgSTE5ThRkIQQ/kifJJIk+QuvJKc4DHizOsLm5uYyoVKpqFarS7zipx" +
  271.         "jjXUF5P4o5bDabodVqgcFgIE1TnU4H7O/vOzg4yHEBL/G0IGjgUVzXX1GXMsvjIm3E+B/FI" +
  272.         "o3wEXfi7zkuRFoVLBYKeIJPZcd0EfdwLc5ZaLMR/bd4Fm+l9BoLu44rsd0FDuM5f1gP/D0A" +
  273.         "BNp57TyT3+MAAAAASUVORK5CYII="
  274.     var image_play = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYA" +
  275.         "AAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2Z" +
  276.         "pbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AUkSYqIQkQSoghodkVUcERRUUEG8" +
  277.         "igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuja9a89+bN/rXXPues852zzwfACAyWSDNRN" +
  278.         "YAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMBAPh+PDwrIsAHvgABeNMLCADATZvAMByH" +
  279.         "/w/qQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAtAGAnf+bTAIC" +
  280.         "d+Jl7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3AMDOEA" +
  281.         "uyAAgMADBRiIUpAAR7AGDIIyN4AISZABRG8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dXL" +
  282.         "h4ozkkXKxQ2YQJhmkAuwnmZGTKBNA/g88wAAKCRFRHgg/P9eM4Ors7ONo62Dl8t6r8G/yJi" +
  283.         "YuP+5c+rcEAAAOF0ftH+LC+zGoA7BoBt/qIl7gRoXgugdfeLZrIPQLUAoOnaV/Nw+H48PEW" +
  284.         "hkLnZ2eXk5NhKxEJbYcpXff5nwl/AV/1s+X48/Pf14L7iJIEyXYFHBPjgwsz0TKUcz5IJhG" +
  285.         "Lc5o9H/LcL//wd0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcUl0v9k4t8s+wM+3zUAsGo+A" +
  286.         "XuRLahdYwP2SycQWHTA4vcAAPK7b8HUKAgDgGiD4c93/+8//UegJQCAZkmScQAAXkQkLlTK" +
  287.         "sz/HCAAARKCBKrBBG/TBGCzABhzBBdzBC/xgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKmA" +
  288.         "v1EAdNMBRaIaTcA4uwlW4Dj1wD/phCJ7BKLyBCQRByAgTYSHaiAFiilgjjggXmYX4IcFIBB" +
  289.         "KLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5h1xGupE7yAAygvyGvEcxlIGyUT3UDLVDuag3G" +
  290.         "oRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8+Q8cwwOgYBzPEbDAuxsNCsTgsCZNjy7Ei" +
  291.         "rAyrxhqwVqwDu4n1Y8+xdwQSgUXACTYEd0IgYR5BSFhMWE7YSKggHCQ0EdoJNwkDhFHCJyK" +
  292.         "TqEu0JroR+cQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQAkmxpFTSEtJG0m5SI+ksqZ" +
  293.         "s0SBojk8naZGuyBzmULCAryIXkneTD5DPkG+Qh8lsKnWJAcaT4U+IoUspqShnlEOU05QZlm" +
  294.         "DJBVaOaUt2ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdpr+h0uhHdlR5O" +
  295.         "l9BX0svpR+iX6AP0dwwNhhWDx4hnKBmbGAcYZxl3GK+YTKYZ04sZx1QwNzHrmOeZD5lvVVg" +
  296.         "qtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI+pXlN9rkZVM1PjqQnUlqtVqp1Q61MbU2" +
  297.         "epO6iHqmeob1Q/pH5Z/YkGWcNMw09DpFGgsV/jvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2K" +
  298.         "ruY/R27iz2qqaE5QzNKM1ezUvOUZj8H45hx+Jx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVxr" +
  299.         "qpaXllirSKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4/OBZ3nU9lT3acKpxZNPTr1ri6" +
  300.         "qa6UbobtEd79up+6Ynr5egJ5Mb6feeb3n+hx9L/1U/W36p/VHDFgGswwkBtsMzhg8xTVxbz" +
  301.         "wdL8fb8VFDXcNAQ6VhlWGX4YSRudE8o9VGjUYPjGnGXOMk423GbcajJgYmISZLTepN7ppST" +
  302.         "bmmKaY7TDtMx83MzaLN1pk1mz0x1zLnm+eb15vft2BaeFostqi2uGVJsuRaplnutrxuhVo5" +
  303.         "WaVYVVpds0atna0l1rutu6cRp7lOk06rntZnw7Dxtsm2qbcZsOXYBtuutm22fWFnYhdnt8W" +
  304.         "uw+6TvZN9un2N/T0HDYfZDqsdWh1+c7RyFDpWOt6azpzuP33F9JbpL2dYzxDP2DPjthPLKc" +
  305.         "RpnVOb00dnF2e5c4PziIuJS4LLLpc+Lpsbxt3IveRKdPVxXeF60vWdm7Obwu2o26/uNu5p7" +
  306.         "ofcn8w0nymeWTNz0MPIQ+BR5dE/C5+VMGvfrH5PQ0+BZ7XnIy9jL5FXrdewt6V3qvdh7xc+" +
  307.         "9j5yn+M+4zw33jLeWV/MN8C3yLfLT8Nvnl+F30N/I/9k/3r/0QCngCUBZwOJgUGBWwL7+Hp" +
  308.         "8Ib+OPzrbZfay2e1BjKC5QRVBj4KtguXBrSFoyOyQrSH355jOkc5pDoVQfujW0Adh5mGLw3" +
  309.         "4MJ4WHhVeGP45wiFga0TGXNXfR3ENz30T6RJZE3ptnMU85ry1KNSo+qi5qPNo3ujS6P8YuZ" +
  310.         "lnM1VidWElsSxw5LiquNm5svt/87fOH4p3iC+N7F5gvyF1weaHOwvSFpxapLhIsOpZATIhO" +
  311.         "OJTwQRAqqBaMJfITdyWOCnnCHcJnIi/RNtGI2ENcKh5O8kgqTXqS7JG8NXkkxTOlLOW5hCe" +
  312.         "pkLxMDUzdmzqeFpp2IG0yPTq9MYOSkZBxQqohTZO2Z+pn5mZ2y6xlhbL+xW6Lty8elQfJa7" +
  313.         "OQrAVZLQq2QqboVFoo1yoHsmdlV2a/zYnKOZarnivN7cyzytuQN5zvn//tEsIS4ZK2pYZLV" +
  314.         "y0dWOa9rGo5sjxxedsK4xUFK4ZWBqw8uIq2Km3VT6vtV5eufr0mek1rgV7ByoLBtQFr6wtV" +
  315.         "CuWFfevc1+1dT1gvWd+1YfqGnRs+FYmKrhTbF5cVf9go3HjlG4dvyr+Z3JS0qavEuWTPZtJ" +
  316.         "m6ebeLZ5bDpaql+aXDm4N2dq0Dd9WtO319kXbL5fNKNu7g7ZDuaO/PLi8ZafJzs07P1SkVP" +
  317.         "RU+lQ27tLdtWHX+G7R7ht7vPY07NXbW7z3/T7JvttVAVVN1WbVZftJ+7P3P66Jqun4lvttX" +
  318.         "a1ObXHtxwPSA/0HIw6217nU1R3SPVRSj9Yr60cOxx++/p3vdy0NNg1VjZzG4iNwRHnk6fcJ" +
  319.         "3/ceDTradox7rOEH0x92HWcdL2pCmvKaRptTmvtbYlu6T8w+0dbq3nr8R9sfD5w0PFl5SvN" +
  320.         "UyWna6YLTk2fyz4ydlZ19fi753GDborZ752PO32oPb++6EHTh0kX/i+c7vDvOXPK4dPKy2+" +
  321.         "UTV7hXmq86X23qdOo8/pPTT8e7nLuarrlca7nuer21e2b36RueN87d9L158Rb/1tWeOT3dv" +
  322.         "fN6b/fF9/XfFt1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v+3Njv3H9qwHeg89HcR/cG" +
  323.         "hYPP/pH1jw9DBY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i/suuFxYvfvjV69fO0Zj" +
  324.         "RoZfyl5O/bXyl/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8IH8o/2j5sfVT0K" +
  325.         "f7kxmTk/8EA5jz/GMzLdsAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAA" +
  326.         "Bdvkl/FRgAAAYZJREFUeNqk08+KklEYBvDf9+lIEYZDZQ0OIrQZahEuBoLuQqiWIl5BG2k5" +
  327.         "W5dzA15AF9EFJOiiRRNkSIw4lTAfCQNmzrToOIkc2nRW5z3n/fe8z/Mm4mcfD3EfCb5hhC/" +
  328.         "bjsmWXcJLPMJNLMP7DhY4wRt8jyWo4hVu4Qyrjf8rpKGjJY7xCXLB4TZeB/ssBCaRTn+ggG" +
  329.         "d4h4s0fDRQxAy5arWq0+nEZpMiQx7P1w938SRUzkGWZbrdrsFgoFarxZJ8xWPspzgIuH+tP" +
  330.         "ZbLpfl8rl6vG41GWq3WdpLLAOUgxb0QfI05Sf7CT9NUr9fT7/dVKpXNmSxRSv3nSQOn+UDV" +
  331.         "H86urq9Wq5V2u+3w8NBkMrFB6w7O80EcFyHJCgqFgmKxaDgcajQaxuNxrPBPnORC8IOgvgx" +
  332.         "puVw2nU41m01ZlsUGuIf3eJtsCOko0DjbEFgsuBQYOMJs7bjABzzFndDVZUTKe8E+xmlsmX" +
  333.         "bxIsC5sZ5J6GiBj/9aptg67wafc3yOrfPvAQDwi2sWVdJBsgAAAABJRU5ErkJggg=="
  334.     var image_prefs = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQC" +
  335.         "AMAAAAoLQ9TAAAAllBMVEUAGQASEhIfHx8fJy8pKSk2NjZBQUFJR0ZQUE9RUVFSUlJNX3No" +
  336.         "aGhsaWdramlycG1meY98fHx+fn5wgpV0iqKKh4R4jaR9jJx8kad9kad/mbONmaWEnrmEnrq" +
  337.         "koZy3t7fIx8bKyMHT0c3S0dDU09DV1NPP1t3W1dXY2Njb2tfe29bf3tzj4uHr6+js6+r39/" +
  338.         "f5+PgAAABrL3yvAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxMAAAsTA" +
  339.         "QCanBgAAAAHdElNRQfWBRoFKh31UQ8DAAAAgUlEQVQY022OxxLCMAwFRSc4BEIPJZQQ08v+" +
  340.         "/8+RsTExDDpIe3ijfSJ/hx9g62Dt4GaAI+8YT0t27+BxxvvE/no5pYT10lGFrE34Ja40W3g" +
  341.         "1oMGmW7YZ6hnCYexKTPVkXivuvWe1Cz1aKqPNI3N0slI2TNYZiARJX30qERc7wBPKC4WRDz" +
  342.         "WdWHfmAAAAAElFTkSuQmCC";
  343.     var image_close = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQC" +
  344.         "AQAAAC1+jfqAAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfW" +
  345.         "BRkTNhxuPxLkAAAAHXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBUaGUgR0lNUO9kJW4AAAE" +
  346.         "KSURBVCjPhdGxSgNBFAXQMzpgYWwsLEQUDBJBQgqFIChZEPR7/DA/QCGQTgQtJE1ENoWohY" +
  347.         "UgbGKQyFjErNv52nObe19wqGWg7z0l5YVgVdOu+wUt507tqIVQ4Zodp861ooELe15M5KFI6" +
  348.         "Zfr9u25MIj6Jl4cmSIPBWrq2o5cufO4aOJDYSozNTa2pK4t03PtwUdMKRRykAmW0dTRcyNX" +
  349.         "pBQpI8GJDTR050zkNzK0bMMZLvUNZ8yCfy6Wvbc1NVyi4dloXjqWvds6uvp41pFmpVOKJWd" +
  350.         "6bgwxkmTMIotWKpwrfBkZl7uMonUHf5wSlV2+fUZrjnXdzrmyy7djD8GWTW9e51z557o1Tz" +
  351.         "85FH/WkOkaHQAAAABJRU5ErkJggg==";
  352.  
  353.  
  354.     // Setup global closure variables
  355.     var fouxConsole = {log:function(){},info:function(){},error:function(){},warn:function(){}};
  356.     var console = unsafeWindow.console || fouxConsole;
  357.     var $ = unsafeWindow.jQuery;
  358.     var timerHandle = 0;
  359.     var reloadTimerHandle = 0; // Used for timer that reloads the gateway every few hours
  360.    
  361.     var timerSwitchHandle = 0;
  362.     var reloadNeeded = false;
  363.     var switchCharacter = false;
  364.       //delays
  365.     var reloadDelay = 1800000; // 30 minutes
  366.     var longDelay = 600000; // 10 minutes
  367.     var delay = 5000; // 8 seconds
  368.     var delayShort = 1000;; // 4 seconds
  369.     var dfdNextRun = $.Deferred();
  370.  
  371.     /*
  372.      * Tasklist can be modified to configure the training you want to perform.
  373.      * The configurable options window sets how many profession slots you want to use for each profession.
  374.      * The level array below for each professions specifies the tasks you want to learn at each crafting level.
  375.      * Each craft slot will pick the first task that meets requirements.
  376.      */
  377.     var tasklist = [
  378.          {
  379.             taskName:"Leadership",
  380.             level: {
  381.                  0:["Hire Your First Mercenary"],
  382.                  1:["Complete Advanced Training", "Protect Grateful Merchant","Pick Up Package", "Basic Training"],
  383.                  2:["Guard Duty"],
  384.                  3:["Guard Duty","Hire a Mercenary"],
  385.                  4:["Protect Caravan","Guard Duty","Hire a Mercenary"],
  386.                  5:["Protect Caravan","Explore Local Area","Guard Duty","Hire a Mercenary"],
  387.                  6:["Protect Caravan","Explore Local Area","Guard Duty","Hire a Mercenary"],
  388.    
  389.                 // Current model
  390.                
  391.                  7:["Protect Caravan","Explore Local Area","Guard Duty","Train a Guard","Hire a Mercenary"],
  392.                  8:["Protect Caravan","Explore Local Area","Guard Duty","Train a Guard","Hire a Mercenary"],
  393.                  9:["Protect Caravan","Chart Region","Explore Local Area","Guard Duty","Train a Guard","Hire a Mercenary"],
  394.                 10:["Protect Caravan","Chart Region","Explore Local Area","Guard Duty","Train a Guard","Hire a Mercenary"],
  395.                 11:["Protect Caravan","Chart Region","Explore Local Area","Guard Duty","Train a Guard","Hire a Mercenary"],
  396.                 12:["Protect Caravan","Chart Region","Explore Local Area","Guard Duty","Train a Guard","Hire a Mercenary"],
  397.                
  398.  
  399.                 13:["Patrol the Mines","War Games Training","Protect Caravan","Chart Region","Explore Local Area","Train a Guard","Battle Undead","Hire a Mercenary"],
  400.                 14:["Patrol the Mines","War Games Training","Protect Caravan","Chart Region","Explore Local Area","Train a Guard","Battle Undead","Hire a Mercenary"],
  401.                 15:["Patrol the Mines","War Games Training","Protect Caravan","Chart Region","Explore Local Area","Train a Guard","Battle Undead","Hire a Mercenary"],
  402.                 16:["Patrol the Mines","War Games Training","Fight Off Spellplagued","Protect Caravan","Chart Region","Explore Local Area","Train a Guard","Battle Undead","Hire a Mercenary"],
  403.                 17:["Patrol the Mines","War Games Training","Fight Off Spellplagued","Protect Caravan","Chart Region","Explore Local Area","Train a Guard","Battle Undead","Hire a Mercenary"],
  404.                 18:["Patrol the Mines","War Games Training","Fight Off Spellplagued","Protect Caravan","Chart Region","Explore Local Area","Train a Guard","Battle Undead","Hire a Mercenary"],
  405.                 19:["Patrol the Mines","War Games Training","Fight Off Spellplagued","Protect Caravan","Chart Region","Explore Local Area","Train a Guard","Battle Undead","Hire a Mercenary"],
  406.                 20:["Deliver Metals","Assault Enemy Stronghold","Follow Map to an Unknown Location","Recover Large Mineral Claim","Protect Diamond Shipment","Destroy Enemy Camp","Collect Taxes","Fight Off Spellplagued","Battle Undead","Give Refugees a Home","Protect Caravan","Patrol the Mines","Chart Region","Explore Local Area"],
  407.      
  408.           /*      // Training Mode
  409.                  7:["Train a Guard","Hire a Mercenary"],
  410.                  8:["Train a Guard","Hire a Mercenary"],
  411.                  9:["Train a Guard","Hire a Mercenary"],
  412.                 10:["Train a Guard","Hire a Mercenary"],
  413.                 11:["Train a Guard","Hire a Mercenary"],
  414.                 12:["Train a Guard","Hire a Mercenary"],
  415.                 13:["Train a Footman","Train a Guard","Hire a Mercenary"],
  416.                 14:["Train a Footman","Train a Guard","Hire a Mercenary"],
  417.                 15:["Train a Footman","Train a Guard","Hire a Mercenary"],
  418.                 16:["Train a Footman","Train a Guard","Hire a Mercenary"],
  419.                 17:["Train a Footman","Train a Guard","Hire a Mercenary"],
  420.                 18:["Train a Footman","Train a Guard","Hire a Mercenary"],
  421.                 19:["Patrol the Mines","War Games Training","Fight Off Spellplagued","Protect Caravan","Chart Region","Explore Local Area","Train a Guard","Battle Undead","Hire a Mercenary"],
  422.                 20:["Deliver Metals","Assault Enemy Stronghold","Follow Map to an Unknown Location","Recover Large Mineral Claim","Protect Diamond Shipment","Destroy Enemy Camp","Collect Taxes","Fight Off Spellplagued","Battle Undead","Give Refugees a Home","Protect Caravan","Patrol the Mines","Chart Region","Explore Local Area"],              
  423.               */
  424.             },
  425.         },
  426.         {
  427.             // Mailsmithing
  428.             taskName:"Armorsmithing_Med",
  429.             level: {
  430.                  0:["Hire your first Prospector"],
  431.                  1:["Chain Boots","Chain Shirt"],
  432.                  2:["Gather Iron Ore","Hire an additional Prospector"],
  433.                  3:["Gather Iron Ore","Hire an additional Prospector"],
  434.                  4:["Gather Iron Ore","Hire an additional Prospector"],
  435.                  5:["Gather Iron Ore","Hire an additional Prospector"],
  436.                  6:["Gather Iron Ore","Hire an additional Prospector"],
  437.                  7:["Gather High quality Iron Ore","Upgrade Prospector","Hire an additional Prospector"],
  438.                  8:["Gather High quality Iron Ore","Upgrade Prospector","Hire an additional Prospector"],
  439.                  9:["Gather High quality Iron Ore","Upgrade Prospector","Hire an additional Prospector"],
  440.                 10:["Gather High quality Iron Ore","Upgrade Prospector","Hire an additional Prospector"],
  441.                 11:["Gather High quality Iron Ore","Upgrade Prospector","Hire an additional Prospector"],
  442.                 12:["Gather High quality Iron Ore","Upgrade Prospector","Hire an additional Prospector"],
  443.                 13:["Gather High quality Iron Ore","Upgrade Prospector","Hire an additional Prospector"],
  444.                 14:["14:Deep Wilderness Gathering","Upgrade Blacksmith","Upgrade Prospector","Hire an additional Prospector"],
  445.                 15:["14:Deep Wilderness Gathering","Upgrade Blacksmith","Upgrade Prospector","Hire an additional Prospector"],
  446.                 16:["14:Deep Wilderness Gathering","Upgrade Blacksmith","Upgrade Prospector","Hire an additional Prospector"],
  447.                 17:["14:Deep Wilderness Gathering","Upgrade Blacksmith","Upgrade Prospector","Hire an additional Prospector"],
  448.                 18:["14:Deep Wilderness Gathering","Upgrade Blacksmith","Upgrade Prospector","Hire an additional Prospector"],
  449.                 19:["14:Deep Wilderness Gathering","Upgrade Blacksmith","Upgrade Prospector","Hire an additional Prospector"],
  450.                 20:[],
  451.             },
  452.         },
  453.         {
  454.             // Platesmithing
  455.             taskName:"Armorsmithing_Heavy",
  456.             level: {
  457.                  0:["Hire your first Miner"],
  458.                  1:["Plate Boots","Plate Shirt","Iron Shield"],
  459.                  2:["Gather Iron Ore","Hire an additional Miner"],
  460.                  3:["Gather Iron Ore","Hire an additional Miner"],
  461.                  4:["Gather Iron Ore","Hire an additional Miner"],
  462.                  5:["Gather Iron Ore","Hire an additional Miner"],
  463.                  6:["Gather Iron Ore","Hire an additional Miner"],
  464.                  7:["Gather High quality Iron Ore","Upgrade Miner","Hire an additional Miner"],
  465.                  8:["Gather High quality Iron Ore","Upgrade Miner","Hire an additional Miner"],
  466.                  9:["Gather High quality Iron Ore","Upgrade Miner","Hire an additional Miner"],
  467.                 10:["Gather High quality Iron Ore","Upgrade Miner","Hire an additional Miner"],
  468.                 11:["Gather High quality Iron Ore","Upgrade Miner","Hire an additional Miner"],
  469.                 12:["Gather High quality Iron Ore","Upgrade Miner","Hire an additional Miner"],
  470.                 13:["Gather High quality Iron Ore","Upgrade Miner","Hire an additional Miner"],
  471.                 14:["14:Deep Wilderness Gathering","Upgrade Armorer","Upgrade Miner","Hire an additional Miner"],
  472.                 15:["14:Deep Wilderness Gathering","Upgrade Armorer","Upgrade Miner","Hire an additional Miner"],
  473.                 16:["14:Deep Wilderness Gathering","Upgrade Armorer","Upgrade Miner","Hire an additional Miner"],
  474.                 17:["14:Deep Wilderness Gathering","Upgrade Armorer","Upgrade Miner","Hire an additional Miner"],
  475.                 18:["14:Deep Wilderness Gathering","Upgrade Armorer","Upgrade Miner","Hire an additional Miner"],
  476.                 19:["14:Deep Wilderness Gathering","Upgrade Armorer","Upgrade Miner","Hire an additional Miner"],
  477.                 20:[],
  478.             },
  479.         },
  480.         {
  481.             taskName:"Leatherworking",
  482.             level: {
  483.                  0:["Hire your first Skinner"],
  484.                  1:["Leather Boots","Leather Shirt"],
  485.                  2:["Gather Simple Pelts","Hire an additional Skinner"],
  486.                  3:["Gather Simple Pelts","Hire an additional Skinner"],
  487.                  4:["Gather Simple Pelts","Hire an additional Skinner"],
  488.                  5:["Gather Simple Pelts","Hire an additional Skinner"],
  489.                  6:["Gather Simple Pelts","Hire an additional Skinner"],
  490.                  7:["Gather Tough Pelts","Upgrade Skinner","Hire an additional Skinner"],
  491.                  8:["Gather Tough Pelts","Upgrade Skinner","Hire an additional Skinner"],
  492.                  9:["Gather Tough Pelts","Upgrade Skinner","Hire an additional Skinner"],
  493.                 10:["Gather Tough Pelts","Upgrade Skinner","Hire an additional Skinner"],
  494.                 11:["Gather Tough Pelts","Upgrade Skinner","Hire an additional Skinner"],
  495.                 12:["Gather Tough Pelts","Upgrade Skinner","Hire an additional Skinner"],
  496.                 13:["Gather Tough Pelts","Upgrade Skinner","Hire an additional Skinner"],
  497.                 14:["14:Deep Wilderness Gathering","Upgrade Tanner","Upgrade Skinner","Hire an additional Skinner"],
  498.                 15:["14:Deep Wilderness Gathering","Upgrade Tanner","Upgrade Skinner","Hire an additional Skinner"],
  499.                 16:["14:Deep Wilderness Gathering","Upgrade Tanner","Upgrade Skinner","Hire an additional Skinner"],
  500.                 17:["14:Deep Wilderness Gathering","Upgrade Tanner","Upgrade Skinner","Hire an additional Skinner"],
  501.                 18:["14:Deep Wilderness Gathering","Upgrade Tanner","Upgrade Skinner","Hire an additional Skinner"],
  502.                 19:["14:Deep Wilderness Gathering","Upgrade Tanner","Upgrade Skinner","Hire an additional Skinner"],
  503.                 20:[],
  504.             },
  505.         },
  506.         {
  507.             taskName:"Tailoring",
  508.             level: {
  509.                  0:["Hire your first Weaver"],
  510.                  1:["Cloth Boots","Cloth Shirt"],
  511.                  2:["Gather Wool Scraps","Hire an additional Weaver"],
  512.                  3:["Gather Wool Scraps","Hire an additional Weaver"],
  513.                  4:["Gather Wool Scraps","Hire an additional Weaver"],
  514.                  5:["Gather Wool Scraps","Hire an additional Weaver"],
  515.                  6:["Gather Wool Scraps","Hire an additional Weaver"],
  516.                  7:["Gather Cotton Scraps","Upgrade Weaver","Hire an additional Weaver"],
  517.                  8:["Gather Cotton Scraps","Upgrade Weaver","Hire an additional Weaver"],
  518.                  9:["Gather Cotton Scraps","Upgrade Weaver","Hire an additional Weaver"],
  519.                 10:["Gather Cotton Scraps","Upgrade Weaver","Hire an additional Weaver"],
  520.                 11:["Gather Cotton Scraps","Upgrade Weaver","Hire an additional Weaver"],
  521.                 12:["Gather Cotton Scraps","Upgrade Weaver","Hire an additional Weaver"],
  522.                 13:["Gather Cotton Scraps","Upgrade Weaver","Hire an additional Weaver"],
  523.                 14:["14:Intensive Scrap Gathering","Upgrade Outfitter","Upgrade Weaver","Hire an additional Weaver"],
  524.                 15:["14:Intensive Scrap Gathering","Upgrade Outfitter","Upgrade Weaver","Hire an additional Weaver"],
  525.                 16:["14:Intensive Scrap Gathering","Upgrade Outfitter","Upgrade Weaver","Hire an additional Weaver"],
  526.                 17:["14:Intensive Scrap Gathering","Upgrade Outfitter","Upgrade Weaver","Hire an additional Weaver"],
  527.                 18:["14:Intensive Scrap Gathering","Upgrade Outfitter","Upgrade Weaver","Hire an additional Weaver"],
  528.                 19:["14:Intensive Scrap Gathering","Upgrade Outfitter","Upgrade Weaver","Hire an additional Weaver"],
  529.                 20:[],
  530.             },
  531.         },
  532.         {
  533.             taskName:"Artificing",
  534.             level: {
  535.                  0:["Hire your first Carver"],
  536.                  1:["Virtuous Symbol +1","1:Gather Ore and Wood"],
  537.                  2:["1:Gather Ore and Wood","Hire an additional Carver"],
  538.                  3:["1:Gather Ore and Wood","Hire an additional Carver"],
  539.                  4:["1:Gather Ore and Wood","Hire an additional Carver"],
  540.                  5:["1:Gather Ore and Wood","Hire an additional Carver"],
  541.                  6:["1:Gather Ore and Wood","Hire an additional Carver"],
  542.                  7:["7:Gather Ore and Wood","Upgrade Carver","Hire an additional Carver"],
  543.                  8:["7:Gather Ore and Wood","Upgrade Carver","Hire an additional Carver"],
  544.                  9:["7:Gather Ore and Wood","Upgrade Carver","Hire an additional Carver"],
  545.                 10:["7:Gather Ore and Wood","Upgrade Carver","Hire an additional Carver"],
  546.                 11:["7:Gather Ore and Wood","Upgrade Carver","Hire an additional Carver"],
  547.                 12:["7:Gather Ore and Wood","Upgrade Carver","Hire an additional Carver"],
  548.                 13:["7:Gather Ore and Wood","Upgrade Carver","Hire an additional Carver"],
  549.                 14:["14:Deep Wilderness Gathering","Upgrade Engraver","Upgrade Carver","Hire an additional Carver"],
  550.                 15:["14:Deep Wilderness Gathering","Upgrade Engraver","Upgrade Carver","Hire an additional Carver"],
  551.                 16:["14:Deep Wilderness Gathering","Upgrade Engraver","Upgrade Carver","Hire an additional Carver"],
  552.                 17:["14:Deep Wilderness Gathering","Upgrade Engraver","Upgrade Carver","Hire an additional Carver"],
  553.                 18:["14:Deep Wilderness Gathering","Upgrade Engraver","Upgrade Carver","Hire an additional Carver"],
  554.                 19:["14:Deep Wilderness Gathering","Upgrade Engraver","Upgrade Carver","Hire an additional Carver"],
  555.                 20:[],
  556.             },
  557.         },
  558.         {
  559.             taskName:"Weaponsmithing",
  560.             level: {
  561.                  0:["Hire your first Smelter"],
  562.                  1:["Dagger +1","Gather Iron Ore and Pine Wood"],
  563.                  2:["Gather Iron Ore and Pine Wood","Hire an additional Smelter"],
  564.                  3:["Gather Iron Ore and Pine Wood","Hire an additional Smelter"],
  565.                  4:["Gather Iron Ore and Pine Wood","Hire an additional Smelter"],
  566.                  5:["Gather Iron Ore and Pine Wood","Hire an additional Smelter"],
  567.                  6:["Gather Iron Ore and Pine Wood","Hire an additional Smelter"],
  568.                  7:["Gather High Quality Ore and Wood","Upgrade Smelter","Hire an additional Smelter"],
  569.                  8:["Gather High Quality Ore and Wood","Upgrade Smelter","Hire an additional Smelter"],
  570.                  9:["Gather High Quality Ore and Wood","Upgrade Smelter","Hire an additional Smelter"],
  571.                 10:["Gather High Quality Ore and Wood","Upgrade Smelter","Hire an additional Smelter"],
  572.                 11:["Gather High Quality Ore and Wood","Upgrade Smelter","Hire an additional Smelter"],
  573.                 12:["Gather High Quality Ore and Wood","Upgrade Smelter","Hire an additional Smelter"],
  574.                 13:["Gather High Quality Ore and Wood","Upgrade Smelter","Hire an additional Smelter"],
  575.                 14:["14:Deep Wilderness Gathering","Upgrade Grinder","Upgrade Smelter","Hire an additional Smelter"],
  576.                 15:["14:Deep Wilderness Gathering","Upgrade Grinder","Upgrade Smelter","Hire an additional Smelter"],
  577.                 16:["14:Deep Wilderness Gathering","Upgrade Grinder","Upgrade Smelter","Hire an additional Smelter"],
  578.                 17:["14:Deep Wilderness Gathering","Upgrade Grinder","Upgrade Smelter","Hire an additional Smelter"],
  579.                 18:["14:Deep Wilderness Gathering","Upgrade Grinder","Upgrade Smelter","Hire an additional Smelter"],
  580.                 19:["14:Deep Wilderness Gathering","Upgrade Grinder","Upgrade Smelter","Hire an additional Smelter"],
  581.                 20:[],
  582.             },
  583.         },
  584.         {
  585.             taskName:"Alchemy",
  586.             level: {
  587.                  0:["Hire your first Apothecary"],
  588.                  1:["Alchemical Research","Rank 1 Experimentation",],
  589.                  2:["Alchemical Research","Rank 2 Experimentation","Gather Simple Components","Hire an additional Apothecary"],
  590.                  3:["Alchemical Research","Rank 3 Experimentation","Gather Simple Components","Hire an additional Apothecary"],
  591.                  4:["Alchemical Research","Rank 4 Experimentation","Gather Simple Components","Hire an additional Apothecary"],
  592.                  5:["Alchemical Research","Rank 5 Experimentation","Gather Simple Components","Hire an additional Apothecary"],
  593.                  6:["Alchemical Research","Rank 6 Experimentation","Gather Simple Components","Hire an additional Apothecary"],
  594.                  7:["Alchemical Research","Rank 7 Experimentation","Gather Advanced Components","Upgrade Apothecary","Hire an additional Apothecary"],
  595.                  8:["Transmutation Research","Rank 8 Experimentation","Gather Advanced Components","Upgrade Apothecary","Hire an additional Apothecary"],
  596.                  9:["Alchemical Research","Rank 9 Experimentation","Gather Advanced Components","Upgrade Apothecary","Hire an additional Apothecary"],
  597.                 10:["Transmutation Research","Rank 10 Experimentation","Gather Advanced Components","Upgrade Apothecary","Hire an additional Apothecary"],
  598.                 11:["Alchemical Research","Rank 11 Experimentation","Gather Advanced Components","Upgrade Apothecary","Hire an additional Apothecary"],
  599.                 12:["Alchemical Research","Rank 12 Experimentation","Gather Advanced Components","Upgrade Apothecary","Hire an additional Apothecary"],
  600.                 13:["Alchemical Research","Rank 13 Experimentation","Gather Advanced Components","Upgrade Apothecary","Hire an additional Apothecary"],
  601.                 14:["Alchemical Research","Rank 14 Experimentation","Gather Complex Components","Upgrade Mixologist","Upgrade Apothecary","Hire an additional Apothecary"],
  602.                 15:["Alchemical Research","Rank 15 Experimentation","Gather Complex Components","Upgrade Mixologist","Upgrade Apothecary","Hire an additional Apothecary"],
  603.                 16:["Alchemical Research","Rank 16 Experimentation","Gather Complex Components","Upgrade Mixologist","Upgrade Apothecary","Hire an additional Apothecary"],
  604.                 17:["Alchemical Research","Rank 17 Experimentation","Gather Complex Components","Upgrade Mixologist","Upgrade Apothecary","Hire an additional Apothecary"],
  605.                 18:["Alchemical Research","Rank 18 Experimentation","Gather Complex Components","Upgrade Mixologist","Upgrade Apothecary","Hire an additional Apothecary"],
  606.                 19:["Alchemical Research","Rank 19 Experimentation","Gather Complex Components","Upgrade Mixologist","Upgrade Apothecary","Hire an additional Apothecary"],
  607.                 20:["Rank 20 Experimentation"],
  608.             },
  609.         },
  610.     ];
  611.     // Load Settings
  612.     /*
  613.         This list is a base setting lits
  614.         The higher in the list the profession related option the more important it is
  615.             Basically if number of slots in few professions sums up to be higher that total number of avaliable slots
  616.             Professions that are higher on the below list will get all their setuped slots used,
  617.             and professions that are lower will be skipped entairly or just get few but not all slots
  618.         Thus if you want for example to prioretize different profession you need to put it as first profession
  619.             But it is global - so you need to setup the list in such way to make each profession primary on each character
  620.             if its even possible that is
  621.     */
  622.     var settingnames = [
  623.         {name: 'paused',        title: 'Pause Script',                         def: false, type:'checkbox', tooltip:'Disable All Automation'},
  624.         {name: 'debug',         title: 'Enable Debug',                         def: false, type:'checkbox', tooltip:'Enable all debug output to console', onsave: function(newValue, oldValue) {console=newValue?unsafeWindow.console||fouxConsole:fouxConsole;}},
  625.         {name: 'autoreload',    title: 'Auto Reload',                          def: false, type:'checkbox', tooltip:'Enabling this will reload the gateway periodically'},
  626.         {name: 'autologin',     title: 'Attempt to login automatically',       def: false, type:'checkbox', tooltip:'Automatically attempt to login to the neverwinter gateway site'},
  627.         {name: 'nw_charcount',  title: ' Number of Characters',                def: '2',   type:'charcount',     tooltip:'Specify between how many characters script should cycle through (reload page after changing)'},
  628.         {name: 'nw_delay',      title: ' Delay Between Characters',            def: '60000', type:'text2',     tooltip:'Specify delay between characters *in seconds* (reload page after changing)'},
  629.         {name: 'nw_username',   title: ' Account Username',                    def: '[email protected]',    type:'text',     tooltip:''},
  630.         {name: 'nw_password',   title: ' Account Password',                    def: 'xxx',   type:'password', tooltip:''},
  631.         {name: 'Label',         title: ' Character Name.......LS...MS...PS...LW...Ta....Ar....WS...Al', def: '', type:'label', tooltip:'', repeat:'1'},
  632.         {name: 'optionals',     title: 'Fill Optional Assets',                 def: true,  type:'checkbox', tooltip:'Enabling filling the optional assets with asset selections'},
  633.         {name: 'autopurchase',  title: 'Auto Purchase Resources',              def: true,  type:'checkbox', tooltip:'Automatically purchase required resources from gateway shop (20 at a time)'},
  634.         {name: 'autorefine',    title: 'Refine Rough Astral Diamonds',         def: true,  type:'checkbox',  tooltip:'Automatically refine rough astral diamonds each time loading a character'},    
  635.         {name: 'excluderare',   title: 'Exclude Rare Tasks',                   def: true,  type:'checkbox', tooltip:'Exclude rare tasks to avoid selecting wrong tasks during profession leveling. When disabled, selection of specific tasks can be performed by specifying level in task name (eg. "4:Leather Armor +1" will craft the rare task only)'},
  636.         {name: 'ActiveChar',    title: 'Actual Character Processed',         def: '1',   type:'text4', tooltip:'Do not touch this. It just shows which character was done previously or is processed right now - as a way of checking if script works fine'},
  637.    
  638.     ];
  639.     var setTemp = [];
  640.     for(var i = 0; i < settingnames.length; ++i)
  641.     {
  642.         var t = settingnames[i];
  643.         setTemp.push(t);
  644.         if(t.repeat == 1)
  645.         {
  646.             for(var j = 1; j <= GM_getValue(settingnames[4].name); ++j)
  647.             {
  648.                 setTemp.push({name: 'nw_charname'+j,         title: 'Neverwinter Character '+j,            def: '',    type:'text1',     tooltip:'Name of your '+j+' Neverwinter Character'});
  649.                 setTemp.push({name: 'Leadership'+j,          title: 'Leadership Tasks.............',        def: '9',   type:'text2',     tooltip:'Number of slots to assign to Leadership for Character '+j });
  650.                 setTemp.push({name: 'Armorsmithing_Med'+j,   title: 'Mailsmithing Tasks...........',        def: '0',   type:'text2',     tooltip:'Number of slots to assign to Mailsmithing for Character '+j });
  651.                 setTemp.push({name: 'Armorsmithing_Heavy'+j, title: 'Platesmithing Tasks.........',         def: '0',   type:'text2',     tooltip:'Number of slots to assign to Platesmithing for Character '+j });
  652.                 setTemp.push({name: 'Leatherworking'+j,      title: 'Leatherworking Tasks......',           def: '0',   type:'text2',     tooltip:'Number of slots to assign to Leatherworking for Character '+j });
  653.                 setTemp.push({name: 'Tailoring'+j,           title: 'Tailoring Tasks...................',   def: '0',   type:'text2',     tooltip:'Number of slots to assign to Tailoring for Character '+j });
  654.                 setTemp.push({name: 'Artificing'+j,          title: 'Artificing Tasks....................', def: '0',   type:'text2',     tooltip:'Number of slots to assign to Artificing for Character '+j });
  655.                 setTemp.push({name: 'Weaponsmithing'+j,      title: 'Weaponsmithing Tasks....',             def: '0',   type:'text2',     tooltip:'Number of slots to assign to Weaponsmithing for Character '+j });
  656.                 setTemp.push({name: 'Alchemy'+j,             title: 'Alchemy Tasks....................',    def: '0',   type:'text2',     tooltip:'Number of slots to assign to Alchemy for Character '+j });  
  657.             }
  658.         }
  659.     }
  660.     settingnames = setTemp;
  661.     // Load local settings cache (unsecured)
  662.    
  663.     var settings = {};
  664.     for (var i = 0; i < settingnames.length; i++) {
  665.         // Ignore label types
  666.         if(settingnames[i].type === 'label') {
  667.             continue;
  668.         }
  669.         settings[settingnames[i].name] = GM_getValue(settingnames[i].name, settingnames[i].def);
  670.         // call the onsave for the setting if it exists
  671.         if(typeof(settingnames[i].onsave) === "function") {
  672.             console.log("Calling 'onsave' for", settingnames[i].name);
  673.             settingnames[i].onsave(settings[settingnames[i].name], settings[settingnames[i].name]);
  674.         }
  675.     }
  676.    
  677.     var loopDelay = (settings["nw_delay"]*1000);
  678.     // Page Settings
  679.     var PAGES = Object.freeze({
  680.         LOGIN : { name: "Login", path: "div#login"},
  681.         GUARD : { name: "Account Guard", path: "div#page-accountguard"},
  682.         CHARSELECT : { name: "Character Select", path: "div.page-characterselect"},
  683.         FRONTPAGE : { name: "Front Page", path: "div.page-front"},
  684.         PROFESSIONS : { name: "Professions", path: "div.page-professions"},
  685.         INVENTORY : { name: "Inventory", path: "div.page-inventory"},
  686.     });
  687.  
  688.     /**
  689.      * Uses the page settings to determine which page is currently displayed
  690.      */
  691.     function GetCurrentPage() {
  692.         for(var __kk in PAGES) {
  693.             if (!PAGES.hasOwnProperty(__kk)) {
  694.                 continue;
  695.             }
  696.             var page = PAGES[__kk];
  697.             if($(page["path"]).filter(":visible").length) {
  698.                 return page;
  699.             }
  700.         }
  701.     }
  702.    
  703.     function page_DEFAULT() {
  704.         dfdNextRun.resolve(false,false);
  705.     }
  706.     function page_LOGIN() {
  707.         //if(!$("form > p.error:visible").length && settings["autologin"]) {
  708.             // No previous log in error - attempt to log in
  709.             console.log("Setting username");
  710.             $("input#user").val(settings["nw_username"]);
  711.             console.log("Setting password");
  712.             $("input#pass").val(settings["nw_password"]);
  713.             console.log("Clicking Login Button");
  714.             $("div#login > input").click();
  715.         //}
  716.         dfdNextRun.resolve(false);
  717.     }
  718.     function page_GUARD() {
  719.         // Do nothing on the guard screen
  720.         dfdNextRun.resolve(false,false);
  721.     }
  722.     function page_CHARSELECT() {
  723.         // Select the character if it is set  nw_charcount   ActiveChar
  724.         unsafeWindow.client.sounds.toggle(false);
  725.         var actualchar = settings["ActiveChar"];
  726.         ++actualchar;
  727.         if(actualchar > settings["nw_charcount"]){
  728.             actualchar = 1;
  729.         }
  730.         console.log("Character number to log: " + actualchar);
  731.         settings["ActiveChar"] = actualchar; // Save to local cache
  732.         GM_setValue("ActiveChar", actualchar); // Save to GM cache
  733.         $('#settings_ActiveChar').val(actualchar);  //uptade vaule in object
  734.         var charname = settings["nw_charname" + actualchar];
  735.         console.log("Character name to log: " + charname);
  736.         if(charname.length) {
  737.             console.log("Trying to click...");
  738.             $(".char-list-name:contains('"+charname+"')").click()
  739.         }
  740.         else {
  741.             console.log("Error: Empty character name");
  742.         }
  743.         dfdNextRun.resolve(false,false);
  744.     }
  745.     function page_FRONTPAGE() {
  746.         // Click the professions tab
  747.         console.log("Click was successfull");
  748.         var af = settings["autorefine"];
  749.         if(af) {
  750.             $("a.inventory").click();
  751.         }
  752.         else {
  753.             $("a.professions").click();
  754.         }
  755.         dfdNextRun.resolve(false,false);
  756.     }
  757.     function page_INVENTORY() {
  758.         // Click the professions tab
  759.         console.log("Tring to refine ADs");
  760.         var refineButton = $("div.bag-currency button").filter(":contains('Refine')");
  761.         var af = settings["autorefine"]
  762.         if(af) {    
  763.             if(refineButton.length) {
  764.                if(refineButton[0].disabled == false){
  765.                     refineButton[0].click();
  766.                     console.log("Refine successfull");
  767.                 }
  768.                 else
  769.                 {
  770.                     console.log("Nothing to refine");
  771.                 }
  772.             }
  773.             $("a.professions").click();
  774.         }
  775.         dfdNextRun.resolve(false,false);
  776.     }
  777.     function page_PROFESSIONS() {
  778.         //unsafeWindow.client.sounds.toggle(false);
  779.         // Switch to overview
  780.         $("a.professions-overview").click();
  781.         WaitForState("").done(function() {
  782.             // List the buttons on the overview
  783.             var completedSlotButtons = $("div.panel-content button").filter(":contains('Collect Result')").filter(":visible");
  784.             var openSlotButtons = $("div.panel-content button").filter(":contains('Choose Task')").filter(":visible");
  785.             var actualchar = settings["ActiveChar"];
  786.             // See if there are any completed tasks on the overview
  787.             if(completedSlotButtons.length) {
  788.                 completedSlotButtons[0].click();
  789.                 WaitForState("div.professions-rewards-modal button:contains('Collect Result')").done(function() {
  790.                     $("div.professions-rewards-modal button:contains('Collect Result')").click();
  791.                     WaitForState("").done(function() {
  792.                         dfdNextRun.resolve(true,false);
  793.                     });
  794.                 });
  795.             }
  796.             // See if there are any open tasks on the overview
  797.             else if(openSlotButtons.length) {
  798.                 var foundTask = false;
  799.                 // Go through the professions to assign tasks until specified slots filled
  800.                 for (var i = 0; i < tasklist.length; i++) {
  801.                     var currentTasks = $("div.professions-slot-icon." + tasklist[i].taskName);
  802.                         if(currentTasks.length < settings[tasklist[i].taskName+actualchar]) {
  803.                             foundTask = true;
  804.                             openSlotButtons[0].click();
  805.                             WaitForState("div#content_professions:visible").done(function() {
  806.                                 // Switch to correct type
  807.                                 $("a.professions-" + tasklist[i].taskName).click();
  808.                                 WaitForState("").done(function() {
  809.                                     createNextTask(tasklist[i], 0, dfdNextRun);
  810.                                 });
  811.                             });
  812.                             break;
  813.                         }
  814.                 }
  815.                 if(!foundTask) {
  816.                     console.log("All task counts assigned");
  817.                     dfdNextRun.resolve(false,false);
  818.                 }
  819.             }
  820.             else {
  821.                 // If no tasks to assign, switch characters
  822.                 if(!timerSwitchHandle) {
  823.                     dfdNextRun.resolve(false,true);
  824.                 }
  825.                 else {
  826.                 // Waiting to switch characters
  827.                     dfdNextRun.resolve(false,false);
  828.                 }
  829.             }
  830.         });
  831.     }
  832.  
  833.     /**
  834.      * Iterative approach to finding the next task to assign to an open slot.
  835.      *
  836.      * @param {Array} list The list of task names to try in order of precedence
  837.      * @param {int} i The current attempt number. Will try to find the i'th task.
  838.      * @param {Deferred} dff The deffered object to resolve when a task is found or if all tasks were not found
  839.      */
  840.     function createNextTask(prof, i, dff) {
  841.         // Check level
  842.         var level = parseInt($("a.professions-"+prof.taskName).closest("span").prevAll("div:first").find("span").text());
  843.         console.log(prof.taskName, "is level", level);
  844.         var list = prof.level[level];
  845.         console.log("createNextTask", list.length, i);
  846.         if(list.length <=i) {
  847.             console.log("Nothing Found");
  848.             dff.resolve(false);
  849.             return;
  850.         }
  851.  
  852.         var taskName = list[i];
  853.         console.log("Searching for task:", taskName);
  854.         var task = SearchForTaskByName(taskName, prof.taskName, level);
  855.         if(task == null) {
  856.             console.log("Skipping task selection to purchase resources");
  857.             dff.resolve(false);
  858.             return;
  859.         }
  860.         if(task) {
  861.             console.log('Task Found');
  862.             task.click();
  863.             WaitForState("div.page-professions-taskdetails").done(function() {
  864.                 // Click all buttons and select an item to use in the slot
  865.                 var def = $.Deferred();
  866.                 var buttonList = $("h3:contains('Optional Assets:')").closest("div").find("button");
  867.                 if(buttonList.length && settings["optionals"]) {
  868.                     SelectItemFor(buttonList, 0, def, prof);
  869.                 }
  870.                 else {
  871.                     def.resolve();
  872.                 }
  873.                 def.done(function() {
  874.                     // All items are populated
  875.                     console.log("Items Populated");
  876.                     // Click the Start Task Button
  877.                     //Get the start task button if it is enabled
  878.                     var enabledButton = $("div.footer-body > div.input-field.button:not('.disabled') > button:contains('Start Task')");
  879.                     if(enabledButton.length) {
  880.                         console.log("Clicking Start Task Button");
  881.                         enabledButton.click();
  882.                         WaitForState("").done(function() {
  883.                             // Done
  884.                             dff.resolve(true);
  885.                         });
  886.                     }
  887.                     else { // Button not enabled, something required was probably missing
  888.                         // Go back
  889.                         $("div.footer-body > div.input-field.button > button:contains('Back')").click();
  890.                         WaitForState("").done(function() {
  891.                             // continue with the next one
  892.                             console.log('Finding next task');
  893.                             createNextTask(prof, i+1, dff);
  894.                         });
  895.                     }
  896.                 });
  897.             });
  898.         }
  899.         else {
  900.             console.log('Finding next task');
  901.             createNextTask(prof, i+1, dff);
  902.         }
  903.     }
  904.     /**
  905.      * Selects the highest level asset for the i'th button in the list. Uses an iterative approach
  906.      * in order to apply a sufficient delay after the asset is assigned
  907.      *
  908.      * @param {Array} The list of buttons to use to click and assign assets for
  909.      * @param {int} i The current iteration number. Will select assets for the i'th button
  910.      * @param {Deferred} jQuery Deferred object to resolve when all of the assets have been assigned
  911.      */
  912.     function SelectItemFor(buttonListIn, i, def, prof) {
  913.         buttonListIn[i].click();
  914.         WaitForState("").done(function() {
  915.             var specialItems = $("div.modal-item-list a.Special");
  916.             var goldItems = $("div.modal-item-list a.Gold");
  917.             var silverItems = $("div.modal-item-list a.Silver");
  918.             var bronzeItems = $("div.modal-item-list a.Bronze");
  919.             var clicked = false;
  920.  
  921.             // Try to avoid using up higher rank assets needlessly
  922.             if(prof.taskName === "Leadership") {
  923.                 var mercenarys = $("div.modal-item-list a.Bronze:contains('Mercenary')");
  924.                 var guards = $("div.modal-item-list a.Bronze:contains('Guard')");
  925.                 var footmen = $("div.modal-item-list a.Bronze:contains('Footman')");
  926.  
  927.                 if(mercenarys.length)   { clicked = true; mercenarys[0].click(); }
  928.                 else if(guards.length)  { clicked = true; guards[0].click(); }
  929.                 else if(footmen.length) { clicked = true; footmen[0].click(); }
  930.             }
  931.             else if(prof.taskName === "Tailoring") {
  932.                 var mercenarys = $("div.modal-item-list a.Bronze:contains('Weaver')");
  933.                 var guards = $("div.modal-item-list a.Bronze:contains('Outfitter')");
  934.                 var footmen = $("div.modal-item-list a.Bronze:contains('Assistant Tailor')");
  935.  
  936.                 if(mercenarys.length)   { clicked = true; mercenarys[0].click(); }
  937.                 else if(guards.length)  { clicked = true; guards[0].click(); }
  938.                 else if(footmen.length) { clicked = true; footmen[0].click(); }
  939.             }
  940.             else if(prof.taskName === "Weaponsmithing") {
  941.                 var mercenarys = $("div.modal-item-list a.Bronze:contains('Smelter')");
  942.                 var guards = $("div.modal-item-list a.Bronze:contains('Grinder')");
  943.                 var footmen = $("div.modal-item-list a.Bronze:contains('Assistant Weaponsmith')");
  944.  
  945.                 if(mercenarys.length)   { clicked = true; mercenarys[0].click(); }
  946.                 else if(guards.length)  { clicked = true; guards[0].click(); }
  947.                 else if(footmen.length) { clicked = true; footmen[0].click(); }
  948.             }
  949.             else if(prof.taskName === "Platesmithing") {
  950.                 var mercenarys = $("div.modal-item-list a.Bronze:contains('Miner')");
  951.                 var guards = $("div.modal-item-list a.Bronze:contains('Armorer')");
  952.                 var footmen = $("div.modal-item-list a.Bronze:contains('Assistant Platesmith')");
  953.  
  954.                 if(mercenarys.length)   { clicked = true; mercenarys[0].click(); }
  955.                 else if(guards.length)  { clicked = true; guards[0].click(); }
  956.                 else if(footmen.length) { clicked = true; footmen[0].click(); }
  957.             }
  958.             else if(prof.taskName === "Mailsmithing") {
  959.                 var mercenarys = $("div.modal-item-list a.Bronze:contains('Prospector')");
  960.                 var guards = $("div.modal-item-list a.Bronze:contains('Blacksmith')");
  961.                 var footmen = $("div.modal-item-list a.Bronze:contains('Assistant Mailsmith')");
  962.  
  963.                 if(mercenarys.length)   { clicked = true; mercenarys[0].click(); }
  964.                 else if(guards.length)  { clicked = true; guards[0].click(); }
  965.                 else if(footmen.length) { clicked = true; footmen[0].click(); }
  966.             }
  967.             else if(prof.taskName === "Leatherworking") {
  968.                 var mercenarys = $("div.modal-item-list a.Bronze:contains('Skinner')");
  969.                 var guards = $("div.modal-item-list a.Bronze:contains('Tanner')");
  970.                 var footmen = $("div.modal-item-list a.Bronze:contains('Assistant Leatherworker')");
  971.  
  972.                 if(mercenarys.length)   { clicked = true; mercenarys[0].click(); }
  973.                 else if(guards.length)  { clicked = true; guards[0].click(); }
  974.                 else if(footmen.length) { clicked = true; footmen[0].click(); }
  975.             }
  976.             else if(prof.taskName === "Artificing") {
  977.                 var mercenarys = $("div.modal-item-list a.Bronze:contains('Carver')");
  978.                 var guards = $("div.modal-item-list a.Bronze:contains('Engraver')");
  979.                 var footmen = $("div.modal-item-list a.Bronze:contains('Assistant Artificer')");
  980.  
  981.                 if(mercenarys.length)   { clicked = true; mercenarys[0].click(); }
  982.                 else if(guards.length)  { clicked = true; guards[0].click(); }
  983.                 else if(footmen.length) { clicked = true; footmen[0].click(); }
  984.             }
  985.             else if(prof.taskName === "Alchemy") {
  986.                 var mercenarys = $("div.modal-item-list a.Bronze:contains('Apothecary')");
  987.                 var guards = $("div.modal-item-list a.Bronze:contains('Mixologist')");
  988.                 var footmen = $("div.modal-item-list a.Bronze:contains('Assistant Alchemist')");
  989.  
  990.                 if(mercenarys.length)   { clicked = true; mercenarys[0].click(); }
  991.                 else if(guards.length)  { clicked = true; guards[0].click(); }
  992.                 else if(footmen.length) { clicked = true; footmen[0].click(); }
  993.             }
  994.  
  995.             if (!clicked) {
  996.                 // Click the highest slot
  997.                 if(specialItems.length)     { specialItems[0].click(); }
  998.                 else if(goldItems.length)   { goldItems[0].click(); }
  999.                 else if(silverItems.length) { silverItems[0].click(); }
  1000.                 else if(bronzeItems.length) { bronzeItems[0].click(); }
  1001.                 else { $("button.close-button").click(); }
  1002.             }
  1003.  
  1004.             console.log("Clicked item");
  1005.             WaitForState("").done(function() {
  1006.                 // Get the new set of select buttons created since the other ones are removed when the asset loads
  1007.                 var buttonList = $("h3:contains('Optional Assets:')").closest("div").find("button");
  1008.                 if(i < buttonList.length - 1) {
  1009.                     SelectItemFor(buttonList, i+1, def, prof);
  1010.                 }
  1011.                 else {
  1012.                     // Let main loop continue
  1013.                     def.resolve();
  1014.                 }
  1015.             });
  1016.         });
  1017.     }
  1018.     /**
  1019.      * Given a task name and that the search pane is active, will attempt to search for the given task
  1020.      * and return the button element if the level and resource criteria are met.
  1021.      *
  1022.      * @param {String} taskname The name of the task to search within the search pane for
  1023.      */
  1024.     function SearchForTaskByName(taskname, profName, profLevel) {
  1025.         var tasklevel = 0;
  1026.         if(taskname.indexOf(":") > -1) {
  1027.             // split task with level requirement
  1028.             tasklevel=taskname.split(":",2)[0];
  1029.             taskname=taskname.split(":",2)[1];
  1030.         }
  1031.         // Filter the results
  1032.         var filterDiv = $("div#tasklist_filter input");
  1033.         console.log("Searching for:", taskname);
  1034.         filterDiv.val(taskname);
  1035.         filterDiv.keyup();
  1036.        
  1037.         // Find the result
  1038.         var taskTitle = $("table#tasklist tr h4 span").filter(function() {
  1039.             return $(this).text() === taskname;
  1040.         });
  1041.         if(taskTitle.length) {
  1042.             for (var i = 0; i < taskTitle.length; i++) {
  1043.                 if($(taskTitle[i]).closest("div.rare").length && profName != "Leadership" && settings["excluderare"]) {
  1044.                     // Avoid rare tasks unless profession is Leadership
  1045.                     console.log("Avoiding rare craft: ", taskname);
  1046.                 }
  1047.                 else if($(taskTitle[i]).closest("div.higherlevel").length) {
  1048.                     // Too high level
  1049.                     console.log("Task level is too high: ", taskname);
  1050.                 }
  1051.                 else if(tasklevel > 0 && $(taskTitle[i]).closest("div").find("span.level-pip").text() != tasklevel) {
  1052.                     // Task level doesn't match
  1053.                     console.log("Task level does not match requirement: ", taskname, tasklevel);
  1054.                 }
  1055.                 else if($(taskTitle[i]).closest("div.unmet").length) {
  1056.                     // Check for required ingredients
  1057.                     console.log("Checking for craftable ingredients for", taskname);
  1058.                     var requires = $(taskTitle[i]).closest("div.unmet").find("div.task-requirements div.icon-slot.red").filter("[data-tt-item]");
  1059.                     for (var j = 0; j < requires.length; j++) {
  1060.                         var ingName = $(requires[j]).attr("data-tt-item");
  1061.                         console.log("Found", ingName);
  1062.                         var searchStr = ingName;
  1063.        
  1064.                         // Specify task search string depending on type of ingredient required
  1065.                         // Add here any ingredient types you want to check tasks for
  1066.                        
  1067.                         // Resources
  1068.                         if     (ingName.indexOf("Resource_Charcoal")         > -1
  1069.                              || ingName.indexOf("Resource_Rocksalt")         > -1
  1070.                              || ingName.indexOf("Resource_Spool_Thread")     > -1
  1071.                              || ingName.indexOf("Resource_Porridge")         > -1
  1072.                              || ingName.indexOf("Resource_Solvent")          > -1
  1073.                              || ingName.indexOf("Resource_Brimstone")        > -1
  1074.                              || ingName.indexOf("Resource_Coal")             > -1
  1075.                              || ingName.indexOf("Resource_Moonseasalt")      > -1
  1076.                              || ingName.indexOf("Resource_Quicksilver")      > -1
  1077.                              || ingName.indexOf("Resource_Spool_Threadsilk") > -1) {
  1078.                             if (settings["autopurchase"]) {
  1079.                                 BuyResource(ingName);
  1080.                                 return null;
  1081.                             }
  1082.                             else {
  1083.                                 console.log("Auto resource purchasing disabled");
  1084.                                 continue;
  1085.                             }
  1086.                         }
  1087.  
  1088.                         // Enable this to use mass gathering / crafting above level 14 only (for levelling)
  1089.                         else if(
  1090.                              (ingName.indexOf("Resource_Pelt")             > -1
  1091.                              || ingName.indexOf("Resource_Wood")             > -1
  1092.                              || ingName.indexOf("Resource_Ore")              > -1
  1093.                              || ingName.indexOf("Resource_Clothscraps")      > -1)
  1094.                              && ( profLevel < 14 || profName == "Alchemy" ) ) { searchStr = "Gather"; }
  1095.                         else if(
  1096.                              (ingName.indexOf("Resource_Pelt")             > -1
  1097.                              || ingName.indexOf("Resource_Wood")             > -1
  1098.                              || ingName.indexOf("Resource_Ore")              > -1)
  1099.                              && profLevel >= 14 ) { searchStr = "Deep Wilderness Gathering"; }
  1100.                         else if( ingName.indexOf("Resource_Clothscraps")      > -1
  1101.                              && profLevel >= 14 ) { searchStr = "Intensive Scrap Gathering"; }
  1102.                         else if(
  1103.                              (ingName.indexOf("Resource_Wood_Carved")      > -1
  1104.                              || ingName.indexOf("Resource_Ornaments")        > -1
  1105.                              || ingName.indexOf("Resource_Weapon")           > -1)
  1106.                              && profLevel < 14 ) { searchStr = "Craft"; }
  1107.                         else if(
  1108.                              (ingName.indexOf("Resource_Wood_Carved")      > -1
  1109.                              || ingName.indexOf("Resource_Ornaments")        > -1
  1110.                              || ingName.indexOf("Resource_Weapon")           > -1)
  1111.                              && profLevel >= 14 ) { searchStr = "Mass Craft"; }
  1112.                         else if(ingName.indexOf("Resource_Leather")          > -1
  1113.                              && profLevel < 14 ) { searchStr = "Cure Pelt"; }
  1114.                         else if(ingName.indexOf("Resource_Leather")          > -1
  1115.                              && profLevel >= 14 ) { searchStr = "Mass Curing"; }
  1116.                         else if(ingName.indexOf("Resource_Rings")            > -1
  1117.                              && profLevel < 14 ) { searchStr = "Forge Ring"; }
  1118.                         else if(ingName.indexOf("Resource_Rings")            > -1
  1119.                              && profLevel >= 14 ) { searchStr = "Mass Ring Forging"; }
  1120.                         else if(ingName.indexOf("Resource_Clothbolt")        > -1
  1121.                              && profLevel < 14 ) { searchStr = "Weave Cloth"; }
  1122.                         else if(ingName.indexOf("Resource_Clothbolt")        > -1
  1123.                              && profLevel >= 14 ) { searchStr = "Mass Weaving"; }
  1124.                         else if(ingName.indexOf("Resource_Ingot")            > -1
  1125.                              && profLevel < 14 ) { searchStr = "Forge Plate"; }
  1126.                         else if(ingName.indexOf("Resource_Ingot")            > -1
  1127.                              && profLevel >= 14 ) { searchStr = "Mass Plate Forging"; }
  1128.  
  1129.                         // Enable this to always gather/craft using mass methods (don't know why)
  1130.                         // else if(ingName.indexOf("Resource_Wood_Carved")      > -1
  1131.                              // || ingName.indexOf("Resource_Ornaments")        > -1
  1132.                              // || ingName.indexOf("Resource_Weapon")           > -1) { searchStr = "Mass Craft"; }
  1133.                         // else if(ingName.indexOf("Resource_Pelt")             > -1
  1134.                              // || ingName.indexOf("Resource_Wood")             > -1
  1135.                              // || ingName.indexOf("Resource_Ore")              > -1) { searchStr = "Deep Wilderness Gathering"; }
  1136.                         // else if(ingName.indexOf("Resource_Clothscraps")      > -1) { searchStr = "Intensive Scrap Gathering"; }
  1137.                         // else if(ingName.indexOf("Resource_Leather")          > -1) { searchStr = "Mass Curing"; }
  1138.                         // else if(ingName.indexOf("Resource_Rings")            > -1) { searchStr = "Mass Ring Forging"; }
  1139.                         // else if(ingName.indexOf("Resource_Clothbolt")        > -1) { searchStr = "Mass Weaving"; }
  1140.                         // else if(ingName.indexOf("Resource_Ingot")            > -1) { searchStr = "Mass Plate Forging"; }
  1141.  
  1142.                         // Enable this to always gather/craft using non-mass methods (when making items)
  1143.                         // else if(ingName.indexOf("Resource_Wood_Carved")      > -1
  1144.                              // || ingName.indexOf("Resource_Ornaments")        > -1
  1145.                              // || ingName.indexOf("Resource_Weapon")           > -1) { searchStr = "Craft"; }
  1146.                         // else if(ingName.indexOf("Resource_Pelt")             > -1
  1147.                              // || ingName.indexOf("Resource_Wood")             > -1
  1148.                              // || ingName.indexOf("Resource_Ore")              > -1
  1149.                              // || ingName.indexOf("Resource_Clothscraps")      > -1) { searchStr = "Gather"; }
  1150.                         // else if(ingName.indexOf("Resource_Leather")          > -1) { searchStr = "Cure Pelt"; }
  1151.                         // else if(ingName.indexOf("Resource_Rings")            > -1) { searchStr = "Forge Ring"; }
  1152.                         // else if(ingName.indexOf("Resource_Clothbolt")        > -1) { searchStr = "Weave Cloth"; }
  1153.                         // else if(ingName.indexOf("Resource_Ingot")            > -1) { searchStr = "Forge Plate"; }
  1154.                        
  1155.                         // Alchemy
  1156.                         else if(ingName.indexOf("Aquavitae")                 > -1) { searchStr = "Aqua Vitae"; }
  1157.                         else if(ingName.indexOf("Aquaregia")                 > -1) { searchStr = "Aqua Regia"; }
  1158.                         else if(ingName.indexOf("Vitriol")                   > -1) { searchStr = "Vitriol Extraction"; }
  1159.                         else if(ingName.indexOf("Potion")                    > -1) { searchStr = ingName.replace(/Potion_/,"").replace(/_[0-9]+$/,""); }
  1160.                        
  1161.                         // Shirts
  1162.                         else if(ingName.indexOf("Chain_Shirt")               > -1) { searchStr = "Chain Shirt"; }
  1163.                         else if(ingName.indexOf("Scale_Shirt")               > -1
  1164.                              || ingName.indexOf("Med_Armorsmithing_Shirt")   > -1) { searchStr = "Scale Shirt"; }
  1165.                         else if(ingName.indexOf("Shirt")                     > -1) { searchStr = "Shirt"; }
  1166.                        
  1167.                         // Pants
  1168.                         else if(ingName.indexOf("Chain_Pants")               > -1) { searchStr = "Chain Pants"; }
  1169.                         else if(ingName.indexOf("Scale_Pants")               > -1
  1170.                              || ingName.indexOf("Med_Armorsmithing_Pants")   > -1) { searchStr = "Scale Pants"; }
  1171.                         else if(ingName.indexOf("Pants")                     > -1) { searchStr = "Pants"; }
  1172.  
  1173.                         // Armor
  1174.                         else if(ingName.indexOf("T1_Chain_Armor")            > -1) { searchStr = "Skip Me"; }
  1175.                         else if(ingName.indexOf("T2_Chain_Armor")            > -1) { searchStr = "Skip Me"; }
  1176.                         else if(ingName.indexOf("Chain_Armor")               > -1) { searchStr = "Chain Armor"; }
  1177.                         else if(ingName.indexOf("T1_Scale_Armor")            > -1) { searchStr = "Skip Me"; }
  1178.                         else if(ingName.indexOf("T2_Scale_Armor")            > -1) { searchStr = "Skip Me"; }
  1179.                         else if(ingName.indexOf("Scale_Armor")               > -1) { searchStr = "Scale Armor"; }
  1180.                         else if(ingName.indexOf("T1_Cloth_Armor")            > -1) { searchStr = "Skip Me"; }
  1181.                         else if(ingName.indexOf("T2_Cloth_Armor")            > -1) { searchStr = "Skip Me"; }
  1182.                         else if(ingName.indexOf("Cloth_Armor")               > -1) { searchStr = "Cloth Robes"; }
  1183.                         else if(ingName.indexOf("T1_Leather_Armor")          > -1) { searchStr = "Skip Me"; }
  1184.                         else if(ingName.indexOf("T2_Leather_Armor")          > -1) { searchStr = "Skip Me"; }
  1185.                         else if(ingName.indexOf("Leather_Armor")             > -1) { searchStr = "Leather Armor"; }
  1186.                         else if(ingName.indexOf("T1_Plate_Armor")            > -1) { searchStr = "Skip Me"; }
  1187.                         else if(ingName.indexOf("T2_Plate_Armor")            > -1) { searchStr = "Skip Me"; }
  1188.                         else if(ingName.indexOf("Plate_Armor")               > -1) { searchStr = "Plate Armor"; }
  1189.  
  1190.                         // Helms
  1191.                         else if(ingName.indexOf("Chain_Helm")                > -1) { searchStr = "Chain Helm"; }
  1192.                         else if(ingName.indexOf("Med_Armorsmithing_T2_Helm") > -1) { searchStr = "Scale Helm"; }
  1193.                         else if(ingName.indexOf("Tailoring_T2_Helm")         > -1) { searchStr = "Cloth Cap"; }
  1194.                         else if(ingName.indexOf("Helm")                      > -1) { searchStr = "Helm"; }
  1195.  
  1196.                         // Arms
  1197.                         else if(ingName.indexOf("T1_Chain_Gloves")           > -1) { searchStr = "Chain Gloves +1"; }
  1198.                         else if(ingName.indexOf("T2_Chain_Gloves")           > -1) { searchStr = "Chain Gloves +2"; }
  1199.                         else if(ingName.indexOf("Chain_Gloves")              > -1) { searchStr = "Chain Gloves"; }
  1200.                         else if(ingName.indexOf("T1_Scale_Gloves")           > -1) { searchStr = "Scale Gauntlets +1"; }
  1201.                         else if(ingName.indexOf("T2_Scale_Gloves")           > -1) { searchStr = "Scale Gauntlets +2"; }
  1202.                         else if(ingName.indexOf("Scale_Gloves")              > -1) { searchStr = "Scale Gauntlets"; }
  1203.                         else if(ingName.indexOf("T1_Cloth_Gloves")           > -1) { searchStr = "Cloth Sleeves +1"; }
  1204.                         else if(ingName.indexOf("T2_Cloth_Gloves")           > -1) { searchStr = "Cloth Sleeves +2"; }
  1205.                         else if(ingName.indexOf("Cloth_Gloves")              > -1) { searchStr = "Cloth Sleeves"; }
  1206.                         else if(ingName.indexOf("T1_Leather_Gloves")         > -1) { searchStr = "Leather Gloves +1"; }
  1207.                         else if(ingName.indexOf("T2_Leather_Gloves")         > -1) { searchStr = "Leather Bracers +2"; }
  1208.                         else if(ingName.indexOf("Leather_Gloves")            > -1) { searchStr = "Leather Bracers"; }
  1209.                         else if(ingName.indexOf("T1_Plate_Gloves")           > -1) { searchStr = "Plate Gauntlets +1"; }
  1210.                         else if(ingName.indexOf("T2_Plate_Gloves")           > -1) { searchStr = "Plate Gauntlets +2"; }
  1211.                         else if(ingName.indexOf("Plate_Gloves")              > -1) { searchStr = "Plate Gauntlets"; }
  1212.  
  1213.                         // Boots
  1214.                         else if(ingName.indexOf("T1_Chain_Boots")            > -1) { searchStr = "Chain Boots +1"; }
  1215.                         else if(ingName.indexOf("T2_Chain_Boots")            > -1) { searchStr = "Chain Boots +2"; }
  1216.                         else if(ingName.indexOf("Chain_Boots")               > -1) { searchStr = "Chain Boots"; }
  1217.                         else if(ingName.indexOf("T1_Scale_Boots")            > -1) { searchStr = "Scale Boots +1"; }
  1218.                         else if(ingName.indexOf("T2_Scale_Boots")            > -1) { searchStr = "Scale Boots +2"; }
  1219.                         else if(ingName.indexOf("Scale_Boots")               > -1) { searchStr = "Scale Boots"; }
  1220.                         else if(ingName.indexOf("T1_Cloth_Boots")            > -1) { searchStr = "Cloth Boots +1"; }
  1221.                         else if(ingName.indexOf("T2_Cloth_Boots")            > -1) { searchStr = "Cloth Boots +2"; }
  1222.                         else if(ingName.indexOf("Cloth_Boots")               > -1) { searchStr = "Cloth Boots"; }
  1223.                         else if(ingName.indexOf("T1_Leather_Boots")          > -1) { searchStr = "Leather Boots +1"; }
  1224.                         else if(ingName.indexOf("T2_Leather_Boots")          > -1) { searchStr = "Leather Boots +2"; }
  1225.                         else if(ingName.indexOf("Leather_Boots")             > -1) { searchStr = "Leather Boots"; }
  1226.                         else if(ingName.indexOf("T1_Plate_Boots")            > -1) { searchStr = "Plate Boots +1"; }
  1227.                         else if(ingName.indexOf("T2_Plate_Boots")            > -1) { searchStr = "Plate Boots +2"; }
  1228.                         else if(ingName.indexOf("Plate_Boots")               > -1) { searchStr = "Plate Boots"; }
  1229.  
  1230.                         // Daggers
  1231.                         else if(ingName.indexOf("T2_Dagger_3")               > -1) { searchStr = "Dagger +3"; }
  1232.                         else if(ingName.indexOf("T2_Dagger_2")               > -1) { searchStr = "Dagger +2"; }
  1233.                         else if(ingName.indexOf("T1_Dagger_1")               > -1) { searchStr = "Dagger +1"; }
  1234.  
  1235.                         // Icons
  1236.                         else if(ingName.indexOf("T3_Icon_Virtuous_4")        > -1) { searchStr = "Virtuous Icon +4"; }
  1237.                         else if(ingName.indexOf("T2_Icon_Virtuous_3")        > -1) { searchStr = "Virtuous Icon +3"; }
  1238.                         else if(ingName.indexOf("T1_Icon_Virtuous_2")        > -1) { searchStr = "Virtuous Icon +2"; }
  1239.                         else if(ingName.indexOf("T1_Icon_Virtuous_1")        > -1) { searchStr = "Virtuous Icon +1"; }
  1240.  
  1241.                         // Shields
  1242.                         else if(ingName.indexOf("T2_Shield")                 > -1) { searchStr = "Steel Shield"; }
  1243.                         else if(ingName.indexOf("T1_Shield")                 > -1) { searchStr = "Iron Shield"; }
  1244.            
  1245.                         else {
  1246.                             console.log("Found unhandled ingredient", ingName);
  1247.                             continue;
  1248.                         }
  1249.        
  1250.                         console.log("Searching for tasks for:", searchStr);
  1251.                         filterDiv.val(searchStr);
  1252.                         filterDiv.keyup();
  1253.                         // Find the ingredient task
  1254.                         var ingTaskIcon = $("table#tasklist div.task-rewards div.icon-slot").filter(function() {
  1255.                             return $(this).attr("data-tt-item") === ingName;
  1256.                         });
  1257.        
  1258.                         // Check ingredient task for requirements and return task if valid
  1259.                         if (ingTaskIcon.length) {
  1260.                             for (var k = 0; k < ingTaskIcon.length; k++) {
  1261.                                 var ingTitle = $($(ingTaskIcon[k]).closest("div.task-list-entry").find("h4 span")).text();
  1262.                                
  1263.                                 console.log("Found ingredient task",ingTitle);
  1264.  
  1265.                                 // Enable this section to skip mass production tasks only when optimal for levelling
  1266.                                 // (Profession level below 14, for Artificing gather below 7, and always for Alchemy)
  1267.                                 if( ingTitle.indexOf("Deep ") == 0 && ( profLevel < 14 || profName == "Alchemy" || ( profLevel < 7 && profName == "Artificing" ) ) ) { continue; }
  1268.                                 if( ingTitle.indexOf("Mass ") == 0 && ( profLevel < 14 || profName == "Alchemy" ) ) { continue; }
  1269.                                 if( ingTitle.indexOf("Intensive ") == 0 && profLevel < 14 ) { continue; }
  1270.  
  1271.                                 // Enable this to skip mass production tasks (when focused on making items)
  1272.                                 // if(ingTitle.indexOf("Mass ") == 0) { continue; }
  1273.                                 // if(ingTitle.indexOf("Deep ") == 0) { continue; }
  1274.                                 // if(ingTitle.indexOf("Intensive ") == 0) { continue; }
  1275.  
  1276.                                 // Alchemy Fixes:
  1277.                                 // Skip Batch gathering tasks
  1278.                                 if(ingTitle.indexOf("Batch ") == 0) { continue; }
  1279.                                 // Skip Empowered gathering tasks if level is too low
  1280.                                 if(profLevel<8){
  1281.                                     if(ingTitle.indexOf("Empowered ") == 0) { continue; }
  1282.                                 }
  1283.  
  1284.                                 // Search for correct level task for same named Artificing gather tasks
  1285.                                 if(ingTitle.indexOf("Gather Ore and Wood") > -1 || ingTitle.indexOf("Craft Ornamental metal and Carved Wood") > -1) {
  1286.                                     if     (ingName.indexOf("_T1") > -1) { ingTitle = "1:" + ingTitle }
  1287.                                     else if(ingName.indexOf("_T2") > -1) { ingTitle = "7:" + ingTitle }
  1288.                                     else if(ingName.indexOf("_T3") > -1) { ingTitle = "14:" + ingTitle }
  1289.                                 }
  1290.                                
  1291.                                 var ingTask = SearchForTaskByName(ingTitle, profName, profLevel);
  1292.                                 console.log("Requesting required ingredient task", ingTitle);
  1293.                                 return ingTask;
  1294.                             }
  1295.                         }
  1296.                         else { console.log("No ingredient tasks available:", taskname); }
  1297.                     }
  1298.                    
  1299.                     // Not enough resources
  1300.                     console.log("Not enough resources:", taskname);
  1301.                 }
  1302.                 else {
  1303.                     return $(taskTitle[i]).closest("tr").find("button");
  1304.                 }
  1305.             }
  1306.             console.log("No valid tasks found:", taskname);
  1307.         }
  1308.         return false;
  1309.     }
  1310.    
  1311.     /**
  1312.      * Will buy a given purchasable resource
  1313.      *
  1314.      * @param {String} item The data-tt-item id of the Resource to purchase
  1315.      */
  1316.     function BuyResource(item) {
  1317.         console.log("Purchasing resources:", item);
  1318.         // Switch to overview
  1319.         $("a.professions-overview").click();
  1320.         WaitForState("").done(function() {
  1321.             // Enter resource shop
  1322.             $("button").filter(function() { return $(this).attr("data-url") === "/professions/vendor"; }).click();
  1323.             WaitForState("ul.vendor-group.resources li.vendor-entry div").done(function() {
  1324.                 // Get shop section for required item
  1325.                 var shopItem = $("ul.vendor-group.resources li.vendor-entry div").filter(function() {
  1326.                     return $(this).attr("data-tt-item") === item;
  1327.                 }).closest("li");
  1328.                 shopItem.find("button").click();
  1329.                 WaitForState("input[name='inventoryBuyQty']").done(function() {
  1330.                     // Set purchase amount to 20 and buy
  1331.                     $("input[name='inventoryBuyQty']").val(20);
  1332.                     $("button:contains('OK')").click();
  1333.                     console.log("Resources purchased");
  1334.                     // Close the notification that never times out
  1335.                     WaitForState("button.closeNotification").done(function() {
  1336.                         $("button.closeNotification").click();
  1337.                     });
  1338.                 });
  1339.             });
  1340.         });
  1341.     }
  1342.    
  1343.     /**
  1344.      * Waits for the loading symbol to be hidden.
  1345.      *
  1346.      * @return {Deferred} A jQuery defferred object that will be resolved when loading is complete
  1347.      */
  1348.     function WaitForLoad() {
  1349.         return WaitForState("");
  1350.     }
  1351.     /**
  1352.      * Creates a deferred object that will be resolved when the state is reached
  1353.      *
  1354.      * @param {string} query The query for the state to wait for
  1355.      * @return {Deferred} A jQuery defferred object that will be resolved when the state is reached
  1356.      */
  1357.     function WaitForState(query) {
  1358.         var dfd = $.Deferred();
  1359.         window.setTimeout(function() {AttemptResolve(query, dfd);}, delayShort); // Doesn't work without a short delay
  1360.         return dfd;
  1361.     }
  1362.     /**
  1363.      * Will continually test for the given query state and resolve the given deferred object when the state is reached
  1364.      * and the loading symbol is not visible
  1365.      *
  1366.      * @param {string} query The query for the state to wait for
  1367.      * @param {Deferred} dfd The jQuery defferred object that will be resolved when the state is reached
  1368.      */
  1369.     function AttemptResolve(query, dfd) {
  1370.         if((query === "" || $(query).length) && $("div.loading-image:visible").length == 0) {
  1371.             dfd.resolve();
  1372.         }
  1373.         else {
  1374.             window.setTimeout(function() {AttemptResolve(query, dfd);}, delayShort); // Try again in a little bit
  1375.         }
  1376.     }
  1377.  
  1378.     function CharPage() {
  1379.         console.log("Changing to character selection page");
  1380.         unsafeWindow.location.href = "http://gateway.playneverwinter.com/#/characterselect";
  1381.         switchCharacter = false;
  1382.         timerSwitchHandle = 0;
  1383.         timerHandle = window.setTimeout(function() {process();}, delay);
  1384.     }
  1385.      
  1386.  
  1387.     /**
  1388.      * The main process loop:
  1389.      * - Determine which page we are on and call the page specific logic
  1390.      * - When processing is complete, process again later
  1391.      *   - Use a short timer when something changed last time through
  1392.      *   - Use a longer timer when waiting for tasks to complete
  1393.      */
  1394.     function process() {
  1395.         // Make sure the settings button exists
  1396.         addSettings();
  1397.  
  1398.         // Check if timer is paused
  1399.         if(settings["paused"]) {
  1400.             // Just continue later - the deferred object is still set and nothing will resolve it until we get past this point
  1401.             var timerHandle = window.setTimeout(function() {process();}, delay);
  1402.             return;
  1403.         }
  1404.         if(switchCharacter) {
  1405.             CharPage();
  1406.             return;
  1407.         }
  1408.  
  1409.  
  1410.         // check for errors
  1411.         if($("title").text() == "Error" && settings["autologin"]) {
  1412.             console.log("Error detected - relogging");
  1413.             unsafeWindow.location.href = "http://gateway.playneverwinter.com";
  1414.             return;
  1415.         }
  1416.  
  1417.         // Check if a reload is needed
  1418.         if(reloadNeeded && settings["autologin"] && settings["autoreload"]) {
  1419.             console.log("Reloading Gateway");
  1420.             unsafeWindow.location.href = "http://gateway.playneverwinter.com";
  1421.             reloadNeeded = false;
  1422.             return;
  1423.         }
  1424.  
  1425.         // Check for Gateway down
  1426.         if(window.location.href.indexOf("gatewaysitedown") > -1) {
  1427.             // Do a long delay and then retry the site
  1428.             var minuty = (longDelay-longDelay%60000)/60000;
  1429.             var sekundy = (longDelay%60000)/1000;
  1430.             console.log("Gateway down detected - relogging in " + (minuty>0?(sekundy>0?minuty + " minute(s) and " + sekundy + " second(s)":minuty + " minute(s)"):sekundy + " second(s)"));
  1431.             window.setTimeout(function() {unsafeWindow.location.href = "http://gateway.playneverwinter.com";}, longDelay);
  1432.             return;
  1433.         }
  1434.  
  1435.         // Determine which page is displaying
  1436.         var currentPage = GetCurrentPage();
  1437.              if(currentPage == PAGES.LOGIN)       { page_LOGIN();       }
  1438.         else if(currentPage == PAGES.GUARD)       { page_GUARD();       }
  1439.         else if(currentPage == PAGES.CHARSELECT)  { page_CHARSELECT();  }
  1440.         else if(currentPage == PAGES.FRONTPAGE)   { page_FRONTPAGE();   }
  1441.         else if(currentPage == PAGES.INVENTORY)   { page_INVENTORY();   }
  1442.         else if(currentPage == PAGES.PROFESSIONS) { page_PROFESSIONS(); }
  1443.         else                                      { page_DEFAULT();     }
  1444.  
  1445.         // Continue again later
  1446.         dfdNextRun.done(function(useShortDelay, charChangeDelay) {
  1447.             dfdNextRun = $.Deferred();
  1448.             if(charChangeDelay) {
  1449.                 var minuty = (loopDelay-loopDelay%60000)/60000;
  1450.                 var sekundy = (loopDelay%60000)/1000;
  1451.                 console.log("Script will change characters in " + (minuty>0?(sekundy>0?minuty + " minute(s) and " + sekundy + " second(s)":minuty + " minute(s)"):sekundy + " second(s)"));
  1452.                 timerSwitchHandle = window.setTimeout(function() {switchCharacter = true;}, loopDelay);
  1453.             }
  1454.             if(!reloadTimerHandle) {
  1455.                 reloadTimerHandle = window.setTimeout(function() { reloadNeeded = true; }, reloadDelay);
  1456.             }
  1457.             timerHandle = window.setTimeout(function() {process();}, useShortDelay===true?delayShort:delay);
  1458.         });
  1459.     }
  1460.  
  1461.     function addSettings() {
  1462.         if($("#settingsButton").length)
  1463.             return;
  1464.         // Add the required CSS
  1465.         AddCss("\
  1466.            #settingsButton{border-bottom: 1px solid rgb(102, 102, 102); border-right: 1px solid rgb(102, 102, 102); background: none repeat scroll 0% 0% rgb(238, 238, 238); display: block; position: fixed; overflow: auto; right: 0px; top: 0px; padding: 3px; z-index: 1000;}\
  1467.            #pauseButton{border-bottom: 1px solid rgb(102, 102, 102); border-right: 1px solid rgb(102, 102, 102); background: none repeat scroll 0% 0% rgb(238, 238, 238); display: block; position: fixed; overflow: auto; right: 23px; top: 0px; padding: 3px; z-index: 1000;}\
  1468.            #settingsPanel{border-bottom: 1px solid rgb(102, 102, 102); border-right: 1px solid rgb(102, 102, 102); background: none repeat scroll 0% 0% rgb(238, 238, 238); color: rgb(0, 0, 0); position: fixed; overflow: auto; right: 0px; top: 0px; width: 360px; font: 12px sans-serif; text-align: left; display: block; z-index: 1000;}\
  1469.            #settings_title{font-weight: bolder; background: none repeat scroll 0% 0% rgb(204, 204, 204); border-bottom: 1px solid rgb(102, 102, 102); padding: 3px;}\
  1470.            #settingsPanelButtonContainer {background: none repeat scroll 0% 0% rgb(204, 204, 204); border-top: 1px solid rgb(102, 102, 102);padding: 3px;text-align:center} \
  1471.            #settingsPanel label.purple {font-weight:bold;color:#7C37F6}\
  1472.            #settingsPanel label.blue {font-weight:bold;color:#007EFF}\
  1473.            #settingsPanel label.green {font-weight:bold;color:#8AFF00}\
  1474.            #settingsPanel label.white {font-weight:bold;color:#FFFFFF}\
  1475.        ");
  1476.  
  1477.         // Add settings panel to page body
  1478.         $("body").append(
  1479.             '<div id="settingsPanel">\
  1480.                <div id="settings_title">\
  1481.                    <img src='+image_prefs+' style="float: left; vertical-align: text-bottom;"\>\
  1482.                    <img id="settings_close" src='+image_close+' title="Click to hide preferences" style="float: right; vertical-align: text-bottom; cursor: pointer; display: block;"\>\
  1483.                    <span style="margin:3px">Settings</span>\
  1484.                </div>\
  1485.                <form style="margin: 0px; padding: 0px">\
  1486.                    <ul style="list-style: none outside none; max-height: 800px; overflow: auto; margin: 3px; padding: 0px;">\
  1487.                    </ul>\
  1488.                </form>\
  1489.            </div>'
  1490.         );
  1491.  
  1492.         // Add each setting input
  1493.         var settingsList = $("#settingsPanel form ul");
  1494.         for (var i=0;i<settingnames.length;i++) {
  1495.             var id = 'settings_' + settingnames[i].name;
  1496.             var indent = countLeadingSpaces(settingnames[i].title) * 2;
  1497.             switch(settingnames[i].type) {
  1498.                 case "checkbox":
  1499.                     settingsList.append('<li title="'+settingnames[i].tooltip+'" style="margin-left:'+indent+'em"><input style="margin:4px" name="'+id+'" id="'+id+'" type="checkbox" /><label class="'+settingnames[i].class+'" for="'+id+'">'+settingnames[i].title+'</label></li>')
  1500.                     $('#'+id).prop('checked', settings[settingnames[i].name]);
  1501.                     break;
  1502.                 case "text1":
  1503.                     appendingus = '<li style="margin-left:'+indent+'em">';
  1504.                     appendingus = appendingus + '<input title="'+settingnames[i].tooltip+'" style="margin:4px; width:120px" name="'+id+'" id="'+id+'" type="text" />';
  1505.                     for(var j = 1; j <= 8; ++j)
  1506.                         {  
  1507.                             var id2 = 'settings_' + settingnames[i+j].name;
  1508.                             appendingus = appendingus + '<input title="'+settingnames[i+j].tooltip+'" style="margin:4px; width:15px" name="'+id2+'" id="'+id2+'" type="text" />';
  1509.                         }
  1510.                     appendingus = appendingus + '</li>';
  1511.                     settingsList.append(appendingus)
  1512.                     for(var j = 0; j <= 9; ++j)
  1513.                         {  
  1514.                             var id2 = 'settings_' + settingnames[i+j].name;
  1515.                             $('#'+id2).val(settings[settingnames[i+j].name]);
  1516.                         }
  1517.                     break;
  1518.                 case "text":
  1519.                     settingsList.append('<li title="'+settingnames[i].tooltip+'" style="margin-left:'+indent+'em"><label class="'+settingnames[i].class+'" for="'+id+'">'+settingnames[i].title+'</label><input style="margin:4px" name="'+id+'" id="'+id+'" type="text" /></li>')
  1520.                     $('#'+id).val(settings[settingnames[i].name]);
  1521.                     break;
  1522.                 case "text4":
  1523.                     settingsList.append('<li title="'+settingnames[i].tooltip+'" style="margin-left:'+indent+'em"><label class="'+settingnames[i].class+'" for="'+id+'">'+settingnames[i].title+'</label><input style="margin:4px; width:20px" name="'+id+'" id="'+id+'" type="text" disabled /></li>')
  1524.                     $('#'+id).val(settings[settingnames[i].name]);
  1525.                     break;
  1526.                 case "charcount":
  1527.                     settingsList.append('<li style="margin-left:'+indent+'em"><label title="'+settingnames[i].tooltip+'" class="'+settingnames[i].class+'" for="'+id+'">'+settingnames[i].title+'</label><input title="'+settingnames[i].tooltip+'" style="margin:4px; width:22px" name="'+id+'" id="'+id+'" type="text" /></li>')
  1528.                     $('#'+id).val(settings[settingnames[i].name]);
  1529.                     var id2 = 'settings_' + settingnames[i+1].name;
  1530.                     settingsList.append('<li style="margin-left:'+indent+'em"><label title="'+settingnames[i+1].tooltip+'" class="'+settingnames[i+1].class+'" for="'+id2+'">'+settingnames[i+1].title+'</label><input title="'+settingnames[i+1].tooltip+'" style="margin:4px; width:40px" name="'+id2+'" id="'+id2+'" type="text" /></li>')
  1531.                     $('#'+id2).val(settings[settingnames[i+1].name]);
  1532.                     break;
  1533.                 case "password":
  1534.                     settingsList.append('<li title="'+settingnames[i].tooltip+'" style="margin-left:'+indent+'em"><label class="'+settingnames[i].class+'" for="'+id+'">'+settingnames[i].title+'</label><input style="margin:4px" name="'+id+'" id="'+id+'" type="password" /></li>')
  1535.                     $('#'+id).val(settings[settingnames[i].name]);
  1536.                     break;
  1537.                 case "select":
  1538.                     settingsList.append('<li title="'+settingnames[i].tooltip+'" style="margin-left:'+indent+'em"><label class="'+settingnames[i].class+'" style="padding-left:4px" for="'+id+'">'+settingnames[i].title+'</label><select style="margin:4px" name="'+id+'" id="'+id+'" /></li>')
  1539.                     var options = settingnames[i].opts;
  1540.                     var select = $('#'+id);
  1541.                     for(var j=0;j<options.length;j++) {
  1542.                         if(settings[settingnames[i].name] == options[j].path)
  1543.                             select.append('<option value="'+options[j].path+'" selected="selected">'+options[j].name+'</option>');
  1544.                         else
  1545.                             select.append('<option value="'+options[j].path+'">'+options[j].name+'</option>');
  1546.                     }
  1547.                     break;
  1548.                 case "label":
  1549.                     settingsList.append('<li title="'+settingnames[i].tooltip+'" style="margin-left:'+indent+'em;><label class="'+settingnames[i].class+'">'+settingnames[i].title+'</label></li>')
  1550.                     break;
  1551.             }
  1552.         }
  1553.         // Add save/cancel buttons to panel
  1554.         $("#settingsPanel form").append('\
  1555.            <div id="settingsPanelButtonContainer">\
  1556.                <input id="settings_save" type="button" value="Save and Apply">\
  1557.                <input id="settings_close" type="button" value="Close">\
  1558.            </div>');
  1559.  
  1560.         // Add open settings button to page
  1561.         $("body").append('<div id="settingsButton"><img src="'+image_prefs+'" title="Click to show preferences" style="cursor: pointer; display: block;"></div>');
  1562.  
  1563.         // Add pause button to page
  1564.         $("body").append('<div id="pauseButton"><img src="'+(settings["paused"]?image_play:image_pause)+'" title="Click to '+(settings["paused"]?"resume":"pause")+' task script" style="cursor: pointer; display: block;"></div>');
  1565.  
  1566.         // Add the javascript
  1567.         $("#settingsPanel").hide();
  1568.         $("#settingsButton").click(function() {
  1569.             $("#settingsButton").hide();
  1570.             $("#pauseButton").hide();
  1571.             $("#settingsPanel").show();
  1572.         });
  1573.         $("#settings_close,settings_cancel").click(function() {
  1574.             $("#settingsButton").show();
  1575.             $("#pauseButton").show();
  1576.             $("#settingsPanel").hide();
  1577.         });
  1578.          $("#pauseButton").click(function() {
  1579.             settings["paused"] = !settings["paused"]
  1580.             GM_setValue("paused", settings["paused"]);
  1581.             $("#settings_paused").prop("checked", settings["paused"]);
  1582.             $("#pauseButton img").attr("src",(settings["paused"]?image_play:image_pause));
  1583.             $("#pauseButton img").attr("title","Click to "+(settings["paused"]?"resume":"pause")+" task script");
  1584.         });
  1585.  
  1586.         // Use setTimeout to workaround permission issues when calling GM functions from main window
  1587.         $("#settings_save").click(function() { setTimeout(function() { SaveSettings();}, 0)});
  1588.     }
  1589.  
  1590.     function SaveSettings() {
  1591.         // Get each value from the UI
  1592.         for (var i=0;i<settingnames.length;i++) {
  1593.             var name = settingnames[i].name;
  1594.             var el = $('#settings_' + name);
  1595.             var value = false;
  1596.             switch(settingnames[i].type) {
  1597.                 case "checkbox":
  1598.                     value = el.prop("checked");
  1599.                     break;
  1600.                 case "text":
  1601.                     value = el.val();
  1602.                     break;
  1603.                 case "text1":
  1604.                     value = el.val();
  1605.                     break;
  1606.                 case "text2":
  1607.                     value = el.val();
  1608.                     break;
  1609.                 case "text3":
  1610.                     value = el.val();
  1611.                     break;
  1612.                 case "text4":
  1613.                      continue;
  1614.                 case "charcount":
  1615.                     value = el.val();
  1616.                     break;
  1617.                 case "password":
  1618.                     value = el.val();
  1619.                     break;
  1620.                 case "select":
  1621.                     value = el.val();
  1622.                     break;
  1623.                 case "label": // Labels don't have values
  1624.                     continue;
  1625.             }
  1626.             if(typeof(settingnames[i].onsave) === "function") {
  1627.                 console.log("Calling 'onsave' for", name);
  1628.                 settingnames[i].onsave(value, settings[name]);
  1629.             }
  1630.             settings[name] = value; // Save to local cache
  1631.             GM_setValue(name, value); // Save to GM cache
  1632.         }
  1633.         // Close the panel
  1634.         $("#settingsButton").show();
  1635.         $("#pauseButton img").attr("src",(settings["paused"]?image_play:image_pause));
  1636.         $("#pauseButton img").attr("title","Click to "+(settings["paused"]?"resume":"pause")+" task script");
  1637.         $("#pauseButton").show();
  1638.         $("#settingsPanel").hide();
  1639.     }
  1640.  
  1641.     // Add the settings button and start a process timer
  1642.     addSettings();
  1643.     timerHandle = window.setTimeout(function() {process();}, delayShort);
  1644. })();
Advertisement
Add Comment
Please, Sign In to add comment