xiaoyao.tin 22 KB

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