xiaoyao.tin 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758
  1. #nop vim: set filetype=tt:;
  2. /*
  3. 本文件属于 PaoTin++ 的一部分
  4. ===========
  5. PaoTin++ © 2020~2023 的所有版权均由担子炮(dzp <danzipao@gmail.com>) 享有并保留一切法律权利
  6. 你可以在遵照 GPLv3 协议的基础之上使用、修改及重新分发本程序。
  7. ===========
  8. */
  9. VAR {逍遥行地图数据} map.xiaoyao.map {};
  10. VAR {逍遥行房间数据} map.xiaoyao.room {};
  11. load-module basic/busy;
  12. event.HandleOnce {map/init} {map/xiaoyao} {map} {xiaoyao.Init};
  13. VAR {逍遥行正在赶路} {xiaoyao.under-way} {0};
  14. #alias {xiaoyao.Init} {
  15. event.Handle {map/GotRoomInfo} {xiaoyao.try-locate} {map/xiaoyao} {xiaoyao.try-locate};
  16. storage.Load {map-xiaoyao} {map.xiaoyao.map;map.xiaoyao.room};
  17. load-config xiaoyao;
  18. xiaoyao.fixMap;
  19. };
  20. #nop fixMap 只修复连接,不允许添加新的节点;
  21. #alias {xiaoyao.fixMap} {
  22. #local node {};
  23. #foreach {*map.xiaoyao.Special[]} {node} {
  24. #if { &map.xiaoyao.map[$node][] == 0 } {
  25. #continue;
  26. };
  27. #local target {};
  28. #foreach {*map.xiaoyao.Special[$node][]} {target} {
  29. #if { &map.xiaoyao.map[$target][] == 0 } {
  30. #continue;
  31. };
  32. #local link {$map.xiaoyao.Special[$node][$target]};
  33. #if { "$link" == "DELETE" } {
  34. #unvar map.xiaoyao.map[$node][$target];
  35. };
  36. #else {
  37. #var map.xiaoyao.map[$node][$target] {$link};
  38. };
  39. };
  40. };
  41. };
  42. #alias {xiaoyao.checkMap} {
  43. #local node {};
  44. #local areaMap {};
  45. #foreach {*map.xiaoyao.map[]} {node} {
  46. #local next {};
  47. #if { &map.xiaoyao.map[$node][] == 1 && "$map.xiaoyao.map[$node][DOCK]" != "" } {
  48. warnLog 这是个纯粹的码头 => $node;
  49. };
  50. #foreach {*map.xiaoyao.map[$node][]} {next} {
  51. #regex {$node} {%*(%*的%*)} {
  52. #format {areaMap[&2][$node]} {true};
  53. };
  54. #local link {$map.xiaoyao.map[$node][$next]};
  55. #if { "$next" == "DOCK" || "$link" == "TODO" } {
  56. errLog $node => $next 尚未联通。;
  57. };
  58. };
  59. };
  60. #local maxNodeNum {0};
  61. #local maxNodeNumArea {};
  62. #local area {};
  63. #foreach {*areaMap[]} {area} {
  64. okLog $area(&areaMap[$area][]): @slist.Join{{@slist.FromList{@list.FromSlist{*areaMap[$area][]}}};、};
  65. #if { &areaMap[$area][] > $maxNodeNum } {
  66. #local maxNodeNum {&areaMap[$area][]};
  67. #local maxNodeNumArea {$area};
  68. };
  69. };
  70. okLog 地图连接性检查正常,一共包含 &map.xiaoyao.map[] 个节点,&areaMap[] 个区域,节点最多的区域是「$maxNodeNumArea」,共有 $maxNodeNum 个节点。;
  71. };
  72. #alias {xiaoyao.SimpleMap} {
  73. #local bigArea {};
  74. #local areaMap {};
  75. #local area {};
  76. #local node {};
  77. #foreach {*map.xiaoyao.map[]} {node} {
  78. #regex {$node} {%*(%*的%*)} {
  79. #format {area} {%s} {&2};
  80. };
  81. #local bigArea {@map.AreaColor{$area}};
  82. #list {areaMap[$bigArea][$area]} add {$node};
  83. };
  84. #local screenWidth {};
  85. #screen get cols screenWidth;
  86. #local lines {};
  87. #local line {};
  88. #local color {};
  89. #local lineWidth {0};
  90. #local buttons {};
  91. #local bigAreaCount {0};
  92. #local areaCount {0};
  93. #local nodeCount {0};
  94. #loop {1} {&areaMap[]} {bigArea} {
  95. #math bigAreaCount {$bigAreaCount + 1};
  96. #local bgColor *areaMap[+$bigArea];
  97. #local fgColor {0};
  98. #loop {1} {&areaMap[+$bigArea][]} {area} {
  99. #math areaCount {$areaCount + 1};
  100. #math fgColor {($fgColor + 1) % 2};
  101. #local index {$bgColor};
  102. #replace index {%*4%+1d%*} {&2};
  103. #if { "$bgColor" == "46" } {
  104. #local color {\e[${bgColor};@math.Eval{30 + $fgColor * 4}m};
  105. };
  106. #elseif { $index == 3 } {
  107. #local color {\e[${bgColor};@math.Eval{30 + $fgColor * 4}m};
  108. };
  109. #else {
  110. #local color {\e[${bgColor};@math.Eval{37 - $fgColor * 4}m};
  111. };
  112. #cat line {$color};
  113. #loop {1} {&areaMap[+$bigArea][+$area][]} {node} {
  114. #local node {$areaMap[+$bigArea][+$area][+$node]};
  115. #local city {$node};
  116. #replace city {%S(%S)} {&1};
  117. #local width {@math.Eval{ ( @math.Int{@str.Width{$city} * 1.0 / 4 + 0.4} + 1 ) * 4 }};
  118. #if { $lineWidth + $width > $screenWidth } {
  119. #if { $screenWidth > $lineWidth } {
  120. #cat line {@str.Space{@math.Eval{$screenWidth - $lineWidth}}};
  121. };
  122. #local lineWidth {0};
  123. #list lines add {{
  124. {text}{$line}
  125. {buttons}{$buttons}
  126. }};
  127. #local line {$color};
  128. #local buttons {};
  129. };
  130. #cat line {@str.AlignLeft{{$city};$width}};
  131. #list buttons add {{
  132. {begin}{@math.Eval{$lineWidth + 1}}
  133. {end}{@math.Eval{$lineWidth + $width}}
  134. {node}{$node}
  135. }};
  136. #local lineWidth {@math.Eval{ $lineWidth + $width }};
  137. };
  138. };
  139. };
  140. #list lines add {{
  141. {text}{$line}
  142. {buttons}{$buttons}
  143. }};
  144. #class xiaoyao.Map kill;
  145. #class xiaoyao.Map open;
  146. #local lineNo {1};
  147. #loop {1} {&lines[]} {lineNo} {
  148. #echo {%s} {$lines[$lineNo][text]};
  149. #local button {};
  150. #foreach {$lines[$lineNo][buttons][]} {button} {
  151. #local row {@math.Eval{$lineNo - 4 - &lines[] - $prompt-bot-max-line}};
  152. #line sub var #button {$row;$button[begin];$row;$button[end]} {
  153. #class xiaoyao.Map kill;
  154. #buffer lock off;
  155. #buffer end;
  156. xiaoyao.Goto $button[node];
  157. };
  158. };
  159. };
  160. #line oneshot #event {RECEIVED INPUT CHARACTER} {
  161. okLog 你略作观察后收起了地图继续赶路。;
  162. #class xiaoyao.Map kill;
  163. #buffer end;
  164. };
  165. #class xiaoyao.Map close;
  166. okLog 共包含 &map.xiaoyao.map[] 个节点,$bigAreaCount 个大区,$areaCount 个区域。;
  167. #buffer lock on;
  168. };
  169. #alias {xiaoyao.Map} {
  170. #local retry {@defaultNum{%1;0}};
  171. #local args {%2};
  172. #if { "$args" != "" } {
  173. xtt.Send {map $args};
  174. #return;
  175. };
  176. #local retry {@defaultNum{%1;0}};
  177. #if { $retry == 0 &&
  178. ( "$gMapRoom[node]$gMapRoom[dock]" == ""
  179. || &gMapRoom[area][] == 0
  180. || "@map.GetArea{}" == "" )
  181. } {
  182. #line sub {func;var} event.HandleOnce {map/GotArea} {xiaoyao/Map} {map} {xiaoyao.Map {@math.Eval{$retry + 1}} $args};
  183. map.GetArea;
  184. #return;
  185. };
  186. #local here {@xiaoyao.Locate{}};
  187. #if { "$here" == "" } {
  188. xtt.Send {map};
  189. #return;
  190. };
  191. #class xiaoyao.Map open;
  192. #alias {xiaoyao.Map.open} {
  193. #class xiaoyao.Map open;
  194. #var xiaoyao.Map.lines {0};
  195. #action {^%*{|ID=map}$} {#math xiaoyao.Map.lines {$xiaoyao.Map.lines + 1}} {2.5};
  196. #sub {~{*UTF8};4;44m{\p{Han}+}} {;4;44m@mslp.Exec{xiaoyao.Map.Goto %%%1;%%%1}};
  197. #action {担子炮修订时间} {xiaoyao.Map.close} {2.0};
  198. #class xiaoyao.Map close;
  199. #if { @existsFile{var/data/map.txt} } {
  200. #scan txt var/data/map.txt;
  201. };
  202. #elseif { @existsFile{mud/$gCurrentMUDLIB/data/map.txt} } {
  203. #scan txt mud/$gCurrentMUDLIB/data/map.txt;
  204. };
  205. #elseif { @existsFile{data/map.txt} } {
  206. #scan txt data/map.txt;
  207. };
  208. #else {
  209. errLog 缺少 data/map.txt 文件。;
  210. xtt.Send {map};
  211. };
  212. };
  213. #alias {xiaoyao.Map.close} {
  214. #local lines {};
  215. #screen get rows lines;
  216. #if { $prompt-bot-max-line > 0 } {
  217. #math lines {$lines - $prompt-bot-max-line - 1};
  218. };
  219. #if { $prompt-top-max-line > 0 } {
  220. #math lines {$lines - $prompt-top-max-line - 1};
  221. };
  222. #buffer end;
  223. keyboard.LessMode;
  224. #math lines {$xiaoyao.Map.lines - $lines + 2};
  225. #if { $lines > 0 } {
  226. #buffer up $lines;
  227. };
  228. #class xiaoyao.Map kill;
  229. };
  230. okLog <560>你展开地图,发现不知为什么许多地方似乎被人涂成了蓝色。<099>;
  231. xiaoyao.Map.open;
  232. #class xiaoyao.Map close;
  233. };
  234. #alias {xiaoyao.Map.Goto} {
  235. #local node {%1};
  236. keyboard.NormalMode;
  237. #if { &map.xiaoyao.map[$node(%*)] == 1 } {
  238. #local node *map.xiaoyao.map[$node(%*)];
  239. };
  240. xiaoyao.Goto $node;
  241. };
  242. #alias {map} {
  243. #local width {0};
  244. #screen get cols width;
  245. #if { $width > 132 } {
  246. xiaoyao.Map 0 {%0};
  247. };
  248. #else {
  249. xiaoyao.SimpleMap;
  250. };
  251. };
  252. ///=== {
  253. // ## xiaoyao.Goto <目的节点>
  254. // 逍遥行快速行走,可以从一个城市移动到另一个城市。支持自动坐船、自动过河。
  255. //
  256. // 逍遥行底层采用的是系统 walk 命令,这要求你必须站在逍遥行节点才能使用本别名。
  257. // 但是本别名<169>可以自动连续 walk<299>,达到长途行走的目的。
  258. //
  259. // 为避免重复,完整的逍遥行节点名称采用「<169>节点名(区域的房间名)<299>」格式表达。
  260. // 目的地暂时仅支持中文,但允许模糊查询。举例来说,假如你想前往「全真派(全真教的宫门)」,
  261. // 那么你输入「全真派」、「全真教」、「宫门」、「全真」、甚至「教的宫」都是可以的。
  262. //
  263. // 本别名存在三个变体,你可以用 HELP 进一步了解:
  264. // - xiaoyao.GotoThen: 允许调用者在行走完成之后,执行一段代码。
  265. // - xiaoyao.GotoEmit: 允许调用者在行走完成之后,发射一个事件。
  266. // - xy: 专供命令行使用并为此做过特别优化的别名,不要在脚本中使用它。
  267. //
  268. // 关于 walk 命令的细节可以参考 help walk。
  269. // };
  270. #alias {xiaoyao.Goto} {
  271. xiaoyao.goto {%1} {%2} {xiaoyao.Goto};
  272. };
  273. ///=== {
  274. // ## xy <目的地> [<回调代码>]
  275. // 通过逍遥行前往目的地。如果指定了回调代码,那么到达目的地之后,会执行它。
  276. // 参见 HELP xiaoyao.Goto。
  277. // };
  278. #alias {xy} {
  279. #local target {%1};
  280. #local callback {%22};
  281. #info arguments save;
  282. #local count &info[ARGUMENTS][];
  283. #unvar info[ARGUMENTS];
  284. #if { $count == 1 } {
  285. xtt.Usage xiaoyao.Goto {<169>这里是 PaoTin++ 逍遥行};
  286. #return;
  287. };
  288. #if { $count > 3 } {
  289. #local callback {%20};
  290. #local old {%20};
  291. #replace {callback} {^$target } {};
  292. #if { "$callback" === "$old" } {
  293. #replace {callback} {^\\x7B$target\\x7D } {};
  294. };
  295. };
  296. #line sub {escapes;var} xiaoyao.GotoThen {$target} {$callback};
  297. };
  298. ///=== {
  299. // ## xiaoyao.GotoThen <目的地> [<回调代码>]
  300. // 通过逍遥行前往目的地。如果指定了回调代码,那么到达目的地之后,会执行它。
  301. // 参见 HELP xiaoyao.Goto。
  302. // };
  303. #alias {xiaoyao.GotoThen} {
  304. #local target {%1};
  305. #local callback {%22};
  306. #local hook {map/xiaoyao/@uuid{}};
  307. #class xiaoyao.Goto open;
  308. #if { "$callback" != "" } {
  309. #line sub {escapes;var} #alias {xiaoyao.Goto.end} {#class xiaoyao.Goto kill; $callback};
  310. event.ClassHandleOnce {map/walk/continue} {$hook} {map/xiaoyao} {xiaoyao.Goto.end};
  311. event.ClassHandleOnce {map/walk/failed} {$hook} {map/xiaoyao} {xiaoyao.Goto.end};
  312. };
  313. #class xiaoyao.Goto close;
  314. xiaoyao.goto {$target} {$hook} {xiaoyao.GotoThen};
  315. };
  316. ///=== {
  317. // ## xiaoyao.GotoEmit <目的地> [<回调钩子名称>]
  318. // 通过逍遥行前往目的地。
  319. // 如果你事先注册了指定名称的回调钩子在事件 map/walk/continue 上,那么到达目的地之后,会唤醒它。
  320. // 参见 HELP xiaoyao.Goto。
  321. // };
  322. #alias {xiaoyao.GotoEmit} {
  323. #local target {%1};
  324. #local hook {%2};
  325. xiaoyao.goto {$target} {$hook} {xiaoyao.GotoEmit};
  326. };
  327. #alias {xiaoyao.goto} {
  328. #local target {%1};
  329. #local hook {@default{%2;xiaoyao/goto/end}};
  330. #local name {@default{%3;xiaoyao.GotoEmit}};
  331. #local retry {@defaultNum{%4;0}};
  332. #if { "$target" == "" } {
  333. xtt.Usage $name {<169>这里是 PaoTin++ 逍遥行};
  334. xiaoyao.goto.cancel {$hook};
  335. #return;
  336. };
  337. #if { &map.xiaoyao.map[] == 0 } {
  338. errLog 加载逍遥行节点数据文件失败。;
  339. okLog 请确保逍遥行数据文件 var/data/map-xiaoyao.tin 或 data/map-xiaoyao.tin 正确无误。;
  340. xiaoyao.goto.cancel {$hook};
  341. #return;
  342. };
  343. #if { $retry > 1 } {
  344. errLog 请先前往逍遥行节点。所有的码头、walk 节点均为逍遥行节点。;
  345. xiaoyao.goto.cancel {$hook};
  346. #return;
  347. };
  348. #if { "$gMapRoom[node]$gMapRoom[dock]" == ""
  349. || &gMapRoom[area][] == 0
  350. || "@map.GetArea{}" == ""
  351. } {
  352. #nop 获取区域的过程中可能无法产生积极的结果,那么就以角色移动为失败标志,取消走路。;
  353. #class xiaoyao.goto.locate open;
  354. #line sub {func;var} event.ClassHandleOnce map/GotArea {xiaoyao/goto/locate} {xiaoyao} {
  355. #class xiaoyao.goto.locate kill;
  356. xiaoyao.goto {$target} {$hook} {@math.Eval{$retry + 1}};
  357. };
  358. #line sub {func;var} event.ClassHandleOnce GMCP.Move {xiaoyao/goto/locate} {xiaoyao} {
  359. xiaoyao.goto.cancel {$hook};
  360. #class xiaoyao.goto.locate kill;
  361. };
  362. map.GetArea;
  363. #class xiaoyao.goto.locate close;
  364. #return;
  365. };
  366. #local here {@xiaoyao.Locate{}};
  367. #if { "$here" == "" } {
  368. errLog 请先前往逍遥行节点。所有的码头、walk 节点均为逍遥行节点。;
  369. xiaoyao.goto.cancel {$hook};
  370. #return;
  371. };
  372. #if { "$here" == "%*$target%*" } {
  373. #if { "$hook" != "" } {
  374. okLog 你已经来到了 $here;
  375. event.DelayEmit map/walk/continue {$hook};
  376. };
  377. #return;
  378. };
  379. infoLog 计算从<129>$here<299>到<139>$target<299>的路径。;
  380. #local target {@xiaoyao.findPath{$here;"NODE" == "%*$target%*"}};
  381. #if { "$target" == "" } {
  382. errLog 找不到路径。;
  383. xiaoyao.goto.cancel {$hook};
  384. #return;
  385. };
  386. #if { "$target[path]" == "" } {
  387. errLog 找不到路径,似乎安装出错了,请联系开发者。;
  388. xiaoyao.goto.cancel {$hook};
  389. #return;
  390. };
  391. okLog 计算结果: {$target[path]};
  392. #replace {target[route]} {(%*)} {};
  393. okLog 途经节点: $target[route];
  394. prompt.Set {{walk}{<139>正在前往 <129>$target[room]<139>...<299>}};
  395. #line sub var event.HandleOnce map/walk/continue {xiaoyao/goto} {map/xiaoyao} {xiaoyao.walk-end $hook};
  396. #var xiaoyao.under-way {1};
  397. map.WalkNodes {$target[path]} {xiaoyao/goto};
  398. };
  399. #alias {xiaoyao.goto.cancel} {
  400. #local hook {%1};
  401. #if { "$hook" != "" } {
  402. event.DelayEmit {map/walk/failed} {$hook};
  403. };
  404. };
  405. #alias {xiaoyao.walk-end} {
  406. #local hook {%1};
  407. okLog 行走完成。;
  408. #if { "$hook" != "" } {
  409. event.DelayEmit map/walk/continue {$hook};
  410. };
  411. #var xiaoyao.under-way {0};
  412. #nop 配合 try-locate 进行定位。;
  413. look;
  414. };
  415. #alias {xiaoyao.try-locate} {
  416. #nop 移动中,位置随时会变。;
  417. #if { ! @ga.AllDone{} || $xiaoyao.under-way } {
  418. #return;
  419. };
  420. #nop 探索中,数据内容不全。 ;
  421. #if { @isTrue{$xiaoyao.explore} } {
  422. #return;
  423. };
  424. #nop 光看房间名就就不像是节点。;
  425. #local nodes {$map.xiaoyao.room[$gMapRoom[name]]};
  426. #if { "$nodes" == "" } {
  427. #if { &map.xiaoyao.map[] > 0 } {
  428. prompt.Set {{walk}{<139>逍遥行已启动,可识别 &map.xiaoyao.map[] 个节点,目前工作正常。<299>}};
  429. };
  430. #return;
  431. };
  432. dbgLog map => 空闲,没有移动,看名字($gMapRoom[name])可能是节点,那么决定调查一下。;
  433. event.HandleOnce {map/GotArea} {xiaoyao.locate} {map/xiaoyao} {xiaoyao.locate};
  434. map.GetArea;
  435. };
  436. #alias {xiaoyao.locate} {
  437. #local here {@xiaoyao.Locate{}};
  438. #if { "$here" == "" } {
  439. #return;
  440. };
  441. okLog 这里是 $here;
  442. #local links {@table.Keys{map.xiaoyao.map[$here];%*}};
  443. #local buttons {};
  444. #local link {};
  445. #foreach {$links} {link} {
  446. #local short {@str.Replace{$link;{%*(%*的%*)};{&1}}};
  447. #local button {【@mslp.Exec{{xiaoyao.Goto $link};<139>$short<299>}】};
  448. #cat buttons {$button};
  449. };
  450. prompt.Set {{walk}{$buttons}};
  451. };
  452. #func {xiaoyao.Locate} {
  453. #local room {$gMapRoom[name]};
  454. #local area {@map.GetArea{}};
  455. #local node {$gMapRoom[node]};
  456. #local dock {$gMapRoom[dock]};
  457. #local pattern {$area的$room};
  458. #nop 光看名字就长得不像,那肯定不是了。;
  459. #local nodes {$map.xiaoyao.room[$room]};
  460. #if { "$nodes" == "" } {
  461. #return {};
  462. };
  463. #if { "$area" == "" } {
  464. #local pattern {%*的$room};
  465. };
  466. #if { "$node" != "" || @slist.Contains{{$gMapRoom[lookable]};{<node>}} } {
  467. #nop 节点以 walk 节点名称标记;
  468. #local pattern {@default{$node;%*}($pattern)};
  469. };
  470. #elseif { "$dock" != "" } {
  471. #nop 没有节点的码头以区域名称加码头标记。;
  472. #local pattern {@default{$area;%*}码头($pattern)};
  473. };
  474. #elseif { "$area" != "" && "@sset.Intersection{{$gMapRoom[mark]};{★;☆}}" != "" } {
  475. #nop 既不是节点,又不是码头,那么如果有地域信息大概也是可以的。;
  476. #local pattern {%*($pattern)};
  477. };
  478. #else {
  479. #return {};
  480. };
  481. #if { "$pattern" != "%*\%*%*" } {
  482. #return {$pattern};
  483. };
  484. #nop 否则参考数据库来确定,当且仅当数据库中只有一条匹配记录时,才能断定;
  485. #if { &map.xiaoyao.map[$pattern][] != 1 } {
  486. #return {};
  487. };
  488. #local location @table.Keys{map.xiaoyao.map;{$pattern}};
  489. #nop 如果房间名和节点名已经获得,那么可以据此更新地区名;
  490. #if { "$area" == "" && "$node" != "" } {
  491. #local area {$location};
  492. #replace area {%*(%*的%*)} {&2};
  493. #var gMapRoom[area][RESOLVED] {$area};
  494. event.Emit map/GotArea;
  495. };
  496. #return {$location};
  497. };
  498. #nop 计算路径;
  499. #func {xiaoyao.findPath} {
  500. #local src {%1};
  501. #local cond {%2};
  502. #local dst {};
  503. #replace cond {NODE} {\$node};
  504. #replace cond {LINK} {\$map.xiaoyao.map[\$node]};
  505. #local routeMap {
  506. {$src}{START}
  507. };
  508. #local checkList {{1}{$src}};
  509. #while {1} {
  510. #if { &checkList[] == 0 || ( "$dst" != "" && "$routeMap[$dst]" != "" ) } {
  511. #break;
  512. };
  513. #nop 遍历所有新发现的节点;
  514. #local nodes {$checkList};
  515. #local checkList {};
  516. #local node {};
  517. #foreach {$nodes[]} {node} {
  518. #local next {};
  519. #local c {};
  520. #line sub {var;functions;escapes} #format c {%s} {$cond};
  521. #if { $c } {
  522. #nop 满足条件的节点。;
  523. #local dst {$node};
  524. #break;
  525. };
  526. #foreach {*map.xiaoyao.map[$node][]} {next} {
  527. #if { "$routeMap[$next]" != "" } {
  528. #nop 已经检索过的节点。;
  529. #continue;
  530. };
  531. #local link {$map.xiaoyao.map[$node][$next]};
  532. #if { "$link" == "TODO" } {
  533. #nop BUG: 不完整的连接。;
  534. #continue;
  535. };
  536. #list {checkList} {add} {$next};
  537. #local routeMap[$next] {$node};
  538. };
  539. };
  540. };
  541. #if { "$dst" == "" || "$routeMap[$dst]" == "" } {
  542. #return {};
  543. };
  544. #local route {$dst};
  545. #local path {};
  546. #local node {$dst};
  547. #while { "$node" != "$src" } {
  548. #local prev {$routeMap[$node]};
  549. #local link {$map.xiaoyao.map[$prev][$node]};
  550. #local node {$prev};
  551. #format route {%s-%s} {$node} {$route};
  552. #list path insert 1 {$link};
  553. };
  554. #list path {simplify};
  555. #return {
  556. {room}{$dst}
  557. {route}{$route}
  558. {path}{$path}
  559. };
  560. };
  561. #func {xiaoyao.locateByName} {
  562. #local name {%1};
  563. #if { "$name" == "" } {
  564. #return {};
  565. };
  566. #if { &map.xiaoyao.map[=$name] > 0 } {
  567. #return {$name};
  568. };
  569. #local nodes {@table.Keys{map.xiaoyao.map;%*$name%*}};
  570. #local best {};
  571. #local better {};
  572. #local normal {};
  573. #local node {};
  574. #foreach {$nodes} {node} {
  575. #if { "$node" == "$name(%*)" } {
  576. #return {$node};
  577. };
  578. #if { "$node" == "%*(%*的$name)" && "$node" != "%*{津|渡|渡口})" } {
  579. #local best {$node};
  580. };
  581. #elseif { "$node" == "%*($name的%*)" && "$node" != "%*{津|渡|渡口})" } {
  582. #local better {$node};
  583. };
  584. #elseif { "$node" == "%*(%*$name%*)" } {
  585. #local normal {$node};
  586. };
  587. };
  588. #if { "$best" != "" } {
  589. #return {$best};
  590. };
  591. #elseif { "$better" != "" } {
  592. #return {$better};
  593. };
  594. #else {
  595. #return {$normal};
  596. };
  597. };
  598. ///=== {
  599. // ## xiaoyao.Query <出发节点> <目的节点>
  600. // 计算逍遥行路径。
  601. // 出发节点和目的节点都支持模糊查询。
  602. //
  603. // 本别名也可简写为 <139>xyq<299>。
  604. // };
  605. #alias {xiaoyao.Query} {
  606. #local begin {@str.Format{%U}};
  607. #local origin {@xiaoyao.locateByName{%1}};
  608. #local target {@xiaoyao.locateByName{%2}};
  609. #if { "$origin" == "" || "$target" == "" } {
  610. xtt.Usage xiaoyao.Query {<169>这里是 PaoTin++ 逍遥行路径查询工具};
  611. #return;
  612. };
  613. infoLog 计算从<129>$origin<299>到<139>$target<299>的路径。;
  614. #local target {@xiaoyao.findPath{$origin;"NODE" == "%*$target%*"}};
  615. #if { "$target" == "" } {
  616. errLog 找不到路径。;
  617. #return;
  618. };
  619. #if { "$target[path]" == "" } {
  620. okLog 你已经来到了 $target[room];
  621. #return;
  622. };
  623. #local end {@str.Format{%U}};
  624. #local elapsed {@math.Eval{($end * 1.000 - $begin * 1.000) / 1000.000}};
  625. okLog 计算结果: {$target[path]};
  626. #replace {target[route]} {(%*)} {};
  627. okLog 途经节点: $target[route];
  628. infoLog 计算耗时: $elapsed 毫秒。;
  629. infoLog;
  630. infoLog PaoTin++ 用户使用 <120>xy %2<299> 即可完成行走,支持自动坐船过河。;
  631. infoLog 下载地址: <488><149>https://pkuxkx.net/wiki/tools/paotin<299>;
  632. infoLog;
  633. };
  634. #alias {xyq} {xiaoyao.Query};
  635. ///=== {
  636. // ## xiaoyao.LoadData
  637. // 加载逍遥行依赖的数据文件。
  638. // };
  639. #alias {xiaoyao.LoadData} {
  640. storage.Load {map-xiaoyao} {map.xiaoyao.map;map.xiaoyao.room};
  641. storage.Load {map-area} {map.area.dict};
  642. };