wsmud_Trigger_ex

武神传说 MUD

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

QingJ © 2025

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