wsmud_Trigger

武神传说 MUD

当前为 2019-03-07 提交的版本,查看 最新版本

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