Neverwinter gateway - Professions Robot

Automatically selects professions for empty slots

目前为 2014-12-19 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Neverwinter gateway - Professions Robot
  3. // @description Automatically selects professions for empty slots
  4. // @namespace https://greasyfork.org/scripts/7061-neverwinter-gateway-professions-robot/
  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 NW Gateway Professions Bot Developers & Contributors
  15.  
  16. /* NW Gateway Professions Bot Developers & Contributors
  17.  
  18. NW Gateway Professions Bot Developers
  19. -----------------------------------
  20. Bluep, Numberb, mac-nw,
  21.  
  22. NW Gateway Professions Bot Contributors
  23. -----------------------------------
  24. Kakoura, Nametaken, rotten_mind,
  25. */
  26. // @version 1.05.0.1d
  27. // @license http://creativecommons.org/licenses/by-nc-sa/3.0/us/
  28. // @grant GM_getValue
  29. // @grant GM_setValue
  30. // @grant GM_listValues
  31. // @grant GM_deleteValue
  32. // ==/UserScript==
  33.  
  34. /* RELEASE NOTES
  35. 1.05.0.1d
  36. - WinterEvent tasks added
  37. - Added AD transfer automation
  38. - Settings Panel UI: Increased size and implemented two columns for options to minimize vertical length. Also implemented new radio and button styles.
  39. 1.05.0.1c
  40. - UI feature: Limit the gateway popup notification messages that appear at the top of the screen to a max of 2 notifications. The oldest (first) notification will always be removed when reaching the limit.
  41. 1.05.0.1b
  42. - Added Reward Chest Opening Option
  43. - Added All button when selling from inventory
  44. - Added condition check for profession slot input val > 0 when processing tasks
  45. 1.05.0.1 (v1, mod 5)
  46. - Started with bluep's edits (https://greasyfork.org/en/forum/discussion/270/x)
  47. - Edited back in leadership asset priority (https://greasyfork.org/en/forum/discussion/comment/7213/#Comment_7213)
  48. - Edited in Jewelcrafting for Mod5 (https://greasyfork.org/en/forum/discussion/comment/6930/#Comment_6930)
  49. - Modified the default leadership tasks to prioritize AD generation (feel free to rever)
  50. /* End Bunta's Edits?
  51. 1.0.0.3
  52. - Fix some gem trading tasks not being filtered correctly
  53. - Add check for gateway disconnected
  54. 1.0.0.2
  55. - Fix leadership tasks not creating assets correctly
  56. - Add option to save task lists per character (experimental)
  57. 1.0.0.1
  58. - Rewrite script using client.dataModel methods to massively improve reliability and performance (thanks Msc)
  59. - AD refining will now only attempt to refine if you are able to collect diamonds
  60. - Change task lists to use exact task names so no ambiguity exists (no longer requires excluderare option)
  61. - Asset resources are now trained as needed (only for required slots)
  62. 0.3.0.5
  63. - Fix resources not buying correctly in all cases
  64. - Fix pause button state saving correctly in firefox
  65. 0.3.0.4
  66. - Add page timeout reloading functions outside of main function (thanks Kreese and Frabtik)
  67. - Add check to ensure tasks are being started for the correct character
  68. - Alter next run resolve function to use delay parameter to allow for unique delay timers to be used in certain cases
  69. 0.3.0.3
  70. - Fix ingredient task selection to correctly iterate through all ingredient tasks
  71. - Alter character selection to pick only exact character name matches
  72. - Update leadership tasks
  73. 0.3.0.2
  74. - Exclude alchemy from rare task exclusions due to Aqua Regia (thanks Eversor)
  75. - Reduce GM_setValue calls to avoid tampermonkey failing to save settings (thanks miah)
  76. 0.3.0.1
  77. - Altered mutichar selector to be faster (thanks miah)
  78. - Updated rare tasks selector (thanks Traktor)
  79. - Add option to refine AD during character switching (thanks Eversor)
  80. - Added some level 20 gather tasks
  81. - Increased supply buying to 100 units
  82. 0.3.0.0
  83. - Added Multi-Character support
  84. - Added function to clear all saved settings for script
  85. - Remove disable sound functionality (now configurable in gateway)
  86. 0.2.0.1.8
  87. - Added pause button to allow easy on/off switching
  88. 0.2.0.1.7
  89. - Added option to enable/disable filling optional asset slots
  90. - Added batch potions tasks to be skipped in ingredient selection
  91. - Added timer to reload page if stuck loading for too long
  92. - Added option to disable page sounds
  93. - Updated license to by-nc-sa
  94. 0.2.0.1.6
  95. - Add configurable option for excluding rare tasks
  96. 0.2.0.1.5
  97. - Add ability to specify specific level for tasks and configure same named artificing resource tasks to request correct level of task
  98. - Remove purchase notification that never times out
  99. 0.2.0.1.4
  100. - Added functionality to purchase required resources from gateway shop
  101. 0.2.0.1.3
  102. - Add Artificing and Weaponsmithing to Robot
  103. (Artificing will not work properly yet as all three tiers of gather and craft tasks have the same task name)
  104. 0.2.0.1.2
  105. - Update reload process
  106. - Fix optional asset selector with gateway update
  107. 0.2.0.1.1
  108. - Simplify asset selection after they fixed bug in previous gateway update
  109. - Update level 20 leadership tasks
  110. - Update with changes in Mustex's script (version 15)
  111. * Added a secondary timer that will reload the gateway every few hours. This should help with disconnects from the server
  112. * Implemented tooltips for settings panel
  113. 0.1.9.1.15
  114. - Repeat task reordering for +2 armor
  115. 0.1.9.1.14
  116. - Fix selection of assets after gateway update
  117. - Skip intensive gather tasks added after gateway update
  118. 0.1.9.1.13
  119. - Change ordering of tasks and ingredient checks
  120. 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.
  121. 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.
  122. 0.1.9.1.12
  123. - Optimise crafting tasks for highest exp/min gains due to ingredient requirements
  124. 0.1.9.1.11
  125. - Add extra craft tasks for when residuum runs out
  126. 0.1.9.1.10
  127. - Only allow rare tasks to be selected for Leadership
  128. This avoids craft loops where higher quality rare crafts require ingredients with the same name
  129. 0.1.9.1.9
  130. - Alter craft tasks to favour armor to optimise inventory space
  131. 0.1.9.1.8
  132. - Fix script restart bug when no tasks found
  133. 0.1.9.1.7
  134. - Update search string for Potions (After the task names for elxiirs have been changed)
  135. - Remove logon error skips to avoid logons sometimes failing on first load (ensure logon details are correct!)
  136. 0.1.9.1.6
  137. - Update tasks for all professions
  138. - Update ingredient search lists for all professions
  139. 0.1.9.1.5
  140. - Fix regular expression used in potion ingredient search
  141. 0.1.9.1.4
  142. - Alter default timeouts (makes script a lot more stable and less prone to errors)
  143. - Remove unused variable
  144. - Add extra logging for task ingredient searches
  145. 0.1.9.1.3
  146. - Fix bug with required resource checks getting stuck on non craftable resources
  147. 0.1.9.1.2
  148. - Added method to check for required task ingredients and choose tasks to create them
  149. Method is currently hard coded to specify certain search strings for ingredient types
  150. Currently working for all Alchemy tasks
  151. There is a current problem that if you have the required potion ingredient but it is in your belt slots
  152. the task is uncraftable but the ingredients show as available and it will not craft a new one
  153. 0.1.9.1
  154. - Update with changes in Mustex's script (version 12)
  155. * Added tasks for Platesmithing, Leatherworking, Tailoring
  156. * Added detection for the gateway being down
  157. 0.1.8.3.8
  158. - Update asset selection to avoid using coloured assets in junk slots for leadership
  159. 0.1.8.3.7
  160. - Update leadership tasks table due to task reward/duration alterations
  161. 0.1.8.3.6
  162. - Add option to enable/disable automation process
  163. - Update alchemy tasks some more
  164. 0.1.8.3.5
  165. - Add ability to select from multiple tasks with same name (eg Alchemical Research)
  166. - Add craft options for alchemy potions (need to be manually switched since they use the same ingredients)
  167. 0.1.8.3.4
  168. - Add alchemy tasks up to level 20
  169. 0.1.8.3.3
  170. - Change task slot selection to be user configurable options in settings window
  171. - Add level 1 alchemical research
  172. 0.1.8.3.2
  173. - Added ability to specify how many tasks of each profession to train multiple professions at once
  174. - Updated mailsmithing level 0 tasks
  175. 0.1.8.3.1
  176. - Changed asset selection to only update Junk assets
  177. - Leadership asset selection for bronze tier picks lowest asset first
  178. - Modified Leadership tasks
  179. 0.1.8.3
  180. - Tweaked Leadership tasks grid
  181. - Added task grid for Alchemy (Partial)
  182. 0.1.8.2
  183. - onsave handlers for settings are now called before the settings values are saved
  184. - Added onsave handler for console to enable/disable using the window console
  185. 0.1.8.1
  186. - Added checking for errors (using the window title) and will navigate back to the main login page if autologin is enabled
  187. 0.1.8
  188. - Added popup for altering settings
  189. - Settings are saved to script cache
  190. - Added mailsmithing tasks to task grid
  191. 0.1.7
  192. - Added lower level leadership tasks to grid
  193. - Added hiring tasks to leadership task
  194. - Uses saved values to determine which profession type to level (Defaults to Leadership, currently no way to change it)
  195.  
  196. 0.1.5
  197. - Is now able to recover from missing assets
  198. - Uses a configurable grid to determine what the next task is to complete
  199.  
  200. 0.1.0
  201. - Is now able to select some hard coded leadership tasks
  202. - Can now collect from any completed slot
  203. */
  204.  
  205. // Make sure it's running on the main page, no frames
  206. if (window.self !== window.top) {
  207. throw "";
  208. }
  209.  
  210. // Set global console variables
  211. var fouxConsole = {log:function(){},info:function(){},error:function(){},warn:function(){}};
  212. var console = unsafeWindow.console || fouxConsole;
  213. var chardiamonds = {};
  214. // Page Reloading function
  215. // Every second the page is idle or loading is tracked
  216. var loading_reset = false; // Enables a periodic reload if this is toggled on by the Auto Reload check box on the settings panel
  217. var s_paused = false; // extend the paused setting to the Page Reloading function
  218.  
  219. (function() {
  220. var $ = unsafeWindow.$;
  221. //MAC-NW
  222. $.fn.waitUntilExists = function (handler, shouldRunHandlerOnce, isChild) {
  223. var found = 'found';
  224. var $this = $(this.selector);
  225. var $elements = $this.not(function () {
  226. return $(this).data(found);
  227. }).each(handler).data(found, true);
  228. if (!isChild) {
  229. (window.waitUntilExists_Intervals = window.waitUntilExists_Intervals || {})[this.selector] = window.setInterval(function () {
  230. $this.waitUntilExists(handler, shouldRunHandlerOnce, true);
  231. }, 500);
  232. } else if (shouldRunHandlerOnce && $elements.length) {
  233. window.clearInterval(window.waitUntilExists_Intervals[this.selector]);
  234. }
  235. return $this;
  236. };
  237.  
  238. $('.vendor-quantity-block span.attention').waitUntilExists(function () {
  239. if ($('.vendor-quantity-block span.attention span').length)
  240. $('.vendor-quantity-block span.attention').replaceWith('<div class="input-field button"><div class="input-bg-left"></div><div class="input-bg-mid"></div><div class="input-bg-right"></div><button onclick="$(\'input[name=inventorySellQty]\').val(\'' + $(".vendor-quantity-block span.attention span").text() + '\');">All (' + $(".vendor-quantity-block span.attention span").text() + ')</button></div>');
  241. });
  242. $('div.notification div.messages li').waitUntilExists(function () {
  243. if ($("div.notification div.messages li").length > 2)
  244. $("div.notification div.messages li").eq(0).remove();
  245. });
  246. //MAC-NW
  247. var state_loading = 0; // If "Page Loading" takes longer than 30 seconds, reload page (maybe a javascript error)
  248. var state_loading_time = 30; // default of 30 seconds
  249. var chardiamonds = {};
  250. var state_idle = 0; // If the page is idle for longer than 60 seconds, reload page (maybe a javascript error)
  251. var state_idle_time = 120; // default of 120 seconds
  252. var reload_hours = [2,5,8,11,14,17,20,23]; // logout and reload every three hours - 2:29 - 5:29 - 8:29 - 11:29 - 14:29 - 17:29 - 20:29 - 23:29
  253. var last_location = ""; // variable to track reference to page URL
  254. var reload_timer = setInterval(function() {
  255. if (!s_paused) {
  256. if (loading_reset) {
  257. var loading_date = new Date();
  258. var loading_sec = Number(loading_date.getSeconds());
  259. var loading_min = Number(loading_date.getMinutes());
  260. var loading_hour = Number(loading_date.getHours());
  261. if (reload_hours.indexOf(loading_hour) >= 0 && loading_min == 29 && loading_sec < 2) {
  262. console.log("Auto Reload");
  263. unsafeWindow.location.href = "http://gateway.playneverwinter.com";
  264. return;
  265. }
  266. }
  267. // check for errors
  268. if ($("title").text().match(/Error/) || $("div.modal-content h3").text().match(/Disconnected/)) {
  269. console.log("Error detected - relogging");
  270. unsafeWindow.location.href = "http://gateway.playneverwinter.com";
  271. return;
  272. }
  273.  
  274. if ($("div.loading-image:visible").length) {
  275. last_location = location.href;
  276. state_idle = 0;
  277. if (state_loading >= state_loading_time) {
  278. console.log("Page Loading too long");
  279. state_loading = 0;
  280. location.reload();
  281. }
  282. else {
  283. state_loading++;
  284. console.log("Page Loading ...", state_loading + "s");
  285. }
  286. }
  287. // TODO: Add check for Gateway disconnected
  288. //<div class="modal-content" id="modal_content"><h3>Disconnected from Gateway</h3><p>You have been disconnected.</p><button type="button" class="modal-button" onclick="window.location.reload(true);">Close</button>
  289.  
  290. /* Can't use idle check with dataModel methods
  291. else if (location.href == last_location) {
  292. state_loading = 0;
  293. if (state_idle >= state_idle_time) {
  294. console.log("Page Idle too long");
  295. state_idle = 0;
  296. unsafeWindow.location.href = "http://gateway.playneverwinter.com";
  297. }
  298. else {
  299. state_idle++;
  300. // comment out to avoid console spam
  301. //console.log("Page Idle ...", state_idle + "s");
  302. }
  303. }
  304. */
  305. else {
  306. last_location = location.href;
  307. state_loading = 0;
  308. state_idle = 0;
  309. }
  310. }
  311. },1000);
  312. })();
  313.  
  314. (function() {
  315.  
  316. /**
  317. * Add a string of CSS to the main page
  318. *
  319. * @param {String} cssString The CSS to add to the main page
  320. */
  321. function AddCss(cssString) {
  322. var head = document.getElementsByTagName('head')[0];
  323. if (!head)
  324. return;
  325. var newCss = document.createElement('style');
  326. newCss.type = "text/css";
  327. newCss.innerHTML = cssString;
  328. head.appendChild(newCss);
  329. }
  330. function countLeadingSpaces(str) {
  331. return str.match(/^(\s*)/)[1].length;
  332. }
  333.  
  334. var image_pause = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAY" +
  335. "AAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2" +
  336. "ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AUkSYqIQkQSoghodkVUcERRUUEG" +
  337. "8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuja9a89+bN/rXXPues852zzwfACAyWSDNR" +
  338. "NYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMBAPh+PDwrIsAHvgABeNMLCADATZvAMBy" +
  339. "H/w/qQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAtAGAnf+bTAI" +
  340. "Cd+Jl7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3AMDOE" +
  341. "AuyAAgMADBRiIUpAAR7AGDIIyN4AISZABRG8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dX" +
  342. "Lh4ozkkXKxQ2YQJhmkAuwnmZGTKBNA/g88wAAKCRFRHgg/P9eM4Ors7ONo62Dl8t6r8G/yJ" +
  343. "iYuP+5c+rcEAAAOF0ftH+LC+zGoA7BoBt/qIl7gRoXgugdfeLZrIPQLUAoOnaV/Nw+H48PE" +
  344. "WhkLnZ2eXk5NhKxEJbYcpXff5nwl/AV/1s+X48/Pf14L7iJIEyXYFHBPjgwsz0TKUcz5IJh" +
  345. "GLc5o9H/LcL//wd0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcUl0v9k4t8s+wM+3zUAsGo+" +
  346. "AXuRLahdYwP2SycQWHTA4vcAAPK7b8HUKAgDgGiD4c93/+8//UegJQCAZkmScQAAXkQkLlT" +
  347. "Ksz/HCAAARKCBKrBBG/TBGCzABhzBBdzBC/xgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKm" +
  348. "Av1EAdNMBRaIaTcA4uwlW4Dj1wD/phCJ7BKLyBCQRByAgTYSHaiAFiilgjjggXmYX4IcFIB" +
  349. "BKLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5h1xGupE7yAAygvyGvEcxlIGyUT3UDLVDuag3" +
  350. "GoRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8+Q8cwwOgYBzPEbDAuxsNCsTgsCZNjy7E" +
  351. "irAyrxhqwVqwDu4n1Y8+xdwQSgUXACTYEd0IgYR5BSFhMWE7YSKggHCQ0EdoJNwkDhFHCJy" +
  352. "KTqEu0JroR+cQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQAkmxpFTSEtJG0m5SI+ksq" +
  353. "Zs0SBojk8naZGuyBzmULCAryIXkneTD5DPkG+Qh8lsKnWJAcaT4U+IoUspqShnlEOU05QZl" +
  354. "mDJBVaOaUt2ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdpr+h0uhHdlR5" +
  355. "Ol9BX0svpR+iX6AP0dwwNhhWDx4hnKBmbGAcYZxl3GK+YTKYZ04sZx1QwNzHrmOeZD5lvVV" +
  356. "gqtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI+pXlN9rkZVM1PjqQnUlqtVqp1Q61MbU" +
  357. "2epO6iHqmeob1Q/pH5Z/YkGWcNMw09DpFGgsV/jvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2" +
  358. "KruY/R27iz2qqaE5QzNKM1ezUvOUZj8H45hx+Jx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVx" +
  359. "rqpaXllirSKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4/OBZ3nU9lT3acKpxZNPTr1ri" +
  360. "6qa6UbobtEd79up+6Ynr5egJ5Mb6feeb3n+hx9L/1U/W36p/VHDFgGswwkBtsMzhg8xTVxb" +
  361. "zwdL8fb8VFDXcNAQ6VhlWGX4YSRudE8o9VGjUYPjGnGXOMk423GbcajJgYmISZLTepN7ppS" +
  362. "TbmmKaY7TDtMx83MzaLN1pk1mz0x1zLnm+eb15vft2BaeFostqi2uGVJsuRaplnutrxuhVo" +
  363. "5WaVYVVpds0atna0l1rutu6cRp7lOk06rntZnw7Dxtsm2qbcZsOXYBtuutm22fWFnYhdnt8" +
  364. "Wuw+6TvZN9un2N/T0HDYfZDqsdWh1+c7RyFDpWOt6azpzuP33F9JbpL2dYzxDP2DPjthPLK" +
  365. "cRpnVOb00dnF2e5c4PziIuJS4LLLpc+Lpsbxt3IveRKdPVxXeF60vWdm7Obwu2o26/uNu5p" +
  366. "7ofcn8w0nymeWTNz0MPIQ+BR5dE/C5+VMGvfrH5PQ0+BZ7XnIy9jL5FXrdewt6V3qvdh7xc" +
  367. "+9j5yn+M+4zw33jLeWV/MN8C3yLfLT8Nvnl+F30N/I/9k/3r/0QCngCUBZwOJgUGBWwL7+H" +
  368. "p8Ib+OPzrbZfay2e1BjKC5QRVBj4KtguXBrSFoyOyQrSH355jOkc5pDoVQfujW0Adh5mGLw" +
  369. "34MJ4WHhVeGP45wiFga0TGXNXfR3ENz30T6RJZE3ptnMU85ry1KNSo+qi5qPNo3ujS6P8Yu" +
  370. "ZlnM1VidWElsSxw5LiquNm5svt/87fOH4p3iC+N7F5gvyF1weaHOwvSFpxapLhIsOpZATIh" +
  371. "OOJTwQRAqqBaMJfITdyWOCnnCHcJnIi/RNtGI2ENcKh5O8kgqTXqS7JG8NXkkxTOlLOW5hC" +
  372. "epkLxMDUzdmzqeFpp2IG0yPTq9MYOSkZBxQqohTZO2Z+pn5mZ2y6xlhbL+xW6Lty8elQfJa" +
  373. "7OQrAVZLQq2QqboVFoo1yoHsmdlV2a/zYnKOZarnivN7cyzytuQN5zvn//tEsIS4ZK2pYZL" +
  374. "Vy0dWOa9rGo5sjxxedsK4xUFK4ZWBqw8uIq2Km3VT6vtV5eufr0mek1rgV7ByoLBtQFr6wt" +
  375. "VCuWFfevc1+1dT1gvWd+1YfqGnRs+FYmKrhTbF5cVf9go3HjlG4dvyr+Z3JS0qavEuWTPZt" +
  376. "Jm6ebeLZ5bDpaql+aXDm4N2dq0Dd9WtO319kXbL5fNKNu7g7ZDuaO/PLi8ZafJzs07P1SkV" +
  377. "PRU+lQ27tLdtWHX+G7R7ht7vPY07NXbW7z3/T7JvttVAVVN1WbVZftJ+7P3P66Jqun4lvtt" +
  378. "Xa1ObXHtxwPSA/0HIw6217nU1R3SPVRSj9Yr60cOxx++/p3vdy0NNg1VjZzG4iNwRHnk6fc" +
  379. "J3/ceDTradox7rOEH0x92HWcdL2pCmvKaRptTmvtbYlu6T8w+0dbq3nr8R9sfD5w0PFl5Sv" +
  380. "NUyWna6YLTk2fyz4ydlZ19fi753GDborZ752PO32oPb++6EHTh0kX/i+c7vDvOXPK4dPKy2" +
  381. "+UTV7hXmq86X23qdOo8/pPTT8e7nLuarrlca7nuer21e2b36RueN87d9L158Rb/1tWeOT3d" +
  382. "vfN6b/fF9/XfFt1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v+3Njv3H9qwHeg89HcR/c" +
  383. "GhYPP/pH1jw9DBY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i/suuFxYvfvjV69fO0Z" +
  384. "jRoZfyl5O/bXyl/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8IH8o/2j5sfVT0" +
  385. "Kf7kxmTk/8EA5jz/GMzLdsAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgA" +
  386. "ABdvkl/FRgAAAZ9JREFUeNqU0z+LE2EQBvDfvsuZ3IkoFzSJiuCfeAkWFmJnkz5wjVjlK4i" +
  387. "tnR9BrP0E4uewE/bQwKko2CjR88+BuSMhycbm3RjjNk41z7szz8w8O5Motzqu4iwW+Ir3+L" +
  388. "YemKzh07iLGziJPL4HjPAKz3FcRnAJD3AKXzBb+b7ABhr4jscYQhoDzuBhrDQsIU9iNz9j7" +
  389. "G28wLQg6OMyhrVaLd3Z2dFoNBwdHdna2tJut9XrdZPJJIzH4xHOo4rXAU3cjJXTfr8vyzJZ" +
  390. "lul2u3q9nizL7O3t2d3dLbr+jFvYDuiggjlMp9Nl3/P53Gw2W+IVfxZFbgecw7SYOc/zZUK" +
  391. "e5//gNU22QxRu4f9tgSTE5ThRkIQQ/kifJJIk+QuvJKc4DHizOsLm5uYyoVKpqFarS7zipx" +
  392. "jjXUF5P4o5bDabodVqgcFgIE1TnU4H7O/vOzg4yHEBL/G0IGjgUVzXX1GXMsvjIm3E+B/FI" +
  393. "o3wEXfi7zkuRFoVLBYKeIJPZcd0EfdwLc5ZaLMR/bd4Fm+l9BoLu44rsd0FDuM5f1gP/D0A" +
  394. "BNp57TyT3+MAAAAASUVORK5CYII=";
  395. var image_play = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYA" +
  396. "AAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2Z" +
  397. "pbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AUkSYqIQkQSoghodkVUcERRUUEG8" +
  398. "igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuja9a89+bN/rXXPues852zzwfACAyWSDNRN" +
  399. "YAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMBAPh+PDwrIsAHvgABeNMLCADATZvAMByH" +
  400. "/w/qQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAtAGAnf+bTAIC" +
  401. "d+Jl7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3AMDOEA" +
  402. "uyAAgMADBRiIUpAAR7AGDIIyN4AISZABRG8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dXL" +
  403. "h4ozkkXKxQ2YQJhmkAuwnmZGTKBNA/g88wAAKCRFRHgg/P9eM4Ors7ONo62Dl8t6r8G/yJi" +
  404. "YuP+5c+rcEAAAOF0ftH+LC+zGoA7BoBt/qIl7gRoXgugdfeLZrIPQLUAoOnaV/Nw+H48PEW" +
  405. "hkLnZ2eXk5NhKxEJbYcpXff5nwl/AV/1s+X48/Pf14L7iJIEyXYFHBPjgwsz0TKUcz5IJhG" +
  406. "Lc5o9H/LcL//wd0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcUl0v9k4t8s+wM+3zUAsGo+A" +
  407. "XuRLahdYwP2SycQWHTA4vcAAPK7b8HUKAgDgGiD4c93/+8//UegJQCAZkmScQAAXkQkLlTK" +
  408. "sz/HCAAARKCBKrBBG/TBGCzABhzBBdzBC/xgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKmA" +
  409. "v1EAdNMBRaIaTcA4uwlW4Dj1wD/phCJ7BKLyBCQRByAgTYSHaiAFiilgjjggXmYX4IcFIBB" +
  410. "KLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5h1xGupE7yAAygvyGvEcxlIGyUT3UDLVDuag3G" +
  411. "oRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8+Q8cwwOgYBzPEbDAuxsNCsTgsCZNjy7Ei" +
  412. "rAyrxhqwVqwDu4n1Y8+xdwQSgUXACTYEd0IgYR5BSFhMWE7YSKggHCQ0EdoJNwkDhFHCJyK" +
  413. "TqEu0JroR+cQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQAkmxpFTSEtJG0m5SI+ksqZ" +
  414. "s0SBojk8naZGuyBzmULCAryIXkneTD5DPkG+Qh8lsKnWJAcaT4U+IoUspqShnlEOU05QZlm" +
  415. "DJBVaOaUt2ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdpr+h0uhHdlR5O" +
  416. "l9BX0svpR+iX6AP0dwwNhhWDx4hnKBmbGAcYZxl3GK+YTKYZ04sZx1QwNzHrmOeZD5lvVVg" +
  417. "qtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI+pXlN9rkZVM1PjqQnUlqtVqp1Q61MbU2" +
  418. "epO6iHqmeob1Q/pH5Z/YkGWcNMw09DpFGgsV/jvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2K" +
  419. "ruY/R27iz2qqaE5QzNKM1ezUvOUZj8H45hx+Jx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVxr" +
  420. "qpaXllirSKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4/OBZ3nU9lT3acKpxZNPTr1ri6" +
  421. "qa6UbobtEd79up+6Ynr5egJ5Mb6feeb3n+hx9L/1U/W36p/VHDFgGswwkBtsMzhg8xTVxbz" +
  422. "wdL8fb8VFDXcNAQ6VhlWGX4YSRudE8o9VGjUYPjGnGXOMk423GbcajJgYmISZLTepN7ppST" +
  423. "bmmKaY7TDtMx83MzaLN1pk1mz0x1zLnm+eb15vft2BaeFostqi2uGVJsuRaplnutrxuhVo5" +
  424. "WaVYVVpds0atna0l1rutu6cRp7lOk06rntZnw7Dxtsm2qbcZsOXYBtuutm22fWFnYhdnt8W" +
  425. "uw+6TvZN9un2N/T0HDYfZDqsdWh1+c7RyFDpWOt6azpzuP33F9JbpL2dYzxDP2DPjthPLKc" +
  426. "RpnVOb00dnF2e5c4PziIuJS4LLLpc+Lpsbxt3IveRKdPVxXeF60vWdm7Obwu2o26/uNu5p7" +
  427. "ofcn8w0nymeWTNz0MPIQ+BR5dE/C5+VMGvfrH5PQ0+BZ7XnIy9jL5FXrdewt6V3qvdh7xc+" +
  428. "9j5yn+M+4zw33jLeWV/MN8C3yLfLT8Nvnl+F30N/I/9k/3r/0QCngCUBZwOJgUGBWwL7+Hp" +
  429. "8Ib+OPzrbZfay2e1BjKC5QRVBj4KtguXBrSFoyOyQrSH355jOkc5pDoVQfujW0Adh5mGLw3" +
  430. "4MJ4WHhVeGP45wiFga0TGXNXfR3ENz30T6RJZE3ptnMU85ry1KNSo+qi5qPNo3ujS6P8YuZ" +
  431. "lnM1VidWElsSxw5LiquNm5svt/87fOH4p3iC+N7F5gvyF1weaHOwvSFpxapLhIsOpZATIhO" +
  432. "OJTwQRAqqBaMJfITdyWOCnnCHcJnIi/RNtGI2ENcKh5O8kgqTXqS7JG8NXkkxTOlLOW5hCe" +
  433. "pkLxMDUzdmzqeFpp2IG0yPTq9MYOSkZBxQqohTZO2Z+pn5mZ2y6xlhbL+xW6Lty8elQfJa7" +
  434. "OQrAVZLQq2QqboVFoo1yoHsmdlV2a/zYnKOZarnivN7cyzytuQN5zvn//tEsIS4ZK2pYZLV" +
  435. "y0dWOa9rGo5sjxxedsK4xUFK4ZWBqw8uIq2Km3VT6vtV5eufr0mek1rgV7ByoLBtQFr6wtV" +
  436. "CuWFfevc1+1dT1gvWd+1YfqGnRs+FYmKrhTbF5cVf9go3HjlG4dvyr+Z3JS0qavEuWTPZtJ" +
  437. "m6ebeLZ5bDpaql+aXDm4N2dq0Dd9WtO319kXbL5fNKNu7g7ZDuaO/PLi8ZafJzs07P1SkVP" +
  438. "RU+lQ27tLdtWHX+G7R7ht7vPY07NXbW7z3/T7JvttVAVVN1WbVZftJ+7P3P66Jqun4lvttX" +
  439. "a1ObXHtxwPSA/0HIw6217nU1R3SPVRSj9Yr60cOxx++/p3vdy0NNg1VjZzG4iNwRHnk6fcJ" +
  440. "3/ceDTradox7rOEH0x92HWcdL2pCmvKaRptTmvtbYlu6T8w+0dbq3nr8R9sfD5w0PFl5SvN" +
  441. "UyWna6YLTk2fyz4ydlZ19fi753GDborZ752PO32oPb++6EHTh0kX/i+c7vDvOXPK4dPKy2+" +
  442. "UTV7hXmq86X23qdOo8/pPTT8e7nLuarrlca7nuer21e2b36RueN87d9L158Rb/1tWeOT3dv" +
  443. "fN6b/fF9/XfFt1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v+3Njv3H9qwHeg89HcR/cG" +
  444. "hYPP/pH1jw9DBY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i/suuFxYvfvjV69fO0Zj" +
  445. "RoZfyl5O/bXyl/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8IH8o/2j5sfVT0K" +
  446. "f7kxmTk/8EA5jz/GMzLdsAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAA" +
  447. "Bdvkl/FRgAAAYZJREFUeNqk08+KklEYBvDf9+lIEYZDZQ0OIrQZahEuBoLuQqiWIl5BG2k5" +
  448. "W5dzA15AF9EFJOiiRRNkSIw4lTAfCQNmzrToOIkc2nRW5z3n/fe8z/Mm4mcfD3EfCb5hhC/" +
  449. "bjsmWXcJLPMJNLMP7DhY4wRt8jyWo4hVu4Qyrjf8rpKGjJY7xCXLB4TZeB/ssBCaRTn+ggG" +
  450. "d4h4s0fDRQxAy5arWq0+nEZpMiQx7P1w938SRUzkGWZbrdrsFgoFarxZJ8xWPspzgIuH+tP" +
  451. "ZbLpfl8rl6vG41GWq3WdpLLAOUgxb0QfI05Sf7CT9NUr9fT7/dVKpXNmSxRSv3nSQOn+UDV" +
  452. "H86urq9Wq5V2u+3w8NBkMrFB6w7O80EcFyHJCgqFgmKxaDgcajQaxuNxrPBPnORC8IOgvgx" +
  453. "puVw2nU41m01ZlsUGuIf3eJtsCOko0DjbEFgsuBQYOMJs7bjABzzFndDVZUTKe8E+xmlsmX" +
  454. "bxIsC5sZ5J6GiBj/9aptg67wafc3yOrfPvAQDwi2sWVdJBsgAAAABJRU5ErkJggg==";
  455. var image_prefs = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQC" +
  456. "AMAAAAoLQ9TAAAAllBMVEUAGQASEhIfHx8fJy8pKSk2NjZBQUFJR0ZQUE9RUVFSUlJNX3No" +
  457. "aGhsaWdramlycG1meY98fHx+fn5wgpV0iqKKh4R4jaR9jJx8kad9kad/mbONmaWEnrmEnrq" +
  458. "koZy3t7fIx8bKyMHT0c3S0dDU09DV1NPP1t3W1dXY2Njb2tfe29bf3tzj4uHr6+js6+r39/" +
  459. "f5+PgAAABrL3yvAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxMAAAsTA" +
  460. "QCanBgAAAAHdElNRQfWBRoFKh31UQ8DAAAAgUlEQVQY022OxxLCMAwFRSc4BEIPJZQQ08v+" +
  461. "/8+RsTExDDpIe3ijfSJ/hx9g62Dt4GaAI+8YT0t27+BxxvvE/no5pYT10lGFrE34Ja40W3g" +
  462. "1oMGmW7YZ6hnCYexKTPVkXivuvWe1Cz1aKqPNI3N0slI2TNYZiARJX30qERc7wBPKC4WRDz" +
  463. "WdWHfmAAAAAElFTkSuQmCC";
  464. var image_close = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQC" +
  465. "AQAAAC1+jfqAAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfW" +
  466. "BRkTNhxuPxLkAAAAHXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBUaGUgR0lNUO9kJW4AAAE" +
  467. "KSURBVCjPhdGxSgNBFAXQMzpgYWwsLEQUDBJBQgqFIChZEPR7/DA/QCGQTgQtJE1ENoWohY" +
  468. "UgbGKQyFjErNv52nObe19wqGWg7z0l5YVgVdOu+wUt507tqIVQ4Zodp861ooELe15M5KFI6" +
  469. "Zfr9u25MIj6Jl4cmSIPBWrq2o5cufO4aOJDYSozNTa2pK4t03PtwUdMKRRykAmW0dTRcyNX" +
  470. "pBQpI8GJDTR050zkNzK0bMMZLvUNZ8yCfy6Wvbc1NVyi4dloXjqWvds6uvp41pFmpVOKJWd" +
  471. "6bgwxkmTMIotWKpwrfBkZl7uMonUHf5wSlV2+fUZrjnXdzrmyy7djD8GWTW9e51z557o1Tz" +
  472. "85FH/WkOkaHQAAAABJRU5ErkJggg==";
  473.  
  474.  
  475. // Setup global closure variables
  476. var $ = unsafeWindow.jQuery;
  477. var timerHandle = 0;
  478. var dfdNextRun = $.Deferred();
  479. var charcurrent = 0; // current character counter
  480. var chartimers = {};
  481. var settingwipe = false; // Use to wipe stored settings
  482. var delay = {
  483. SHORT : 1000,
  484. MEDIUM : 5000,
  485. LONG : 30000,
  486. MINS : 300000,
  487. DEFAULT : 10000, // default delay
  488. TIMEOUT : 60000, // delay for cycle processing timeout
  489. };
  490.  
  491. /*
  492. * Tasklist can be modified to configure the training you want to perform.
  493. * The configurable options window sets how many profession slots you want to use for each profession.
  494. * The level array below for each professions specifies the tasks you want to learn at each crafting level.
  495. * Each craft slot will pick the first task that meets requirements.
  496. * See http://pastebin.com/VaGntEha for Task Name Map.
  497. * Some names above do not match, use below code to check:
  498. * var tasks = client.dataModel.model.craftinglist['craft_' + profname].entries.filter(function(entry) { return entry.def && entry.def.displayname == taskname; }); tasks[0].def.name;
  499. */
  500. var tasklist;
  501. var defaultTasklist = [
  502. {
  503. // modded to prioritize RAD production
  504. taskName:"Leadership",
  505. level: {
  506. 0:["Leadership_Tier0_Intro_1"],
  507. 1:["Leadership_Tier0_Intro_5", "Leadership_Tier0_Intro_4","Leadership_Tier0_Intro_3", "Leadership_Tier0_Intro_2"],
  508. 2:["Leadership_Tier1_2_Guardduty"],
  509. 3:["Leadership_Tier1_2_Guardduty"],
  510. 4:["Leadership_Tier1_4_Protect","Leadership_Tier1_2_Guardduty"],
  511. 5:["Leadership_Tier1_4_Protect","Leadership_Tier1_5_Explore","Leadership_Tier1_2_Guardduty"],
  512. 6:["Leadership_Tier1_4_Protect","Leadership_Tier1_5_Explore","Leadership_Tier1_2_Guardduty"],
  513. 7:["Leadership_Tier1_4_Protect","Leadership_Tier1_5_Explore","Leadership_Tier1_2_Guardduty"],
  514. 8:["Leadership_Tier1_4_Protect","Leadership_Tier1_5_Explore","Leadership_Tier1_2_Guardduty"],
  515. 9:["Leadership_Tier1_4_Protect","Leadership_Tier2_9_Chart","Leadership_Tier1_5_Explore"],
  516. // Begin prioritizing "Battle Undead"
  517. 10:["Leadership_Tier2_10_Battle","Leadership_Tier1_4_Protect","Leadership_Tier2_9_Chart","Leadership_Tier1_5_Explore"],
  518. 11:["Leadership_Tier2_10_Battle","Leadership_Tier1_4_Protect","Leadership_Tier2_9_Chart","Leadership_Tier1_5_Explore"],
  519. 12:["Leadership_Tier2_10_Battle","Leadership_Tier1_4_Protect","Leadership_Tier2_9_Chart","Leadership_Tier1_5_Explore"],
  520. // Add "protect diamonds rare" and the patrol quest as a backup
  521. 13:["Leadership_Tier3_13r_Protectdiamonds","Leadership_Tier2_10_Battle","Leadership_Tier1_4_Protect","Leadership_Tier3_13_Patrol","Leadership_Tier2_9_Chart","Leadership_Tier1_5_Explore"],
  522. 14:["Leadership_Tier3_13r_Protectdiamonds","Leadership_Tier2_10_Battle","Leadership_Tier1_4_Protect","Leadership_Tier3_13_Patrol","Leadership_Tier2_9_Chart","Leadership_Tier1_5_Explore"],
  523. 15:["Leadership_Tier3_13r_Protectdiamonds","Leadership_Tier2_10_Battle","Leadership_Tier1_4_Protect","Leadership_Tier3_13_Patrol","Leadership_Tier2_9_Chart","Leadership_Tier1_5_Explore"],
  524. // AD Production mode: Spellplague + Battle Undead
  525. 16:["Leadership_Tier3_13r_Protectdiamonds","Leadership_Tier3_16_Fight","Leadership_Tier2_10_Battle","Leadership_Tier3_13_Patrol","Leadership_Tier2_9_Chart","Leadership_Tier1_5_Explore"],
  526. 17:["Leadership_Tier3_13r_Protectdiamonds","Leadership_Tier3_16_Fight","Leadership_Tier2_10_Battle","Leadership_Tier3_13_Patrol","Leadership_Tier3_17_Deliver","Leadership_Tier2_12_Taxes","Leadership_Tier2_9_Chart","Leadership_Tier1_5_Explore"],
  527. 18:["Leadership_Tier3_13r_Protectdiamonds","Leadership_Tier3_16_Fight","Leadership_Tier2_10_Battle","Leadership_Tier3_13_Patrol","Leadership_Tier3_17_Deliver","Leadership_Tier2_12_Taxes","Leadership_Tier2_9_Chart","Leadership_Tier1_5_Explore"],
  528. 19:["Leadership_Tier3_13r_Protectdiamonds","Leadership_Tier3_16_Fight","Leadership_Tier2_10_Battle","Leadership_Tier3_13_Patrol","Leadership_Tier3_17_Deliver","Leadership_Tier2_12_Taxes","Leadership_Tier2_9_Chart","Leadership_Tier1_5_Explore"],
  529. // 20
  530. 20:["Leadership_Tier3_20r_Master2","Leadership_Tier3_20r_Master1","Leadership_Tier3_20r_Master3","Leadership_Tier3_20_Destroy","Leadership_Tier3_13r_Protectdiamonds","Leadership_Tier2_12_Taxes","Leadership_Tier3_16_Fight","Leadership_Tier2_10_Battle","Leadership_Tier3_13_Patrol","Leadership_Tier2_9_Chart","Leadership_Tier1_5_Explore"],
  531. },
  532. },
  533. {
  534. //WinterEvent
  535. taskName:"WinterEvent",
  536. level: {
  537. 0:["Event_Winter_Tier0_Intro"],
  538. 1:["Event_Winter_Tier1_Rankup","Event_Winter_Tier1_Shiny_Lure","Event_Winter_Tier1_Refine","Event_Winter_Tier1_Gather"], //
  539. 2:["Event_Winter_Tier1_Rankup_2","Event_Winter_Tier1_Shiny_Lure_Mass","Event_Winter_Tier1_Refine_2","Event_Winter_Tier1_Gather_2"], //
  540. 3:["Event_Winter_Tier1_Mesmerizing_Lure","Event_Winter_Tier1_Gather_3"], //"Event_Winter_Tier1_Lightwine"
  541. },
  542. },
  543. {
  544. // Black Ice Shaping
  545. taskName:"BlackIce",
  546. level: {
  547. 1:["Blackice_Tier1_Process_Blackice"],
  548. 2:["Blackice_Tier1_Process_Blackice"],
  549. 3:["Blackice_Tier1_Process_Blackice"],
  550. /*
  551. 1:["Forge Hammerstone Pick","Gather Raw Black Ice","Truesilver Pick Grip","Process Raw Black Ice","Upgrade Chillwright","Hire an additional Chillwright"],
  552. 2:["Forge Hammerstone Pick","Gather Raw Black Ice","Truesilver Pick Grip","Process Raw Black Ice","Upgrade Chillwright","Hire an additional Chillwright"],
  553. 3:["Forge Hammerstone Pick","Gather Raw Black Ice","Truesilver Pick Grip","Process Raw Black Ice","Upgrade Chillwright","Hire an additional Chillwright"],
  554. */
  555. },
  556. },
  557. {
  558. // Jewelcrafting
  559. taskName:"Jewelcrafting",
  560. level: {
  561. 0:["Jewelcrafting_Tier0_Intro"],
  562. 1:[ "Jewelcrafting_Tier1_Waist_Offense_1","Jewelcrafting_Tier1_Refine_Basic","Jewelcrafting_Tier1_Gather_Basic"],
  563. 2:[ "Jewelcrafting_Tier1_Waist_Offense_1","Jewelcrafting_Tier1_Refine_Basic","Jewelcrafting_Tier1_Gather_Basic"],
  564. 3:[ "Jewelcrafting_Tier1_Neck_Offense_1","Jewelcrafting_Tier1_Waist_Offense_1","Jewelcrafting_Tier1_Refine_Basic","Jewelcrafting_Tier1_Gather_Basic"],
  565. 4:[ "Jewelcrafting_Tier1_Neck_Offense_1","Jewelcrafting_Tier1_Waist_Misc_1","Jewelcrafting_Tier1_Refine_Basic","Jewelcrafting_Tier1_Gather_Basic"],
  566. 5:[ "Jewelcrafting_Tier1_Neck_Offense_1","Jewelcrafting_Tier1_Waist_Misc_1","Jewelcrafting_Tier1_Refine_Basic","Jewelcrafting_Tier1_Gather_Basic"],
  567. 6:["Jewelcrafting_Tier1_Neck_Misc_1","Jewelcrafting_Tier1_Waist_Misc_1","Jewelcrafting_Tier1_Refine_Basic","Jewelcrafting_Tier1_Gather_Basic"],
  568. 7:[ "Jewelcrafting_Tier2_Waist_Offense_2","Jewelcrafting_Tier2_Refine_Basic","Jewelcrafting_Tier2_Gather_Basic","Jewelcrafting_Tier1_Gather_Basic"],
  569. 8:[ "Jewelcrafting_Tier2_Waist_Offense_2","Jewelcrafting_Tier2_Refine_Basic","Jewelcrafting_Tier2_Gather_Basic","Jewelcrafting_Tier1_Gather_Basic"],
  570. 9:[ "Jewelcrafting_Tier2_Neck_Offense_2","Jewelcrafting_Tier2_Waist_Offense_2","Jewelcrafting_Tier2_Refine_Basic","Jewelcrafting_Tier2_Gather_Basic","Jewelcrafting_Tier1_Gather_Basic"],
  571. 10:[ "Jewelcrafting_Tier2_Waist_Misc_2","Jewelcrafting_Tier2_Neck_Offense_2", "Jewelcrafting_Tier2_Refine_Basic","Jewelcrafting_Tier2_Gather_Basic","Jewelcrafting_Tier1_Gather_Basic"],
  572. 11:[ "Jewelcrafting_Tier2_Waist_Misc_2","Jewelcrafting_Tier2_Neck_Offense_2", "Jewelcrafting_Tier2_Refine_Basic","Jewelcrafting_Tier2_Gather_Basic","Jewelcrafting_Tier1_Gather_Basic"],
  573. 12:[ "Jewelcrafting_Tier2_Waist_Misc_2","Jewelcrafting_Tier2_Neck_Offense_2", "Jewelcrafting_Tier2_Refine_Basic","Jewelcrafting_Tier2_Gather_Basic","Jewelcrafting_Tier1_Gather_Basic"],
  574. 13:["Jewelcrafting_Tier2_Neck_Misc_2","Jewelcrafting_Tier2_Waist_Misc_2", "Jewelcrafting_Tier2_Refine_Basic","Jewelcrafting_Tier2_Gather_Basic","Jewelcrafting_Tier1_Gather_Basic"],
  575. 14:[ "Jewelcrafting_Tier3_Waist_Offense_3","Jewelcrafting_Tier3_Refine_Basic","Jewelcrafting_Tier3_Gather_Basic","Jewelcrafting_Tier2_Gather_Basic","Jewelcrafting_Tier1_Gather_Basic"],
  576. 15:[ "Jewelcrafting_Tier3_Waist_Offense_3","Jewelcrafting_Tier3_Refine_Basic","Jewelcrafting_Tier3_Gather_Basic","Jewelcrafting_Tier2_Gather_Basic","Jewelcrafting_Tier1_Gather_Basic"],
  577. 16:["Jewelcrafting_Tier3_Neck_Offense_3","Jewelcrafting_Tier3_Waist_Defense_3", "Jewelcrafting_Tier3_Refine_Basic","Jewelcrafting_Tier3_Gather_Basic","Jewelcrafting_Tier2_Gather_Basic","Jewelcrafting_Tier1_Gather_Basic"],
  578. 17:["Jewelcrafting_Tier3_Neck_Defense_3","Jewelcrafting_Tier3_Waist_Defense_3", "Jewelcrafting_Tier3_Refine_Basic","Jewelcrafting_Tier3_Gather_Basic","Jewelcrafting_Tier2_Gather_Basic","Jewelcrafting_Tier1_Gather_Basic"],
  579. 18:["Jewelcrafting_Tier3_Neck_Defense_3","Jewelcrafting_Tier3_Waist_Defense_3", "Jewelcrafting_Tier3_Refine_Basic","Jewelcrafting_Tier3_Gather_Basic","Jewelcrafting_Tier2_Gather_Basic","Jewelcrafting_Tier1_Gather_Basic"],
  580. 19:["Jewelcrafting_Tier3_Neck_Defense_3","Jewelcrafting_Tier3_Waist_Defense_3", "Jewelcrafting_Tier3_Refine_Basic","Jewelcrafting_Tier3_Gather_Basic","Jewelcrafting_Tier2_Gather_Basic","Jewelcrafting_Tier1_Gather_Basic"],
  581. 20:["Jewelcrafting_Tier2_Refine_Basic","Jewelcrafting_Tier1_Refine_Basic"],
  582. },
  583. },
  584. {
  585. // Mailsmithing
  586. taskName:"Armorsmithing_Med",
  587. level: {
  588. 0:["Med_Armorsmithing_Tier0_Intro"],
  589. 1:["Med_Armorsmithing_Tier1_Chain_Boots_1","Med_Armorsmithing_Tier1_Chain_Shirt_1"],
  590. 2:["Med_Armorsmithing_Tier1_Chain_Armor_1","Med_Armorsmithing_Tier1_Chain_Pants_1"],
  591. 3:["Med_Armorsmithing_Tier1_Chain_Armor_1","Med_Armorsmithing_Tier1_Chain_Boots_Set_1"],
  592. 4:["Med_Armorsmithing_Tier1_Chain_Armor_1","Med_Armorsmithing_Tier1_Chain_Boots_Set_1"],
  593. 5:["Med_Armorsmithing_Tier1_Chain_Armor_Set_1","Med_Armorsmithing_Tier1_Chain_Boots_Set_1"],
  594. 6:["Med_Armorsmithing_Tier1_Chain_Armor_Set_1","Med_Armorsmithing_Tier1_Chain_Boots_Set_1"],
  595. 7:["Med_Armorsmithing_Tier1_Chain_Armor_Set_1","Med_Armorsmithing_Tier2_Chain_Boots_Set_1","Med_Armorsmithing_Tier2_Chain_Shirt"],
  596. 8:["Med_Armorsmithing_Tier2_Chain_Armor_Set_1","Med_Armorsmithing_Tier2_Chain_Pants_1","Med_Armorsmithing_Tier2_Chain_Boots_Set_1","Med_Armorsmithing_Tier2_Chain_Shirt"],
  597. 9:["Med_Armorsmithing_Tier2_Chain_Armor_Set_1","Med_Armorsmithing_Tier2_Chain_Pants_1","Med_Armorsmithing_Tier2_Chain_Boots_Set_1","Med_Armorsmithing_Tier2_Chain_Shirt"],
  598. 10:["Med_Armorsmithing_Tier2_Chain_Armor_Set_1","Med_Armorsmithing_Tier2_Chain_Pants_1","Med_Armorsmithing_Tier2_Chain_Boots_Set_1","Med_Armorsmithing_Tier2_Chain_Shirt_2"],
  599. 11:["Med_Armorsmithing_Tier2_Chain_Armor_Set_1","Med_Armorsmithing_Tier2_Chain_Pants_2","Med_Armorsmithing_Tier2_Chain_Boots_Set_1","Med_Armorsmithing_Tier2_Chain_Shirt_2","Med_Armorsmithing_Tier2_Chain_Pants_1"],
  600. 12:["Med_Armorsmithing_Tier2_Chain_Armor_Set_1","Med_Armorsmithing_Tier2_Chain_Pants_2","Med_Armorsmithing_Tier2_Chain_Boots_Set_1","Med_Armorsmithing_Tier2_Chain_Shirt_2","Med_Armorsmithing_Tier2_Chain_Pants_1"],
  601. 13:["Med_Armorsmithing_Tier2_Chain_Armor_Set_1","Med_Armorsmithing_Tier2_Chain_Pants_2","Med_Armorsmithing_Tier2_Chain_Boots_Set_1","Med_Armorsmithing_Tier2_Chain_Shirt_2","Med_Armorsmithing_Tier2_Chain_Pants_1"],
  602. 14:["Med_Armorsmithing_Tier2_Chain_Armor_Set_1","Med_Armorsmithing_Tier2_Chain_Pants_2","Med_Armorsmithing_Tier3_Chain_Shirt","Med_Armorsmithing_Tier3_Chain_Boots_Set_1"],
  603. 15:["Med_Armorsmithing_Tier3_Chain_Armor_Set_1","Med_Armorsmithing_Tier3_Chain_Pants","Med_Armorsmithing_Tier3_Chain_Shirt2","Med_Armorsmithing_Tier3_Chain_Boots_Set_1"],
  604. 16:["Med_Armorsmithing_Tier3_Chain_Armor_Set_1","Med_Armorsmithing_Tier3_Chain_Pants2","Med_Armorsmithing_Tier3_Chain_Shirt2","Med_Armorsmithing_Tier3_Chain_Helm_Set_1","Med_Armorsmithing_Tier3_Chain_Pants"],
  605. 17:["Med_Armorsmithing_Tier3_Chain_Armor_Set_1","Med_Armorsmithing_Tier3_Chain_Pants2","Med_Armorsmithing_Tier3_Chain_Shirt2","Med_Armorsmithing_Tier3_Chain_Helm_Set_1","Med_Armorsmithing_Tier3_Chain_Pants"],
  606. 18:["Med_Armorsmithing_Tier3_Chain_Armor_Set_1","Med_Armorsmithing_Tier3_Chain_Pants2","Med_Armorsmithing_Tier3_Chain_Shirt2","Med_Armorsmithing_Tier3_Chain_Helm_Set_1","Med_Armorsmithing_Tier3_Chain_Pants"],
  607. 19:["Med_Armorsmithing_Tier3_Chain_Armor_Set_1","Med_Armorsmithing_Tier3_Chain_Pants2","Med_Armorsmithing_Tier3_Chain_Shirt2","Med_Armorsmithing_Tier3_Chain_Helm_Set_1","Med_Armorsmithing_Tier3_Chain_Pants"],
  608. 20:["Med_Armorsmithing_Tier2_Refine_Basic"],
  609. //19:["Chain Armor +4","Fancy Chain Pants","Fancy Chain Shirt","Chain Helm +4","Ornate Chain Pants","Upgrade Blacksmith","Upgrade Prospector","Hire an additional Prospector"],
  610. //20:["Forge Steel Rings and Scales"],
  611. },
  612. },
  613. {
  614. // Platesmithing
  615. taskName:"Armorsmithing_Heavy",
  616. level: {
  617. 0:["Hvy_Armorsmithing_Tier0_Intro"],
  618. 1:["Hvy_Armorsmithing_Tier1_Plate_Boots_1","Hvy_Armorsmithing_Tier1_Plate_Shirt_1","Hvy_Armorsmithing_Tier1_Shield_1"],
  619. 2:["Hvy_Armorsmithing_Tier1_Plate_Armor_1","Hvy_Armorsmithing_Tier1_Plate_Pants_1"],
  620. 3:["Hvy_Armorsmithing_Tier1_Plate_Armor_1","Hvy_Armorsmithing_Tier1_Plate_Boots_Set_1"],
  621. 4:["Hvy_Armorsmithing_Tier1_Plate_Armor_1","Hvy_Armorsmithing_Tier1_Plate_Boots_Set_1"],
  622. 5:["Hvy_Armorsmithing_Tier1_Plate_Armor_Set_1","Hvy_Armorsmithing_Tier1_Plate_Boots_Set_1"],
  623. 6:["Hvy_Armorsmithing_Tier1_Plate_Armor_Set_1","Hvy_Armorsmithing_Tier1_Plate_Boots_Set_1"],
  624. 7:["Hvy_Armorsmithing_Tier1_Plate_Armor_Set_1","Hvy_Armorsmithing_Tier2_Plate_Boots_Set_1","Hvy_Armorsmithing_Tier2_Plate_Shirt","Hvy_Armorsmithing_Tier2_Shield_Set_1"],
  625. 8:["Hvy_Armorsmithing_Tier2_Plate_Armor_Set_1","Hvy_Armorsmithing_Tier2_Plate_Pants_1","Hvy_Armorsmithing_Tier2_Plate_Boots_Set_1","Hvy_Armorsmithing_Tier2_Plate_Shirt"],
  626. 9:["Hvy_Armorsmithing_Tier2_Plate_Armor_Set_1","Hvy_Armorsmithing_Tier2_Plate_Pants_1","Hvy_Armorsmithing_Tier2_Plate_Boots_Set_1","Hvy_Armorsmithing_Tier2_Plate_Shirt"],
  627. 10:["Hvy_Armorsmithing_Tier2_Plate_Armor_Set_1","Hvy_Armorsmithing_Tier2_Plate_Pants_1","Hvy_Armorsmithing_Tier2_Plate_Boots_Set_1","Hvy_Armorsmithing_Tier2_Plate_Shirt_2"],
  628. 11:["Hvy_Armorsmithing_Tier2_Plate_Armor_Set_1","Hvy_Armorsmithing_Tier2_Plate_Pants_2","Hvy_Armorsmithing_Tier2_Plate_Boots_Set_1","Hvy_Armorsmithing_Tier2_Plate_Shirt_2","Hvy_Armorsmithing_Tier2_Plate_Pants_1"],
  629. 12:["Hvy_Armorsmithing_Tier2_Plate_Armor_Set_1","Hvy_Armorsmithing_Tier2_Plate_Pants_2","Hvy_Armorsmithing_Tier2_Plate_Boots_Set_1","Hvy_Armorsmithing_Tier2_Plate_Shirt_2","Hvy_Armorsmithing_Tier2_Plate_Pants_1"],
  630. 13:["Hvy_Armorsmithing_Tier2_Plate_Armor_Set_1","Hvy_Armorsmithing_Tier2_Plate_Pants_2","Hvy_Armorsmithing_Tier2_Plate_Boots_Set_1","Hvy_Armorsmithing_Tier2_Plate_Shirt_2","Hvy_Armorsmithing_Tier2_Plate_Pants_1"],
  631. 14:["Hvy_Armorsmithing_Tier2_Plate_Armor_Set_1","Hvy_Armorsmithing_Tier2_Plate_Pants_2","Hvy_Armorsmithing_Tier3_Plate_Shirt","Hvy_Armorsmithing_Tier3_Plate_Boots_Set_1"],
  632. 15:["Hvy_Armorsmithing_Tier3_Plate_Armor_Set_1","Hvy_Armorsmithing_Tier3_Plate_Pants","Hvy_Armorsmithing_Tier3_Plate_Shirt2","Hvy_Armorsmithing_Tier3_Plate_Boots_Set_1"],
  633. 16:["Hvy_Armorsmithing_Tier3_Plate_Armor_Set_1","Hvy_Armorsmithing_Tier3_Plate_Pants2","Hvy_Armorsmithing_Tier3_Plate_Shirt2","Hvy_Armorsmithing_Tier3_Plate_Helm_Set_1","Hvy_Armorsmithing_Tier3_Plate_Pants"],
  634. 17:["Hvy_Armorsmithing_Tier3_Plate_Armor_Set_1","Hvy_Armorsmithing_Tier3_Plate_Pants2","Hvy_Armorsmithing_Tier3_Plate_Shirt2","Hvy_Armorsmithing_Tier3_Plate_Helm_Set_1","Hvy_Armorsmithing_Tier3_Plate_Pants"],
  635. 18:["Hvy_Armorsmithing_Tier3_Plate_Armor_Set_1","Hvy_Armorsmithing_Tier3_Plate_Pants2","Hvy_Armorsmithing_Tier3_Plate_Shirt2","Hvy_Armorsmithing_Tier3_Plate_Helm_Set_1","Hvy_Armorsmithing_Tier3_Plate_Pants"],
  636. 19:["Hvy_Armorsmithing_Tier3_Plate_Armor_Set_1","Hvy_Armorsmithing_Tier3_Plate_Pants2","Hvy_Armorsmithing_Tier3_Plate_Shirt2","Hvy_Armorsmithing_Tier3_Plate_Helm_Set_1","Hvy_Armorsmithing_Tier3_Plate_Pants"],
  637. 20:["Hvy_Armorsmithing_Tier2_Refine_Basic"],
  638. //19:["Plate Armor +4","Fancy Plate Pants","Fancy Plate Shirt","Plate Helm +4","Ornate Plate Pants","Upgrade Armorer","Upgrade Miner","Hire an additional Miner"],
  639. //20:["Forge Steel Plates"],
  640. },
  641. },
  642. {
  643. taskName:"Leatherworking",
  644. level: {
  645. 0:["Leatherworking_Tier0_Intro_1"],
  646. 1:["Leatherworking_Tier1_Leather_Boots_1","Leatherworking_Tier1_Leather_Shirt_1"],
  647. 2:["Leatherworking_Tier1_Leather_Armor_1","Leatherworking_Tier1_Leather_Pants_1"],
  648. 3:["Leatherworking_Tier1_Leather_Armor_1","Leatherworking_Tier1_Leather_Boots_Set_1"],
  649. 4:["Leatherworking_Tier1_Leather_Armor_1","Leatherworking_Tier1_Leather_Boots_Set_1"],
  650. 5:["Leatherworking_Tier1_Leather_Armor_Set_1","Leatherworking_Tier1_Leather_Boots_Set_1"],
  651. 6:["Leatherworking_Tier1_Leather_Armor_Set_1","Leatherworking_Tier1_Leather_Boots_Set_1"],
  652. 7:["Leatherworking_Tier1_Leather_Armor_Set_1","Leatherworking_Tier2_Leather_Boots_Set_1","Leatherworking_Tier2_Leather_Shirt"],
  653. 8:["Leatherworking_Tier2_Leather_Armor_Set_1","Leatherworking_Tier2_Leather_Pants_1","Leatherworking_Tier2_Leather_Boots_Set_1","Leatherworking_Tier2_Leather_Shirt"],
  654. 9:["Leatherworking_Tier2_Leather_Armor_Set_1","Leatherworking_Tier2_Leather_Pants_1","Leatherworking_Tier2_Leather_Boots_Set_1","Leatherworking_Tier2_Leather_Shirt"],
  655. 10:["Leatherworking_Tier2_Leather_Armor_Set_1","Leatherworking_Tier2_Leather_Pants_1","Leatherworking_Tier2_Leather_Boots_Set_1","Leatherworking_Tier2_Leather_Shirt_2"],
  656. 11:["Leatherworking_Tier2_Leather_Armor_Set_1","Leatherworking_Tier2_Leather_Pants_2","Leatherworking_Tier2_Leather_Boots_Set_1","Leatherworking_Tier2_Leather_Shirt_2","Leatherworking_Tier2_Leather_Pants_1"],
  657. 12:["Leatherworking_Tier2_Leather_Armor_Set_1","Leatherworking_Tier2_Leather_Pants_2","Leatherworking_Tier2_Leather_Boots_Set_1","Leatherworking_Tier2_Leather_Shirt_2","Leatherworking_Tier2_Leather_Pants_1"],
  658. 13:["Leatherworking_Tier2_Leather_Armor_Set_1","Leatherworking_Tier2_Leather_Pants_2","Leatherworking_Tier2_Leather_Boots_Set_1","Leatherworking_Tier2_Leather_Shirt_2","Leatherworking_Tier2_Leather_Pants_1"],
  659. 14:["Leatherworking_Tier2_Leather_Armor_Set_1","Leatherworking_Tier2_Leather_Pants_2","Ornate Leatherworking_Tier1_Leather_Shirt_1","Leatherworking_Tier3_Leather_Boots_Set_1"],
  660. 15:["Leatherworking_Tier3_Leather_Armor_Set_1","Leatherworking_Tier3_Leather_Pants","Leatherworking_Tier3_Leather_Shirt2","Leatherworking_Tier3_Leather_Boots_Set_1"],
  661. 16:["Leatherworking_Tier3_Leather_Armor_Set_1","Leatherworking_Tier3_Leather_Pants2","Leatherworking_Tier3_Leather_Shirt2","Leatherworking_Tier3_Leather_Helm_Set_1","Leatherworking_Tier3_Leather_Pants"],
  662. 17:["Leatherworking_Tier3_Leather_Armor_Set_1","Leatherworking_Tier3_Leather_Pants2","Leatherworking_Tier3_Leather_Shirt2","Leatherworking_Tier3_Leather_Helm_Set_1","Leatherworking_Tier3_Leather_Pants"],
  663. 18:["Leatherworking_Tier3_Leather_Armor_Set_1","Leatherworking_Tier3_Leather_Pants2","Leatherworking_Tier3_Leather_Shirt2","Leatherworking_Tier3_Leather_Helm_Set_1","Leatherworking_Tier3_Leather_Pants"],
  664. 19:["Leatherworking_Tier3_Leather_Armor_Set_1","Leatherworking_Tier3_Leather_Pants2","Leatherworking_Tier3_Leather_Shirt2","Leatherworking_Tier3_Leather_Helm_Set_1","Leatherworking_Tier3_Leather_Pants"],
  665. 20:["Leatherworking_Tier2_Refine_Basic"],
  666. //19:["Leather Armor +4","Fancy Leather Pants","Fancy Leather Shirt","Leather Helm +4","Ornate Leather Pants","Upgrade Tanner","Upgrade Skinner","Hire an additional Skinner"],
  667. //20:["Cure Tough Pelts"],
  668. },
  669. },
  670. {
  671. taskName:"Tailoring",
  672. level: {
  673. 0:["Tailoring_Tier0_Intro"],
  674. 1:["Tailoring_Tier1_Cloth_Boots_1","Tailoring_Tier1_Cloth_Shirt_1"],
  675. 2:["Tailoring_Tier1_Cloth_Armor_1","Tailoring_Tier1_Cloth_Pants_1"],
  676. 3:["Tailoring_Tier1_Cloth_Armor_1","Tailoring_Tier1_Cloth_Boots_Set_1"],
  677. 4:["Tailoring_Tier1_Cloth_Armor_1","Tailoring_Tier1_Cloth_Boots_Set_1"],
  678. 5:["Tailoring_Tier1_Cloth_Armor_Set_1","Tailoring_Tier1_Cloth_Boots_Set_1"],
  679. 6:["Tailoring_Tier1_Cloth_Armor_Set_1","Tailoring_Tier1_Cloth_Boots_Set_1"],
  680. 7:["Tailoring_Tier1_Cloth_Armor_Set_1","Tailoring_Tier2_Cloth_Boots_Set_1","Tailoring_Tier2_Cloth_Shirt"],
  681. 8:["Tailoring_Tier2_Cloth_Armor_Set_1","Tailoring_Tier2_Cloth_Pants_1","Tailoring_Tier2_Cloth_Boots_Set_1","Tailoring_Tier2_Cloth_Shirt"],
  682. 9:["Tailoring_Tier2_Cloth_Armor_Set_1","Tailoring_Tier2_Cloth_Pants_1","Tailoring_Tier2_Cloth_Boots_Set_1","Tailoring_Tier2_Cloth_Shirt"],
  683. 10:["Tailoring_Tier2_Cloth_Armor_Set_1","Tailoring_Tier2_Cloth_Pants_1","Tailoring_Tier2_Cloth_Boots_Set_1","Tailoring_Tier2_Cloth_Shirt_2"],
  684. 11:["Tailoring_Tier2_Cloth_Armor_Set_1","Tailoring_Tier2_Cloth_Pants_2","Tailoring_Tier2_Cloth_Boots_Set_1","Tailoring_Tier2_Cloth_Shirt_2","Tailoring_Tier2_Cloth_Pants_1"],
  685. 12:["Tailoring_Tier2_Cloth_Armor_Set_1","Tailoring_Tier2_Cloth_Pants_2","Tailoring_Tier2_Cloth_Boots_Set_1","Tailoring_Tier2_Cloth_Shirt_2","Tailoring_Tier2_Cloth_Pants_1"],
  686. 13:["Tailoring_Tier2_Cloth_Armor_Set_1","Tailoring_Tier2_Cloth_Pants_2","Tailoring_Tier2_Cloth_Boots_Set_1","Tailoring_Tier2_Cloth_Shirt_2","Tailoring_Tier2_Cloth_Pants_1"],
  687. 14:["Tailoring_Tier2_Cloth_Armor_Set_1","Tailoring_Tier2_Cloth_Pants_2", "Tailoring_Tier3_Cloth_Shirt","Tailoring_Tier3_Cloth_Boots_Set_1"],
  688. 15:["Tailoring_Tier3_Cloth_Armor_Set_1","Tailoring_Tier3_Cloth_Pants","Tailoring_Tier3_Cloth_Shirt2","Tailoring_Tier3_Cloth_Boots_Set_1"],
  689. 16:["Tailoring_Tier3_Cloth_Armor_Set_1","Tailoring_Tier3_Cloth_Pants2","Tailoring_Tier3_Cloth_Shirt2","Tailoring_Tier3_Cloth_Helm_Set_1","Tailoring_Tier3_Cloth_Pants"],
  690. 17:["Tailoring_Tier3_Cloth_Armor_Set_1","Tailoring_Tier3_Cloth_Pants2","Tailoring_Tier3_Cloth_Shirt2","Tailoring_Tier3_Cloth_Helm_Set_1","Tailoring_Tier3_Cloth_Pants"],
  691. 18:["Tailoring_Tier3_Cloth_Armor_Set_1","Tailoring_Tier3_Cloth_Pants2","Tailoring_Tier3_Cloth_Shirt2","Tailoring_Tier3_Cloth_Helm_Set_1","Tailoring_Tier3_Cloth_Pants"],
  692. 19:["Tailoring_Tier3_Cloth_Armor_Set_1","Tailoring_Tier3_Cloth_Pants2","Tailoring_Tier3_Cloth_Shirt2","Tailoring_Tier3_Cloth_Helm_Set_1","Tailoring_Tier3_Cloth_Pants"],
  693. 20:["Tailoring_Tier2_Refine_Basic"],
  694. //19:["Cloth Robes +4","Fancy Cloth Pants","Fancy Cloth Shirt","Cloth Cap +4","Ornate Cloth Pants","Upgrade Outfitter","Upgrade Weaver","Hire an additional Weaver"],
  695. //20:["Weave Cotton Cloth"],
  696. },
  697. },
  698. {
  699. taskName:"Artificing",
  700. level: {
  701. 0:["Artificing_Tier0_Intro_1"],
  702. 1:["Artificing_Tier1_Symbol_Virtuous_1"],
  703. 2:["Artificing_Tier1_Icon_Virtuous_1"],
  704. 3:["Artificing_Tier1_Icon_Virtuous_1"],
  705. 4:["Artificing_Tier1_Icon_Virtuous_2"],
  706. 5:["Artificing_Tier1_Icon_Virtuous_2"],
  707. 6:["Artificing_Tier1_Icon_Virtuous_2"],
  708. 7:["Artificing_Tier1_Icon_Virtuous_2"],
  709. 8:["Artificing_Tier2_Icon_Virtuous_3"],
  710. 9:["Artificing_Tier2_Icon_Virtuous_3"],
  711. 10:["Artificing_Tier2_Icon_Virtuous_3"],
  712. 11:["Artificing_Tier2_Icon_Virtuous_3"],
  713. 12:["Artificing_Tier2_Icon_Virtuous_3"],
  714. 13:["Artificing_Tier2_Icon_Virtuous_3"],
  715. 14:["Artificing_Tier3_Icon_Virtuous_4"],
  716. 15:["Artificing_Tier3_Icon_Virtuous_4"],
  717. 16:["Artificing_Tier3_Icon_Virtuous_4"],
  718. 17:["Artificing_Tier3_Icon_Virtuous_5"],
  719. 18:["Artificing_Tier3_Icon_Virtuous_5"],
  720. 19:["Artificing_Tier3_Icon_Virtuous_5"],
  721. 20:["Artificing_Tier2_Refine_Basic"],
  722. //19:["Virtuous Icon +5","Upgrade Engraver","Upgrade Carver","Hire an additional Carver"],
  723. //20:["7:Craft Ornamental metal and Carved Wood"],
  724. },
  725. },
  726. {
  727. taskName:"Weaponsmithing",
  728. level: {
  729. 0:["Weaponsmithing_Tier0_Intro"],
  730. 1:["Weaponsmithing_Tier1_Dagger_1"],
  731. 2:["Weaponsmithing_Tier1_Dagger_1"],
  732. 3:["Weaponsmithing_Tier1_Dagger_1"],
  733. 4:["Weaponsmithing_Tier1_Dagger_2"],
  734. 5:["Weaponsmithing_Tier1_Dagger_2"],
  735. 6:["Weaponsmithing_Tier1_Dagger_2"],
  736. 7:["Weaponsmithing_Tier2_Dagger_3"],
  737. 8:["Weaponsmithing_Tier2_Dagger_3"],
  738. 9:["Weaponsmithing_Tier2_Dagger_3"],
  739. 10:["Weaponsmithing_Tier2_Dagger_3"],
  740. 11:["Weaponsmithing_Tier2_Dagger_3"],
  741. 12:["Weaponsmithing_Tier2_Dagger_3"],
  742. 13:["Weaponsmithing_Tier2_Dagger_3"],
  743. 14:["Weaponsmithing_Tier3_Dagger_4"],
  744. 15:["Weaponsmithing_Tier3_Dagger_4"],
  745. 16:["Weaponsmithing_Tier3_Dagger_4"],
  746. 17:["Weaponsmithing_Tier3_Dagger_4"],
  747. 18:["Weaponsmithing_Tier3_Dagger_4"],
  748. 19:["Weaponsmithing_Tier3_Dagger_4"],
  749. 20:["Weaponsmithing_Tier2_Refine_Basic"],
  750. //19:["Dagger+4","Upgrade Grinder","Upgrade Smelter","Hire an additional Smelter"],
  751. //20:["Craft Steel Blades and Barausk Hafts"],
  752. },
  753. },
  754. {
  755. taskName:"Alchemy",
  756. level: {
  757. 0:["Alchemy_Tier0_Intro_1"],
  758. 1:["Alchemy_Tier1_Experiment_Rank2","Alchemy_Tier1_Experimentation_Rank1"],
  759. 2:["Alchemy_Tier1_Experiment_Rank3","Alchemy_Tier1_Experimentation_Rank2"],
  760. 3:["Alchemy_Tier1_Experiment_Rank4","Alchemy_Tier1_Experimentation_Rank3"],
  761. 4:["Alchemy_Tier1_Experiment_Rank5","Alchemy_Tier1_Experimentation_Rank4"],
  762. 5:["Alchemy_Tier1_Experiment_Rank6","Alchemy_Tier1_Experimentation_Rank5"],
  763. 6:["Alchemy_Tier1_Experiment_Rank7","Alchemy_Tier1_Experimentation_Rank6"],
  764. 7:["Alchemy_Tier2_Experiment_Rank08","Alchemy_Tier2_Experimentation_Rank07"],
  765. 8:["Alchemy_Tier2_Experiment_Rank09","Alchemy_Tier2_Experimentation_Rank08"],
  766. 9:["Alchemy_Tier2_Experiment_Rank10","Alchemy_Tier2_Experimentation_Rank09"],
  767. 10:["Alchemy_Tier2_Experiment_Rank11","Alchemy_Tier2_Experimentation_Rank10"],
  768. 11:["Alchemy_Tier2_Experiment_Rank12","Alchemy_Tier2_Experimentation_Rank11"],
  769. 12:["Alchemy_Tier2_Experiment_Rank13","Alchemy_Tier2_Experimentation_Rank12"],
  770. 13:["Alchemy_Tier2_Experiment_Rank14","Alchemy_Tier2_Experimentation_Rank13"],
  771. 14:["Alchemy_Tier3_Experiment_Rank15","Alchemy_Tier3_Experimentation_Rank14"],
  772. 15:["Alchemy_Tier3_Experiment_Rank16","Alchemy_Tier3_Experimentation_Rank15"],
  773. 16:["Alchemy_Tier3_Experiment_Rank17","Alchemy_Tier3_Experimentation_Rank16"],
  774. 17:["Alchemy_Tier3_Experiment_Rank18","Alchemy_Tier3_Experimentation_Rank17"],
  775. 18:["Alchemy_Tier3_Experiment_Rank19","Alchemy_Tier3_Experimentation_Rank18"],
  776. 19:["Alchemy_Tier3_Experiment_Rank20","Alchemy_Tier3_Experimentation_Rank19"],
  777. //20:["Alchemy_Tier3_Experimentation_Rank20"],
  778. //19:["Alchemical Research","Rank 20 Experimentation","Upgrade Mixologist","Upgrade Apothecary","Hire an additional Apothecary"],
  779. //20:["Alchemy_Tier2_Aquavitae_2"],
  780. 20:["Alchemy_Tier3_Potency_Potion_Major","Alchemy_Tier2_Aquaregia","Alchemy_Tier3_Refine_Basic","Alchemy_Tier3_Gather_Components"],
  781. },
  782. },
  783. ];
  784. // Load Settings
  785. var settingnames = [
  786. {name: 'paused', title: 'Pause Script', def: false, type:'checkbox', tooltip:'Disable All Automation'},
  787. {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;}},
  788. {name: 'optionals', title: 'Fill Optional Assets', def: true, type:'checkbox', tooltip:'Enable to include selecting the optional assets of tasks'},
  789. {name: 'autopurchase', title: 'Auto Purchase Resources', def: true, type:'checkbox', tooltip:'Automatically purchase required resources from gateway shop (100 at a time)'},
  790. {name: 'trainassets', title: 'Train Assets', def: true, type:'checkbox', tooltip:'Enable training/upgrading of asset worker resources'},
  791. {name: 'refinead', title: 'Refine AD', def: true, type:'checkbox', tooltip:'Enable refining of AD on character switch'},
  792. {name: 'openrewards', title: 'Open Reward Chests', def: false, type:'checkbox', tooltip:'Enable opeing of leadership chests on character switch'}, //MAC-NW
  793. {name: 'autoreload', title: 'Auto Reload', def: false, type:'checkbox', tooltip:'Enabling this will reload the gateway periodically. (Ensure Auto Login is enabled)'},
  794. {name: 'autologin', title: 'Attempt to login automatically', def: false, type:'checkbox', tooltip:'Automatically attempt to login to the neverwinter gateway site'},
  795. {name: 'nw_username', title: ' Neverwinter Username', def: '', type:'text', tooltip:''},
  796. {name: 'nw_password', title: ' Neverwinter Password', def: '', type:'password', tooltip:''},
  797. {name: 'charcount', title: ' Number of Characters', def: '2', type:'text', tooltip:'Enter number of characters to use (reload page to update settings form)'},
  798. // MAC-NW AD Consolidation
  799. {name: 'autoexchange', title: 'Consolidate AD via ZEX', def: false, type:'checkbox', tooltip:'Automatically attempt to post, cancel and withdraw AD via ZEX and consolidate to designated character'},
  800. {name: 'bankchar', title: ' Character Name of Banker', def: '', type:'text', tooltip:'Enter name of the character to hold account AD'},
  801. {name: 'banktransmin', title: ' Min AD for Transfer', def: '22000', type:'text', tooltip:'Enter minimum AD limit for it to be cosidered for transfer off a character'},
  802. {name: 'bankcharmin', title: ' Min Character balance', def: '8000', type:'text', tooltip:'Enter the amount of AD to always keep available on characters'},
  803. {name: 'banktransrate', title: ' AD per Zen Rate (in zen)', def: '300', type:'text', tooltip:'Enter default rate to use for transfering through ZEX'},
  804. // MAC-NW
  805. ];
  806. // Load local settings cache (unsecured)
  807. var settings = {};
  808. for (var i = 0; i < settingnames.length; i++) {
  809. // Ignore label types
  810. if (settingnames[i].type === 'label') {
  811. continue;
  812. }
  813. settings[settingnames[i].name] = GM_getValue(settingnames[i].name, settingnames[i].def);
  814. // call the onsave for the setting if it exists
  815. if (typeof(settingnames[i].onsave) === "function") {
  816. console.log("Calling 'onsave' for", settingnames[i].name);
  817. settingnames[i].onsave(settings[settingnames[i].name], settings[settingnames[i].name]);
  818. }
  819. }
  820. if (settings["charcount"]<1) { settings["charcount"] = 1; }
  821. if (settings["charcount"]>99) { settings["charcount"] = 99; }
  822.  
  823. var charSettings = [];
  824. for (var i = 0; i < settings["charcount"]; i++) {
  825. charSettings.push({name: 'nw_charname'+i, title: 'Character', def: 'Character '+(i+1), type:'text', tooltip:'Characters Name'});
  826. charSettings.push({name: 'WinterEvent'+i, title: 'WinterEvent', def: '0', type:'text', tooltip:'Number of slots to assign to WinterEvent'});
  827. charSettings.push({name: 'Leadership'+i, title: 'Leadership', def: '9', type:'text', tooltip:'Number of slots to assign to Leadership'});
  828. charSettings.push({name: 'BlackIce'+i, title: 'Black Ice Shaping',def: '0', type:'text', tooltip:'Number of slots to assign to BIS'});
  829. charSettings.push({name: 'Jewelcrafting'+i, title: 'Jewelcrafting', def: '0', type:'text', tooltip:'Number of slots to assign to Jewelcrafting'});
  830. charSettings.push({name: 'Armorsmithing_Med'+i, title: 'Mailsmithing', def: '0', type:'text', tooltip:'Number of slots to assign to Mailsmithing'});
  831. charSettings.push({name: 'Armorsmithing_Heavy'+i, title: 'Platesmithing', def: '0', type:'text', tooltip:'Number of slots to assign to Platesmithing'});
  832. charSettings.push({name: 'Leatherworking'+i, title: 'Leatherworking', def: '0', type:'text', tooltip:'Number of slots to assign to Leatherworking'});
  833. charSettings.push({name: 'Tailoring'+i, title: 'Tailoring', def: '0', type:'text', tooltip:'Number of slots to assign to Tailoring'});
  834. charSettings.push({name: 'Artificing'+i, title: 'Artificing', def: '0', type:'text', tooltip:'Number of slots to assign to Artificing'});
  835. charSettings.push({name: 'Weaponsmithing'+i, title: 'Weaponsmithing', def: '0', type:'text', tooltip:'Number of slots to assign to Weaponsmithing'});
  836. charSettings.push({name: 'Alchemy'+i, title: 'Alchemy', def: '0', type:'text', tooltip:'Number of slots to assign to Alchemy'});
  837.  
  838. // task settings are slightly different
  839. charSettings.push({name: 'tasklist'+i, title: 'Task List', def: '', type:'void', tooltip:''});
  840. }
  841. for (var i = 0; i < charSettings.length; i++) {
  842. settings[charSettings[i].name] = GM_getValue(charSettings[i].name, charSettings[i].def);
  843. }
  844. // Page Settings
  845. var PAGES = Object.freeze({
  846. LOGIN : { name: "Login", path: "div#login"},
  847. GUARD : { name: "Account Guard", path: "div#page-accountguard"},
  848. });
  849.  
  850. /**
  851. * Uses the page settings to determine which page is currently displayed
  852. */
  853. function GetCurrentPage() {
  854. for each(var page in PAGES) {
  855. if ($(page["path"]).filter(":visible").length) {
  856. return page;
  857. }
  858. }
  859. }
  860. /**
  861. * Logs in to gateway
  862. * No client.dataModel exists at this stage
  863. */
  864. function page_LOGIN() {
  865. //if (!$("form > p.error:visible").length && settings["autologin"]) {
  866. // No previous log in error - attempt to log in
  867. console.log("Setting username");
  868. $("input#user").val(settings["nw_username"]);
  869. console.log("Setting password");
  870. $("input#pass").val(settings["nw_password"]);
  871. console.log("Clicking Login Button");
  872. $("div#login > input").click();
  873. //}
  874. dfdNextRun.resolve(delay.LONG);
  875. }
  876. /**
  877. * Action to perform on account guard page
  878. */
  879. function page_GUARD() {
  880. // Do nothing on the guard screen
  881. dfdNextRun.resolve(delay.LONG);
  882. }
  883.  
  884. /**
  885. * Collects rewards for tasks or starts new tasks
  886. * Function is called once per new task and returns true if an action is created
  887. * If no action is started function returns false to switch characters
  888. */
  889. function processCharacter() {
  890. // Switch to professions page to show task progression
  891. unsafeWindow.location.hash="#char("+encodeURI(unsafeWindow.client.getCurrentCharAtName())+")/professions";
  892. // Collect rewards for completed tasks and restart
  893. if (unsafeWindow.client.dataModel.model.ent.main.itemassignments.complete) {
  894. unsafeWindow.client.dataModel.model.ent.main.itemassignments.assignments.forEach(function(entry) {
  895. if (entry.hascompletedetails) { unsafeWindow.client.professionTaskCollectRewards(entry.uassignmentid); }
  896. });
  897. dfdNextRun.resolve();
  898. return true;
  899. }
  900. // Check for available slots and start new task
  901. if (unsafeWindow.client.dataModel.model.ent.main.itemassignments.assignments.filter(function(entry) { return (!entry.islockedslot && !entry.uassignmentid); }).length) {
  902. // Go through the professions to assign tasks until specified slots filled
  903. for (var i = 0; i < tasklist.length; i++) {
  904. if (settings[tasklist[i].taskName] > 0) { //MAC-NW
  905. var currentTasks = unsafeWindow.client.dataModel.model.ent.main.itemassignments.assignments.filter(function(entry) { return entry.category == tasklist[i].taskName; });
  906. if (currentTasks.length < settings[tasklist[i].taskName]) {
  907. unsafeWindow.client.professionFetchTaskList('craft_' + tasklist[i].taskName);
  908. unsafeWindow.client.dataModel.fetchVendor('Nw_Gateway_Professions_Merchant');
  909. window.setTimeout(function() { createNextTask(tasklist[i], 0); }, delay.SHORT);
  910. return true;
  911. }
  912. } //MAC-NW
  913. }
  914. console.log("All task counts assigned");
  915. }
  916. else {
  917. console.log("No available task slots");
  918. }
  919. // TODO: Add code to get next task finish time
  920. chartimers[charcurrent] = getNextFinishedTask();
  921. // Add diamond count 883 // Add diamond count
  922. chardiamonds[charcurrent] = unsafeWindow.client.dataModel.model.ent.main.currencies.diamonds;
  923. return false;
  924. }
  925. /**
  926. * Finds the task finishing next & returns the date or NULL otherwise
  927. *
  928. * @return {Date} / {null}
  929. */
  930. function getNextFinishedTask() {
  931. var tmpNext, next = null;
  932. unsafeWindow.client.dataModel.model.ent.main.itemassignments.assignments.forEach(function(entry) {
  933. if (entry.uassignmentid) {
  934. tmpNext = new Date(entry.ufinishdate);
  935. if (!next || tmpNext < next) { next = tmpNext; }
  936. }
  937. });
  938. if (next) {
  939. console.log("Next finished task at " + next.toLocaleString());
  940. } else {
  941. console.log("No next finishing date found!!");
  942. }
  943. return next;
  944. }
  945.  
  946. /**
  947. * Iterative approach to finding the next task to assign to an open slot.
  948. *
  949. * @param {Array} prof The tasklist for the profession being used
  950. * @param {int} i The current task number being attempted
  951. */
  952. function createNextTask(prof, i) {
  953. // TODO: Use callback function
  954. if (!unsafeWindow.client.dataModel.model.craftinglist || unsafeWindow.client.dataModel.model.craftinglist === null || !unsafeWindow.client.dataModel.model.craftinglist['craft_' + prof.taskName] || unsafeWindow.client.dataModel.model.craftinglist['craft_' + prof.taskName] === null) {
  955. console.log('Task list not loaded for:', prof.taskName);
  956. window.setTimeout(function() { createNextTask(prof, i); }, delay.SHORT);
  957. return false;
  958. }
  959.  
  960. // Check level
  961. var level = unsafeWindow.client.dataModel.model.ent.main.itemassignmentcategories.categories.filter(function(entry) { return entry.name == prof.taskName; })[0].currentrank;
  962. var list = prof.level[level];
  963. if (list.length <=i) {
  964. console.log("Nothing Found");
  965. switchChar();
  966. return false;
  967. }
  968. console.log(prof.taskName, "is level", level);
  969. console.log("createNextTask", list.length, i);
  970.  
  971. var taskName = list[i];
  972. console.log("Searching for task:", taskName);
  973. // Search for task to start
  974. var task = searchForTask(taskName, prof.taskName);
  975.  
  976. /** TODO: Use this code once below can be replaced properly
  977. if (task === null) {
  978. console.log("Skipping task selection to purchase resources");
  979. dfdNextRun.resolve();
  980. }
  981. else if (task) {
  982. startTask(task);
  983. dfdNextRun.resolve();
  984. }
  985. else {
  986. console.log('Finding next task');
  987. createNextTask(prof, i+1);
  988. }
  989. **/
  990.  
  991.  
  992. // Finish createNextTask function
  993. if (task === null) {
  994. console.log("Skipping task selection to purchase resources");
  995. dfdNextRun.resolve();
  996. return true;
  997. }
  998. if (task) {
  999. task = '/professions-tasks/' + prof.taskName + '/' + task.def.name;
  1000. console.log('Task Found');
  1001. unsafeWindow.location.hash = unsafeWindow.location.hash.replace(/\)\/.+/,')' + task);
  1002. WaitForState("div.page-professions-taskdetails").done(function() {
  1003. // Click all buttons and select an item to use in the slot
  1004. var def = $.Deferred();
  1005. var buttonList = $("h3:contains('Optional Assets:')").closest("div").find("button");
  1006. if (buttonList.length && settings["optionals"]) {
  1007. SelectItemFor(buttonList, 0, def, prof);
  1008. }
  1009. else {
  1010. def.resolve();
  1011. }
  1012. def.done(function() {
  1013. // All items are populated
  1014. console.log("Items Populated");
  1015. // Click the Start Task Button
  1016. //Get the start task button if it is enabled
  1017. var enabledButton = $("div.footer-body > div.input-field.button:not('.disabled') > button:contains('Start Task')");
  1018. if (enabledButton.length) {
  1019. console.log("Clicking Start Task Button");
  1020. enabledButton.click();
  1021. WaitForState("").done(function() {
  1022. // Done
  1023. dfdNextRun.resolve(delay.SHORT);
  1024. });
  1025. return true;
  1026. }
  1027. else { // Button not enabled, something required was probably missing
  1028. // Go back
  1029. $("div.footer-body > div.input-field.button > button:contains('Back')").click();
  1030. WaitForState("").done(function() {
  1031. // continue with the next one
  1032. console.log('Finding next task');
  1033. createNextTask(prof, i+1);
  1034. });
  1035. }
  1036. });
  1037. });
  1038. }
  1039. else {
  1040. console.log('Finding next task');
  1041. createNextTask(prof, i+1);
  1042. }
  1043. }
  1044. /**
  1045. * Checks task being started for requirements and initiates beginning task if found
  1046. *
  1047. * @param {string} taskname The name of the task being started
  1048. * @param {string} profname The name of the profession being used
  1049. * @param {Deferred} dfd Deferred object to process on return
  1050. */
  1051. function searchForTask(taskname, profname) {
  1052. // Return first object that matches exact craft name
  1053. var thisTask = unsafeWindow.client.dataModel.model.craftinglist['craft_' + profname].entries.filter(function(entry) {
  1054. return entry.def && entry.def.name == taskname;
  1055. })[0];
  1056. // If no task is returned we either have three of this task already, the task is a rare that doesn't exist currently, or we have the name wrong in tasklist
  1057. if (!thisTask) {
  1058. console.log('Could not find task for:', taskname);
  1059. return false;
  1060. }
  1061. // start task if requirements are met
  1062. if (!thisTask.failedrequirementsreasons.length) {
  1063. return thisTask;
  1064. }
  1065. // Too high level
  1066. if (thisTask.failslevelrequirements) {
  1067. console.log("Task level is too high:", taskname);
  1068. return false;
  1069. }
  1070. var searchItem = null;
  1071. var searchAsset = false;
  1072. // Missing assets or ingredients
  1073. if (thisTask.failsresourcesrequirements) {
  1074. var failedAssets = thisTask.required.filter(function(entry) { return !entry.fillsrequirements; });
  1075. // Missing required assets
  1076. if (failedAssets.length) {
  1077. var failedCrafter = failedAssets.filter(function(entry) { return entry.categories.indexOf("Person") >= 0; });
  1078. if (failedCrafter.length && settings["trainassets"]) {
  1079. console.log("Found required asset:", failedCrafter[0].icon);
  1080. searchItem = failedCrafter[0].icon;
  1081. searchAsset = true;
  1082. }
  1083. else {
  1084. // TODO: Automatically purchase item assets from shop
  1085. console.log("Not enough assets for task:", taskname);
  1086. return false;
  1087. }
  1088. }
  1089.  
  1090. // Check for craftable or buyable ingredients
  1091. else {
  1092. var failedResources = thisTask.consumables.filter(function(entry) { return entry.required && !entry.fillsrequirements; });
  1093. // Check first required ingredient only
  1094. // If it fails to buy or craft task cannot be completed anyway
  1095. // If it succeeds script will search for tasks anew
  1096. var itemName = failedResources[0].hdef.match(/\[(\w+)\]/)[1];
  1097. // purchase buyable resources
  1098. if (itemName.match(/^Crafting_Resource_(Charcoal|Rocksalt|Spool_Thread|Porridge|Solvent|Brimstone|Coal|Moonseasalt|Quicksilver|Spool_Threadsilk)$/)) {
  1099. if (settings["autopurchase"]) {
  1100. buyResource(itemName);
  1101. return null;
  1102. }
  1103. else {
  1104. console.log("Buyable resource required for:", taskname);
  1105. return false;
  1106. }
  1107. }
  1108. // craft ingredient items
  1109. else {
  1110. console.log("Found required ingredient:", itemName);
  1111. searchItem = itemName;
  1112. }
  1113. }
  1114. }
  1115. // either no craftable items/assets found or other task requirements are not met
  1116. // Skip crafting ingredient tasks for Leadership
  1117. if (searchItem === null || !searchItem.length || (profname == 'Leadership' && !searchAsset && !searchItem.match(/Crafting_Asset_Craftsman/))) {
  1118. console.log("Failed to resolve item requirements for task:", taskname);
  1119. return false;
  1120. }
  1121.  
  1122. // Generate list of available tasks to search ingredients/assets from
  1123. console.log("Searching ingredient tasks for:", profname);
  1124. var taskList = unsafeWindow.client.dataModel.model.craftinglist['craft_' + profname].entries.filter(function(entry) {
  1125. // remove header lines first to avoid null def
  1126. if (entry.isheader) { return false; }
  1127. // Too high level
  1128. if (entry.failslevelrequirements) { return false; }
  1129. // Rewards do not contain item we want to make
  1130. if (searchAsset) {
  1131. if (entry.def.icon != searchItem || !entry.def.name.match(/Recruit/) || entry.def.requiredrank > 14) { return false; }
  1132. }
  1133. else {
  1134. if (!(entry.rewards.some(function (itm) { try { return itm.hdef.match(/\[(\w+)\]/)[1] == searchItem; } catch(e) {} }))) { return false; }
  1135. }
  1136. // Skip mass production tasks
  1137. if (entry.def.displayname.match(/^(Batch|Mass|Deep|Intensive) /)) { return false; }
  1138. // Skip trading tasks
  1139. if (entry.def.displayname.match(/rading$/)) { return false; }
  1140. // Skip looping Transmute tasks
  1141. if (entry.def.displayname.match(/^(Transmute|Create) /)) { return false; }
  1142. return true;
  1143. });
  1144. if (!taskList.length) {
  1145. console.log("No ingredient tasks found for:", taskname, searchItem);
  1146. return false;
  1147. }
  1148. // Use more efficient Empowered task for Aqua Vitae if available.
  1149. if (searchItem == "Crafting_Resource_Aquavitae" && taskList.length > 1) { taskList.shift(); }
  1150. // Should really only be one result now but lets iterate through anyway.
  1151. for (var i = 0; i < taskList.length; i++) {
  1152. console.log("Attempting search for ingredient task:", taskList[i].def.name);
  1153. var task = searchForTask(taskList[i].def.name, profname);
  1154. if (task === null || task) {
  1155. return task;
  1156. }
  1157. }
  1158. return false;
  1159. }
  1160. /** --------- MAC-NW : Unused old function
  1161. * Fills resource slots and begins a profession task
  1162. *
  1163. * @param {string} taskDetail The craftindetail object for the task to be started
  1164. function startTask(taskDetail) {
  1165. return;
  1166. unsafeWindow.client.professionFetchTaskDetail(taskDetail.def.name);
  1167. //client.dataModel.addDefaultResources();
  1168. client.professionStartAssignment(taskDetail.def.name);
  1169. }*/
  1170.  
  1171. /**
  1172. * Selects the highest level asset for the i'th button in the list. Uses an iterative approach
  1173. * in order to apply a sufficient delay after the asset is assigned
  1174. *
  1175. * @param {Array} The list of buttons to use to click and assign assets for
  1176. * @param {int} i The current iteration number. Will select assets for the i'th button
  1177. * @param {Deferred} jQuery Deferred object to resolve when all of the assets have been assigned
  1178. */
  1179. function SelectItemFor(buttonListIn, i, def, prof) {
  1180. buttonListIn[i].click();
  1181. WaitForState("").done(function() {
  1182. var $assets = $("div.modal-item-list a").has("img[src*='_Resource_'],img[src*='_Assets_']");
  1183. var $persons = $("div.modal-item-list a").has("img[src*='_Follower_']");
  1184. var quality = [".Special",".Gold",".Silver",".Bronze"];
  1185. var ic, $it;
  1186. var clicked = false;
  1187.  
  1188. // Try to avoid using up higher rank assets needlessly
  1189. if (prof.taskName === "Leadership") {
  1190. var mercenarys = $("div.modal-item-list a.Bronze:contains('Mercenary')");
  1191. var guards = $("div.modal-item-list a.Bronze:contains('Guard')");
  1192. var footmen = $("div.modal-item-list a.Bronze:contains('Footman')");
  1193.  
  1194. if (mercenarys.length) { clicked = true; mercenarys[0].click(); }
  1195. else if (guards.length) { clicked = true; guards[0].click(); }
  1196. else if (footmen.length) { clicked = true; footmen[0].click(); }
  1197. }
  1198. // check resources & assets for best quality, in descending order
  1199. for (ic in quality) {
  1200. $it = $assets.filter(quality[ic]);
  1201. if ($it.length) {
  1202. $it[0].click();
  1203. clicked = true;
  1204. break;
  1205. }
  1206. }
  1207. // if no asset was selected, check for persons for best speed, in descending order
  1208. if (!clicked) {
  1209. for (ic in quality) {
  1210. $it = $persons.filter(quality[ic]);
  1211. if ($it.length) {
  1212. $it[0].click();
  1213. clicked = true;
  1214. break;
  1215. }
  1216. }
  1217. }
  1218. // if nothing was found at all, return immediately (skip other optional slots)
  1219. if (!clicked) {
  1220. $("button.close-button").click();
  1221. console.log("Nothing more to click..");
  1222. WaitForState("").done(function() {
  1223. // Let main loop continue
  1224. def.resolve();
  1225. });
  1226. }
  1227.  
  1228. console.log("Clicked item");
  1229. WaitForState("").done(function() {
  1230. // Get the new set of select buttons created since the other ones are removed when the asset loads
  1231. var buttonList = $("h3:contains('Optional Assets:')").closest("div").find("button");
  1232. if(i < buttonList.length - 1) {
  1233. SelectItemFor(buttonList, i+1, def, prof);
  1234. }
  1235. else {
  1236. // Let main loop continue
  1237. def.resolve();
  1238. }
  1239. });
  1240. });
  1241. }
  1242. /* ################# original
  1243. function SelectItemFor(buttonListIn, i, def, prof) {
  1244. buttonListIn[i].click();
  1245. WaitForState("").done(function() {
  1246. var specialItems = $("div.modal-item-list a.Special");
  1247. var goldItems = $("div.modal-item-list a.Gold");
  1248. var silverItems = $("div.modal-item-list a.Silver");
  1249. var bronzeItems = $("div.modal-item-list a.Bronze");
  1250. var clicked = false;
  1251.  
  1252. // Try to avoid using up higher rank assets needlessly
  1253. if (prof.taskName === "Leadership") {
  1254. var mercenarys = $("div.modal-item-list a.Bronze:contains('Mercenary')");
  1255. var guards = $("div.modal-item-list a.Bronze:contains('Guard')");
  1256. var footmen = $("div.modal-item-list a.Bronze:contains('Footman')");
  1257.  
  1258. if (mercenarys.length) { clicked = true; mercenarys[0].click(); }
  1259. else if (guards.length) { clicked = true; guards[0].click(); }
  1260. else if (footmen.length) { clicked = true; footmen[0].click(); }
  1261. }
  1262. // TODO: add remaining professions in the same way for bronze tier assets.
  1263.  
  1264. if (!clicked) {
  1265. // Click the highest slot
  1266. if (specialItems.length) { specialItems[0].click(); }
  1267. else if (goldItems.length) { goldItems[0].click(); }
  1268. else if (silverItems.length) { silverItems[0].click(); }
  1269. else if (bronzeItems.length) { bronzeItems[0].click(); }
  1270. else { $("button.close-button").click(); }
  1271. }
  1272.  
  1273. console.log("Clicked item");
  1274. WaitForState("").done(function() {
  1275. // Get the new set of select buttons created since the other ones are removed when the asset loads
  1276. var buttonList = $("h3:contains('Optional Assets:')").closest("div").find("button");
  1277. if (i < buttonList.length - 1) {
  1278. SelectItemFor(buttonList, i+1, def, prof);
  1279. }
  1280. else {
  1281. // Let main loop continue
  1282. def.resolve();
  1283. }
  1284. });
  1285. });
  1286. }
  1287. */
  1288. /**
  1289. * Will buy a given purchasable resource
  1290. *
  1291. * @param {String} item The data-tt-item id of the Resource to purchase
  1292. */
  1293. function buyResource(item) {
  1294. console.log("Purchasing resources:", item);
  1295. var resourceID = {
  1296. Crafting_Resource_Charcoal : 0,
  1297. Crafting_Resource_Rocksalt : 1,
  1298. Crafting_Resource_Spool_Thread : 2,
  1299. Crafting_Resource_Porridge : 3,
  1300. Crafting_Resource_Solvent : 4,
  1301. Crafting_Resource_Brimstone : 5,
  1302. Crafting_Resource_Coal : 6,
  1303. Crafting_Resource_Moonseasalt : 7,
  1304. Crafting_Resource_Quicksilver : 8,
  1305. Crafting_Resource_Spool_Threadsilk : 9,
  1306. };
  1307. // Make purchase
  1308. unsafeWindow.client.sendCommand("GatewayVendor_PurchaseVendorItem",{vendor:'Nw_Gateway_Professions_Merchant',store:'Store_Crafting_Resources',idx:resourceID[item],count:50}); // MAC-NW: Purchase of prof resources lowred from 100 to 30
  1309. WaitForState("button.closeNotification").done(function() {
  1310. $("button.closeNotification").click();
  1311. });
  1312. }
  1313. // MAC-NW -- AD Transfer through exchange functions (Consolidation)
  1314. // Function used to check exchange data model and post calculated AD/Zen for transfer if all requirements are met
  1315. function postZexOffer() {
  1316. // Make sure the exchange data is loaded to model
  1317. if (unsafeWindow.client.dataModel.model.exchangeaccountdata) {
  1318. // Check that there is atleast 1 free zex order slot
  1319. if (unsafeWindow.client.dataModel.model.exchangeaccountdata.openorders.length < 5) {
  1320. // Place the order
  1321. var charDiamonds = parseInt(unsafeWindow.client.dataModel.model.ent.main.currencies.diamonds);
  1322. var ZenRate = parseInt(settings["banktransrate"]);
  1323. var ZenQty = Math.floor( (charDiamonds - parseInt(settings["bankcharmin"])) / ZenRate);
  1324.  
  1325. console.log("Posting Zex buy listing for " + ZenQty + " ZEN at the rate of " + ZenRate + " AD/ZEN. AD remainder: " + charDiamonds + " - " + (ZenRate*ZenQty) + " = " + (charDiamonds-(ZenRate*ZenQty)));
  1326. unsafeWindow.client.createBuyOrder(ZenQty, ZenRate);
  1327. } else { console.log("Zen Max Listings Reached (5). Skipping Zex Posting.."); }
  1328. } else { console.log("Zen Exchange data did not load in time for transfer. Skipping Zex Posting.."); }
  1329. }
  1330. // Function used to check exchange data model and withdraw listed orders that use the settings zen transfer rate
  1331. function withdrawZexOffer() {
  1332. // Make sure the exchange data is loaded to model
  1333. if (unsafeWindow.client.dataModel.model.exchangeaccountdata) {
  1334. if (unsafeWindow.client.dataModel.model.exchangeaccountdata.openorders.length >= 1) {
  1335. var charDiamonds = parseInt(unsafeWindow.client.dataModel.model.ent.main.currencies.diamonds);
  1336. var ZenRate = parseInt(settings["banktransrate"]);
  1337. // cycle through the zex listings
  1338. unsafeWindow.client.dataModel.model.exchangeaccountdata.openorders.forEach(function(item){
  1339. // find any buy orders in the list with our set zen rate
  1340. if (parseInt(item.price) == ZenRate && item.ordertype == "Buy") {
  1341. // cancel/withdraw the order
  1342. client.withdrawOrder(item.orderid);
  1343. console.log("Withdrawing Zex listing for " + item.quantity + " ZEN at the rate of " + item.price + " . Total value in AD: " + item.totaltc);
  1344. }
  1345. });
  1346.  
  1347. } else { console.log("No listings found on Zex. Skipping Zex Withrdaw.."); }
  1348. } else { console.log("Zen Exchange data did not load in time for transfer. Skipping Zex Withrdaw.."); }
  1349. }
  1350. // MAC-NW
  1351. function switchChar() {
  1352.  
  1353. if (settings["refinead"]) {
  1354. var _currencies = unsafeWindow.client.dataModel.model.ent.main.currencies;
  1355. if (_currencies.diamondsconvertleft && _currencies.roughdiamonds) {
  1356. console.log("Refining AD");
  1357. unsafeWindow.client.sendCommand('Gateway_ConvertNumeric', 'Astral_Diamonds');
  1358. WaitForState("button.closeNotification").done(function() {
  1359. $("button.closeNotification").click();
  1360. });
  1361. }
  1362. }
  1363. // MAC-NW -- AD Consolidation
  1364. if (settings["autoexchange"]) {
  1365. // Check that we dont take money from the character assigned as the banker // Zen Transfer / Listing
  1366. if (settings["bankchar"] != unsafeWindow.client.dataModel.model.ent.main.name) {
  1367. // Check the required min AD amount on character
  1368. if (settings["banktransmin"] && settings["bankcharmin"] && parseInt(unsafeWindow.client.dataModel.model.ent.main.currencies.diamonds) >= ( parseInt(settings["banktransmin"]) + parseInt(settings["bankcharmin"]) ) ) {
  1369. // Check that the rate is not less than the min & max
  1370. if (settings["banktransrate"] && parseInt(settings["banktransrate"]) >= 50 && parseInt(settings["banktransrate"]) <= 500) {
  1371. //unsafeWindow.client.dataModel.fetchExchangeAccountData();
  1372. window.setTimeout(postZexOffer, delay.SHORT);
  1373. } else { console.log("Zen transfer rate does not meet the minimum (50) or maximum (500). Skipping Zex Posting.."); }
  1374. } else { console.log("Character does not have minimum AD balance to do funds transfer. Skipping Zex Posting.."); }
  1375. }
  1376. } else { console.log("Zen Exchange AD transfer not enabled. Skipping Zex Posting.."); }
  1377. // MAC-NW
  1378. //MAC-NW
  1379. if (settings["openrewards"]) {
  1380. var _pbags = client.dataModel.model.ent.main.inventory.playerbags;
  1381. var _cRewardPat = /Reward_Item_Chest/;
  1382. console.log("Opening Rewards");
  1383. $.each(_pbags, function( bi, bag ) {
  1384. bag.slots.forEach(function( slot ) {
  1385. if (slot && _cRewardPat.test(slot.name)) {
  1386. for (i = 1; i <= slot.count; i++) {
  1387. unsafeWindow.client.sendCommand('GatewayInventory_OpenRewardPack', slot.uid);
  1388. }
  1389. }
  1390. });
  1391. });
  1392. }
  1393. //MAC-NW
  1394. console.log("Switching Characters");
  1395. var chardelay, chardate = null, nowdate = new Date();
  1396. nowdate = nowdate.getTime();
  1397. curdiamonds = 0;
  1398. for (var cc = 0; cc < settings["charcount"]; cc++) {
  1399. if (chartimers[cc] != null) {
  1400. console.log("Date found for " + settings["nw_charname"+cc]);
  1401. if (!chardate || chartimers[cc] < chardate) {
  1402. chardate = chartimers[cc];
  1403. charcurrent = cc;
  1404. chardelay = chardate.getTime() - nowdate - unsafeWindow.client.getServerOffsetSeconds()*1000;
  1405. if (chardelay < delay.SHORT) {chardelay = delay.SHORT;}
  1406. }
  1407. } else {
  1408. charcurrent = cc;
  1409. chardelay = delay.SHORT;
  1410. chardate = null;
  1411. console.log("No date found for " + settings["nw_charname"+cc] + ", switching now.");
  1412. break;
  1413. }
  1414. if(chardiamonds[cc] != null) {
  1415. curdiamonds += chardiamonds[cc];
  1416. }
  1417. }
  1418. console.log("Next run for " + settings["nw_charname"+charcurrent] + " in " + parseInt(chardelay/1000) + " seconds.");
  1419. $("#prinfopane").empty().append("<h3 class='promo-image copy-top prh3'>Professions Robot<br />Next task for " + settings["nw_charname"+charcurrent] + "<br /><span data-timer='" + chardate + "' data-timer-length='2'></span><br />Diamonds: " + curdiamonds.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") + "</h3>");
  1420. GM_setValue("charcurrent", charcurrent);
  1421. dfdNextRun.resolve(chardelay);
  1422. }
  1423. /**
  1424. * Waits for the loading symbol to be hidden.
  1425. *
  1426. * @return {Deferred} A jQuery defferred object that will be resolved when loading is complete
  1427. */
  1428. function WaitForLoad() {
  1429. return WaitForState("");
  1430. }
  1431. /**
  1432. * Creates a deferred object that will be resolved when the state is reached
  1433. *
  1434. * @param {string} query The query for the state to wait for
  1435. * @return {Deferred} A jQuery defferred object that will be resolved when the state is reached
  1436. */
  1437. function WaitForState(query) {
  1438. var dfd = $.Deferred();
  1439. window.setTimeout(function() {AttemptResolve(query, dfd);}, delay.SHORT); // Doesn't work without a short delay
  1440. return dfd;
  1441. }
  1442. /**
  1443. * Will continually test for the given query state and resolve the given deferred object when the state is reached
  1444. * and the loading symbol is not visible
  1445. *
  1446. * @param {string} query The query for the state to wait for
  1447. * @param {Deferred} dfd The jQuery defferred object that will be resolved when the state is reached
  1448. */
  1449. function AttemptResolve(query, dfd) {
  1450. if ((query === "" || $(query).length) && $("div.loading-image:visible").length === 0) {
  1451. dfd.resolve();
  1452. }
  1453. else {
  1454. window.setTimeout(function() {AttemptResolve(query, dfd);}, delay.SHORT); // Try again in a little bit
  1455. }
  1456. }
  1457. /**
  1458. * The main process loop:
  1459. * - Determine which page we are on and call the page specific logic
  1460. * - When processing is complete, process again later
  1461. * - Use a short timer when something changed last time through
  1462. * - Use a longer timer when waiting for tasks to complete
  1463. */
  1464. function process() {
  1465. // Make sure the settings button exists
  1466. addSettings();
  1467.  
  1468. // Enable/Disable the unconditional page reload depending on settings
  1469. loading_reset = settings["autoreload"];
  1470.  
  1471. // Check if timer is paused
  1472. s_paused = settings["paused"]; // let the Page Reloading function know the pause state
  1473. if (settings["paused"]) {
  1474. // Just continue later - the deferred object is still set and nothing will resolve it until we get past this point
  1475. var timerHandle = window.setTimeout(function() {process();}, delay.DEFAULT);
  1476. return;
  1477. }
  1478.  
  1479. // Check for Gateway down
  1480. if (window.location.href.indexOf("gatewaysitedown") > -1) {
  1481. // Do a long delay and then retry the site
  1482. console.log("Gateway down detected - relogging in " + (delay.MINS/1000) + " seconds");
  1483. window.setTimeout(function() {unsafeWindow.location.href = "http://gateway.playneverwinter.com";}, delay.MINS);
  1484. return;
  1485. }
  1486.  
  1487. // Check for login or account guard and process accordingly
  1488. var currentPage = GetCurrentPage();
  1489. if (currentPage == PAGES.LOGIN) { page_LOGIN(); return; }
  1490. else if (currentPage == PAGES.GUARD) { page_GUARD(); return; }
  1491. window.setTimeout(function() {loginProcess();}, delay.SHORT);
  1492. // Continue again later
  1493. dfdNextRun.done(function(delayTimer) {
  1494. dfdNextRun = $.Deferred();
  1495. timerHandle = window.setTimeout(function() {process();}, typeof delayTimer!== 'undefined' ? delayTimer:delay.DEFAULT);
  1496. });
  1497. }
  1498. function loginProcess() {
  1499. // Get logged on account details
  1500. var accountName;
  1501. try {
  1502. accountName = unsafeWindow.client.dataModel.model.loginInfo.publicaccountname;
  1503. }
  1504. catch (e) {
  1505. // TODO: Use callback function
  1506. window.setTimeout(function() {loginProcess();}, delay.SHORT);
  1507. return;
  1508. }
  1509. // Check if timer is paused again to avoid starting new task between timers
  1510. s_paused = settings["paused"]; // let the Page Reloading function know the pause state
  1511. if (settings["paused"]) {
  1512. // Just continue later - the deferred object is still set and nothing will resolve it until we get past this point
  1513. var timerHandle = window.setTimeout(function() {process();}, delay.DEFAULT);
  1514. return;
  1515. }
  1516.  
  1517. if (accountName) {
  1518. // load current character position and values
  1519. charcurrent = GM_getValue("charcurrent", 0);
  1520. for (var i = 0; i < (charSettings.length/settings["charcount"]); i++) {
  1521. j = i + (charcurrent*charSettings.length/settings["charcount"]);
  1522. settings[charSettings[j].name.replace(new RegExp(charcurrent+"$"),'')] = settings[charSettings[j].name];
  1523. }
  1524. // Load task list from settings if saved
  1525. if (settings["tasklist"].length) {
  1526. tasklist = JSON.parse(settings["tasklist"]);
  1527. }
  1528. else {
  1529. tasklist = defaultTasklist;
  1530. }
  1531.  
  1532. var charName = settings["nw_charname"];
  1533. var fullCharName = charName + '@' + accountName;
  1534.  
  1535. if (unsafeWindow.client.getCurrentCharAtName() != fullCharName) {
  1536. loadCharacter(fullCharName);
  1537. return;
  1538. }
  1539.  
  1540. // Try to start tasks
  1541. if (processCharacter()) { return; }
  1542.  
  1543. // Switch characters as necessary
  1544. switchChar();
  1545. }
  1546. }
  1547.  
  1548. function loadCharacter(charname) {
  1549. // Load character and restart next load loop
  1550. console.log("Loading gateway script for", charname);
  1551. unsafeWindow.client.dataModel.loadEntityByName(charname);
  1552. // MAC-NW -- AD Consolidation -- Banker Withdraw Secion
  1553. try {
  1554. var testChar = unsafeWindow.client.dataModel.model.ent.main.name;
  1555. }
  1556. catch (e) {
  1557. // TODO: Use callback function
  1558. window.setTimeout(function() {loadCharacter(charname);}, delay.SHORT);
  1559. return;
  1560. }
  1561.  
  1562. if (settings["autoexchange"]) {
  1563. unsafeWindow.client.dataModel.fetchExchangeAccountData();
  1564. try {
  1565. var testExData = unsafeWindow.client.dataModel.model.exchangeaccountdata.openorders;
  1566. }
  1567. catch (e) {
  1568. // TODO: Use callback function
  1569. window.setTimeout(function() {loadCharacter(charname);}, delay.SHORT);
  1570. return;
  1571. }
  1572. // Check to see if this is the designated banker character
  1573. if (settings["bankchar"] == unsafeWindow.client.dataModel.model.ent.main.name) {
  1574. // This is the banker -- withdraw any buy listings that match the transfer rate set in panel
  1575. window.setTimeout(withdrawZexOffer, delay.MEDIUM);
  1576. // withdraw the balance from exchange
  1577. window.setTimeout(function () {
  1578. client.sendCommand("GatewayExchange_ClaimTC", client.dataModel.model.exchangeaccountdata.readytoclaimescrow);
  1579. client.sendCommand("GatewayExchange_ClaimMTC", client.dataModel.model.exchangeaccountdata.readytoclaimmtc);
  1580. console.log("Attempting to withdraw exchange balancees... ClaimTC: " + client.dataModel.model.exchangeaccountdata.readytoclaimescrow + ". ClaimMT: " + client.dataModel.model.exchangeaccountdata.readytoclaimmtc);
  1581. }, delay.SHORT);
  1582. }
  1583. WaitForState("button.closeNotification").done(function() {
  1584. //$("button.closeNotification").click();
  1585. });
  1586. unsafeWindow.client.dataModel.loadEntityByName(charname);
  1587. } else { console.log("Zen Exchange AD transfer not enabled. Skipping Zex Posting.."); }
  1588. // MAC-NW
  1589. dfdNextRun.resolve();
  1590. }
  1591. function addSettings() {
  1592. if ($("#settingsButton").length)
  1593. return;
  1594. // Add the required CSS
  1595. AddCss("\
  1596. #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;}\
  1597. #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;}\
  1598. /* MAC-NW -- Put Panel at a higher layer than status window */ #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: 550px;max-height:750px;font: 12px sans-serif; text-align: left; display: block; z-index: 1001;}\
  1599. #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;}\
  1600. #settingsPanelButtonContainer {background: none repeat scroll 0% 0% rgb(204, 204, 204); border-top: 1px solid rgb(102, 102, 102);padding: 3px;text-align:center} \
  1601. #settingsPanel label.purple {font-weight:bold;color:#7C37F6}\
  1602. #settingsPanel label.blue {font-weight:bold;color:#007EFF}\
  1603. #settingsPanel label.green {font-weight:bold;color:#8AFF00}\
  1604. #settingsPanel label.white {font-weight:bold;color:#FFFFFF}\
  1605. #charPanel {width:98%;max-height:400px;overflow:auto;display:block;padding:3px;}\
  1606. #charPanel div div ul li { display: inline-block; width: 48%; }\
  1607. .inventory-container {float: left; clear: none; width: 270px; margin-right: 20px;}\
  1608. #prinfopane {position: fixed; top: 5px; left: 200px; display: block; z-index: 1000;}\
  1609. .prh3 {padding: 5px; height: auto!important; width: auto!important; background-color: rgba(0, 0, 0, 0.7);}\
  1610. .custom-radio{width:16px;height:16px;display:inline-block;position:relative;z-index:1;top:3px;background-color:#fff;margin:0 4px 0 2px;}\
  1611. .custom-radio:hover{background-color:black;} .custom-radio.selected{background-color:red;} .custom-radio-selected-text{color:darkred;font-weight:500;}\
  1612. .custom-radio input[type='radio']{margin:1px;position:absolute;z-index:2;cursor:pointer;outline:none;opacity:0;_nofocusline:expression(this.hideFocus=true);-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=0);filter:alpha(opacity=0);-khtml-opacity:0;-moz-opacity:0}\
  1613. #settingsPanel input[type='button'].button-green,#settingsPanel input[type='button'].button-red,#settingsPanel input[type='button'].button-yellow,#settingsPanel input[type='button'].button-blue{color:#eff;border-radius:4px;text-shadow:0 1px 1px rgba(0,0,0,0.2);font-size:110%;font-weight:bold;}\
  1614. .pure-button{display:inline-block;*display:inline;zoom:1;line-height:normal;white-space:nowrap;vertical-align:baseline;text-align:center;cursor:pointer;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.pure-button::-moz-focus-inner{padding:0;border:0}.pure-button{font-family:inherit;font-size:100%;*font-size:90%;*overflow:visible;padding:.5em 1em;color:#444;color:rgba(0,0,0,.8);*color:#444;border:1px solid #999;border:0 rgba(0,0,0,0);background-color:#E6E6E6;text-decoration:none;border-radius:2px}.pure-button-hover,.pure-button:hover,.pure-button:focus{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#1a000000', GradientType=0);background-image:-webkit-gradient(linear,0 0,0 100%,from(transparent),color-stop(40%,rgba(0,0,0,.05)),to(rgba(0,0,0,.1)));background-image:-webkit-linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1));background-image:-moz-linear-gradient(top,rgba(0,0,0,.05) 0,rgba(0,0,0,.1));background-image:-o-linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1));background-image:linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1))}.pure-button:focus{outline:0}.pure-button-active,.pure-button:active{box-shadow:0 0 0 1px rgba(0,0,0,.15) inset,0 0 6px rgba(0,0,0,.2) inset}.pure-button[disabled],.pure-button-disabled,.pure-button-disabled:hover,.pure-button-disabled:focus,.pure-button-disabled:active{border:0;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);filter:alpha(opacity=40);-khtml-opacity:.4;-moz-opacity:.4;opacity:.4;cursor:not-allowed;box-shadow:none}.pure-button-hidden{display:none}.pure-button::-moz-focus-inner{padding:0;border:0}.pure-button-primary,.pure-button-selected,a.pure-button-primary,a.pure-button-selected{background-color:#0078e7;color:#fff}\
  1615. #settingsPanel input[type='button'].button-green{background:#1cb841; margin: 2px 20px 2px 2px;}\
  1616. #settingsPanel input[type='button'].button-red{background:#ca3c3c; margin: 2px 2px 2px 2px;}\
  1617. #settingsPanel input[type='button'].button-yellow{background:#df7514; margin: 2px 2px 2px 2px;}\
  1618. #settingsPanel input[type='button'].button-blue{background:#42b8dd; margin: 2px 2px 2px 2px;}\
  1619. ");
  1620.  
  1621. // Add settings panel to page body
  1622. $("body").append(
  1623. '<div id="settingsPanel">\
  1624. <div id="settings_title">\
  1625. <img src='+image_prefs+' style="float: left; vertical-align: text-bottom;"\>\
  1626. <img id="settings_close" src='+image_close+' title="Click to hide preferences" style="float: right; vertical-align: text-bottom; cursor: pointer; display: block;"\>\
  1627. <span style="margin:3px">Settings</span>\
  1628. </div>\
  1629. <form style="margin: 0px; padding: 0px">\
  1630. <ul style="list-style: none outside none; max-height: 500px; overflow: auto; margin: 3px; padding: 0px;">\
  1631. </ul>\
  1632. </form>\
  1633. </div>'
  1634. );
  1635.  
  1636. // Add each setting input
  1637. var settingsList = $("#settingsPanel form ul");
  1638. for (var i = 0; i < settingnames.length; i++) {
  1639. var id = 'settings_' + settingnames[i].name;
  1640. var indent = (countLeadingSpaces(settingnames[i].title) >= 1) ? 1 : 0;
  1641. if ( i > 0 && settingnames[i].type.toString().replace(/password/, "text") != settingnames[i-1].type.toString().replace(/password/, "text") ) // MAC-NW -- AD Consolidation FIX: Remove even/odd test
  1642. settingsList.append('<li style="margin-left:0em; width: 48%; display: inline-block;"/>&nbsp;</li>')
  1643.  
  1644. switch(settingnames[i].type) {
  1645. case "checkbox":
  1646. settingsList.append('<li title="'+settingnames[i].tooltip+'" style="padding-left:'+indent+'em; width: 48%; display: inline-block;"><input style="margin:4px" name="'+id+'" id="'+id+'" type="checkbox" /><label class="'+settingnames[i].class+'" for="'+id+'">'+settingnames[i].title+'</label></li>')
  1647. $('#'+id).prop('checked', settings[settingnames[i].name]);
  1648. break;
  1649. case "text":
  1650. settingsList.append('<li title="'+settingnames[i].tooltip+'" style="padding-left:'+indent+'em; margin-top:1em; width: 46%; display: inline-block;"<label class="'+settingnames[i].class+'" for="'+id+'">'+settingnames[i].title+'</label><input style="margin:4px; padding: 2px; min-width: 80%;" name="'+id+'" id="'+id+'" type="text" /></li>')
  1651. $('#'+id).val(settings[settingnames[i].name]);
  1652. break;
  1653. case "password":
  1654. settingsList.append('<li title="'+settingnames[i].tooltip+'" style="padding-left:'+indent+'em; margin-top:1em; width: 46%; display: inline-block;"'+settingnames[i].class+'" for="'+id+'">'+settingnames[i].title+'</label><input style="margin:4px; padding: 2px; min-width: 80%;" name="'+id+'" id="'+id+'" type="password" /></li>')
  1655. $('#'+id).val(settings[settingnames[i].name]);
  1656. break;
  1657. case "select":
  1658. settingsList.append('<li title="'+settingnames[i].tooltip+'" style="padding-left:'+indent+'em; width: 48%; display: inline-block;"'+settingnames[i].class+'" style="padding-left:4px" for="'+id+'">'+settingnames[i].title+'</label><select style="margin:4px" name="'+id+'" id="'+id+'" /></li>')
  1659. var options = settingnames[i].opts;
  1660. var select = $('#'+id);
  1661. for (var j = 0; j < options.length; j++) {
  1662. if (settings[settingnames[i].name] == options[j].path)
  1663. select.append('<option value="'+options[j].path+'" selected="selected">'+options[j].name+'</option>');
  1664. else
  1665. select.append('<option value="'+options[j].path+'">'+options[j].name+'</option>');
  1666. }
  1667. break;
  1668. case "label":
  1669. settingsList.append('<li title="'+settingnames[i].tooltip+'" style="margin-left:'+indent+'em;><label class="'+settingnames[i].class+'">'+settingnames[i].title+'</label></li>')
  1670. break;
  1671. }
  1672. }
  1673. // Add character settings for each char
  1674. var addText = '\
  1675. <script type="text/javascript">\
  1676. <!--\
  1677. function click_position(obj)\
  1678. {\
  1679. change_position(obj.value)\
  1680. }\
  1681. \
  1682. function customRadio(radioName) {\
  1683. var radioButton = $( \'input[name="\'+ radioName +\'"]\');\
  1684. $(radioButton).each(function(){\
  1685. $(this).wrap( "<span class=\'custom-radio\'></span>" );\
  1686. if($(this).is(\':checked\')){\
  1687. $(this).parent().addClass("selected");\
  1688. $(this).parent().parent().addClass("custom-radio-selected-text");\
  1689. }\
  1690. });\
  1691. $(radioButton).click(function(){\
  1692. if($(this).is(\':checked\')){\
  1693. $(this).parent().addClass("selected");\
  1694. $(this).parent().parent().addClass("custom-radio-selected-text");\
  1695. }\
  1696. $(radioButton).not(this).each(function(){\
  1697. $(this).parent().removeClass("selected");\
  1698. $(this).parent().parent().removeClass("custom-radio-selected-text");\
  1699. });\
  1700. });\
  1701. }\
  1702. function change_position(val)\
  1703. {\
  1704. for (var i = 0; i < '+settings["charcount"]+'; i++)\
  1705. {\
  1706. document.getElementById("charContainer"+i).style.display="none";\
  1707. }\
  1708. document.getElementById("charContainer"+val).style.display="block";\
  1709. }\
  1710. //-->\
  1711. </script>\
  1712. <div id="charPanel">\
  1713. <div style="width:30%;float:left;max-height:400px;overflow:auto;">\
  1714. ';
  1715. for (var i = 0; i < settings["charcount"]; i++) {
  1716. addText += '\
  1717. <div><label for="value_'+i+'" style="display:block;padding-top:2px;"><input autocomplete="off" type="radio" name="radio_position" onclick="click_position(this)" id="value_'+i+'" value="'+i+'" />'+settings["nw_charname"+i]+'</label></div>\
  1718. ';
  1719. }
  1720. addText += '\
  1721. </div>\
  1722. <div style="width:69%;float:right;">\
  1723. ';
  1724. for (var i = 0; i < settings["charcount"]; i++) {
  1725. addText += '\
  1726. <div id="charContainer'+i+'" style="display:none">\
  1727. <ul style="list-style: none outside none; max-height: 500px; overflow: auto;">\
  1728. ';
  1729. var k = 0 + (i*charSettings.length/settings["charcount"]);
  1730. var id = 'settings_' + charSettings[k].name;
  1731. addText += '<li title="'+charSettings[k].tooltip+'"><input style="margin:4px; padding: 2px;" name="'+id+'" id="'+id+'" type="text" /></li>';
  1732. for (var j = 1; j < (charSettings.length/settings["charcount"]); j++) {
  1733. k = j + (i*charSettings.length/settings["charcount"]);
  1734. if (charSettings[k].type == 'void') { continue; }
  1735. id = 'settings_' + charSettings[k].name;
  1736. addText += '<li title="'+charSettings[k].tooltip+'"><input maxlength="2" size="1" style="margin:4px; padding: 2px;" name="'+id+'" id="'+id+'" type="text" /><label class="'+charSettings[k].class+'" for="'+id+'">'+charSettings[k].title+'</label></li>';
  1737. }
  1738. addText += '</ul>'
  1739.  
  1740. // Add task list save buttons
  1741. addText += '\
  1742. <input id="save_tasklist'+i+'" type="button" class="button-green pure-button" value="Save Tasks" title="Saves current task list in script to this character">\
  1743. <input id="clear_tasklist'+i+'" type="button" class="button-red pure-button" value="Clear Tasks" title="Clears the saved task list for this character to use defaults">\
  1744. </div>';
  1745. }
  1746. addText += '\
  1747. </div>\
  1748. </div>\
  1749. ';
  1750. $("#settingsPanel form").append(addText);
  1751.  
  1752. // Add values to character input fields
  1753. for (var i = 0; i < charSettings.length; i++) {
  1754. var id = 'settings_' + charSettings[i].name;
  1755. $('#'+id).val(settings[charSettings[i].name]);
  1756. }
  1757. // Add code to tasklist buttons
  1758. for (var i = 0; i < settings["charcount"]; i++) {
  1759. $("#save_tasklist"+i).click(function() {
  1760. var num = this.id.replace("save_tasklist", "");
  1761. charSettings["tasklist"+num] = tasklist;
  1762. setTimeout(function() { GM_setValue("tasklist"+num, JSON.stringify(defaultTasklist)); }, 0);
  1763. });
  1764. $("#clear_tasklist"+i).click(function() {
  1765. var num = this.id.replace("clear_tasklist", "");
  1766. charSettings["tasklist"+num] = "";
  1767. setTimeout(function() { GM_setValue("tasklist"+num, ""); }, 0);
  1768. });
  1769. }
  1770.  
  1771. // Add save/cancel buttons to panel
  1772. $("#settingsPanel form").append('\
  1773. <div id="settingsPanelButtonContainer">\
  1774. <input id="settings_save" class="button-blue pure-button" type="button" value="Save and Apply">\
  1775. <input id="settings_close" class="button-yellow pure-button" type="button" value="Close">\
  1776. </div>');
  1777.  
  1778. // Add open settings button to page
  1779. $("body").append('<div id="settingsButton"><img src="'+image_prefs+'" title="Click to show preferences" style="cursor: pointer; display: block;"></div>');
  1780.  
  1781. // Add pause button to page
  1782. $("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>');
  1783. // Add info pane
  1784. $("body").append("<div id='prinfopane' class='header-newrelease'>");
  1785.  
  1786. // Add the javascript
  1787. $("#settingsPanel").hide();
  1788. $("#settingsButton").click(function() {
  1789. $("#settingsButton").hide();
  1790. $("#pauseButton").hide();
  1791. $("#settingsPanel").show();
  1792. });
  1793. $("#settings_close,settings_cancel").click(function() {
  1794. $("#settingsButton").show();
  1795. $("#pauseButton").show();
  1796. $("#settingsPanel").hide();
  1797. });
  1798. $("#pauseButton").click(function() {
  1799. settings["paused"] = !settings["paused"]
  1800. setTimeout(function() { GM_setValue("paused", settings["paused"]); }, 0);
  1801. $("#settings_paused").prop("checked", settings["paused"]);
  1802. $("#pauseButton img").attr("src",(settings["paused"]?image_play:image_pause));
  1803. $("#pauseButton img").attr("title","Click to "+(settings["paused"]?"resume":"pause")+" task script");
  1804. });
  1805.  
  1806. // Use setTimeout to workaround permission issues when calling GM functions from main window
  1807. $("#settings_save").click(function() { setTimeout(function() { SaveSettings();}, 0)});
  1808. customRadio("radio_position");
  1809. }
  1810.  
  1811. function SaveSettings() {
  1812. var charcount = settings["charcount"];
  1813.  
  1814. // Get each value from the UI
  1815. for (var i = 0; i < settingnames.length; i++) {
  1816. var name = settingnames[i].name;
  1817. var el = $('#settings_' + name);
  1818. var value = false;
  1819. switch(settingnames[i].type) {
  1820. case "checkbox":
  1821. value = el.prop("checked");
  1822. break;
  1823. case "text":
  1824. value = el.val();
  1825. break;
  1826. case "password":
  1827. value = el.val();
  1828. break;
  1829. case "select":
  1830. value = el.val();
  1831. break;
  1832. case "label": // Labels don't have values
  1833. continue;
  1834. }
  1835. if (typeof(settingnames[i].onsave) === "function") {
  1836. console.log("Calling 'onsave' for", name);
  1837. settingnames[i].onsave(value, settings[name]);
  1838. }
  1839. if (settings[name] !== value) { settings[name] = value; } // Save to local cache
  1840. if (GM_getValue(name) !== value) { GM_setValue(name, value); } // Save to GM cache
  1841. }
  1842.  
  1843. // Get character settings from UI
  1844. for (var i = 0; i < charSettings.length; i++) {
  1845. if (charSettings[i].type == 'void') { continue; }
  1846. var name = charSettings[i].name;
  1847. var el = $('#settings_' + name);
  1848. var value = el.val();
  1849. if (settings[name] !== value) { settings[name] = value; } // Save to local cache
  1850. if (GM_getValue(name) !== value) { GM_setValue(name, value); } // Save to GM cache
  1851. }
  1852. // If character numbers have changed reload page
  1853. if (charcount != settings["charcount"]) {
  1854. console.log("Reloading Gateway to update character count");
  1855. unsafeWindow.location.href = "http://gateway.playneverwinter.com";
  1856. return;
  1857. }
  1858.  
  1859. // Delete all saved settings // MAC-NW: Not sure this could of worked before with how it was coded...
  1860. if (settingwipe) {
  1861. var keys = GM_listValues();
  1862. for (i = 0; i < keys.length ; i++) {
  1863. var key = keys[i];
  1864. GM_deleteValue(key);
  1865. }
  1866. }
  1867. // Close the panel
  1868. $("#settingsButton").show();
  1869. $("#pauseButton img").attr("src",(settings["paused"]?image_play:image_pause));
  1870. $("#pauseButton img").attr("title","Click to "+(settings["paused"]?"resume":"pause")+" task script");
  1871. $("#pauseButton").show();
  1872. $("#settingsPanel").hide();
  1873. }
  1874.  
  1875. // Add the settings button and start a process timer
  1876. addSettings();
  1877. timerHandle = window.setTimeout(function() {process();}, delay.SHORT);
  1878. })();