Eternity Tower Chat Scroll Fix

Automatically scrolls down in chat whenever the chat box is restored/maximized.

  1. // ==UserScript==
  2. // @name Eternity Tower Chat Scroll Fix
  3. // @icon https://www.eternitytower.net/favicon.png
  4. // @namespace http://mean.cloud/
  5. // @version 1.05
  6. // @description Automatically scrolls down in chat whenever the chat box is restored/maximized.
  7. // @match *://eternitytower.net/*
  8. // @match *://www.eternitytower.net/*
  9. // @author psouza4@gmail.com
  10. // @copyright 2018-2023, MeanCloud
  11. // @run-at document-end
  12. // ==/UserScript==
  13.  
  14.  
  15. ////////////////////////////////////////////////////////////////
  16. ////////////// ** SCRIPT GLOBAL INITIALIZATION ** //////////////
  17. function startup() { ETMod_ChatScrollFix.load(); }
  18. ////////////////////////////////////////////////////////////////
  19.  
  20.  
  21. // Note: can't declare this with 'var' or 'window.' etc. or TamperMonkey barfs on eval();
  22. ETMod_ChatScrollFix =
  23. {
  24. lastChatShowStatus: false,
  25.  
  26. load: function()
  27. {
  28. ET.MCMF.Ready(function()
  29. {
  30. Meteor.connection._stream.on('message', function(sMeteorRawData)
  31. {
  32. try
  33. {
  34. var oMeteorData = JSON.parse(sMeteorRawData);
  35.  
  36.  
  37. if (oMeteorData.msg === "changed")
  38. {
  39. if (oMeteorData.collection === "users") {
  40. if (oMeteorData.fields === undefined) return;
  41. if (oMeteorData.fields.uiState === undefined) return;
  42. if (oMeteorData.fields.uiState.showChat === undefined) return;
  43. if (oMeteorData.fields.uiState.showChat) {
  44. ETMod_ChatHelper.lastChatShowStatus = true;
  45. }
  46. else {
  47. ETMod_ChatHelper.lastChatShowStatus = false;
  48. }
  49. }
  50. else if (oMeteorData.collection === "simpleChats")
  51. {
  52. if (oMeteorData.fields === undefined) return;
  53. if (oMeteorData.fields.uiState === undefined) return;
  54. if (oMeteorData.fields.uiState.showChat === undefined) return;
  55. if (oMeteorData.fields.uiState.showChat)
  56. {
  57. if (!ETMod_ChatScrollFix.lastChatShowStatus)
  58. {
  59. ETMod_ChatScrollFix.lastChatShowStatus = true;
  60. // every 250ms for a second = mostly overkill, but it won't affect performance and will catch odd lag instances
  61. for (var i = 1; i <= 4; i++)
  62. {
  63. var oEl_raw;
  64. setTimeout(function()
  65. {
  66. try { oEl_raw = jQ('div.chat-container') .get(0); oEl_raw.scrollTop = oEl_raw.scrollHeight; } catch (err) { }
  67. try { oEl_raw = jQ('div.chat-scroll') .get(0); oEl_raw.scrollTop = oEl_raw.scrollHeight; } catch (err) { }
  68. try { oEl_raw = jQ('div.direct-chat-messages').get(0); oEl_raw.scrollTop = oEl_raw.scrollHeight; } catch (err) { }
  69. try { oEl_raw = jQ('div.scroll-height') .get(0); oEl_raw.scrollTop = oEl_raw.scrollHeight; } catch (err) { }
  70. try { jQ("input#simple-chat-message").focus(); } catch (err) { }
  71. }, 250 * i);
  72. }
  73. }
  74. }
  75. else
  76. ETMod_ChatScrollFix.lastChatShowStatus = false;
  77. }
  78. }
  79. }
  80. catch (err)
  81. {
  82. ET.MCMF.Log("ChatHelper addon exception!");
  83. ET.MCMF.Log(err);
  84. }
  85. });
  86. }, "ChatScrollFix");
  87. }
  88. };
  89.  
  90.  
  91. ////////////////////////////////////////////////////////////////
  92. /////////////// ** common.js -- DO NOT MODIFY ** ///////////////
  93. time_val = function()
  94. {
  95. return CDbl(Math.floor(Date.now() / 1000));
  96. };
  97.  
  98. IsValid = function(oObject)
  99. {
  100. if (oObject === undefined) return false;
  101. if (oObject === null) return false;
  102. return true;
  103. };
  104.  
  105. const CommonRandom = function(iMin, iMax)
  106. {
  107. return parseInt(iMin + Math.floor(Math.random() * iMax));
  108. };
  109.  
  110. ShiftClick = function(oEl)
  111. {
  112. jQ(oEl).trigger(ShiftClickEvent());
  113. };
  114.  
  115. ShiftClickEvent = function(target)
  116. {
  117. let shiftclickOrig = jQ.Event("click");
  118. shiftclickOrig.which = 1; // 1 = left, 2 = middle, 3 = right
  119. //shiftclickOrig.type = "click"; // "mousedown" ?
  120. shiftclickOrig.currentTarget = target;
  121. shiftclickOrig.shiftKey = true;
  122.  
  123. let shiftclick = jQ.Event("click");
  124. //shiftclick.type = "click"; // "mousedown" ?
  125. shiftclick.which = 1; // 1 = left, 2 = middle, 3 = right
  126. shiftclick.shiftKey = true;
  127. shiftclick.currentTarget = target;
  128. shiftclick.originalEvent = shiftclickOrig;
  129.  
  130. //document.ET_Util_Log(shiftclick);
  131.  
  132. return shiftclick;
  133. };
  134.  
  135. if (!String.prototype.replaceAll)
  136. String.prototype.replaceAll = function(search, replace) { return ((replace === undefined) ? this.toString() : this.replace(new RegExp('[' + search + ']', 'g'), replace)); };
  137.  
  138. if (!String.prototype.startsWith)
  139. String.prototype.startsWith = function(search, pos) { return this.substr(((!pos) || (pos < 0)) ? 0 : +pos, search.length) === search; };
  140.  
  141. CInt = function(v)
  142. {
  143. try
  144. {
  145. if (!isNaN(v)) return Math.floor(v);
  146. if (typeof v === 'undefined') return parseInt(0);
  147. if (v === null) return parseInt(0);
  148. let t = parseInt(v);
  149. if (isNaN(t)) return parseInt(0);
  150. return Math.floor(t);
  151. }
  152. catch (err) { }
  153.  
  154. return parseInt(0);
  155. };
  156.  
  157. CDbl = function(v)
  158. {
  159. try
  160. {
  161. if (!isNaN(v)) return parseFloat(v);
  162. if (typeof v === 'undefined') return parseFloat(0.0);
  163. if (v === null) return parseFloat(0.0);
  164. let t = parseFloat(v);
  165. if (isNaN(t)) return parseFloat(0.0);
  166. return t;
  167. }
  168. catch (err) { }
  169.  
  170. return parseFloat(0.0);
  171. };
  172.  
  173. // dup of String.prototype.startsWith, but uses indexOf() instead of substr()
  174. startsWith = function (haystack, needle) { return (needle === "") || (haystack.indexOf(needle) === 0); };
  175. endsWith = function (haystack, needle) { return (needle === "") || (haystack.substring(haystack.length - needle.length) === needle); };
  176.  
  177. Chopper = function(sText, sSearch, sEnd)
  178. {
  179. let sIntermediate = "";
  180.  
  181. if (sSearch === "")
  182. sIntermediate = sText.substring(0, sText.length);
  183. else
  184. {
  185. let iIndexStart = sText.indexOf(sSearch);
  186. if (iIndexStart === -1)
  187. return sText;
  188.  
  189. sIntermediate = sText.substring(iIndexStart + sSearch.length);
  190. }
  191.  
  192. if (sEnd === "")
  193. return sIntermediate;
  194.  
  195. let iIndexEnd = sIntermediate.indexOf(sEnd);
  196.  
  197. return (iIndexEnd === -1) ? sIntermediate : sIntermediate.substring(0, iIndexEnd);
  198. };
  199.  
  200. ChopperBlank = function(sText, sSearch, sEnd)
  201. {
  202. let sIntermediate = "";
  203.  
  204. if (sSearch === "")
  205. sIntermediate = sText.substring(0, sText.length);
  206. else
  207. {
  208. let iIndexStart = sText.indexOf(sSearch);
  209. if (iIndexStart === -1)
  210. return "";
  211.  
  212. sIntermediate = sText.substring(iIndexStart + sSearch.length);
  213. }
  214.  
  215. if (sEnd === "")
  216. return sIntermediate;
  217.  
  218. let iIndexEnd = sIntermediate.indexOf(sEnd);
  219.  
  220. return (iIndexEnd === -1) ? "" : sIntermediate.substring(0, iIndexEnd);
  221. };
  222.  
  223. CondenseSpacing = function(text)
  224. {
  225. while (text.indexOf(" ") !== -1)
  226. text = text.replace(" ", " ");
  227. return text;
  228. };
  229.  
  230. // pad available both ways as pad(string, width, [char]) or string.pad(width, [char])
  231. pad = function(sText, iWidth, sChar)
  232. {
  233. sChar = ((sChar !== undefined) ? sChar : ('0'));
  234. sText = sText.toString();
  235. return ((sText.length >= iWidth) ? (sText) : (new Array(iWidth - sText.length + 1).join(sChar) + sText));
  236. };
  237.  
  238. if (!String.prototype.pad)
  239. String.prototype.pad = function(iWidth, sChar)
  240. {
  241. sChar = ((sChar !== undefined) ? sChar : ('0'));
  242. sText = sText.toString();
  243. return ((sText.length >= iWidth) ? (sText) : (new Array(iWidth - sText.length + 1).join(sChar) + sText));
  244. };
  245.  
  246. String.prototype.toHHMMSS = function () {
  247. var sec_num = parseInt(this, 10);
  248. var hours = Math.floor(sec_num / 3600);
  249. var minutes = Math.floor((sec_num - (hours * 3600)) / 60);
  250. var seconds = sec_num - (hours * 3600) - (minutes * 60);
  251.  
  252. if (hours < 10) {hours = "0"+hours;}
  253. if (minutes < 10) {minutes = "0"+minutes;}
  254. if (seconds < 10) {seconds = "0"+seconds;}
  255. return hours+':'+minutes+':'+seconds;
  256. };
  257. is_visible = (function () {
  258. var x = window.pageXOffset ? window.pageXOffset + window.innerWidth - 1 : 0,
  259. y = window.pageYOffset ? window.pageYOffset + window.innerHeight - 1 : 0,
  260. relative = !!((!x && !y) || !document.elementFromPoint(x, y));
  261. function inside(child, parent) {
  262. while(child){
  263. if (child === parent) return true;
  264. child = child.parentNode;
  265. }
  266. return false;
  267. }
  268. return function (elem) {
  269. if (
  270. hidden ||
  271. elem.offsetWidth==0 ||
  272. elem.offsetHeight==0 ||
  273. elem.style.visibility=='hidden' ||
  274. elem.style.display=='none' ||
  275. elem.style.opacity===0
  276. ) return false;
  277. var rect = elem.getBoundingClientRect();
  278. if (relative) {
  279. if (!inside(document.elementFromPoint(rect.left + elem.offsetWidth/2, rect.top + elem.offsetHeight/2),elem)) return false;
  280. } else if (
  281. !inside(document.elementFromPoint(rect.left + elem.offsetWidth/2 + window.pageXOffset, rect.top + elem.offsetHeight/2 + window.pageYOffset), elem) ||
  282. (
  283. rect.top + elem.offsetHeight/2 < 0 ||
  284. rect.left + elem.offsetWidth/2 < 0 ||
  285. rect.bottom - elem.offsetHeight/2 > (window.innerHeight || document.documentElement.clientHeight) ||
  286. rect.right - elem.offsetWidth/2 > (window.innerWidth || document.documentElement.clientWidth)
  287. )
  288. ) return false;
  289. if (window.getComputedStyle || elem.currentStyle) {
  290. var el = elem,
  291. comp = null;
  292. while (el) {
  293. if (el === document) {break;} else if(!el.parentNode) return false;
  294. comp = window.getComputedStyle ? window.getComputedStyle(el, null) : el.currentStyle;
  295. if (comp && (comp.visibility=='hidden' || comp.display == 'none' || (typeof comp.opacity !=='undefined' && comp.opacity != 1))) return false;
  296. el = el.parentNode;
  297. }
  298. }
  299. return true;
  300. };
  301. })();
  302. ////////////////////////////////////////////////////////////////
  303.  
  304.  
  305. ////////////////////////////////////////////////////////////////
  306. ////////////// ** common_ET.js -- DO NOT MODIFY ** /////////////
  307. if (window.ET === undefined) window.ET = { };
  308. if ((window.ET.MCMF === undefined) || (CDbl(window.ET.MCMF.version) < 1.05)) // MeanCloud mod framework
  309. {
  310. window.ET.MCMF =
  311. {
  312. version: 1.05,
  313. TryingToLoad: false,
  314. WantDebug: false,
  315. WantFasterAbilityCDs: false,
  316.  
  317. InBattle: false,
  318. FinishedLoading: false,
  319. Initialized: false,
  320. AbilitiesReady: false,
  321. InitialAbilityCheck: true,
  322. TimeLeftOnCD: 9999,
  323. TimeLastFight: 0,
  324.  
  325. CombatID: undefined,
  326. BattleID: undefined,
  327.  
  328. ToastMessageSuccess: function(msg)
  329. {
  330. toastr.success(msg);
  331. },
  332.  
  333. ToastMessageWarning: function(msg)
  334. {
  335. toastr.warning(msg);
  336. },
  337.  
  338. EventSubscribe: function(sEventName, fnCallback, sNote)
  339. {
  340. if (window.ET.MCMF.EventSubscribe_events === undefined)
  341. window.ET.MCMF.EventSubscribe_events = [];
  342.  
  343. let newEvtData = {};
  344. newEvtData.name = ((!sEventName.startsWith("ET:")) ? ("ET:" + sEventName) : (sEventName));
  345. newEvtData.callback = fnCallback;
  346. newEvtData.note = sNote;
  347.  
  348. window.ET.MCMF.EventSubscribe_events.push(newEvtData);
  349.  
  350. /*
  351. jQ("div#ET_meancloud_bootstrap").off("ET:" + sEventName.trim()).on("ET:" + sEventName.trim(), function()
  352. {
  353. window.ET.MCMF.EventSubscribe_events.forEach(function(oThisEvent)
  354. {
  355. if (sEventName === oThisEvent.name)
  356. {
  357. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("FIRING '" + oThisEvent.name + "'!" + ((oThisEvent.note === undefined) ? "" : " (" + oThisEvent.note + ")"));
  358. oThisEvent.callback();
  359. }
  360. });
  361. });
  362. */
  363.  
  364. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("Added event subscription '" + sEventName + "'!" + ((sNote === undefined) ? "" : " (" + sNote + ")"));
  365. },
  366.  
  367. EventTrigger: function(sEventName)
  368. {
  369. //jQ("div#ET_meancloud_bootstrap").trigger(sEventName);
  370.  
  371. if (window.ET.MCMF.EventSubscribe_events === undefined) return;
  372.  
  373. window.ET.MCMF.EventSubscribe_events.forEach(function(oThisEvent)
  374. {
  375. if (sEventName === oThisEvent.name)
  376. {
  377. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("FIRING '" + oThisEvent.name + "'!" + ((oThisEvent.note === undefined) ? "" : " (" + oThisEvent.note + ")"));
  378. try { oThisEvent.callback(); } catch (err) { if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("Exception: " + err); }
  379. }
  380. });
  381. },
  382. Log: function(msg)
  383. {
  384. try
  385. {
  386. let now_time = new Date();
  387. let timestamp = (now_time.getMonth() + 1).toString() + "/" + now_time.getDate().toString() + "/" + (now_time.getYear() + 1900).toString() + " " + ((now_time.getHours() === 0) ? (12) : ((now_time.getHours() > 12) ? (now_time.getHours() - 12) : (now_time.getHours()))).toString() + ":" + now_time.getMinutes().toString().padStart(2, "0") + ":" + now_time.getSeconds().toString().padStart(2, "0") + ((now_time.getHours() < 12) ? ("am") : ("pm")) + " :: ";
  388. console.log(timestamp.toString() + msg);
  389. }
  390. catch (err) { }
  391. },
  392.  
  393. Time: function() // returns time in milliseconds (not seconds!)
  394. {
  395. return CInt((new Date()).getTime());
  396. },
  397.  
  398. SubscribeToGameChannel: function(channel_name)
  399. {
  400. let oChannel;
  401.  
  402. try
  403. {
  404. channel_name = channel_name.toString().trim();
  405.  
  406. let bAlreadySubscribed = false;
  407.  
  408. jQuery.makeArray(Object.keys(Package.meteor.global.Accounts.connection._subscriptions).map(key => Package.meteor.global.Accounts.connection._subscriptions[key])).forEach(function(oThisConnection)
  409. {
  410. try
  411. {
  412. if (oThisConnection.name === channel_name)
  413. bAlreadySubscribed = true;
  414. }
  415. catch (err) { }
  416. });
  417.  
  418. if (!bAlreadySubscribed)
  419. {
  420. Meteor.subscribe(channel_name);
  421. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("Meteor::Subscribed to channel '" + channel_name + "'");
  422. }
  423. //else if (ET.MCMF.WantDebug)
  424. // window.ET.MCMF.Log("Meteor::Already subscribed to channel '" + channel_name + "'");
  425. }
  426. catch (err)
  427. {
  428. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("Meteor::Exception in SubscribeToGameChannel(\"" + channel_name + "\")");
  429. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log(err);
  430. }
  431.  
  432. return oChannel;
  433. },
  434. CraftingBuff: function()
  435. {
  436. let oDate, iTimeLeft;
  437. try
  438. {
  439. oDate = new Date(Meteor.connection._stores.state._getCollection().find({ name: "buffCrafting" }).fetch()[0].value.activeTo);
  440. iTimeLeft = ((oDate) > (new Date())) ? CInt(Math.floor(Math.abs(oDate - (new Date())) / 1000.0)) : 0;
  441. return { active: (iTimeLeft > 0), remaining: iTimeLeft, expires: oDate };
  442. }
  443. catch (err) { }
  444. return { active: false, remaining: 0, expires: oDate };
  445. },
  446. CombatBuff: function()
  447. {
  448. let oDate, iTimeLeft;
  449. try
  450. {
  451. oDate = new Date(Meteor.connection._stores.state._getCollection().find({ name: "buffCombat" }).fetch()[0].value.activeTo);
  452. iTimeLeft = ((oDate) > (new Date())) ? CInt(Math.floor(Math.abs(oDate - (new Date())) / 1000.0)) : 0;
  453. return { active: (iTimeLeft > 0), remaining: iTimeLeft, expires: oDate };
  454. }
  455. catch (err) { }
  456. return { active: false, remaining: 0, expires: oDate };
  457. },
  458. GatheringBuff: function()
  459. {
  460. let oDate, iTimeLeft;
  461. try
  462. {
  463. oDate = new Date(Meteor.connection._stores.state._getCollection().find({ name: "buffGathering" }).fetch()[0].value.activeTo);
  464. iTimeLeft = ((oDate) > (new Date())) ? CInt(Math.floor(Math.abs(oDate - (new Date())) / 1000.0)) : 0;
  465. return { active: (iTimeLeft > 0), remaining: iTimeLeft, expires: oDate };
  466. }
  467. catch (err) { }
  468. return { active: false, remaining: 0, expires: oDate };
  469. },
  470. IsNewCombatTab: function()
  471. {
  472. try {
  473. if (window.location.href.indexOf("/newCombat") !== -1) {
  474. return true; }
  475. }
  476. catch (err) {
  477. }
  478. return false;
  479. },
  480. GetActiveTab: function()
  481. {
  482. let active_tab = "";
  483. /*
  484. try
  485. {
  486. active_tab = jQuery(jQuery("a.active").get(0)).text().trim().toLowerCase();
  487. if (active_tab.length === 0)
  488. throw "Invalid active tab";
  489. if (active_tab === "mine") active_tab = "mining";
  490. if (active_tab === "craft") active_tab = "crafting";
  491. if (active_tab === "battle") active_tab = "combat";
  492. if (active_tab === "woodcut") active_tab = "woodcutting";
  493. if (active_tab === "farm") active_tab = "farming";
  494. if (active_tab === "inscribe") active_tab = "inscription";
  495. //if (active_tab === "inscription") active_tab = "inscription";
  496. //if (active_tab === "magic") active_tab = "magic";
  497. //if (active_tab === "shop") active_tab = "shop";
  498. }
  499. catch (err)
  500. {
  501. */
  502. if (window.location.href.indexOf("/gameHome") !== -1) active_tab = "home";
  503. if (window.location.href.indexOf("/mining") !== -1) active_tab = "mining";
  504. if (window.location.href.indexOf("/crafting") !== -1) active_tab = "crafting";
  505. if (window.location.href.indexOf("/combat") !== -1) active_tab = "combat";
  506. if (window.location.href.indexOf("/newCombat") !== -1) active_tab = "combat";
  507. if (window.location.href.indexOf("/woodcutting") !== -1) active_tab = "woodcutting";
  508. if (window.location.href.indexOf("/farming") !== -1) active_tab = "farming";
  509. if (window.location.href.indexOf("/inscription") !== -1) active_tab = "inscription";
  510. if (window.location.href.indexOf("/magic") !== -1) active_tab = "magic";
  511. if (window.location.href.indexOf("/faq") !== -1) active_tab = "faq";
  512. if (window.location.href.indexOf("/chat") !== -1) active_tab = "chat";
  513. if (window.location.href.indexOf("/skills") !== -1) active_tab = "skills";
  514. if (window.location.href.indexOf("/achievements") !== -1) active_tab = "achievements";
  515. if (window.location.href.indexOf("/updates") !== -1) active_tab = "updates";
  516. /*
  517. }
  518. */
  519. return active_tab;
  520. },
  521. GetActiveTabSection: function()
  522. {
  523. let active_tab_section = "";
  524. try
  525. {
  526. let active_tab = window.ET.MCMF.GetActiveTab();
  527.  
  528. if (active_tab === "mining") active_tab_section = Meteor.connection._stores.users._getCollection().find().fetch()[0].uiState.miningTab;
  529. if (active_tab === "crafting") active_tab_section = Meteor.connection._stores.users._getCollection().find().fetch()[0].uiState.craftingFilter;
  530. if (active_tab === "combat")
  531. {
  532. if (window.ET.MCMF.IsNewCombatTab())
  533. active_tab_section = Meteor.connection._stores.users._getCollection().find().fetch()[0].uiState.newCombatType;
  534. else
  535. active_tab_section = Meteor.connection._stores.users._getCollection().find().fetch()[0].uiState.combatTab;
  536. }
  537. if (active_tab === "farming") active_tab_section = Meteor.connection._stores.users._getCollection().find().fetch()[0].uiState.farmingTab;
  538. if (active_tab === "inscription") active_tab_section = Meteor.connection._stores.users._getCollection().find().fetch()[0].uiState.inscriptionFilter;
  539. if (active_tab === "achievements") active_tab_section = Meteor.connection._stores.users._getCollection().find().fetch()[0].uiState.achievementTab;
  540. if (active_tab === "magic") active_tab_section = Meteor.connection._stores.users._getCollection().find().fetch()[0].uiState.magicTab;
  541.  
  542. active_tab_section = active_tab_section.trim().toLowerCase();
  543.  
  544. if (active_tab_section === "minepit") active_tab_section = "mine pit";
  545. if (active_tab_section === "personalquest") active_tab_section = "personal quest";
  546. if (active_tab_section === "tower") active_tab_section = "the tower";
  547. if (active_tab_section === "battlelog") active_tab_section = "battle log";
  548. if (active_tab_section === "pigment") active_tab_section = "pigments";
  549. if (active_tab_section === "book") active_tab_section = "books";
  550. if (active_tab_section === "magic_book") active_tab_section = "magic books";
  551. if (active_tab_section === "spellbook") active_tab_section = "spell book";
  552. if (active_tab_section.length === 0)
  553. throw "Invalid active tab section";
  554. }
  555. catch (err)
  556. {
  557. try
  558. {
  559. active_tab_section = jQuery(jQuery("a.active").get(1)).text().trim().toLowerCase();
  560. if (active_tab_section.length === 0)
  561. throw "Invalid active tab section";
  562. }
  563. catch (err) { }
  564. }
  565. return active_tab_section;
  566. },
  567. BattleSocket_UseAbility: function(abil, targ)
  568. {
  569. try
  570. {
  571. let sMsg = '';
  572. if (targ === undefined)
  573. {
  574. sMsg = '["action",{"abilityId":"' + abil + '","targets":[],"caster":"' + window.ET.MCMF.UserID + '"}]';
  575. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("Battle socket emitting: '" + sMsg + "'");
  576. battleSocket.emit
  577. (
  578. "action",
  579. {
  580. abilityId: abil,
  581. targets: [],
  582. caster: window.ET.MCMF.UserID
  583. }
  584. );
  585. }
  586. else
  587. {
  588. sMsg = '["action",{"abilityId":"' + abil + '","targets":[' + targ + '],"caster":"' + window.ET.MCMF.UserID + '"}]';
  589. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("Battle socket emitting: '" + sMsg + "'");
  590. battleSocket.emit
  591. (
  592. "action",
  593. {
  594. abilityId: abil,
  595. targets: [targ],
  596. caster: window.ET.MCMF.UserID
  597. }
  598. );
  599. }
  600. }
  601. catch (err) { }
  602. },
  603.  
  604. CallGameCmd: function()
  605. {
  606. try
  607. {
  608. if (arguments.length > 0)
  609. {
  610. let cmd = arguments[0];
  611. let fnc = function() { };
  612.  
  613. if (arguments.length === 1)
  614. {
  615. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("Calling: '" + cmd + "' with no data");
  616. Package.meteor.Meteor.call(cmd, fnc);
  617. }
  618. else
  619. {
  620. let data1, data2, data3, data4;
  621.  
  622. if (typeof arguments[arguments.length - 1] === "function")
  623. {
  624. fnc = arguments[arguments.length - 1];
  625. if (arguments.length >= 3) data1 = arguments[1];
  626. if (arguments.length >= 4) data2 = arguments[2];
  627. if (arguments.length >= 5) data3 = arguments[3];
  628. if (arguments.length >= 6) data4 = arguments[4];
  629. }
  630. else
  631. {
  632. if (arguments.length >= 2) data1 = arguments[1];
  633. if (arguments.length >= 3) data2 = arguments[2];
  634. if (arguments.length >= 4) data3 = arguments[3];
  635. if (arguments.length >= 5) data4 = arguments[4];
  636. }
  637.  
  638. if (data1 === undefined)
  639. {
  640. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("Calling: '" + cmd + "' with no data");
  641. Package.meteor.Meteor.call(cmd, fnc);
  642. }
  643. else if (data2 === undefined)
  644. {
  645. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("Calling: '" + cmd + "' with { " + JSON.stringify(data1) + " }");
  646. Package.meteor.Meteor.call(cmd, data1, fnc);
  647. }
  648. else if (data3 === undefined)
  649. {
  650. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("Calling: '" + cmd + "' with { " + JSON.stringify(data1) + ", " + JSON.stringify(data2) + " }");
  651. Package.meteor.Meteor.call(cmd, data1, data2, fnc);
  652. }
  653. else if (data4 === undefined)
  654. {
  655. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("Calling: '" + cmd + "' with { " + JSON.stringify(data1) + ", " + JSON.stringify(data2) + ", " + JSON.stringify(data3) + " }");
  656. Package.meteor.Meteor.call(cmd, data1, data2, data3, fnc);
  657. }
  658. else
  659. {
  660. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("Calling: '" + cmd + "' with { " + JSON.stringify(data1) + ", " + JSON.stringify(data2) + ", " + JSON.stringify(data3) + ", " + JSON.stringify(data4) + " }");
  661. Package.meteor.Meteor.call(cmd, data1, data2, data3, data4, fnc);
  662. }
  663. }
  664. }
  665. else if (window.ET.MCMF.WantDebug)
  666. window.ET.MCMF.Log("Meteor::Warning, CallGameCmd() with no arguments!");
  667. }
  668. catch (err)
  669. {
  670. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("Meteor::Exception in CallGameCmd()");
  671. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log(err);
  672. }
  673. },
  674.  
  675. SendGameCmd: function(cmd)
  676. {
  677. try
  678. {
  679. Meteor.connection._send(cmd);
  680. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("Meteor::Sending: " + JSON.stringify(cmd));
  681. }
  682. catch (err)
  683. {
  684. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("Meteor::Exception in SendGameCmd(" + JSON.stringify(cmd) + ")");
  685. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log(err);
  686. }
  687. },
  688.  
  689. FasterAbilityUpdates: function()
  690. {
  691. try
  692. {
  693. window.ET.MCMF.SubscribeToGameChannel("abilities");
  694. if ((window.ET.MCMF.WantFasterAbilityCDs) && (window.ET.MCMF.FinishedLoading) && (!window.ET.MCMF.InBattle) && (!window.ET.MCMF.AbilitiesReady))
  695. window.ET.MCMF.CallGameCmd("abilities.gameUpdate");
  696. }
  697. catch (err) { }
  698.  
  699. setTimeout(window.ET.MCMF.FasterAbilityUpdates, 2000);
  700. },
  701.  
  702. PlayerInCombat: function()
  703. {
  704. return ((window.ET.MCMF.InBattle) || ((time_val() - window.ET.MCMF.TimeLastFight) < 3));
  705. },
  706. AbilityCDTrigger: function()
  707. {
  708. try
  709. {
  710. if ((window.ET.MCMF.FinishedLoading) && (!window.ET.MCMF.PlayerInCombat()))
  711. {
  712. iTotalCD = 0;
  713. iTotalCDTest = 0;
  714. iHighestCD = 0;
  715.  
  716. window.ET.MCMF.GetAbilities().forEach(function(oThisAbility)
  717. {
  718. if (oThisAbility.equipped)
  719. {
  720. if (parseInt(oThisAbility.currentCooldown) > 0)
  721. {
  722. iTotalCD += parseInt(oThisAbility.currentCooldown);
  723. if (iHighestCD < parseInt(oThisAbility.currentCooldown))
  724. iHighestCD = parseInt(oThisAbility.currentCooldown);
  725. }
  726. }
  727.  
  728. iTotalCDTest += parseInt(oThisAbility.cooldown);
  729. });
  730.  
  731. if ((iTotalCDTest > 0) && (iTotalCD === 0))
  732. {
  733. if (!window.ET.MCMF.AbilitiesReady)
  734. {
  735. if (!window.ET.MCMF.InitialAbilityCheck)
  736. {
  737. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("<-- triggering ET:abilitiesReady -->");
  738. window.ET.MCMF.EventTrigger("ET:abilitiesReady");
  739. }
  740. }
  741.  
  742. window.ET.MCMF.AbilitiesReady = true;
  743. window.ET.MCMF.TimeLeftOnCD = 0;
  744. }
  745. else
  746. {
  747. window.ET.MCMF.AbilitiesReady = false;
  748. window.ET.MCMF.TimeLeftOnCD = iHighestCD;
  749. }
  750.  
  751. window.ET.MCMF.InitialAbilityCheck = false;
  752. }
  753. else
  754. {
  755. window.ET.MCMF.AbilitiesReady = false;
  756. window.ET.MCMF.TimeLeftOnCD = 9999;
  757. }
  758. }
  759. catch (err) { }
  760.  
  761. setTimeout(window.ET.MCMF.AbilityCDTrigger, 500);
  762. },
  763. BattleUITemplate: undefined,
  764.  
  765. LiveBattleData: function()
  766. {
  767. try
  768. {
  769. if (window.ET.MCMF.BattleUITemplate !== undefined)
  770. return window.ET.MCMF.BattleUITemplate.state.get("currentBattle");
  771. }
  772. catch (err) { }
  773. return undefined;
  774. },
  775. InitGameTriggers: function()
  776. {
  777. if ((Package.meteor.Meteor === undefined) || (Package.meteor.Meteor.connection === undefined) || (Package.meteor.Meteor.connection._stream === undefined) || (Template.currentBattleUi === undefined))
  778. {
  779. setTimeout(window.ET.MCMF.InitGameTriggers, 100);
  780. return;
  781. }
  782. Template.currentBattleUi.onCreated(function()
  783. {
  784. window.ET.MCMF.BattleUITemplate = this;
  785. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("<-- Template.currentBattleUi.onCreated triggered -->");
  786. });
  787. Template.currentBattleUi.onDestroyed(function()
  788. {
  789. window.ET.MCMF.BattleUITemplate = undefined;
  790. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("<-- Template.currentBattleUi.onDestroyed triggered -->");
  791. });
  792.  
  793. Package.meteor.Meteor.connection._stream.on('message', function(sMeteorRawData)
  794. {
  795. if (window.ET.MCMF.CombatID === undefined)
  796. window.ET.MCMF.GetPlayerCombatData();
  797.  
  798. try
  799. {
  800. oMeteorData = JSON.parse(sMeteorRawData);
  801.  
  802. /////////////////////////////////////////////////////////////////////////////////////////////////////////
  803. //
  804. // BACKUP TO RETRIEVE USER AND COMBAT IDS
  805. //
  806. if (oMeteorData.collection === "users")
  807. if ((window.ET.MCMF.UserID === undefined) || (window.ET.MCMF.UserID.length !== 17))
  808. window.ET.MCMF.UserID = oMeteorData.id;
  809.  
  810. if (oMeteorData.collection === "combat")
  811. if ((window.ET.MCMF.CombatID === undefined) || (window.ET.MCMF.CombatID.length !== 17))
  812. if (oMeteorData.fields.owner === window.ET.MCMF.UserID)
  813. window.ET.MCMF.CombatID = oMeteorData.id;
  814. //
  815. /////////////////////////////////////////////////////////////////////////////////////////////////////////
  816.  
  817. if (oMeteorData.collection === "battlesList")
  818. {
  819. window.ET.MCMF.AbilitiesReady = false;
  820.  
  821. if ((oMeteorData.msg === "added") || (oMeteorData.msg === "removed"))
  822. {
  823. window.ET.MCMF.InBattle = (oMeteorData.msg === "added");
  824. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("<-- triggering ET:combat" + (((oMeteorData.msg === "added")) ? ("Start") : ("End")) + " -->");
  825. window.ET.MCMF.EventTrigger("ET:combat" + (((oMeteorData.msg === "added")) ? ("Start") : ("End")));
  826. if (window.ET.MCMF.InBattle)
  827. {
  828. battleSocket.on('tick', function(oAllData)
  829. {
  830. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("<-- triggering ET:combatTick -->");
  831. window.ET.MCMF.EventTrigger("ET:combatTick");
  832. });
  833. }
  834. }
  835. }
  836.  
  837. if ((oMeteorData.collection === "battles") && (oMeteorData.msg === "added"))
  838. {
  839. if (oMeteorData.fields.finished)
  840. {
  841. window.ET.MCMF.WonLast = oMeteorData.fields.win;
  842. window.ET.MCMF.TimeLastFight = time_val();
  843.  
  844. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("<-- triggering ET:combat" + ((oMeteorData.fields.win) ? ("Won") : ("Lost")) + " -->");
  845. window.ET.MCMF.EventTrigger("ET:combat" + ((oMeteorData.fields.win) ? ("Won") : ("Lost")));
  846. }
  847. }
  848. }
  849. catch (err) { }
  850. });
  851. },
  852. PlayerHP: function()
  853. {
  854. //if (!window.ET.MCMF.PlayerInCombat())
  855. return window.ET.MCMF.GetPlayerCombatData().stats.health;
  856. //return window.ET.MCMF.PlayerUnitData.stats.health;
  857. },
  858. PlayerHPMax: function()
  859. {
  860. //if (!window.ET.MCMF.PlayerInCombat())
  861. return window.ET.MCMF.GetPlayerCombatData().stats.healthMax;
  862. //return window.ET.MCMF.PlayerUnitData.stats.healthMax;
  863. },
  864. PlayerEnergy: function()
  865. {
  866. //if (!window.ET.MCMF.PlayerInCombat())
  867. return window.ET.MCMF.GetPlayerCombatData().stats.energy;
  868. //return window.ET.MCMF.PlayerUnitData.stats.energy;
  869. },
  870.  
  871. AbilityCDCalc: function()
  872. {
  873. iTotalCD = 0;
  874. iTotalCDTest = 0;
  875. iHighestCD = 0;
  876.  
  877. window.ET.MCMF.GetAbilities().forEach(function(oThisAbility)
  878. {
  879. if (oThisAbility.equipped)
  880. {
  881. if (parseInt(oThisAbility.currentCooldown) > 0)
  882. {
  883. iTotalCD += parseInt(oThisAbility.currentCooldown);
  884. if (iHighestCD < parseInt(oThisAbility.currentCooldown))
  885. iHighestCD = parseInt(oThisAbility.currentCooldown);
  886. }
  887. }
  888.  
  889. iTotalCDTest += parseInt(oThisAbility.cooldown);
  890. });
  891.  
  892. if ((iTotalCDTest > 0) && (iTotalCD === 0))
  893. {
  894. if (!window.ET.MCMF.AbilitiesReady)
  895. {
  896. if (!window.ET.MCMF.InitialAbilityCheck)
  897. {
  898. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("<-- triggering ET:abilitiesReady -->");
  899. window.ET.MCMF.EventTrigger("ET:abilitiesReady");
  900. //jQ("div#ET_meancloud_bootstrap").trigger("ET:abilitiesReady");
  901. }
  902. }
  903.  
  904. window.ET.MCMF.AbilitiesReady = true;
  905. window.ET.MCMF.TimeLeftOnCD = 0;
  906. }
  907. else
  908. {
  909. window.ET.MCMF.AbilitiesReady = false;
  910. window.ET.MCMF.TimeLeftOnCD = iHighestCD;
  911. }
  912.  
  913. window.ET.MCMF.InitialAbilityCheck = false;
  914. },
  915.  
  916. GetUnitCombatData: function(sUnitID)
  917. {
  918. let oCombatPlayerData;
  919. try
  920. {
  921. // get recent combat data from stored 'state' data in 'BattleUITemplate' template (comes from 'battleSocket')
  922. if (window.ET.MCMF.LiveBattleData() !== undefined)
  923. {
  924. jQ.makeArray(window.ET.MCMF.LiveBattleData().units).forEach(function(oCurrentUnit)
  925. {
  926. if (oCurrentUnit.id === sUnitID)
  927. oCombatPlayerData = oCurrentUnit;
  928. });
  929. }
  930. }
  931. catch (err) { }
  932. return oCombatPlayerData;
  933. },
  934. GetEnemyCombatData: function(sUnitID)
  935. {
  936. let oCombatEnemyData;
  937. try
  938. {
  939. // get recent combat data from stored 'state' data in 'BattleUITemplate' template (comes from 'battleSocket')
  940. if (window.ET.MCMF.LiveBattleData() !== undefined)
  941. {
  942. jQ.makeArray(window.ET.MCMF.LiveBattleData().enemies).forEach(function(oCurrentUnit)
  943. {
  944. if (oCurrentUnit.id === sUnitID)
  945. oCombatEnemyData = oCurrentUnit;
  946. });
  947. }
  948. }
  949. catch (err) { }
  950. return oCombatEnemyData;
  951. },
  952. GetPlayerCombatData: function()
  953. {
  954. let oCombatPlayerData;
  955. try
  956. {
  957. window.ET.MCMF.CombatID = undefined;
  958. Meteor.connection._stores.combat._getCollection().find().fetch().forEach(function(oThisCombatUnit)
  959. {
  960. if (oThisCombatUnit.owner === window.ET.MCMF.UserID)
  961. {
  962. oCombatPlayerData = oThisCombatUnit;
  963. window.ET.MCMF.CombatID = oCombatPlayerData._id;
  964. if (!window.ET.MCMF.PlayerInCombat())
  965. window.ET.MCMF.PlayerUnitData = oCombatPlayerData;
  966. }
  967. });
  968. // new: get updated combat data from stored 'state' data in 'BattleUITemplate' template (comes from 'battleSocket')
  969. if (window.ET.MCMF.LiveBattleData() !== undefined)
  970. {
  971. jQ.makeArray(window.ET.MCMF.LiveBattleData().units).forEach(function(oCurrentUnit)
  972. {
  973. if (oCurrentUnit.id === window.ET.MCMF.UserID)
  974. window.ET.MCMF.PlayerUnitData = oCurrentUnit;
  975. });
  976. oCombatPlayerData = window.ET.MCMF.PlayerUnitData;
  977. }
  978. }
  979. catch (err) { }
  980. return oCombatPlayerData;
  981. },
  982. GetAbilities: function()
  983. {
  984. return Meteor.connection._stores.abilities._getCollection().find().fetch()[0].learntAbilities;
  985. },
  986. GetAdventures: function()
  987. {
  988. let oAdventureDetails = { AllAdventures: [], ShortAdventures: [], LongAdventures: [], EpicAdventures: [], PhysicalAdventures: [], MagicalAdventures: [], ActiveAdventures: [], CurrentAdventure: undefined };
  989. // oThisAdventure
  990. // .duration {duration in seconds} (integer)
  991. // .endDate {end date/time} (Date()) (property only exists if the adventure is ongoing)
  992. // .floor {corresponding Tower Floor} (integer)
  993. // .icon "{imageofbattle.ext}" (string)
  994. // .id "{guid}" (13-digit alphanumeric string)
  995. // .length "short" / "long" / "epic" (string)
  996. // .level {general level} (integer)
  997. // .name "{Name of Battle}" (string)
  998. // .room {corresponding Tower Room in Tower Floor} (integer)
  999. // .type "physical" / "magic" (string)
  1000. // .startDate {start date/time} (Date()) (property only exists if the adventure is ongoing)
  1001. window.ET.MCMF.GetAdventures_raw().forEach(function(oThisAdventure)
  1002. {
  1003. try
  1004. {
  1005. oAdventureDetails.AllAdventures.push(oThisAdventure);
  1006. if (oThisAdventure.length === "short") oAdventureDetails.ShortAdventures .push(oThisAdventure);
  1007. if (oThisAdventure.length === "long") oAdventureDetails.LongAdventures .push(oThisAdventure);
  1008. if (oThisAdventure.length === "epic") oAdventureDetails.EpicAdventures .push(oThisAdventure);
  1009. if (oThisAdventure.type === "physical") oAdventureDetails.PhysicalAdventures.push(oThisAdventure);
  1010. if (oThisAdventure.type === "magic") oAdventureDetails.MagicalAdventures .push(oThisAdventure);
  1011. if (oThisAdventure.endDate !== undefined) oAdventureDetails.ActiveAdventures .push(oThisAdventure);
  1012. }
  1013. catch (err) { }
  1014. });
  1015. oAdventureDetails.AllAdventures.sort(function(advA, advB)
  1016. {
  1017. if ((advA.startDate === undefined) && (advB.startDate !== undefined)) return 1;
  1018. if ((advA.startDate !== undefined) && (advB.startDate === undefined)) return -1;
  1019. if ((advA.startDate !== undefined) && (advB.startDate !== undefined))
  1020. {
  1021. if (advA.startDate > advB.startDate) return 1;
  1022. if (advA.startDate < advB.startDate) return -1;
  1023. }
  1024. if (advA.duration > advB.duration) return 1;
  1025. if (advA.duration < advB.duration) return -1;
  1026. return 0;
  1027. });
  1028. oAdventureDetails.ActiveAdventures.sort(function(advA, advB)
  1029. {
  1030. if (advA.startDate > advB.startDate) return 1;
  1031. if (advA.startDate < advB.startDate) return -1;
  1032. return 0;
  1033. });
  1034. oAdventureDetails.PhysicalAdventures.sort(function(advA, advB)
  1035. {
  1036. if (advA.duration > advB.duration) return 1;
  1037. if (advA.duration < advB.duration) return -1;
  1038. return 0;
  1039. });
  1040. oAdventureDetails.MagicalAdventures.sort(function(advA, advB)
  1041. {
  1042. if (advA.duration > advB.duration) return 1;
  1043. if (advA.duration < advB.duration) return -1;
  1044. return 0;
  1045. });
  1046. if (oAdventureDetails.ActiveAdventures.length > 0)
  1047. oAdventureDetails.CurrentAdventure = oAdventureDetails.ActiveAdventures[0];
  1048. return oAdventureDetails;
  1049. },
  1050.  
  1051. GetAdventures_raw: function()
  1052. {
  1053. return Meteor.connection._stores.adventures._getCollection().find().fetch()[0].adventures;
  1054. },
  1055. GetChats: function()
  1056. {
  1057. return Meteor.connection._stores.simpleChats._getCollection().find().fetch();
  1058. },
  1059.  
  1060. GetItems: function()
  1061. {
  1062. return Meteor.connection._stores.items._getCollection().find().fetch();
  1063. },
  1064. GetSkills: function()
  1065. {
  1066. return Meteor.connection._stores.skills._getCollection().find().fetch();
  1067. },
  1068.  
  1069. // need a better way to check if the game has loaded basic data, but this is fine for now
  1070. Setup: function()
  1071. {
  1072. if ((!window.ET.MCMF.TryingToLoad) && (!window.ET.MCMF.FinishedLoading))
  1073. {
  1074. // use whatever version of jQuery available to us
  1075. $("body").append("<div id=\"ET_meancloud_bootstrap\" style=\"visibility: hidden; display: none;\"></div>");
  1076. window.ET.MCMF.TryingToLoad = true;
  1077. window.ET.MCMF.Setup_Initializer();
  1078. }
  1079. },
  1080.  
  1081. Setup_Initializer: function()
  1082. {
  1083. // wait for Meteor availability
  1084. if ((Package === undefined) || (Package.meteor === undefined) || (Package.meteor.Meteor === undefined) || (Package.meteor.Meteor.connection === undefined) || (Package.meteor.Meteor.connection._stream === undefined))
  1085. {
  1086. setTimeout(window.ET.MCMF.Setup_Initializer, 10);
  1087. return;
  1088. }
  1089.  
  1090. if (!window.ET.MCMF.Initialized)
  1091. {
  1092. window.ET.MCMF.Initialized = true;
  1093. window.ET.MCMF.Setup_SendDelayedInitializer();
  1094. window.ET.MCMF.InitGameTriggers();
  1095. window.ET.MCMF.Setup_remaining();
  1096. }
  1097. },
  1098.  
  1099. Setup_SendDelayedInitializer: function()
  1100. {
  1101. try
  1102. {
  1103. jQ("div#ET_meancloud_bootstrap").trigger("ET:initialized");
  1104. window.ET.MCMF.EventTrigger("ET:initialized");
  1105. //if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("<-- triggering ET:initialized -->");
  1106. }
  1107. catch (err)
  1108. {
  1109. setTimeout(window.ET.MCMF.Setup_SendDelayedInitializer, 100);
  1110. }
  1111. },
  1112.  
  1113. Setup_remaining: function()
  1114. {
  1115. try
  1116. {
  1117. if (Meteor === undefined) throw "[MCMF Setup] Not loaded yet: Meteor not initialized";
  1118. if (Meteor.connection === undefined) throw "[MCMF Setup] Not loaded yet: Meteor not initialized";
  1119. if (Meteor.connection._userId === undefined) throw "[MCMF Setup] Not loaded yet: Meteor not initialized";
  1120. window.ET.MCMF.UserID = Meteor.connection._userId;
  1121. window.ET.MCMF.UserName = [...Meteor.connection._stores.users._getCollection()._collection._docs._map.values()][0].username;
  1122. window.ET.MCMF.GetPlayerCombatData();
  1123.  
  1124. if (window.ET.MCMF.GetAbilities().length < 0) throw "[MCMF Setup] Not loaded yet: no abilities";
  1125. if (window.ET.MCMF.GetItems().length < 0) throw "[MCMF Setup]Not loaded yet: no items";
  1126. if (window.ET.MCMF.GetChats().length < 0) throw "[MCMF Setup]Not loaded yet: no chats";
  1127. if (window.ET.MCMF.GetSkills().length < 0) throw "[MCMF Setup]Not loaded yet: no skills";
  1128.  
  1129. // if the above is all good, then this should be no problem:
  1130.  
  1131. window.ET.MCMF.AbilityCDTrigger(); // set up ability CD trigger
  1132. window.ET.MCMF.AbilityCDCalc();
  1133. window.ET.MCMF.FasterAbilityUpdates(); // set up faster ability updates (do not disable, this is controlled via configurable setting)
  1134.  
  1135. // trigger finished-loading event
  1136. if (!window.ET.MCMF.FinishedLoading)
  1137. {
  1138. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("<-- triggering ET:loaded -->");
  1139. window.ET.MCMF.EventTrigger("ET:loaded");
  1140. window.ET.MCMF.FinishedLoading = true;
  1141. }
  1142. }
  1143. catch (err) // any errors and we retry setup
  1144. {
  1145. if (err.toString().indexOf("[MCMF Setup]") !== -1)
  1146. {
  1147. window.ET.MCMF.Log("ET MCMF setup exception");
  1148. window.ET.MCMF.Log(err);
  1149. }
  1150. setTimeout(window.ET.MCMF.Setup_remaining, 500);
  1151. }
  1152. },
  1153.  
  1154. // Ready means the mod framework has been initialized, but Meteor is not yet available
  1155. Ready: function(fnCallback, sNote)
  1156. {
  1157. if (!window.ET.MCMF.Initialized)
  1158. window.ET.MCMF.EventSubscribe("initialized", fnCallback, sNote);
  1159. else
  1160. fnCallback();
  1161. },
  1162.  
  1163. // Loaded means the mod framework and Meteor are fully loaded and available
  1164. Loaded: function(fnCallback, sNote)
  1165. {
  1166. if (!window.ET.MCMF.FinishedLoading)
  1167. window.ET.MCMF.EventSubscribe("loaded", fnCallback, sNote);
  1168. else
  1169. fnCallback();
  1170. },
  1171. };
  1172.  
  1173. window.ET.MCMF.Setup();
  1174. }
  1175. ////////////////////////////////////////////////////////////////
  1176.  
  1177.  
  1178. ////////////////////////////////////////////////////////////////
  1179. ////////// ** CORE SCRIPT STARTUP -- DO NOT MODIFY ** //////////
  1180. function LoadJQ(callback) {
  1181. if (window.jQ === undefined) { var script=document.createElement("script");script.setAttribute("src","//ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js");script.addEventListener('load',function() {
  1182. var subscript=document.createElement("script");subscript.textContent="window.jQ=jQuery.noConflict(true);("+callback.toString()+")();";document.body.appendChild(subscript); },
  1183. !1);document.body.appendChild(script); } else callback(); } LoadJQ(startup);
  1184. ////////////////////////////////////////////////////////////////