Dreadcast Development Kit

Development kit to ease Dreadcast scripts integration.

当前为 2024-10-08 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Dreadcast Development Kit
  3. // @namespace Dreadcast
  4. // @match https://www.dreadcast.net/Main
  5. // @version 1.1.2
  6. // @author Pelagia/Isilin
  7. // @description Development kit to ease Dreadcast scripts integration.
  8. // @license https://github.com/Isilin/dreadcast-scripts?tab=GPL-3.0-1-ov-file
  9. // @grant GM_xmlhttpRequest
  10. // @grant GM_addStyle
  11. // @grant GM_setValue
  12. // @grant GM_getValue
  13. // @grant GM_deleteValue
  14. // @grant GM_listValues
  15. // @connect docs.google.com
  16. // @connect googleusercontent.com
  17. // @connect sheets.googleapis.com
  18. // @connect raw.githubusercontent.com
  19. // ==/UserScript==
  20.  
  21. // ===== JQuery utilities =====
  22.  
  23. $.fn.insertAt = function (index, element) {
  24. var lastIndex = this.children().size();
  25. if (index < 0) {
  26. index = Math.max(0, lastIndex + 1 + index);
  27. }
  28. this.append(element);
  29. if (index < lastIndex) {
  30. this.children().eq(index).before(this.children().last());
  31. }
  32. return this;
  33. };
  34.  
  35. // ===== Lib =====
  36.  
  37. const Util = {
  38. guard: (condition, message) => {
  39. if (!condition) throw new Error(message);
  40. return;
  41. },
  42.  
  43. deprecate: (name, replacement) => {
  44. console.warn(
  45. name +
  46. ': this function has been deprecated and should not be used anymore.' +
  47. (replacement && replacement !== ''
  48. ? 'Prefer: ' + replacement + '.'
  49. : ''),
  50. );
  51. },
  52.  
  53. isArray: (o, optional = false) =>
  54. $.type(o) === 'array' ||
  55. (optional && ($.type(o) === 'undefined' || $.type(o) === 'null')),
  56.  
  57. isString: (o, optional = false) =>
  58. $.type(o) === 'string' ||
  59. (optional && ($.type(o) === 'undefined' || $.type(o) === 'null')),
  60.  
  61. isBoolean: (o, optional = false) =>
  62. $.type(o) === 'boolean' ||
  63. (optional && ($.type(o) === 'undefined' || $.type(o) === 'null')),
  64.  
  65. isNumber: (o, optional = false) =>
  66. $.type(o) === 'number' ||
  67. (optional && ($.type(o) === 'undefined' || $.type(o) === 'null')),
  68.  
  69. isFunction: (o, optional = false) =>
  70. $.type(o) === 'function' ||
  71. (optional && ($.type(o) === 'undefined' || $.type(o) === 'null')),
  72.  
  73. isDate: (o, optional = false) =>
  74. $.type(o) === 'date' ||
  75. (optional && ($.type(o) === 'undefined' || $.type(o) === 'null')),
  76.  
  77. isError: (o, optional = false) =>
  78. $.type(o) === 'error' ||
  79. (optional && ($.type(o) === 'undefined' || $.type(o) === 'null')),
  80.  
  81. isRegex: (o, optional = false) =>
  82. $.type(o) === 'regexp' ||
  83. (optional && ($.type(o) === 'undefined' || $.type(o) === 'null')),
  84.  
  85. isObject: (o, optional = false) =>
  86. $.type(o) === 'object' ||
  87. (optional && ($.type(o) === 'undefined' || $.type(o) === 'null')),
  88.  
  89. isColor: (o, optional = false) => {
  90. if (optional && ($.type(o) === 'undefined' || $.type(o) === 'null'))
  91. return true;
  92. else {
  93. const colors = ['rouge', 'bleu', 'vert', 'jaune'];
  94. return (
  95. $.type(o) === 'string' &&
  96. (colors.includes(o) ||
  97. o.match(/^[0-9a-f]{8}|[0-9a-f]{6}|[0-9a-f]{4}|[0-9a-f]{3}$/gi))
  98. );
  99. }
  100. },
  101.  
  102. isJQuery: (o, optional = false) =>
  103. (optional && ($.type(o) === 'undefined' || $.type(o) === 'null')) ||
  104. o instanceof $,
  105.  
  106. guardArray: (context, name, parameter, optional = false) =>
  107. Util.guard(
  108. Util.isArray(parameter, optional),
  109. `${context}: '${name}' ${
  110. optional ? 'optional ' : ''
  111. }parameter should be an array.`,
  112. ),
  113.  
  114. guardString: (context, name, parameter, optional = false) =>
  115. Util.guard(
  116. Util.isString(parameter, optional),
  117. `${context}: '${name}' ${
  118. optional ? 'optional ' : ''
  119. }parameter should be a string.`,
  120. ),
  121.  
  122. guardBoolean: (context, name, parameter, optional = false) =>
  123. Util.guard(
  124. Util.isBoolean(parameter, optional),
  125. `${context}: '${name}' ${
  126. optional ? 'optional ' : ''
  127. }parameter should be a boolean.`,
  128. ),
  129.  
  130. guardNumber: (context, name, parameter, optional = false) =>
  131. Util.guard(
  132. Util.isNumber(parameter, optional),
  133. `${context}: '${name}' ${
  134. optional ? 'optional ' : ''
  135. }parameter should be a number.`,
  136. ),
  137.  
  138. guardFunction: (context, name, parameter, optional = false) =>
  139. Util.guard(
  140. Util.isFunction(parameter, optional),
  141. `${context}: '${name}' ${
  142. optional ? 'optional ' : ''
  143. }parameter should be a a function.`,
  144. ),
  145.  
  146. guardDate: (context, name, parameter, optional = false) =>
  147. Util.guard(
  148. Util.isDate(parameter, optional),
  149. `${context}: '${name}' ${
  150. optional ? 'optional ' : ''
  151. }parameter should be a date.`,
  152. ),
  153.  
  154. guardError: (context, name, parameter, optional = false) =>
  155. Util.guard(
  156. Util.isError(parameter, optional),
  157. `${context}: '${name}' ${
  158. optional ? 'optional ' : ''
  159. }parameter should be an error.`,
  160. ),
  161.  
  162. guardRegex: (context, name, parameter, optional = false) =>
  163. Util.guard(
  164. Util.isRegex(parameter, optional),
  165. `${context}: '${name}' ${
  166. optional ? 'optional ' : ''
  167. }parameter should be a regex.`,
  168. ),
  169.  
  170. guardObject: (context, name, parameter, optional = false) =>
  171. Util.guard(
  172. Util.isObject(parameter, optional),
  173. `${context}: '${name}' ${
  174. optional ? 'optional ' : ''
  175. }parameter should be an object.`,
  176. ),
  177.  
  178. guardColor: (context, name, parameter, optional = false) =>
  179. Util.guard(
  180. Util.isColor(parameter, optional),
  181. `${context}: '${name}' ${
  182. optional ? 'optional ' : ''
  183. }parameter should be a color.`,
  184. ),
  185.  
  186. guardJQuery: (context, name, parameter, optional = false) =>
  187. Util.guard(
  188. Util.isJQuery(parameter, optional),
  189. `${context}: '${name}' ${
  190. optional ? 'optional ' : ''
  191. }parameter should be a jQuery element.`,
  192. ),
  193.  
  194. isGame: () => window.location.href.includes('https://www.dreadcast.net/Main'),
  195.  
  196. isForum: () =>
  197. window.location.href.includes('https://www.dreadcast.net/Forum') ||
  198. window.location.href.includes('https://www.dreadcast.net/FAQ'),
  199.  
  200. isEDC: () => window.location.href.includes('https://www.dreadcast.net/EDC'),
  201.  
  202. isWiki: () => window.location.href.includes('http://wiki.dreadcast.eu/wiki'),
  203.  
  204. getContext: () => {
  205. return Util.isGame()
  206. ? 'game'
  207. : Util.isForum()
  208. ? 'forum'
  209. : Util.isEDC()
  210. ? 'edc'
  211. : 'wiki';
  212. },
  213. };
  214.  
  215. // ===== Overwrite DC functions =====
  216.  
  217. if (Util.isGame() && MenuChat.prototype.originalSend === undefined) {
  218. MenuChat.prototype.originalSend = MenuChat.prototype.send;
  219. MenuChat.prototype.sendCallbacks = [];
  220. MenuChat.prototype.afterSendCallbacks = [];
  221. MenuChat.prototype.send = function () {
  222. const $nextFn = () => true;
  223. const $abortFn = () => false;
  224. const $message = $('#chatForm .text_chat').val();
  225. const $res = this.sendCallbacks.every((callback) =>
  226. callback($message, $nextFn, $abortFn),
  227. );
  228. if (!$res) {
  229. throw new Error('MenuChat.prototype.send: Error on sending message.');
  230. }
  231.  
  232. this.originalSend();
  233.  
  234. this.afterSendCallbacks.every((callback) => callback($message));
  235. };
  236. MenuChat.prototype.onSend = (callback) => {
  237. Util.guard(
  238. Util.isGame(),
  239. 'MenuChat.prototype.onSend: this function should be called in Game only.',
  240. );
  241. MenuChat.prototype.sendCallbacks.push(callback);
  242. };
  243. MenuChat.prototype.onAfterSend = (callback) => {
  244. Util.guard(
  245. Util.isGame(),
  246. 'MenuChat.prototype.onSend: this function should be called in Game only.',
  247. );
  248. MenuChat.prototype.afterSendCallbacks.push(callback);
  249. };
  250. }
  251.  
  252. // ============================
  253.  
  254. const DC = {};
  255.  
  256. DC.LocalMemory = {
  257. init: (label, defaultValue) => {
  258. const $currentVal = GM_getValue(label);
  259. if ($currentVal === undefined) {
  260. GM_setValue(label, defaultValue);
  261. return defaultValue;
  262. } else {
  263. return $currentVal;
  264. }
  265. },
  266.  
  267. set: (label, value) => GM_setValue(label, value),
  268.  
  269. get: (label) => GM_getValue(label),
  270.  
  271. delete: (label) => GM_deleteValue(label),
  272.  
  273. list: () => GM_listValues(),
  274. };
  275.  
  276. DC.Style = {
  277. apply: (css) => {
  278. Util.guardString('DC.Style.apply', 'css', css);
  279.  
  280. if (typeof GM_addStyle !== 'undefined') {
  281. GM_addStyle(css);
  282. } else {
  283. let $styleNode = document.createElement('style');
  284. $styleNode.appendChild(document.createTextNode(css));
  285. (document.querySelector('head') || document.documentElement).appendChild(
  286. $styleNode,
  287. );
  288. }
  289. },
  290. };
  291.  
  292. DC.TopMenu = {
  293. get: () => {
  294. Util.guard(
  295. Util.isGame(),
  296. 'MenuChat.prototype.onSend: this function should be called in Game only.',
  297. );
  298. return $('.menus');
  299. },
  300.  
  301. add: (element, index = 0) => {
  302. Util.guard(
  303. Util.isGame(),
  304. 'MenuChat.prototype.onSend: this function should be called in Game only.',
  305. );
  306. Util.guardJQuery('DC.TopMenu.add', 'element', element);
  307. Util.guardNumber('DC.TopMenu.add', 'index', index);
  308.  
  309. const $dom = DC.TopMenu.get();
  310. if (index === 0) {
  311. $dom.prepend(element);
  312. } else {
  313. $dom.insertAt(index, element);
  314. }
  315. },
  316. };
  317.  
  318. DC.UI = {
  319. Separator: () => $('<li class="separator" />'),
  320.  
  321. Menu: (label, fn) => {
  322. Util.guardString('DC.UI.Menu', 'label', label);
  323. Util.guardFunction('DC.UI.Menu', 'fn', fn);
  324.  
  325. return $(`<li id="${label}" class="couleur5">${label}</li>`).bind(
  326. 'click',
  327. fn,
  328. );
  329. },
  330.  
  331. SubMenu: (label, fn, separatorBefore = false) => {
  332. Util.guardString('DC.UI.SubMenu', 'label', label);
  333. Util.guardFunction('DC.UI.SubMenu', 'fn', fn);
  334. Util.guardBoolean('DC.UI.SubMenu', 'separatorBefore', separatorBefore);
  335.  
  336. return $(
  337. `<li class="link couleur2 ${
  338. separatorBefore ? 'separator' : ''
  339. }">${label}</li>`,
  340. ).bind('click', fn);
  341. },
  342.  
  343. DropMenu: (label, submenu) => {
  344. Util.guardString('DC.UI.DropMenu', 'label', label);
  345. Util.guardArray('DC.UI.DropMenu', 'submenu', submenu);
  346.  
  347. const $label = label + '▾';
  348.  
  349. const $list = $('<ul></ul>');
  350. submenu.forEach(($submenu) => {
  351. $($list).append($submenu);
  352. });
  353.  
  354. return $(
  355. `<li id="${label}" class="parametres couleur5 right hover" onclick="$(this).find('ul').slideDown();">${$label}</li>`,
  356. ).append($list);
  357. },
  358.  
  359. addSubMenuTo: (name, element, index = 0) => {
  360. Util.guard(
  361. Util.isGame(),
  362. 'MenuChat.prototype.onSend: this function should be called in Game only.',
  363. );
  364. Util.guardString('DC.UI.addSubMenuTo', 'name', name);
  365. Util.guardJQuery('DC.UI.addSubMenuTo', 'element', element);
  366. Util.guardNumber('DC.UI.addSubMenuTo', 'index', index);
  367.  
  368. const $menu = $(`.menus li:contains("${name}") ul`);
  369.  
  370. if (index === 0) {
  371. $menu.prepend(element);
  372. } else {
  373. $menu.insertAt(index, element);
  374. }
  375. },
  376.  
  377. TextButton: (id, label, fn) => {
  378. Util.guardString('DC.UI.TextButton', 'id', id);
  379. Util.guardString('DC.UI.TextButton', 'label', label);
  380. Util.guardFunction('DC.UI.TextButton', 'fn', fn);
  381.  
  382. return $(`<div id="${id}" class="btnTxt">${label}</div>`).bind('click', fn);
  383. },
  384.  
  385. Button: (id, label, fn) => {
  386. Util.guardString('DC.UI.Button', 'id', id);
  387. Util.guardString('DC.UI.Button', 'label', label);
  388. Util.guardFunction('DC.UI.Button', 'fn', fn);
  389.  
  390. return $(
  391. `<div id="${id}" class="btn add link infoAide"><div class="gridCenter">${label}</div></div>`,
  392. ).bind('click', fn);
  393. },
  394.  
  395. ColorPicker: (id, value, fn) => {
  396. Util.guardString('DC.UI.ColorPicker', 'id', id);
  397. Util.guardString('DC.UI.ColorPicker', 'value', value);
  398. Util.guardFunction('DC.UI.ColorPicker', 'fn', fn);
  399.  
  400. return $(`<input id="${id}" value="${value}"`).bind('click', (e) =>
  401. fn(e.target.value),
  402. );
  403. },
  404.  
  405. Tooltip: (text, content) => {
  406. Util.guardString('DC.UI.Tooltip', 'text', text);
  407. Util.guardJQuery('DC.UI.Tooltip', 'content', content);
  408.  
  409. DC.Style.apply(`
  410. .tooltip {
  411. position: relative;
  412. display: inline-block;
  413. }
  414. .tooltip .tooltiptext {
  415. visibility: hidden;
  416. background-color: rgba(24,24,24,0.95);
  417. color: #fff;
  418. text-align: center;
  419. padding: 5px;
  420. border-radius: 6px;
  421. position: absolute;
  422. z-index: 1;
  423. font-size: 1rem;
  424. }
  425. .tooltip:hover .tooltiptext {
  426. visibility: visible;
  427. }
  428. `);
  429.  
  430. return $(`<div class="tooltip">
  431. <span class="tooltiptext">${text}</span>
  432. </div>`).prepend(content);
  433. },
  434.  
  435. Checkbox: (id, defaultEnable, onAfterClick) => {
  436. Util.guardString('DC.UI.Checkbox', 'id', id);
  437. Util.guardBoolean('DC.UI.Checkbox', 'defaultEnable', defaultEnable);
  438. Util.guardFunction('DC.UI.Checkbox', 'onAfterClick', onAfterClick);
  439.  
  440. DC.Style.apply(`
  441. .dc_ui_checkbox {
  442. cursor: pointer;
  443. width: 30px;
  444. height: 18px;
  445. background: url(../../../images/fr/design/boutons/b_0.png) 0 0 no-repeat;
  446. }
  447.  
  448. .dc_ui_checkbox_on {
  449. background: url(../../../images/fr/design/boutons/b_1.png) 0 0 no-repeat;
  450. }
  451. `);
  452.  
  453. return $(
  454. `<div id="${id}" class="dc_ui_checkbox ${
  455. defaultEnable ? 'dc_ui_checkbox_on' : ''
  456. }" />`,
  457. ).bind('click', () => {
  458. $(`#${id}`).toggleClass('dc_ui_checkbox_on');
  459. onAfterClick?.($(`#${id}`).hasClass('dc_ui_checkbox_on'));
  460. });
  461. },
  462.  
  463. PopUp: (id, title, content) => {
  464. Util.guard(
  465. Util.isGame(),
  466. 'MenuChat.prototype.onSend: this function should be called in Game only.',
  467. );
  468. Util.guardString('DC.UI.PopUp', 'id', id);
  469. Util.guardString('DC.UI.PopUp', 'title', title);
  470. Util.guardJQuery('DC.UI.PopUp', 'content', content);
  471.  
  472. $('#loader').fadeIn('fast');
  473.  
  474. const html = `
  475. <div id="${id}" class="dataBox" onClick="engine.switchDataBox(this)" style="display: block; z-index: 5; left: 764px; top: 16px;">
  476. <relative>
  477. <div class="head" ondblclick="$('#${id}').toggleClass('reduced');">
  478. <div title="Fermer la fenêtre (Q)" class="info1 link close transition3s" onClick="engine.closeDataBox($(this).parent().parent().parent().attr('id'));" alt="$('${id}').removeClass('active')">
  479. <i class="fas fa-times"></i>
  480. </div>
  481. <div title="Reduire/Agrandir la fenêtre" class="info1 link reduce transition3s" onClick="$('#${id}').toggleClass('reduced');">
  482. <span>-</span>
  483. </div>
  484. <div class="title">${title}</div>
  485. </div>
  486. <div class="dbloader"></div>
  487. <div class="content" style="max-width: 800px; max-height: 600px; overflow-y: auto; overflow-x: hidden;">
  488. </div>
  489. </relative>
  490. </div>`;
  491.  
  492. engine.displayDataBox(html);
  493. $(`#${id} .content`).append(content);
  494.  
  495. $('#loader').hide();
  496. },
  497.  
  498. SideMenu: (id, label, content) => {
  499. Util.guardString('DC.UI.SideMenu', 'id', id);
  500. Util.guardString('DC.UI.SideMenu', 'label', label);
  501. Util.guardJQuery('DC.UI.SideMenu', 'content', content);
  502.  
  503. const $idContainer = id + '_container';
  504. const $idButton = id + '_button';
  505. const $idContent = id + '_content';
  506.  
  507. if ($('div#zone_sidemenu').length === 0) {
  508. $('body').append('<div id="zone_sidemenu"></div>');
  509. }
  510. $('#zone_sidemenu').append(
  511. `<div id="${$idContainer}" class="sidemenu_container"></div>`,
  512. );
  513.  
  514. $(`#${$idContainer}`).append(
  515. DC.UI.TextButton(
  516. $idButton,
  517. '<i class="fas fa-chevron-left"></i>' + label,
  518. () => {
  519. const isOpen = $(`#${$idButton}`).html().includes('fa-chevron-right');
  520. if (isOpen) {
  521. $(`#${$idButton}`)
  522. .empty()
  523. .append('<i class="fas fa-chevron-left"></i>' + label);
  524. $(`#${$idContainer}`).css('right', '-220px');
  525. } else {
  526. $(`#${$idButton}`)
  527. .empty()
  528. .append('<i class="fas fa-chevron-right"></i>' + label);
  529. $(`#${$idContainer}`).css('right', '0px');
  530. }
  531. },
  532. ),
  533. );
  534.  
  535. $(`#${$idContainer}`).append(
  536. `<div id="${$idContent}" class="sidemenu_content"></div>`,
  537. );
  538. $(`#${idContent}`).append(content);
  539.  
  540. DC.Style.apply(`
  541. #zone_sidemenu {
  542. display: flex;
  543. flex-direction: column;
  544. position: absolute;
  545. right: 0px;
  546. top: 80px;
  547. z-index: 999999;
  548. }
  549.  
  550. .sidemenu_container {
  551. display: flex;
  552. right: -220px;
  553. }
  554.  
  555. #zone_sidemenu .btnTxt {
  556. margin: 0 auto;
  557. min-width: 100px;
  558. max-width: 100px;
  559. font-size: 1rem;
  560. padding: 1%;
  561. display: grid;
  562. height: 100%;
  563. box-sizing: border-box;
  564. grid-template-columns: 10% 1fr;
  565. align-items: center;
  566. text-transform: uppercase;
  567. font-family: Arial !important;
  568. line-height: normal !important;
  569. }
  570.  
  571. #zone_sidemenu .btnTxt:hover {
  572. background: #0b9bcb;
  573. color: #fff;
  574. }
  575.  
  576. .sidemenu_content {
  577. background-color: #000;
  578. color: #fff !important;
  579. box-shadow: 0 0 15px -5px inset #a2e4fc !important;
  580. padding: 10px;
  581. width: 200px;
  582. }
  583. `);
  584. },
  585. };
  586.  
  587. DC.Network = {
  588. fetch: (args) => {
  589. Util.guardObject('DC.Network.fetch', 'args', args);
  590.  
  591. return new Promise((resolve, reject) => {
  592. GM_xmlhttpRequest(
  593. Object.assign({}, args, {
  594. onload: (e) => resolve(e.response),
  595. onerror: reject,
  596. ontimeout: reject,
  597. }),
  598. );
  599. });
  600. },
  601.  
  602. loadSpreadsheet: async (sheetId, tabName, range, apiKey, onLoad) => {
  603. Util.guardString('DC.Network.loadSpreadsheet', 'sheetId', sheetId);
  604. Util.guardString('DC.Network.loadSpreadsheet', 'tabName', tabName);
  605. Util.guardString('DC.Network.loadSpreadsheet', 'range', range);
  606. Util.guardString('DC.Network.loadSpreadsheet', 'apiKey', apiKey);
  607. Util.guardFunction('DC.Network.loadSpreadsheet', 'onLoad', onLoad);
  608.  
  609. const urlGoogleSheetDatabase = `https://sheets.googleapis.com/v4/spreadsheets/${sheetId}/values/${tabName}!${range}?key=${apiKey}`;
  610. const result = await DC.Network.fetch({
  611. method: 'GET',
  612. url: urlGoogleSheetDatabase,
  613. headers: {
  614. 'Content-Type': 'application/json',
  615. },
  616. responseType: 'json',
  617. });
  618. onLoad(result.values);
  619. },
  620.  
  621. loadScript: async (url, onAfterLoad) => {
  622. Util.guardString('DC.Network.loadScript', 'url', url);
  623. Util.guardFunction(
  624. 'DC.Network.loadScript',
  625. 'onAfterLoad',
  626. onAfterLoad,
  627. true,
  628. );
  629.  
  630. // TODO we should check that url is from a valid and secure source.
  631. const result = await DC.Network.fetch({
  632. method: 'GET',
  633. url,
  634. headers: {
  635. 'Content-Type': 'text/javascript',
  636. },
  637. });
  638. // TODO we have to secure more this call
  639. eval(result);
  640.  
  641. onAfterLoad?.();
  642. },
  643.  
  644. loadJson: async (url) => {
  645. Util.guardString('DC.Network.loadJson', 'url', url);
  646.  
  647. const result = await DC.Network.fetch({
  648. method: 'GET',
  649. url,
  650. headers: {
  651. 'Content-Type': 'application/json',
  652. },
  653. responseType: 'json',
  654. });
  655. return result;
  656. },
  657. };
  658.  
  659. DC.Chat = {
  660. sendMessage: (message) => {
  661. Util.guard(
  662. Util.isGame(),
  663. 'MenuChat.prototype.onSend: this function should be called in Game only.',
  664. );
  665. Util.guardString('DC.Chat.sendMessage', 'message', message);
  666.  
  667. $('#chatForm .text_chat').val(message);
  668. $('#chatForm .text_valider').click();
  669. },
  670.  
  671. t: (message, decoration) => {
  672. Util.guardString('DC.Chat.t', 'message', message);
  673. Util.guardObject('DC.Chat.t', 'decoration', decoration);
  674. Util.guardBoolean('DC.Chat.t', 'decoration.bold', decoration.bold, true);
  675. Util.guardBoolean(
  676. 'DC.Chat.t',
  677. 'decoration.italic',
  678. decoration.italic,
  679. true,
  680. );
  681. Util.guardColor('DC.Chat.t', 'decoration.color', decoration.color, true);
  682.  
  683. var prefix = '';
  684. var suffix = '';
  685.  
  686. if (decoration.bold) {
  687. prefix += '[b]';
  688. suffix += '[b]';
  689. }
  690.  
  691. if (decoration.italic) {
  692. prefix += '[i]';
  693. suffix = '[/i]' + suffix;
  694. }
  695.  
  696. if (decoration.color && decoration.color !== '') {
  697. prefix += '[c=' + decoration.color + ']';
  698. suffix = '[/c]' + suffix;
  699. }
  700.  
  701. return prefix + message + suffix;
  702. },
  703.  
  704. addCommand: (label, fn) => {
  705. Util.guard(
  706. Util.isGame(),
  707. 'MenuChat.prototype.onSend: this function should be called in Game only.',
  708. );
  709. Util.guardString('DC.Chat.addCommand', 'label', label);
  710. Util.guardFunction('DC.Chat.addCommand', 'fn', fn);
  711.  
  712. nav.getChat().onSend((message, next, abort) => {
  713. const forbiden = ['me', 'y', 'ye', 'yme', 'w', 'we', 'wme', 'roll', ''];
  714.  
  715. const labelUsed = message.split(' ')[0].substr(1);
  716. if (
  717. message[0] !== '/' ||
  718. labelUsed !== label ||
  719. forbiden.includes(labelUsed)
  720. ) {
  721. return next();
  722. }
  723.  
  724. const content = message.substr(labelUsed.length + 1);
  725.  
  726. if (fn(labelUsed, content)) {
  727. return next();
  728. } else {
  729. return abort();
  730. }
  731. });
  732. },
  733. };
  734.  
  735. DC.Deck = {
  736. checkSkill: (info) => {
  737. Util.guard(
  738. Util.isGame(),
  739. 'DC.Deck.checkSkill: this function should be called in Game only.',
  740. );
  741. Util.guardNumber('DC.Deck.checkSkill', 'info', info);
  742.  
  743. return info <= $('.stat_6_entier').first().html();
  744. },
  745.  
  746. write: (node) => {
  747. Util.guard(
  748. Util.isGame(),
  749. 'DC.Deck.write: this function should be called in Game only.',
  750. );
  751. Util.guardJQuery('DC.Deck.write', 'node', node);
  752.  
  753. const deckId = 'db_deck_' + settings.data.match(/[0-9]*$/)[0];
  754.  
  755. const mode =
  756. $(`#${deckId} .zone_ecrit div:last-child`).attr('class') ===
  757. 'ligne_resultat_fixed';
  758.  
  759. if (mode) {
  760. $(`#${deckId} .ligne_resultat_fixed`).last().append(node);
  761. } else {
  762. $('<div class="ligne_resultat_fixed" />')
  763. .append(node)
  764. .appendTo($(`#${deckId} .zone_ecrit`));
  765. }
  766. },
  767.  
  768. createCommand: (info, command, fn, helpFn, help) => {
  769. Util.guard(
  770. Util.isGame(),
  771. 'DC.Deck.createCommand: this function should be called in Game only.',
  772. );
  773. Util.guardNumber('DC.Deck.createCommand', 'info', info);
  774. Util.guardString('DC.Deck.createCommand', 'command', command);
  775. Util.guardFunction('DC.Deck.createCommand', 'fn', fn);
  776. Util.guardFunction('DC.Deck.createCommand', 'helpFn', helpFn);
  777. Util.guardString('DC.Deck.createCommand', 'help', help);
  778.  
  779. $(document).ajaxComplete(function (event, xhr, settings) {
  780. // Handle custom deck command
  781. if (/Command/.test(settings.url)) {
  782. var deckId = 'db_deck_' + settings.data.match(/[0-9]*$/)[0];
  783. var lastCommand = $(`#${deckId} .ligne_ecrite_fixed input`)
  784. .last()
  785. .val();
  786.  
  787. // Handle Date command
  788.  
  789. if (new RegExp(`^${command}`, 'gi').test(lastCommand)) {
  790. if (DC.Deck.checkSkill(info)) {
  791. fn(lastCommand, deckId);
  792. } else {
  793. DC.Deck.write(
  794. $(
  795. '<span>Votre niveau en informatique est trop faible pour réussir cette commande</span>',
  796. ),
  797. );
  798. }
  799. }
  800. // Handle help Date command
  801. else if (new RegExp(`^help ${command}`, 'gi').test(lastCommand)) {
  802. helpFn(deckId);
  803. }
  804. // Handle help Date command
  805. else if (/^help$/gi.test(lastCommand)) {
  806. DC.Deck.write($(`<br />${help}`));
  807. }
  808. }
  809. });
  810. },
  811. };