GOTA_Extender_Production

Separate production module for the game.

此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.gf.qytechs.cn/scripts/7611/50299/GOTA_Extender_Production.js

  1. var production = (function ($, localStorage, log, error, buildingBySymbol,
  2. buildingProducing, buildingFinished, buildingBySymbol,
  3. doFinishProduction, userContext, doProduction,
  4. applySelectedUpgrade, buildingUpgrades, inform) {
  5.  
  6. var _this = {
  7. init: init,
  8. attempt: attempt,
  9. persist: persist,
  10. enqueue: enqueue,
  11. render: render,
  12. config: config,
  13. clear: clear,
  14. getElement: getElement,
  15. removeElement: removeElement,
  16. executeElement: executeElement,
  17. speedUp: speedUp,
  18.  
  19. queue: [],
  20. queueDelay: 4E3,
  21. superiorMaterials: true,
  22. doSpeedUp: false
  23. };
  24.  
  25. // Retrieves production
  26. // queue from localStorage
  27. function init(o) {
  28. _this.queue = localStorage.get("productionQueue", []);
  29.  
  30. _this.config(o);
  31.  
  32. $("#modal_dialogs_top").on('click', '#upgradeQueue', enqueue);
  33. $("#modal_dialogs_top").on('click', 'span.btnwrap.btnmed.equipbtn.queue', enqueue);
  34. $('body').on('click', '.tableRow', deleteTableRow);
  35.  
  36. // Attempt production on initialize
  37. //attempt();
  38. }
  39.  
  40. function config(o){
  41. //console.debug(o);
  42.  
  43. try {
  44. _this.queueDelay = o.queueDelay * 1E3;
  45. _this.superiorMaterials = o.superiorMaterials;
  46. _this.doSpeedUp = o.doSpeedUp;
  47. } catch(e){
  48. error(e);
  49. }
  50. }
  51.  
  52. function clear(building) {
  53. _this.queue = building != void 0
  54. ? _this.queue.filter(function (a) {
  55. return a.activeBuildingPanel != building
  56. }) : [];
  57.  
  58. persist();
  59. }
  60.  
  61. // Saves the queue locally
  62. // NOTE: do it after every change of the queue!
  63. function persist() {
  64. localStorage.set("productionQueue", _this.queue);
  65. }
  66.  
  67. // Attempts building
  68. // production
  69. function attempt(bSymbol) {
  70.  
  71. if (!_this.queue || _this.queue.length == 0) {
  72. log('Attempted production, but queue was missing or empty. Exiting...', "PRODUCTION");
  73. return;
  74. }
  75.  
  76. var element;
  77. var building;
  78.  
  79. if (bSymbol != void 0) {
  80.  
  81. // Check _this building for production
  82. building = buildingBySymbol(bSymbol);
  83.  
  84. if (buildingProducing(building)) {
  85. log("Building " + building.symbol + " is busy.", "PRODUCTION");
  86. return;
  87. }
  88.  
  89. if (buildingFinished(building)) {
  90. log("Building " + building.symbol + " finished production.", "PRODUCTION");
  91.  
  92. doFinishProduction(building.item_id, function () {
  93. setTimeout(function () {
  94. attempt(building.symbol);
  95. }, _this.queueDelay);
  96. });
  97.  
  98. return;
  99. }
  100.  
  101. element = getElement(building.symbol);
  102. element && executeElement(element);
  103. return;
  104. }
  105.  
  106. for (var i = 0; i < userContext.buildingsData.length; i++) {
  107. building = userContext.buildingsData[i];
  108.  
  109. if (buildingProducing(building)) {
  110. log("Building " + building.symbol + " is busy.", "PRODUCTION");
  111. continue;
  112. }
  113.  
  114. if (buildingFinished(building)) {
  115. log("Building " + building.symbol + " finished production.", "PRODUCTION");
  116. doFinishProduction(building.item_id, function () {
  117. setTimeout(function () {
  118. attempt();
  119. }, _this.queueDelay);
  120. });
  121.  
  122. return;
  123. }
  124.  
  125. element = getElement(building.symbol);
  126. element && executeElement(element,
  127. function () {
  128. attempt();
  129. });
  130. }
  131. }
  132.  
  133. function getElement(bSymbol) {
  134. //if (!_this.queue || _this.queue.length == 0) {
  135. // log('Attempted to extract item from queue, but the production queue was missing or empty. Exiting...', "PRODUCTION");
  136. // return null;
  137. //}
  138.  
  139. var element;
  140.  
  141. for (var i = 0; i < _this.queue.length; i++) {
  142.  
  143. if (_this.queue[i].activeBuildingPanel == bSymbol) {
  144. element = _this.queue[i];
  145. break;
  146. }
  147. }
  148.  
  149. if (!element) {
  150. log('No elements enqueued for building ' + bSymbol + '. Array size: ' + _this.queue.length, "PRODUCTION");
  151. return null;
  152. }
  153.  
  154. return element;
  155. }
  156.  
  157. function executeElement(element, callback) {
  158.  
  159. var index = _this.queue.indexOf(element);
  160. log('Production of element ' + element.name + ' : ' + element.type + ' with index ' + index + ' initiated. ' +
  161. (callback == void 0 ? 'No callback set.' : 'Callback set after production.'), "PRODUCTION");
  162.  
  163. if (element.type == "item") {
  164. userContext.recipeData = element.recipeData;
  165. userContext.activeBuildingPanel = element.activeBuildingPanel;
  166.  
  167. doProduction(element.outputSymbol, element.recipeCategory, null, null, element.recipeName, callback);
  168. _this.queue.splice(index, 1);
  169. persist();
  170.  
  171. log('Production details: ' + element.name + ' at ' + element.activeBuildingPanel + ', ' + element.outputSymbol + ', ' + element.recipeCategory + ', ' + element.recipeName + ';', "PRODUCTION");
  172. } else {
  173.  
  174. var buildingId = buildingBySymbol(element.activeBuildingPanel).id;
  175.  
  176. applySelectedUpgrade({building_id: buildingId, id: element.upgradeId, gold: 0, silver: 0}, null, callback);
  177. _this.queue.splice(index, 1);
  178. persist();
  179.  
  180. log('Production details: ' + element.name + ' : ' + element.type + ' at ' + element.activeBuildingPanel + ', ' + element.symbol + ';', "PRODUCTION");
  181. }
  182. }
  183.  
  184. function removeElement(index) {
  185. if (_this.queue.length == 1) {
  186. _this.queue.pop();
  187. } else {
  188. _this.queue.splice(index, 1);
  189. persist();
  190. }
  191. }
  192.  
  193. function enqueue(e) {
  194. e.preventDefault();
  195.  
  196. try {
  197. var queueingUpgrade = $(this).hasClass('upgradeQueue');
  198. log("Queing " + (queueingUpgrade ? "upgrade." : "item(s)."));
  199.  
  200. if (queueingUpgrade) {
  201.  
  202. var container = $(this).parents('div#selected_upgrade');
  203. var name = $(container).find('h5:first').text();
  204.  
  205. var infoBtm = $(this).parents('div.buildinginfobtm');
  206. var func = $(infoBtm).find('.upgradeicon.active').attr('onclick');
  207. var upgradeImg = $(infoBtm).find('.upgradeicon.active .upgradeiconart img').attr('src');
  208.  
  209. if (func.indexOf("clickSelectUpgrade") == -1) {
  210. error("Cannot resolve upgrade id.");
  211. return;
  212. }
  213.  
  214. // TODO: Improve...
  215. // "return clickSelectUpgrade('7', 'balcony');"
  216. var symbol = func.split("'")[3];
  217. log("Selected " + symbol + " upgrade. Retrieve successful.");
  218.  
  219. var upgradeId;
  220.  
  221. var bUpgrades = buildingUpgrades[userContext.activeBuildingPanel];
  222. for (var j = 0; j < bUpgrades.length; j++) {
  223. if (bUpgrades[j].symbol == symbol) {
  224. upgradeId = bUpgrades[j].id;
  225. break;
  226. }
  227. }
  228.  
  229. if (!upgradeId) {
  230. error("Fatal error, cannot resolve upgrade id.");
  231. return;
  232. }
  233.  
  234. log("Upgrade id resolved: " + upgradeId);
  235.  
  236. var upgrade = {
  237. "name": name,
  238. "upgradeId": upgradeId,
  239. "type": "upgrade",
  240. "symbol": symbol,
  241. "img": upgradeImg,
  242. "activeBuildingPanel": userContext.activeBuildingPanel
  243. };
  244.  
  245. _this.queue.push(upgrade);
  246. persist();
  247.  
  248. log("Pushed upgrade to queue.");
  249.  
  250. } else {
  251.  
  252. // Extract and construct object
  253. var statview = $(this).parents(".statview");
  254. var imgSrc = $(statview).find("div.statviewimg img").attr('src');
  255.  
  256. if (typeof (imgSrc) == "undefined") {
  257. imgSrc = $(statview).find("span.iconview img").attr('src');
  258. }
  259.  
  260. var statViewName = $(statview).find(".statviewname h3").text();
  261. var quantity = $(this).attr("data-quantity");
  262.  
  263. // Extract variables needed
  264. var recipeName;
  265. var recipeData;
  266.  
  267. var source = userContext.productionItemsClick[userContext.currentProductionItem];
  268.  
  269. if (!source) {
  270. error('Failed to extract source production item.');
  271. return;
  272. }
  273.  
  274. for (var i = 0; i < userContext.recipeData.length; i++) {
  275. var r = userContext.recipeData[i];
  276. if (r.output == source.outputSymbol) {
  277. recipeName = r.symbol;
  278. recipeData = [r];
  279. break;
  280. }
  281.  
  282. if (r.success_loot_table && r.success_loot_table == source.outputSymbol) {
  283. recipeName = r.symbol;
  284. recipeData = [r];
  285. break;
  286. }
  287.  
  288. if (r.success_loot_item && r.success_loot_item == source.outputSymbol) {
  289. recipeName = r.symbol;
  290. recipeData = [r];
  291. break;
  292. }
  293. }
  294.  
  295. // Last attempt, these here are expensive operations
  296. if (!recipeName) {
  297. for (var i = 0; i < userContext.recipeData.length; i++) {
  298. var r = userContext.recipeData[i];
  299. var recipeInputs = JSON.stringify(r.input.split(","));
  300. if (JSON.stringify(source.recipeInputs) === recipeInputs) {
  301. recipeName = r.symbol;
  302. recipeData = [r];
  303. break;
  304. }
  305. }
  306. }
  307.  
  308. if (!recipeName) {
  309. error('Failed to extract recipeName.');
  310. return;
  311. }
  312.  
  313. if (!recipeData) {
  314. error('Failed to extract recipeData.');
  315. return;
  316. }
  317.  
  318. log('All needed variables were extracted.');
  319.  
  320. do {
  321.  
  322. // Construct production element
  323. var element = {
  324. "recipeName": recipeName,
  325. "name": statViewName,
  326. "img": imgSrc,
  327. "type": "item",
  328. "outputSymbol": source.outputSymbol,
  329. "recipeCategory": source.recipeCategory,
  330. "recipeData": recipeData,
  331. "activeBuildingPanel": userContext.activeBuildingPanel
  332. };
  333.  
  334. // Insert the element into the queueArray (cloneInto for Mozilla)
  335. //if (typeof (cloneInto) == "function") {
  336. // var elementClone = cloneInto(element, unsafeWindow);
  337. // _this.queue.push(elementClone);
  338. //} else {
  339. // _this.queue.push(element);
  340. //}
  341.  
  342. _this.queue.push(element);
  343. persist();
  344.  
  345. //options._this.queue = _this.queue;
  346. //options.set("_this.queue");
  347.  
  348. quantity--;
  349.  
  350. log('Pushed element to queue.');
  351.  
  352. } while (quantity > 0);
  353. }
  354.  
  355. log('Attempting immediate production...');
  356. attempt(userContext.activeBuildingPanel);
  357. inform('Enqueued.');
  358.  
  359. } catch (err) {
  360. error(err);
  361. }
  362. }
  363.  
  364. function speedUp(building, timer) {
  365.  
  366. var speedUpAt = 300 - _this.queueDelay / 1000;
  367.  
  368. // Analyze and get rid of timer
  369. if (timer && timer == speedUpAt) { // check at the exact time
  370. log('Timer reached speeding up boundary: ' + timer + 's, try sequence.', 'PRODUCTION');
  371.  
  372. speedUp(building);
  373. return;
  374. } else if (timer && timer < speedUpAt - 30) { // check thirty seconds later
  375. log('Timer falls into speed up boundary: ' + timer + 's, suspend further calls and try sequence.', 'PRODUCTION');
  376.  
  377. // Suspend further calls to this function
  378. clearTimeout(userContext.buildingTimer[building.symbol]);
  379. speedUp(building);
  380. return;
  381. } else if (timer != void 0){ // exit function in all other times if the timer exists
  382. return;
  383. }
  384.  
  385. doFinishProduction(building.item_id, function (r) {
  386.  
  387. if (r.building == void 0) {
  388. warn("Cannot resolve building!", "PRODUCTION");
  389. return;
  390. }
  391.  
  392. // Analyze response
  393. var b = r.building;
  394.  
  395. // building finished up
  396. if (!buildingProducing(b)) {
  397. log('Building is idle, attempt production.', 'PRODUCTION');
  398.  
  399. setTimeout(function () {
  400. attempt(building.symbol);
  401. }, _this.queueDelay);
  402.  
  403. return;
  404. }
  405.  
  406. if (r.building.build_remaining == void 0) {
  407. warn("Cannot resolve remaining time for this building!", "PRODUCTION");
  408. return;
  409. }
  410.  
  411. // building should undergo speed up check
  412. var br = r.building.build_remaining;
  413. log('Building undergoes speed up check...', 'PRODUCTION');
  414.  
  415. if (br <= speedUpAt) {
  416. var d = building;
  417. var c = building.id;
  418.  
  419. if (_this.doSpeedUp) {
  420. log('Production speed up is enabled, trying to speed up building now.', 'PRODUCTION');
  421. clearTimeout(userContext.buildingTimer[d.symbol]);
  422. doInstantSpeedUp(c, false, function () {
  423. speedUp(building);
  424. });
  425. } else {
  426. log('Production speed up is disabled, attempt a finish on production after ' + (br + _this.queueDelay / 1000) + 's.', 'PRODUCTION');
  427.  
  428. // Suspend further calls to this function
  429. clearTimeout(userContext.buildingTimer[building.symbol]);
  430. setTimeout(function () {
  431. speedUp(building);
  432. }, (br * 1E3 + _this.queueDelay));
  433. }
  434.  
  435. } else { // building does not hit the speedAt limit
  436. log('Building cannot speed up at the moment, check again after ' + (br - speedUpAt) + 's.', 'PRODUCTION');
  437.  
  438. setTimeout(function () {
  439. speedUp(building);
  440. }, (br - speedUpAt) * 1E3);
  441. }
  442. });
  443. }
  444.  
  445. function tableRow(i, el) {
  446. return '<tr class="tableRow" style="cursor: pointer">' +
  447. '<td><span class="ranklist colsort">' + i + '</span></td>' +
  448. '<td><span class="ranklist colsort">' + el.type + '</span></td>' +
  449. '<td><span class="name colsort">' + el.activeBuildingPanel + '</span></td>' +
  450. '<td><span class="name colsort">' + el.name + '</span></td>' +
  451. '<td><span class="avatarimg"><img src="' + el.img + '"></span></td>' +
  452. '</tr>';
  453. }
  454.  
  455. function deleteTableRow(e) {
  456. e.preventDefault();
  457.  
  458. try {
  459. var index = $(this).find("td:first span.ranklist").text();
  460.  
  461. log("Attempting to delete element with index " + index + " from the queue array.");
  462.  
  463. removeElement(index);
  464. render(userContext.activeBuildingPanel);
  465.  
  466. } catch (err) {
  467. error(err);
  468. }
  469.  
  470. }
  471.  
  472. function render(building) {
  473.  
  474. log("Rendering production queue table. Building: " + (building == void 0 ? "All" : building));
  475.  
  476. var qTable = $(".queueTable.powertable:visible");
  477. if (qTable.length == 0) {
  478. error("Can't find queue table! Rendering production items failed.");
  479. return;
  480. }
  481.  
  482. // Clear table from any rows first
  483. qTable.find(".tableRow").each(function () {
  484. $(this).remove();
  485. });
  486.  
  487. if (!_this.queue || _this.queue.length == 0) {
  488. log("No queue was found to render.");
  489. return;
  490. }
  491.  
  492. // Render items
  493. for (var i = 0; i < _this.queue.length; i++) {
  494. if(building != void 0 && building != _this.queue[i].activeBuildingPanel) {
  495. continue;
  496. }
  497.  
  498. qTable.find(".headerRow").after(tableRow(i, _this.queue[i]));
  499. }
  500.  
  501. log("Production queue rendered. Queue length: " + _this.queue.length + " items.");
  502. }
  503. return _this;
  504.  
  505. }($, localStorage, log, error, buildingBySymbol,
  506. buildingProducing, buildingFinished, buildingBySymbol,
  507. doFinishProduction, userContext, doProduction,
  508. applySelectedUpgrade, buildingUpgrades, inform));

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址