wsmud_Trigger

武神传说 MUD

当前为 2021-01-13 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name wsmud_Trigger
  3. // @namespace cqv3
  4. // @version 0.0.41
  5. // @date 03/03/2019
  6. // @modified 13/01/2021
  7. // @homepage https://gf.qytechs.cn/zh-CN/scripts/378984
  8. // @description 武神传说 MUD
  9. // @author Bob.cn, 初心, 白三三
  10. // @match http://*.wsmud.com/*
  11. // @run-at document-end
  12. // @require https://cdn.staticfile.org/vue/2.2.2/vue.min.js
  13. // @grant unsafeWindow
  14. // @grant GM_getValue
  15. // @grant GM_setValue
  16. // @grant GM_deleteValue
  17. // @grant GM_listValues
  18. // @grant GM_setClipboard
  19. // ==/UserScript==
  20.  
  21. (function () {
  22. 'use strict';
  23.  
  24. function CopyObject(obj) {
  25. return JSON.parse(JSON.stringify(obj));
  26. }
  27.  
  28. /***********************************************************************************\
  29. Notification Center
  30. \***********************************************************************************/
  31.  
  32. class Notification {
  33. constructor(name, params) {
  34. this.name = name;
  35. this.params = params;
  36. }
  37. }
  38.  
  39. class NotificationObserver {
  40. constructor(targetName, action) {
  41. this.targetName = targetName;
  42. this.action = action;
  43. }
  44. }
  45.  
  46. const NotificationCenter = {
  47. observe: function(notificationName, action) {
  48. const index = this._getOberverIndex();
  49. const observer = new NotificationObserver(notificationName, action);
  50. this._observers[index] = observer;
  51. return index;
  52. },
  53. removeOberver: function(index) {
  54. delete this._observers[index];
  55. },
  56. /**
  57. * @param {Notification} notification
  58. */
  59. post: function(notification) {
  60. for (const key in this._observers) {
  61. if (!this._observers.hasOwnProperty(key)) continue;
  62. const observer = this._observers[key];
  63. if (observer.targetName != notification.name) continue;
  64. observer.action(notification.params);
  65. }
  66. },
  67.  
  68. _observerCounter: 0,
  69. _observers: {},
  70. _getOberverIndex: function() {
  71. const index = this._observerCounter;
  72. this._observerCounter += 1;
  73. return index;
  74. }
  75. };
  76.  
  77. /***********************************************************************************\
  78. Monitor Center
  79. \***********************************************************************************/
  80.  
  81. class Monitor {
  82. constructor(run) {
  83. this.run = run;
  84. }
  85. }
  86.  
  87. const MonitorCenter = {
  88. addMonitor: function(monitor) {
  89. this._monitors.push(monitor);
  90. },
  91. run: function() {
  92. for (const monitor of this._monitors) {
  93. monitor.run();
  94. }
  95. },
  96.  
  97. _monitors: []
  98. };
  99.  
  100. /***********************************************************************************\
  101. Trigger Template And Trigger
  102. \***********************************************************************************/
  103.  
  104. //---------------------------------------------------------------------------
  105. // Trigger Template
  106. //---------------------------------------------------------------------------
  107.  
  108. const EqualAssert = function(lh, rh) {
  109. return lh == rh;
  110. };
  111.  
  112. const ContainAssert = function(lh, rh) {
  113. if (/^\s*\*?\s*$/.test(lh)) return true;
  114. const list = lh.split("|");
  115. return list.indexOf(rh) != -1;
  116. };
  117. const ContainReverseAssert = function (lh, rh) {
  118. console.log(lh,rh);
  119. if (/^\s*\*?\s*$/.test(lh)) return true;
  120. const list = lh.split("|");
  121. return list.indexOf(rh) == -1;
  122. };
  123.  
  124. const KeyAssert = function(lh, rh) {
  125. if (/^\s*\*?\s*$/.test(lh)) return true;
  126. const list = lh.split("|");
  127. for (const key of list) {
  128. if (rh.indexOf(key) != -1) return true;
  129. }
  130. return false;
  131. };
  132.  
  133. class Filter {
  134. constructor(name, type, defaultValue, assert) {
  135. this.name = name;
  136. this.type = type;
  137. this.defaultValue = defaultValue;
  138. this.assert = assert == null ? EqualAssert : assert;
  139. }
  140. description(value) {
  141. if (value != null) {
  142. this._desc = value;
  143. return;
  144. }
  145. return this._desc == null ? this.name : this._desc;
  146. }
  147. }
  148.  
  149. class SelectFilter extends Filter {
  150. constructor(name, options, defaultNumber, assert) {
  151. const defaultValue = options[defaultNumber];
  152. super(name, "select", defaultValue, assert);
  153. this.options = options;
  154. }
  155. }
  156.  
  157. const InputFilterFormat = {
  158. number: "数字",
  159. text: "文本"
  160. };
  161.  
  162. class InputFilter extends Filter {
  163. /**
  164. * @param {String} name
  165. * @param {InputFilterFormat} format
  166. * @param {*} defaultValue
  167. */
  168. constructor(name, format, defaultValue, assert) {
  169. super(name, "input", defaultValue, assert);
  170. this.format = format;
  171. }
  172. }
  173.  
  174. class TriggerTemplate {
  175. constructor(event, filters, introdution) {
  176. this.event = event;
  177. this.filters = filters;
  178. this.introdution = `${introdution}\n// 如需更多信息,可以到论坛触发器版块发帖。`;
  179. }
  180. getFilter(name) {
  181. for (const filter of this.filters) {
  182. if (filter.name == name) return filter;
  183. }
  184. return null;
  185. }
  186. }
  187.  
  188. const TriggerTemplateCenter = {
  189. add: function(template) {
  190. this._templates[template.event] = template;
  191. },
  192. getAll: function() {
  193. return Object.values(this._templates);
  194. },
  195. get: function(event) {
  196. return this._templates[event];
  197. },
  198.  
  199. _templates: {},
  200. };
  201.  
  202. //---------------------------------------------------------------------------
  203. // Trigger
  204. //---------------------------------------------------------------------------
  205.  
  206. class Trigger {
  207. constructor(name, template, conditions, source) {
  208. this.name = name;
  209. this.template = template;
  210. this.conditions = conditions;
  211. this.source = source;
  212. this._action = function(params) {
  213. let realParams = CopyObject(params);
  214. for (const key in conditions) {
  215. if (!conditions.hasOwnProperty(key)) continue;
  216. const filter = template.getFilter(key);
  217. const fromUser = conditions[key];
  218. const fromGame = params[key];
  219. if (!filter.assert(fromUser, fromGame)) return;
  220. delete realParams[key];
  221. }
  222. let realSource = source;
  223. for (const key in realParams) {
  224. realSource = `($${key}) = ${realParams[key]}\n${realSource}`;
  225. }
  226. if (/\/\/\s*~silent\s*\n/.test(source) == false) {
  227. realSource = `@print 💡<hio>触发=>${name}</hio>\n${realSource}`;
  228. }
  229. ToRaid.perform(realSource, name, false);
  230. };
  231. this._observerIndex = null;
  232. }
  233.  
  234. event() { return this.template.event; }
  235. active() { return this._observerIndex != null; }
  236.  
  237. _activate() {
  238. if (this._observerIndex != null) return;
  239. this._observerIndex = NotificationCenter.observe(this.template.event, this._action);
  240. }
  241. _deactivate() {
  242. if (this._observerIndex == null) return;
  243. NotificationCenter.removeOberver(this._observerIndex);
  244. this._observerIndex = null;
  245. }
  246. }
  247.  
  248. class TriggerData {
  249. constructor(name, event, conditions, source, active) {
  250. this.name = name;
  251. this.event = event;
  252. this.conditions = conditions;
  253. this.source = source;
  254. this.active = active;
  255. }
  256. }
  257.  
  258. const TriggerCenter = {
  259. run: function() {
  260. const allData = GM_getValue(this._saveKey(), {});
  261. for (const name in allData) {
  262. this._loadTrigger(name);
  263. }
  264. },
  265. reload: function() {
  266. for (const name in this._triggers) {
  267. if (!this._triggers.hasOwnProperty(name)) continue;
  268. const trigger = this._triggers[name];
  269. trigger._deactivate();
  270. delete this._triggers[name];
  271. }
  272. this.run();
  273. },
  274.  
  275. // for upload and download
  276. getAllData: function() {
  277. return GM_getValue(this._saveKey(), {});
  278. },
  279. corver: function(triggerDatas) {
  280. for (const old of this.getAll()) {
  281. this.remove(old.name);
  282. }
  283. for (const name in triggerDatas) {
  284. const trigger = triggerDatas[name];
  285. this.create(trigger.name, trigger.event, trigger.conditions, trigger.source, trigger.active);
  286. }
  287. },
  288.  
  289. getAll: function() {
  290. return Object.values(this._triggers);
  291. },
  292. create: function(name, event, conditions, source, active) {
  293. const checkResult = this._checkName(name);
  294. if (checkResult != true) return checkResult;
  295.  
  296. const theActive = active == null ? false : active;
  297. const data = new TriggerData(name, event, conditions, source, theActive);
  298. this._updateData(data);
  299.  
  300. this._loadTrigger(name);
  301. return true;
  302. },
  303. modify: function(originalName, name, conditions, source) {
  304. const trigger = this._triggers[originalName];
  305. if (trigger == null) return "修改不存在的触发器?";
  306.  
  307. const event = trigger.event();
  308. if (originalName == name) {
  309. const data = new TriggerData(name, event, conditions, source, trigger.active());
  310. this._updateData(data);
  311. this._reloadTrigger(name);
  312. return true;
  313. }
  314.  
  315. const result = this.create(name, event, conditions, source);
  316. if (result == true) {
  317. this.remove(originalName);
  318. this._loadTrigger(name);
  319. }
  320. return result;
  321. },
  322. remove: function(name) {
  323. const trigger = this._triggers[name];
  324. if (trigger == null) return;
  325.  
  326. trigger._deactivate();
  327. delete this._triggers[name];
  328. let allData = GM_getValue(this._saveKey(), {});
  329. delete allData[name];
  330. GM_setValue(this._saveKey(), allData);
  331. },
  332.  
  333. activate: function(name) {
  334. const trigger = this._triggers[name];
  335. if (trigger == null) return;
  336. if (trigger.active()) return;
  337. trigger._activate();
  338. let data = this._getData(name);
  339. data.active = true;
  340. this._updateData(data);
  341. },
  342. deactivate: function(name) {
  343. const trigger = this._triggers[name];
  344. if (trigger == null) return;
  345. if (!trigger.active()) return;
  346. trigger._deactivate();
  347. let data = this._getData(name);
  348. data.active = false;
  349. this._updateData(data);
  350. },
  351.  
  352. _triggers: {},
  353.  
  354. _saveKey: function() {
  355. return `${Role.id}@triggers`;
  356. },
  357. _reloadTrigger: function(name) {
  358. const oldTrigger = this._triggers[name];
  359. if (oldTrigger != null) {
  360. oldTrigger._deactivate();
  361. }
  362. this._loadTrigger(name);
  363. },
  364. _loadTrigger: function(name) {
  365. const data = this._getData(name);
  366. if (data == null) return;
  367. // patch new trigger
  368. if (data['event'] === '新聊天信息' && data['conditions']['忽略发言人']===undefined){
  369. data['conditions']['忽略发言人']=''
  370. }
  371. const trigger = this._toTrigger(data);
  372. this._triggers[name] = trigger;
  373. if (data.active) {
  374. trigger._activate();
  375. }
  376. },
  377. _getData: function(name) {
  378. let allData = GM_getValue(this._saveKey(), {});
  379. const data = allData[name];
  380. return data;
  381. },
  382. _updateData: function(data) {
  383. let allData = GM_getValue(this._saveKey(), {});
  384. allData[data.name] = data;
  385. GM_setValue(this._saveKey(), allData);
  386. },
  387. _toTrigger: function(data) {
  388. const template = TriggerTemplateCenter.get(data.event);
  389. const trigger = new Trigger(data.name, template, data.conditions, data.source);
  390. return trigger;
  391. },
  392. _checkName: function(name) {
  393. if (this._triggers[name] != null) return "无法修改名称,已经存在同名触发器!";
  394. if (!/\S+/.test(name)) return "触发器的名称不能为空。";
  395. if (!/^[_a-zA-Z0-9\u4e00-\u9fa5]+$/.test(name)) return "触发器的名称只能使用中文、英文和数字字符。";
  396. return true;
  397. }
  398. };
  399.  
  400. /***********************************************************************************\
  401. WSMUD
  402. \***********************************************************************************/
  403.  
  404. var WG = null;
  405. var messageAppend = null;
  406. var messageClear = null;
  407. var ToRaid = null;
  408. var Role = null;
  409.  
  410. //---------------------------------------------------------------------------
  411. // status
  412. //---------------------------------------------------------------------------
  413.  
  414. (function() {
  415. const type = new SelectFilter("改变类型", ["新增", "移除", "层数刷新"], 0);
  416. const value = new InputFilter("BuffId", InputFilterFormat.text, "weapon", ContainAssert);
  417. const target = new SelectFilter("触发对象", ["自己", "他人"], 0);
  418. let filters = [type, value, target];
  419. const intro = `// Buff状态改变触发器
  420. // 触发对象id:(id)
  421. // buff的sid:(sid)
  422. // buff层数:(count)`;
  423. const t = new TriggerTemplate("Buff状态改变", filters, intro);
  424. TriggerTemplateCenter.add(t);
  425.  
  426. const run = function() {
  427. const post = function(data, sid, type) {
  428. let params = {
  429. "改变类型": type,
  430. "BuffId": sid,
  431. "触发对象": data.id == Role.id ? "自己" : "他人"
  432. };
  433. params["id"] = data.id;
  434. params["sid"] = sid;
  435. params["count"] = 0;
  436. if (data.count != null) params["count"] = data.count;
  437. const n = new Notification("Buff状态改变", params);
  438. NotificationCenter.post(n);
  439. };
  440. WG.add_hook("status", data => {
  441. if (data.action == null || data.id == null || data.sid == null) return;
  442. const types = {
  443. "add": "新增",
  444. "remove": "移除",
  445. "refresh": "层数刷新"
  446. };
  447. const type = types[data.action];
  448. if (type == null) return;
  449. if (data.sid instanceof Array) {
  450. for (const s of data.sid) {
  451. post(data, s, type);
  452. }
  453. } else {
  454. post(data, data.sid, type);
  455. }
  456. });
  457. };
  458. const monitor = new Monitor(run);
  459. MonitorCenter.addMonitor(monitor);
  460. })();
  461.  
  462. //---------------------------------------------------------------------------
  463. // msg
  464. //---------------------------------------------------------------------------
  465.  
  466. (function() {
  467. const channel = new SelectFilter(
  468. "频道",
  469. ["全部", "世界", "队伍", "门派", "全区", "帮派", "谣言", "系统"],
  470. 0,
  471. function(fromUser, fromGame) {
  472. if (fromUser == "全部") return true;
  473. return fromUser == fromGame;
  474. }
  475. );
  476. const talker = new InputFilter("发言人", InputFilterFormat.text, "", ContainAssert);
  477. const pass_talker = new InputFilter("忽略发言人", InputFilterFormat.text, "", ContainReverseAssert);
  478. const key = new InputFilter("关键字", InputFilterFormat.text, "", KeyAssert);
  479. let filters = [channel, talker, pass_talker, key];
  480. const intro = `// 新聊天信息触发器
  481. // 聊天信息内容:(content)
  482. // 发言人:(name)
  483. // 发言人id:(id)
  484. // 频道:(channel)`;
  485. const t = new TriggerTemplate("新聊天信息", filters, intro);
  486. TriggerTemplateCenter.add(t);
  487.  
  488. const run = function() {
  489. WG.add_hook("msg", data => {
  490. if (data.ch == null || data.content == null) return;
  491. const types = {
  492. "chat": "世界",
  493. "tm": "队伍",
  494. "fam": "门派",
  495. "es": "全区",
  496. "pty": "帮派",
  497. "rumor": "谣言",
  498. "sys": "系统"
  499. };
  500. const channel = types[data.ch];
  501. if (channel == null) return;
  502. const name = data.name == null ? "无" : data.name;
  503. const id = data.uid == null ? null : data.uid;
  504. const datacontent = data.content.replace(/\n/g,"")
  505. let params = {
  506. "频道": channel,
  507. "发言人": name,
  508. "关键字": data.content,
  509. "忽略发言人": name
  510. };
  511. params["content"] = datacontent;
  512. params["name"] = name;
  513. params["id"] = id;
  514. params["channel"] = channel;
  515. const n = new Notification("新聊天信息", params);
  516. NotificationCenter.post(n);
  517. });
  518. };
  519. const monitor = new Monitor(run);
  520. MonitorCenter.addMonitor(monitor);
  521. })();
  522.  
  523. //---------------------------------------------------------------------------
  524. // item add
  525. //---------------------------------------------------------------------------
  526.  
  527. (function() {
  528. const name = new InputFilter("人物名称", InputFilterFormat.text, "", KeyAssert);
  529. name.description("人名关键字");
  530. let filters = [name];
  531. const intro = `// 人物刷新触发器
  532. // 刷新人物id:(id)
  533. // 刷新人物名称:(name)`;
  534. const t = new TriggerTemplate("人物刷新", filters, intro);
  535. TriggerTemplateCenter.add(t);
  536.  
  537. const run = function() {
  538. WG.add_hook("itemadd", data => {
  539. if (data.name == null || data.id == null) return;
  540. let params = {
  541. "人物名称": data.name,
  542. };
  543. params["id"] = data.id;
  544. params["name"] = data.name;
  545. const n = new Notification("人物刷新", params);
  546. NotificationCenter.post(n);
  547. });
  548. };
  549. const monitor = new Monitor(run);
  550. MonitorCenter.addMonitor(monitor);
  551. })();
  552.  
  553. //---------------------------------------------------------------------------
  554. // dialog pack
  555. //---------------------------------------------------------------------------
  556.  
  557. (function() {
  558. const name = new InputFilter("名称关键字", InputFilterFormat.text, "", KeyAssert);
  559. let filters = [name];
  560. const intro = `// 物品拾取触发器
  561. // 拾取物品id:(id)
  562. // 拾取物品名称:(name)
  563. // 拾取物品数量:(count)
  564. // 物品品质:(quality) 值:白、绿、蓝、黄、紫、橙、红、未知`;
  565. const t = new TriggerTemplate("物品拾取", filters, intro);
  566. TriggerTemplateCenter.add(t);
  567.  
  568. const run = function() {
  569. WG.add_hook("dialog", function(data) {
  570. if (data.dialog != "pack" || data.id == null || data.name == null || data.count == null || data.remove != null) return;
  571. let params = {
  572. "名称关键字": data.name,
  573. };
  574. params["id"] = data.id;
  575. params["name"] = data.name;
  576. params["count"] = data.count;
  577. let quality = "未知";
  578. const tag = /<\w{3}>/.exec(data.name)[0];
  579. const tagMap = {
  580. "<wht>": "白",
  581. "<hig>": "绿",
  582. "<hic>": "蓝",
  583. "<hiy>": "黄",
  584. "<HIZ>": "紫",
  585. "<hio>": "橙",
  586. "<ord>": "红"
  587. }
  588. quality = tagMap[tag];
  589. params["quality"] = quality;
  590. const n = new Notification("物品拾取", params);
  591. NotificationCenter.post(n);
  592. });
  593. };
  594. const monitor = new Monitor(run);
  595. MonitorCenter.addMonitor(monitor);
  596. })();
  597.  
  598. //---------------------------------------------------------------------------
  599. // text
  600. //---------------------------------------------------------------------------
  601.  
  602. (function() {
  603. const name = new InputFilter("关键字", InputFilterFormat.text, "", KeyAssert);
  604. let filters = [name];
  605. const intro = `// 新提示信息触发器
  606. // 提示信息:(text)`;
  607. const t = new TriggerTemplate("新提示信息", filters, intro);
  608. TriggerTemplateCenter.add(t);
  609.  
  610. const run = function() {
  611. WG.add_hook("text", data => {
  612. if (data.msg == null) return;
  613. let params = {
  614. "关键字": data.msg,
  615. };
  616. params["text"] = data.msg;
  617. const n = new Notification("新提示信息", params);
  618. NotificationCenter.post(n);
  619. });
  620. };
  621. const monitor = new Monitor(run);
  622. MonitorCenter.addMonitor(monitor);
  623. })();
  624.  
  625. //---------------------------------------------------------------------------
  626. // combat
  627. //---------------------------------------------------------------------------
  628.  
  629. (function() {
  630. const type = new SelectFilter("类型", ["进入战斗", "脱离战斗"], 0);
  631. let filters = [type];
  632. const intro = "// 战斗状态切换触发器";
  633. const t = new TriggerTemplate("战斗状态切换", filters, intro);
  634. TriggerTemplateCenter.add(t);
  635.  
  636. const run = function() {
  637. WG.add_hook("combat", data => {
  638. let params = null;
  639. if (data.start != null && data.start == 1) {
  640. params = { "类型": "进入战斗" };
  641. } else if (data.end != null && data.end == 1) {
  642. params = { "类型": "脱离战斗" };
  643. }
  644. const n = new Notification("战斗状态切换", params);
  645. NotificationCenter.post(n);
  646. });
  647. WG.add_hook("text", function(data) {
  648. if (data.msg == null) return;
  649. if (data.msg.indexOf('只能在战斗中使用') != -1 || data.msg.indexOf('这里不允许战斗') != -1 || data.msg.indexOf('没时间这么做') != -1) {
  650. const params = { "类型": "脱离战斗" };
  651. const n = new Notification("战斗状态切换", params);
  652. NotificationCenter.post(n);
  653. }
  654. });
  655. };
  656. const monitor = new Monitor(run);
  657. MonitorCenter.addMonitor(monitor);
  658. })();
  659.  
  660. //---------------------------------------------------------------------------
  661. // combat
  662. //---------------------------------------------------------------------------
  663.  
  664. (function() {
  665. const type = new SelectFilter("类型", ["已经死亡", "已经复活"], 0);
  666. let filters = [type];
  667. const intro = "// 死亡状态改变触发器";
  668. const t = new TriggerTemplate("死亡状态改变", filters, intro);
  669. TriggerTemplateCenter.add(t);
  670.  
  671. const run = function() {
  672. WG.add_hook("die", data => {
  673. const value = data.relive == null ? "已经死亡" : "已经复活";
  674. let params = {
  675. "类型": value
  676. };
  677. const n = new Notification("死亡状态改变", params);
  678. NotificationCenter.post(n);
  679. });
  680. };
  681. const monitor = new Monitor(run);
  682. MonitorCenter.addMonitor(monitor);
  683. })();
  684.  
  685. //---------------------------------------------------------------------------
  686. // time
  687. //---------------------------------------------------------------------------
  688.  
  689. (function() {
  690. const hours = [
  691. 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
  692. 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
  693. 20, 21, 22, 23
  694. ];
  695. const minutes = [
  696. 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
  697. 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
  698. 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
  699. 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
  700. 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
  701. 50, 51, 52, 53, 54, 55, 56, 57, 58, 59
  702. ];
  703. const hour = new SelectFilter("时", hours, 0, EqualAssert);
  704. const minute = new SelectFilter("分", minutes, 0, EqualAssert);
  705. const second = new SelectFilter("秒", minutes, 0, EqualAssert);
  706. let filters = [hour, minute, second];
  707. const intro = "// 时辰已到触发器";
  708. const t = new TriggerTemplate("时辰已到", filters, intro);
  709. TriggerTemplateCenter.add(t);
  710.  
  711. const run = function() {
  712. setInterval(_ => {
  713. const date = new Date();
  714. const params = {
  715. "时": date.getHours(),
  716. "分": date.getMinutes(),
  717. "秒": date.getSeconds()
  718. };
  719. const n = new Notification("时辰已到", params);
  720. NotificationCenter.post(n);
  721. }, 1000);
  722. };
  723. const monitor = new Monitor(run);
  724. MonitorCenter.addMonitor(monitor);
  725. })();
  726.  
  727. //---------------------------------------------------------------------------
  728. // dispfm
  729. //---------------------------------------------------------------------------
  730.  
  731. (function() {
  732. const sid = new InputFilter("技能id", InputFilterFormat.text, "", ContainAssert);
  733. let filters = [sid];
  734. const intro = `// 技能释放触发器
  735. // 技能id:(id)
  736. // 出招时间:(rtime)
  737. // 冷却时间:(distime)`;
  738. const t = new TriggerTemplate("技能释放", filters, intro);
  739. TriggerTemplateCenter.add(t);
  740.  
  741. const sid1 = new InputFilter("技能id", InputFilterFormat.text, "", ContainAssert);
  742. let filters1 = [sid1];
  743. const intro1 = `// 技能冷却结束触发器
  744. // 技能id:(id)`;
  745. const t1 = new TriggerTemplate("技能冷却结束", filters1, intro1);
  746. TriggerTemplateCenter.add(t1);
  747.  
  748. const run = function() {
  749. WG.add_hook("dispfm", data => {
  750. if (data.id == null || data.distime == null || data.rtime == null) return;
  751. let params = {
  752. "技能id": data.id
  753. };
  754. params["id"] = data.id;
  755. params["rtime"] = data.rtime;
  756. params["distime"] = data.distime;
  757. const n = new Notification("技能释放", params);
  758. NotificationCenter.post(n);
  759.  
  760. setTimeout(_ => {
  761. let params = {
  762. "技能id": data.id
  763. };
  764. params["id"] = data.id;
  765. const n = new Notification("技能冷却结束", params);
  766. NotificationCenter.post(n);
  767. }, data.distime);
  768. });
  769. };
  770. const monitor = new Monitor(run);
  771. MonitorCenter.addMonitor(monitor);
  772. })();
  773.  
  774. //---------------------------------------------------------------------------
  775. // hp mp
  776. //---------------------------------------------------------------------------
  777.  
  778. var RoomItems = {};
  779.  
  780. (function() {
  781. const name = new InputFilter("人名关键字", InputFilterFormat.text, "", KeyAssert);
  782. const type = new SelectFilter("类型", ["气血", "内力"], 0, EqualAssert);
  783. const compare = new SelectFilter("当", ["低于", "高于"], 0, EqualAssert);
  784. const valueType = new SelectFilter("值类型", ["百分比", "数值"], 0, EqualAssert);
  785. const value = new InputFilter("值", InputFilterFormat.number, 0, function(fromUser, fromGame) {
  786. const parts = fromGame.split(";");
  787. const oldvalue = parseFloat(parts[0]);
  788. const newvalue = parseFloat(parts[1]);
  789. if (oldvalue >= fromUser && newvalue < fromUser) return true;
  790. if (oldvalue <= fromUser && newvalue > fromUser) return true;
  791. return false;
  792. });
  793. let filters = [name, type, compare, valueType, value];
  794. const intro = `// 气血内力改变触发器
  795. // 人物id:(id)
  796. // 人物当前气血:(hp)
  797. // 人物最大气血:(maxHp)
  798. // 人物当前内力:(mp)
  799. // 人物最大内力:(maxMp)`;
  800. const t = new TriggerTemplate("气血内力改变", filters, intro);
  801. TriggerTemplateCenter.add(t);
  802.  
  803. const run = function() {
  804. WG.add_hook("items", data => {
  805. if (data.items == null) return;
  806. RoomItems = {};
  807. for (const item of data.items) {
  808. RoomItems[item.id] = CopyObject(item);
  809. }
  810. });
  811. WG.add_hook("itemadd", data => {
  812. RoomItems[data.id] = CopyObject(data);
  813. });
  814. const decorate = function(params, item) {
  815. params["id"] = item.id;
  816. params["hp"] = item.hp;
  817. params["maxHp"] = item.max_hp;
  818. params["mp"] = item.mp;
  819. params["maxMp"] = item.max_mp;
  820. };
  821. WG.add_hook("sc", data => {
  822. if (data.id == null) return;
  823. let item = RoomItems[data.id];
  824. if (item == null) return;
  825. if (data.hp != null) {
  826. let compare = "低于";
  827. if (data.hp > item.hp) compare = "高于";
  828. const oldValue = item.hp;
  829. const oldPer = (item.hp/item.max_hp*100).toFixed(2);
  830. item.hp = data.hp;
  831. if (item.max_hp < item.hp) item.max_hp = item.hp;
  832. if (data.max_hp != null) item.max_hp = data.max_hp;
  833. const newValue = item.hp;
  834. const newPer = (item.hp/item.max_hp*100).toFixed(2);
  835. let params1 = {
  836. "人名关键字": item.name,
  837. "类型": "气血",
  838. "当": compare,
  839. "值类型": "百分比",
  840. "值": `${oldPer};${newPer}`
  841. };
  842. decorate(params1, item);
  843. const n1 = new Notification("气血内力改变", params1);
  844. NotificationCenter.post(n1);
  845. let params2 = {
  846. "人名关键字": item.name,
  847. "类型": "气血",
  848. "当": compare,
  849. "值类型": "数值",
  850. "值": `${oldValue};${newValue}`
  851. };
  852. decorate(params2, item);
  853. const n2 = new Notification("气血内力改变", params2);
  854. NotificationCenter.post(n2);
  855. }
  856. if (data.mp != null) {
  857. let compare = "低于";
  858. if (data.mp > item.mp) compare = "高于";
  859. const oldValue = item.mp;
  860. const oldPer = (item.mp/item.max_mp*100).toFixed(2);
  861. item.mp = data.mp;
  862. if (item.max_mp < item.mp) item.max_mp = item.mp;
  863. if (data.max_mp != null) item.max_mp = data.max_mp;
  864. const newValue = item.mp;
  865. const newPer = (item.mp/item.max_mp*100).toFixed(2);
  866. let params1 = {
  867. "人名关键字": item.name,
  868. "类型": "内力",
  869. "当": compare,
  870. "值类型": "百分比",
  871. "值": `${oldPer};${newPer}`
  872. };
  873. decorate(params1, item);
  874. const n1 = new Notification("气血内力改变", params1);
  875. NotificationCenter.post(n1);
  876. let params2 = {
  877. "人名关键字": item.name,
  878. "类型": "内力",
  879. "当": compare,
  880. "值类型": "数值",
  881. "值": `${oldValue};${newValue}`
  882. };
  883. decorate(params2, item);
  884. const n2 = new Notification("气血内力改变", params2);
  885. NotificationCenter.post(n2);
  886. }
  887. });
  888. };
  889. const monitor = new Monitor(run);
  890. MonitorCenter.addMonitor(monitor);
  891. })();
  892.  
  893. //---------------------------------------------------------------------------
  894. // damage
  895. //---------------------------------------------------------------------------
  896.  
  897. (function() {
  898. const name = new InputFilter("人名关键字", InputFilterFormat.text, "", KeyAssert);
  899. const valueType = new SelectFilter("值类型", ["百分比", "数值"], 0, EqualAssert);
  900. const value = new InputFilter("值", InputFilterFormat.number, 0, (fromUser, fromGame) => {
  901. const parts = fromGame.split(";");
  902. const oldvalue = parseFloat(parts[0]);
  903. const newvalue = parseFloat(parts[1]);
  904. if (oldvalue <= fromUser && newvalue > fromUser) return true;
  905. return false;
  906. });
  907. let filters = [name, valueType, value];
  908. const intro = `// 伤害已满触发器
  909. // 备注:限制条件-值 不支持多条件
  910. // 人物id:(id)
  911. // 人物名称:(name)
  912. // 伤害数值:(value)
  913. // 伤害百分比:(percent)`;
  914. const t = new TriggerTemplate("伤害已满", filters, intro);
  915. TriggerTemplateCenter.add(t);
  916.  
  917. const run = function() {
  918. const decorate = function(params, item, value, percent) {
  919. params["id"] = item.id;
  920. params["name"] = item.name;
  921. params["value"] = value;
  922. params["percent"] = percent;
  923. };
  924. WG.add_hook("sc", data => {
  925. if (data.id == null || data.damage == null) return;
  926. let item = RoomItems[data.id];
  927. if (item == null || item.id == null || item.name == null || item.max_hp == null) return;
  928. // 获取之前保存的伤害和伤害百分比
  929. const oldValue = item._damage == null ? 0 : item._damage;
  930. const oldPer = item._damagePer == null ? 0 : item._damagePer;
  931. const value = data.damage;
  932. const percent = (data.damage/item.max_hp*100).toFixed(2);
  933. // 保存伤害和伤害百分比
  934. item._damage = value;
  935. item._damagePer = percent;
  936. let params1 = {
  937. "人名关键字": item.name,
  938. "值类型": "百分比",
  939. "值": `${oldPer};${percent}`
  940. };
  941. decorate(params1, item, value, percent);
  942. const n1 = new Notification("伤害已满", params1);
  943. NotificationCenter.post(n1);
  944. let params2 = {
  945. "人名关键字": item.name,
  946. "值类型": "数值",
  947. "值": `${oldValue};${value}`
  948. };
  949. decorate(params2, item, value, percent);
  950. const n2 = new Notification("伤害已满", params2);
  951. NotificationCenter.post(n2);
  952. });
  953. };
  954. const monitor = new Monitor(run);
  955. MonitorCenter.addMonitor(monitor);
  956. })();
  957.  
  958. /***********************************************************************************\
  959. UI
  960. \***********************************************************************************/
  961.  
  962. const Message = {
  963. append: function(msg) {
  964. messageAppend(msg);
  965. },
  966. clean: function() {
  967. messageClear();
  968. },
  969. };
  970.  
  971. const UI = {
  972. triggerHome: function() {
  973. const content = `
  974. <style>.breakText {word-break:keep-all;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}</style>
  975. <span class="zdy-item" style="width:120px" v-for="t in triggers" :style="activeStyle(t)">
  976. <div style="width: 30px; float: left; background-color: rgba(255, 255, 255, 0.31); border-radius: 4px;" v-on:click="editTrigger(t)">⚙</div>
  977. <div class="breakText" style="width: 85px; float: right;" v-on:click="switchStatus(t)">{{ t.name }}</div>
  978. </span>
  979. `;
  980. const rightText = "<span v-on:click='createTrigger()'><wht>新建</wht></span>";
  981. UI._appendHtml("🍟 <hio>触发器</hio>", content, rightText);
  982. new Vue({
  983. el: '#app',
  984. data: {
  985. triggers: TriggerCenter.getAll()
  986. },
  987. methods: {
  988. switchStatus: function(t) {
  989. if (t.active()) {
  990. TriggerCenter.deactivate(t.name);
  991. } else {
  992. TriggerCenter.activate(t.name);
  993. }
  994. UI.triggerHome();
  995. },
  996. editTrigger: UI.editTrigger,
  997. activeStyle: function(t) {
  998. if (t.active()) {
  999. return {
  1000. "background-color": "#a0e6e0",
  1001. "border": "1px solid #7284ff",
  1002. "color": "#001bff"
  1003. };
  1004. } else {
  1005. return { "background-color": "none" };
  1006. }
  1007. },
  1008. createTrigger: UI.selectTriggerTemplate
  1009. }
  1010. });
  1011. },
  1012. selectTriggerTemplate: function() {
  1013. const content = `
  1014. <span class="zdy-item" style="width:120px" v-for="t in templates" v-on:click="select(t)">{{ t.event }}</span>
  1015. `;
  1016. const leftText = "<span v-on:click='back()'>< 返回</span>";
  1017. UI._appendHtml("<wht>选择触发事件</wht>", content, null, leftText);
  1018. new Vue({
  1019. el: '#app',
  1020. data: {
  1021. templates: TriggerTemplateCenter.getAll()
  1022. },
  1023. methods: {
  1024. select: UI.createTrigger,
  1025. back: UI.triggerHome
  1026. }
  1027. });
  1028. },
  1029. createTrigger: function(template) {
  1030. UI._updateTrigger(template);
  1031. },
  1032. editTrigger: function(trigger) {
  1033. UI._updateTrigger(trigger.template, trigger);
  1034. },
  1035. _updateTrigger: function(template, trigger) {
  1036. const content = `
  1037. <div style="margin:0 2em 0 2em">
  1038. <div style="float:left;width:120px">
  1039. <span class="zdy-item" style="width:90px" v-for="f in filters">
  1040. <p style="margin:0"><wht>{{ f.description() }}</wht></p>
  1041. <input v-if="f.type=='input'" style="width:80%" v-model="conditions[f.name]">
  1042. <select v-if="f.type=='select'" v-model="conditions[f.name]">
  1043. <option v-for="opt in f.options" :value="opt">{{ opt }}</option>
  1044. </select>
  1045. </span>
  1046. </div>
  1047. <div style="float:right;width:calc(100% - 125px)">
  1048. <textarea class = "settingbox hide" style = "height:10rem;display:inline-block;font-size:0.8em;width:100%" v-model="source"></textarea>
  1049. <span class="raid-item shareTrigger" v-if="canShared" v-on:click="share()">分享此触发器</span>
  1050. </div>
  1051. </div>
  1052. `;
  1053. const title = `<input style='width:110px' type="text" placeholder="输入触发器名称" v-model="name">`;
  1054. let rightText = "<span v-on:click='save'><wht>保存</wht></span>";
  1055. if (trigger) {
  1056. rightText = "<span v-on:click='remove'>删除</span>"
  1057. }
  1058. let leftText = "<span v-on:click='back'>< 返回</span>";
  1059. if (trigger) {
  1060. leftText = "<span v-on:click='saveback'>< 保存&返回</span>"
  1061. }
  1062. UI._appendHtml(title, content, rightText, leftText);
  1063. let conditions = {};
  1064. if (trigger != null) {
  1065. conditions = trigger.conditions;
  1066. } else {
  1067. for (const f of template.filters) {
  1068. conditions[f.name] = f.defaultValue;
  1069. }
  1070. }
  1071. let source = template.introdution;
  1072. if (trigger != null) source = trigger.source;
  1073. new Vue({
  1074. el: '#app',
  1075. data: {
  1076. filters: template.filters,
  1077. name: trigger ? trigger.name : "",
  1078. conditions: conditions,
  1079. source: source,
  1080. canShared: trigger != null
  1081. },
  1082. methods: {
  1083. save: function() {
  1084. const result = TriggerCenter.create(this.name, template.event, this.conditions, this.source);
  1085. if (result == true) {
  1086. UI.triggerHome();
  1087. } else {
  1088. alert(result);
  1089. }
  1090. },
  1091. remove: function() {
  1092. const verify = confirm("确认删除此触发器吗?");
  1093. if (verify) {
  1094. TriggerCenter.remove(trigger.name);
  1095. UI.triggerHome();
  1096. }
  1097. },
  1098. back: function() {
  1099. UI.selectTriggerTemplate();
  1100. },
  1101. saveback: function() {
  1102. const result = TriggerCenter.modify(trigger.name, this.name, this.conditions, this.source);
  1103. if (result == true) {
  1104. UI.triggerHome();
  1105. } else {
  1106. alert(result);
  1107. }
  1108. },
  1109.  
  1110. share: function() {
  1111. ToRaid.shareTrigger(TriggerCenter._getData(trigger.name));
  1112. }
  1113. }
  1114. })
  1115. },
  1116.  
  1117. _appendHtml: function(title, content, rightText, leftText) {
  1118. var realLeftText = leftText == null ? "" : leftText;
  1119. var realRightText = rightText == null ? "" : rightText;
  1120. var html = `
  1121. <div class = "item-commands" style="text-align:center" id="app">
  1122. <div style="margin-top:0.5em">
  1123. <div style="width:8em;float:left;text-align:left;padding:0px 0px 0px 2em;height:1.23em" id="wsmud_raid_left">${realLeftText}</div>
  1124. <div style="width:calc(100% - 16em);float:left;height:1.23em">${title}</div>
  1125. <div style="width:8em;float:left;text-align:right;padding:0px 2em 0px 0px;height:1.23em" id="wsmud_raid_right">${realRightText}</div>
  1126. </div>
  1127. <br><br>
  1128. ${content}
  1129. </div>`;
  1130. Message.clean();
  1131. Message.append(html);
  1132. },
  1133. };
  1134.  
  1135. /***********************************************************************************\
  1136. Trigger Config
  1137. \***********************************************************************************/
  1138.  
  1139. const TriggerConfig = {
  1140. get: function() {
  1141. let all = {};
  1142. let keys = GM_listValues();
  1143. keys.forEach(key => {
  1144. all[key] = GM_getValue(key);
  1145. });
  1146. return all;
  1147. },
  1148. set: function(config) {
  1149. for (const key in config) {
  1150. GM_setValue(key, config[key]);
  1151. }
  1152. TriggerCenter.reload();
  1153. }
  1154. };
  1155.  
  1156. /***********************************************************************************\
  1157. Ready
  1158. \***********************************************************************************/
  1159.  
  1160. let Running = false;
  1161.  
  1162. $(document).ready(function () {
  1163. __init__();
  1164. if (WG == undefined || WG == null || ToRaid == undefined || ToRaid == null) {
  1165. setTimeout(__init__, 300);
  1166. }
  1167. });
  1168.  
  1169. function __init__(){
  1170. WG = unsafeWindow.WG;
  1171.  
  1172. messageAppend = unsafeWindow.messageAppend;
  1173. messageClear = unsafeWindow.messageClear;
  1174. ToRaid = unsafeWindow.ToRaid;
  1175.  
  1176. if (WG == undefined || WG == null || ToRaid == undefined || ToRaid == null) {
  1177. setTimeout(()=>{__init__()}, 300);
  1178. return;
  1179. }
  1180. Role = unsafeWindow.Role;
  1181.  
  1182. unsafeWindow.TriggerUI = UI;
  1183. unsafeWindow.TriggerConfig = TriggerConfig;
  1184. unsafeWindow.TriggerCenter = TriggerCenter;
  1185.  
  1186. WG.add_hook("login", function (data) {
  1187. if (Running) return;
  1188. Running = true;
  1189.  
  1190. TriggerCenter.run();
  1191. MonitorCenter.run();
  1192. });
  1193. }
  1194. })();

QingJ © 2025

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