Greasy Fork 还支持 简体中文。

wsmud_Trigger

武神传说 MUD

目前為 2019-03-19 提交的版本,檢視 最新版本

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