cmds.tin 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  1. #nop vim: set filetype=tt:;
  2. /*
  3. 本文件属于 PaoTin++ 的一部分。
  4. PaoTin++ © 2020~2023 的所有版权均由担子炮(dzp <danzipao@gmail.com>) 享有并保留一切法律权利
  5. 你可以在遵照 GPLv3 协议的基础之上使用、修改及重新分发本程序。
  6. */
  7. #nop 本文件是 xtintin 的一部分,实现了一些实用命令。;
  8. ///=== {
  9. ///// 实用命令:
  10. //
  11. // ## clear
  12. // 清屏。类似于 DOS/Unix,也可以用 cls,作用相同。
  13. // };
  14. #alias {cls} {clear};
  15. #alias {clear} {
  16. #system {tput clear};
  17. tmux.SetTheme GAME;
  18. prompt.refresh;
  19. };
  20. ///=== {
  21. // ## exit
  22. // 退出客户端,但不退出游戏角色。也可以用 quit,作用相同。
  23. // 一些中文 MUD 服务器在接收到 quit 命令时会让角色从服务器上下线,
  24. // 这往往会导致玩家丢失背包里的物品。新手玩家常常因此懊恼万分。
  25. // 为了避免悲剧发生,这里特别映射一下,改成仅断开连接,而不退出服务器角色。
  26. // 如果玩家真的需要向服务器发送 quit 指令,请输入 #send quit。exit 同理。
  27. // };
  28. #alias {exit} {#end};
  29. #alias {quit} {#end};
  30. ///=== {
  31. // ## xtt.Tick <ID> <代码> <间隔时间>
  32. // 跟 #tick 功能类似,但是会立即执行一次代码。对于间隔时间比较长的定时器来说尤其有用。
  33. // 你也可以通过 Tick 别名来使用本别名。
  34. // };
  35. #alias {Tick} {xtt.Tick};
  36. #alias {xtt.Tick} {
  37. #local id {%1};
  38. #local code {%2};
  39. #local interval {%3};
  40. #line sub var #untick {$id};
  41. #line sub var #tick {$id} {$code} $interval;
  42. $code;
  43. };
  44. ///=== {
  45. // ## xtt.ListTicker
  46. // 列出系统中所有的定时器。因为定时器一般不会很多因此暂时没有做过滤功能。
  47. // 你也可以通过 TICKS 别名来使用本别名。
  48. // };
  49. #alias {TICKS} {xtt.ListTicker};
  50. #alias {xtt.ListTicker} {
  51. #info tickers save;
  52. #echo {<128> %-30s %+20s %+10s %+20s} {所属模块} {定时器名称} {执行周期} {距离下次执行(s)};
  53. #draw Yellow scroll line 1 1 1 90;
  54. #format utime %U;
  55. #local index {};
  56. #loop {1} {&info[TICKERS][]} {index} {
  57. #local uval {};
  58. #math uval $info[TICKERS][+$index][arg3] * 1000000;
  59. #local name {$info[TICKERS][+$index][arg1]};
  60. #echo { %-30s %+20s %+10s %+20m}
  61. {@genModuleLink{$info[TICKERS][+$index][class];MOD}}
  62. {$name @mslp.Exec{{xtt.delTrigger tick $name};<119>✗<269>;false}}
  63. {$info[TICKERS][+$index][arg3]}
  64. {($uval - ($utime - $info[TICKERS][+$index][arg4]) % $uval) / 1000000.00};
  65. };
  66. };
  67. ///=== {
  68. // ## xtt.ListAlias [<正则表达式>]
  69. // 列出系统中符合条件的别名,如果省略条件则列出所有别名。
  70. // 一些不够规整的别名不会被列出。只有符合 PaoTin++ 规范的别名才会被列出。
  71. // 正则表达式会被运用到别名所属模块名称和别名名称上,两者符合其一即可被列出。
  72. // 你也可以通过 ALIASES 别名来使用本别名。
  73. // };
  74. #alias {ALIASES} {xtt.ListAlias};
  75. #alias {xtt.ListAlias} {
  76. #local pattern {%1};
  77. #info aliases save;
  78. #local aliasTable {};
  79. #local index {};
  80. #loop {1} {&info[ALIASES][]} {index} {
  81. #local name {$info[ALIASES][+$index][arg1]};
  82. #local class {$info[ALIASES][+$index][class]};
  83. #if { "$class" == "" && "$pattern" != "all" } {
  84. #continue;
  85. };
  86. #if { "$class" == "" } {
  87. #local class {未分组};
  88. };
  89. #if { "$name" == "%*{[^a-zA-Z0-9-_.]}%*" } {
  90. #continue;
  91. };
  92. #if { "$pattern" != "{|all}" && "$class/$name" != "%*$pattern%*" } {
  93. #continue;
  94. };
  95. #list {aliasTable[$class]} sort {$name};
  96. };
  97. #local format { %-30s %-40s %-10s};
  98. #echo {<128>$format} {class} {别名} {类型};
  99. #draw Yellow scroll line 1 1 1 90;
  100. #local classList {@list.Sort{*aliasTable[]}};
  101. #local class {};
  102. #foreach {$classList} {class} {
  103. #local name {};
  104. #foreach {${aliasTable[$class][]}} {name} {
  105. #local type {<139>自定义<299>};
  106. #if { "$name" == "%*.{[A-Z][a-zA-Z0-9]+}" } {
  107. #local type {<129>开放API<299>};
  108. };
  109. #if { "$class" == "module-loader" } {
  110. #if { "$name" == "{[A-Z]+}" } {
  111. #local type {<169>快捷方式<299>};
  112. };
  113. #else {
  114. #local type {<229>语法增强<299>};
  115. }
  116. };
  117. #if { "${class}.$name" == "main.class.%*" } {
  118. #local type {<229>语法增强<299>};
  119. };
  120. #if { "${class}.$name" == "main.load-file" } {
  121. #local type {<229>语法增强<299>};
  122. };
  123. #if { "${class}.$name" == "main.%*Log" } {
  124. #local type {<129>日志接口<299>};
  125. };
  126. #if { "$pattern" == "" && "$type" == "%*自定义%*" } {
  127. #continue;
  128. };
  129. #echo {<060>$format}
  130. {@genModuleLink{$class;MOD}<060>}
  131. {@mslp.Exec{{xtt.delTrigger alias $name};<119>✗<269>;false} @linkToHelp{$class;$name}}
  132. {$type};
  133. };
  134. };
  135. };
  136. ///=== {
  137. // ## xtt.ListVar [<正则表达式>]
  138. // 列出系统中符合条件的变量,如果省略条件则列出所有变量。
  139. // 一些不够规整的变量不会被列出。只有符合 PaoTin++ 规范的变量才会被列出。
  140. // 正则表达式会被运用到变量所属模块名称和变量名称上,两者符合其一即可被列出。
  141. // 你也可以通过 VARS 别名来使用本别名。
  142. // };
  143. #alias {VARS} {xtt.ListVar};
  144. #alias {xtt.ListVar} {
  145. #local pattern {%1};
  146. #info variable save;
  147. #local varTable {};
  148. #local index {};
  149. #loop {1} {&info[VARIABLES][]} {index} {
  150. #local name {$info[VARIABLES][+$index][arg1]};
  151. #local class {$info[VARIABLES][+$index][class]};
  152. #local value {$info[VARIABLES][+$index][arg2]};
  153. #local nest {$info[VARIABLES][+$index][nest]};
  154. #if { "$class" == "" && "$pattern" != "all" } {
  155. #continue;
  156. };
  157. #if { "$class" == "" } {
  158. #local class {未分组};
  159. };
  160. #if { "$pattern" != "{|all}" && "$class/$name" != "%*$pattern%*" } {
  161. #continue;
  162. };
  163. #local {varTable[$class][$name]} {
  164. {nest}{$nest}
  165. {value}{$value}
  166. };
  167. };
  168. #local format { %-30s %-40s %-10s %s};
  169. #echo {<128>$format} {class} {变量} {类型} {值};
  170. #draw Yellow scroll line 1 1 1 95;
  171. #local classList {@slist.Sort{*varTable[]}};
  172. #local class {};
  173. #foreach {$classList} {class} {
  174. #local name {};
  175. #local nameList {@slist.Sort{*varTable[$class][]}};
  176. #foreach {$nameList} {name} {
  177. #local type {<229>字符串<299>};
  178. #local value {<169>$varTable[$class][$name][value]<299>};
  179. #local nest {$varTable[$class][$name][nest]};
  180. #if { $nest > 0 } {
  181. #local type {<259>表格<299>};
  182. #local value {@mslp.Var{$name;<139>[... 共 $nest 项数据]<299>}};
  183. };
  184. #echo {<060>$format}
  185. {@genModuleLink{$class;MOD}<060>}
  186. {@mslp.Exec{{xtt.delTrigger var $name};<119>✗<269>;false} @linkToHelp{$class;$name}}
  187. {$type}
  188. {$value};
  189. };
  190. };
  191. };
  192. #alias {xtt.delTrigger} {
  193. #local type {%1};
  194. #local trigger {%2};
  195. #local cmd {#un$type $trigger};
  196. $cmd;
  197. };
  198. ///=== {
  199. // ## xtt.ListFunc [<正则表达式>]
  200. // 列出系统中符合条件的函数,如果省略条件则列出所有函数。
  201. // 正则表达式会被运用到函数所属模块名称和函数名称上,两者符合其一即可被列出。
  202. // 一些不够规整的函数不会被列出。只有符合 PaoTin++ 规范的函数才会被列出。
  203. // 你也可以通过 FUNCS 别名来使用本别名。
  204. // };
  205. #alias {FUNCS} {xtt.ListFunc};
  206. #alias {xtt.ListFunc} {
  207. #local pattern {%1};
  208. #info functions save;
  209. #local funcsTable {};
  210. #local index {};
  211. #loop {1} {&info[FUNCTIONS][]} {index} {
  212. #local name {$info[FUNCTIONS][+$index][arg1]};
  213. #local class {$info[FUNCTIONS][+$index][class]};
  214. #if { "$class" == "" && "$pattern" != "all" } {
  215. #continue;
  216. };
  217. #if { "$class" == "" } {
  218. #local class {未分组};
  219. };
  220. #if { "$name" == "%*{[^a-zA-Z0-9_./-]}%*" } {
  221. #continue;
  222. };
  223. #if { "$pattern" != "{|all}" && "$class/$name" != "%*$pattern%*" } {
  224. #continue;
  225. };
  226. #list {funcsTable[$class]} sort {$name};
  227. };
  228. #local format { %-30s %-40s %-10s};
  229. #echo {<128>$format} {class} {函数} {类型};
  230. #draw Yellow scroll line 1 1 1 90;
  231. #local classList {@list.Sort{*funcsTable[]}};
  232. #local class {};
  233. #foreach {$classList} {class} {
  234. #local name {};
  235. #foreach {${funcsTable[$class][]}} {name} {
  236. #local type {<139>自定义<299>};
  237. #if { "$name" == "%*.{[A-Z][a-zA-Z0-9]+}" } {
  238. #local type {<129>开放API<299>};
  239. };
  240. #if { "$class" == "{lib/xtintin|main}" } {
  241. #local type {<229>语法增强<299>};
  242. };
  243. #if { "${class}.$name" == "main.%*Log" } {
  244. #local type {<129>日志接口<299>};
  245. };
  246. #if { "$pattern" == "" && "$type" == "%*自定义%*" } {
  247. #continue;
  248. };
  249. #echo {<060>$format}
  250. {@genModuleLink{$class;MOD}<060>}
  251. {@mslp.Exec{{xtt.delTrigger func $name};<119>✗<269>;false} @linkToHelp{$class;$name}}
  252. {$type};
  253. };
  254. };
  255. };
  256. ///=== {
  257. // ## xtt.Send <命令> [<参数> ...]
  258. // 向服务器发送命令。如果命令拦截总开关被打开,则不会真的向服务器发送。
  259. // };
  260. #alias {xtt.Send} {
  261. #if { "$xttOptions[DisableOutput]" == "true" } {
  262. #echo {<169>命令已被抑制: <429>%p<299>} {%0};
  263. #return;
  264. };
  265. #send %0;
  266. };
  267. ///=== {
  268. // ## xtt.SendAtOnce <分号分隔的命令序列>
  269. // 一次性向服务器发送多条命令。
  270. // 有的 MUD 服务器专门为这种方式开辟了通道,本方法可以使用这种通道。
  271. // TODO: 需要区分 MUD,需要支持定制的命令分隔符。
  272. // };
  273. #alias {xtt.SendAtOnce} {
  274. #local cmds {%1};
  275. #send {#$cmds#};
  276. };
  277. ///=== {
  278. // ## xtt.Answer <问题答复>
  279. // 如果游戏中有需要回答的问题,并且给出了特定的提示符(就是不带换行的文本),
  280. // 那么由于 TinTin++ 的某种机制,导致回答的内容和问题就会有重叠,不能正确显示。
  281. // 此时建议用 xtt.Answer 来回答此类问题。将会留下美观的 buffer 记录。
  282. // };
  283. #alias {xtt.Answer} {
  284. #delay 0 {
  285. #echo {};
  286. #buffer end;
  287. #send {%1};
  288. };
  289. };
  290. ///=== {
  291. // ## xtt.Stop <命令>
  292. // 暂时阻断某个命令的执行。
  293. // 某些基于触发的机器会周而复始地执行动作。本命令可以用来终止它的运行,并保留状态。
  294. // 例如新手机器人会循环执行 ask job/do/finish 流程,那么只需要输入 xtt.Stop ask,
  295. // 就可以在下一次 ask NPC 时,暂停机器执行,但并不影响机器状态。此时玩家可以手动
  296. // 操作角色,临时去做点别的,比如收个包袱之类的,然后回到房间,手动执行一次 ask 命令,
  297. // 就可以继续机器运行了。
  298. // };
  299. #alias {xtt.Stop} {
  300. #line oneshot #alias {%1} {halt; #echo {<119>任务已暂停,请输入 <139>%1 %s <119>继续运行。<299>} {%%0}}
  301. };
  302. ///=== {
  303. // ## xtt.DisableAllCommand
  304. // 禁止发送任何命令。
  305. // 某些游戏模式下,玩家必须小心地输入,否则一旦输错会造成损失。此时可以用本
  306. // 命令来禁止所有的触发、定时器、快捷键,等等,防止误发命令。
  307. // 此时玩家只能用 #send {.....} 命令来发送命令。
  308. // };
  309. #alias {xtt.DisableAllCommand} {
  310. #class disable-all-command open;
  311. #alias {xtt.UndoDisableAllCommand} {
  312. #class disable-all-command kill;
  313. #line quiet #ignore actions off;
  314. #line quiet #ignore tickers off;
  315. #line quiet #ignore delays off;
  316. #line quiet #ignore events off;
  317. #line quiet #ignore macros off;
  318. okLog 命令已恢复正常。;
  319. } {1.000};
  320. #alias {^%*{|ID=paotin/disable-all-command}$} {
  321. #echo {<119>命令已被抑制,可用 <129>#send<119> 强制发送。撤销请用 <129>xtt.UndoDisableAllCommand<119> : <139>%s<299>} {%%0}
  322. } {1.001};
  323. #line quiet #ignore actions on;
  324. #line quiet #ignore tickers on;
  325. #line quiet #ignore delays on;
  326. #line quiet #ignore events on;
  327. #line quiet #ignore macros on;
  328. #class disable-all-command close;
  329. };
  330. #func {linkToHelp} {
  331. #local module {%1};
  332. #local keyword {%2};
  333. #local text {$keyword};
  334. #local cmd {HELP $keyword};
  335. #if { "$keyword" == "" } {
  336. #local text {$module};
  337. #local keyword {MODULE};
  338. #local cmd {HELP $module};
  339. };
  340. #if { "$module" == "" } {
  341. #return {$text};
  342. };
  343. #if { &xtt.module-doc[$module][] == 0 } {
  344. #return {$text};
  345. };
  346. #if { &xtt.module-doc[$module][$keyword][] == 0 } {
  347. #return {$text};
  348. };
  349. #return {<149>@mslp.Exec{{$cmd};{$text}}<299>};
  350. };
  351. ///=== {
  352. // ## cli.SmartToggle
  353. // 命令行智能切换。
  354. // 出于方便起见,该命令实际上集成了三个作用,并推荐使用快捷键来调用本命令。
  355. // - 作用1: 当命令行尚未输入内容时,用来切换 PaoTin++ 的调试开关。
  356. // 调试开关开启时,玩家可以看到触发的执行细节,方便调试代码。
  357. // - 作用2: 当命令行输入了 #alias/#action 等 TinTin++ 可被取消的触发时,会
  358. // 自动修改成对应的 #unalias/#unaction 命令,利用这一点可以方便取
  359. // 消已有触发。可被取消的触发列表见下方完整清单。
  360. // - 作用3: 当命令行输入了其它命令时,会自动开启或关闭以调试方式执行该命令。
  361. // 该切换并不会影响全局调试开关。因此不会受到来自其它触发的干扰,
  362. // 内容更精准,方便查看。
  363. //
  364. // 作用2中可被取消的命令清单:
  365. // - 常用 TinTin++ 命令: action alias tick variable delay gag
  366. // - 不常用 TinTin++ 命令: button event function highlight macro pathdir
  367. // prompt substitute tab
  368. // 以上命令的 3 字母以上简写,无论大小写,都会被自动添加或者删除 un,
  369. // 以达到切换的目的。
  370. // - 常用的 PaoTin++ 命令: event.Handle/event.HandleOnce VS event.UnHandle
  371. // };
  372. #alias {cli.SmartToggle} {
  373. #local input {};
  374. #cursor get input;
  375. #line quiet #ignore function on;
  376. #if { {$input} == {} } {
  377. #line quiet #ignore function off;
  378. xtt.ToggleDebug;
  379. #return;
  380. };
  381. #if { {$input} == {#line debug %*} } {
  382. #replace input {^#line debug } {};
  383. };
  384. #else {
  385. #local cmds {act(|i(|o(|n)))|ali(|a(|s))|tic(|k(|e(|r)))
  386. |var(|i(|a(|b(|l(|e)))))
  387. |del(|a(|y))|gag|tab
  388. |but(|t(|o(|n)))|eve(|n(|t))
  389. |fun(|c(|t(|i(|o(|n)))))
  390. |hig(|h(|l(|i(|g(|h(|t))))))
  391. |mac(|r(|o))|pat(|h(|d(|i(|r))))
  392. |pro(|m(|p(|t)))
  393. |sub(|s(|t(|i(|t(|u(|t(|e)))))))};
  394. #replace cmds { } {};
  395. #if { {$input} == {{?i}#un{$cmds} %*} } {
  396. #replace input {{?i}#un} {#};
  397. };
  398. #elseif { {$input} == {{?i}#{$cmds} %*} } {
  399. #replace input {^#} {#un};
  400. };
  401. #elseif { {$input} == {event.Handle{|Once} %*} } {
  402. #replace input {^event.Handle{Once|}} {event.UnHandle};
  403. };
  404. #elseif { {$input} == {event.UnHandle %*} } {
  405. #replace input {^event.UnHandle} {event.Handle};
  406. };
  407. #else {
  408. #local input {#line debug $input};
  409. };
  410. };
  411. #cursor clear;
  412. #local cmd {
  413. #line quiet #ignore variable on;
  414. #cursor set {$input};
  415. #line quiet #ignore variable off;
  416. };
  417. $cmd;
  418. #line quiet #ignore function off;
  419. };