xiaoyao.tin 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479
  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-lib storage;
  12. load-lib event;
  13. load-module basic/busy;
  14. event.HandleOnce {map/init} {map/xiaoyao} {map} {xiaoyao.Init};
  15. #alias {xiaoyao.Init} {
  16. event.Handle map/walk/continue {xiaoyao.walk-end} {xiaoyao} {xiaoyao.walk-end};
  17. storage.Load {map-xiaoyao} {map.xiaoyao.map;map.xiaoyao.room};
  18. };
  19. #alias {xiaoyao.checkMap} {
  20. #local node {};
  21. #local areaMap {};
  22. #foreach {*map.xiaoyao.map[]} {node} {
  23. #local next {};
  24. #if { &map.xiaoyao.map[$node][] == 1 && "$map.xiaoyao.map[$node][+1][link]" == "DOCK" } {
  25. warnLog 这是个纯粹的码头 => $node;
  26. };
  27. #foreach {*map.xiaoyao.map[$node][]} {next} {
  28. #regex {$node} {%*(%*的%*)} {
  29. #format {areaMap[&2][$node]} {true};
  30. };
  31. #local link {$map.xiaoyao.map[$node][$next][link]};
  32. #if { "$link" == "" } {
  33. errLog $node => $next 尚未联通。;
  34. };
  35. };
  36. };
  37. #local maxNodeNum {0};
  38. #local maxNodeNumArea {};
  39. #local area {};
  40. #foreach {*areaMap[]} {area} {
  41. okLog $area(&areaMap[$area][]): @slist.Join{{@slist.FromList{@list.FromSlist{*areaMap[$area][]}}};、};
  42. #if { &areaMap[$area][] > $maxNodeNum } {
  43. #local maxNodeNum {&areaMap[$area][]};
  44. #local maxNodeNumArea {$area};
  45. };
  46. };
  47. okLog 地图连接性检查正常,一共包含 &map.xiaoyao.map[] 个节点,&areaMap[] 个区域,节点最多的区域是「$maxNodeNumArea」,共有 $maxNodeNum 个节点。;
  48. };
  49. #alias {xiaoyao.SimpleMap} {
  50. #local bigArea {};
  51. #local areaMap {};
  52. #local area {};
  53. #local node {};
  54. #foreach {*map.xiaoyao.map[]} {node} {
  55. #regex {$node} {%*(%*的%*)} {
  56. #format {area} {%s} {&2};
  57. };
  58. #local bigArea {@map.AreaColor{$area}};
  59. #list {areaMap[$bigArea][$area]} add {$node};
  60. };
  61. #local screenWidth {};
  62. #screen get cols screenWidth;
  63. #local lines {};
  64. #local line {};
  65. #local color {};
  66. #local lineWidth {0};
  67. #local buttons {};
  68. #local bigAreaCount {0};
  69. #local areaCount {0};
  70. #local nodeCount {0};
  71. #loop {1} {&areaMap[]} {bigArea} {
  72. #math bigAreaCount {$bigAreaCount + 1};
  73. #local bgColor *areaMap[+$bigArea];
  74. #local fgColor {0};
  75. #loop {1} {&areaMap[+$bigArea][]} {area} {
  76. #math areaCount {$areaCount + 1};
  77. #math fgColor {($fgColor + 1) % 2};
  78. #local index {$bgColor};
  79. #replace index {%*4%+1d%*} {&2};
  80. #if { "$bgColor" == "46" } {
  81. #local color {\e[${bgColor};@math.Eval{30 + $fgColor * 4}m};
  82. };
  83. #elseif { $index == 3 } {
  84. #local color {\e[${bgColor};@math.Eval{30 + $fgColor * 4}m};
  85. };
  86. #else {
  87. #local color {\e[${bgColor};@math.Eval{37 - $fgColor * 4}m};
  88. };
  89. #cat line {$color};
  90. #loop {1} {&areaMap[+$bigArea][+$area][]} {node} {
  91. #local node {$areaMap[+$bigArea][+$area][+$node]};
  92. #local city {$node};
  93. #replace city {%S(%S)} {&1};
  94. #local width {@math.Eval{ ( @math.Int{@str.Width{$city} * 1.0 / 4 + 0.4} + 1 ) * 4 }};
  95. #if { $lineWidth + $width > $screenWidth } {
  96. #if { $screenWidth > $lineWidth } {
  97. #cat line {@str.Space{@math.Eval{$screenWidth - $lineWidth}}};
  98. };
  99. #local lineWidth {0};
  100. #list lines add {{
  101. {text}{$line}
  102. {buttons}{$buttons}
  103. }};
  104. #local line {$color};
  105. #local buttons {};
  106. };
  107. #cat line {@str.AlignLeft{{$city};$width}};
  108. #list buttons add {{
  109. {begin}{@math.Eval{$lineWidth + 1}}
  110. {end}{@math.Eval{$lineWidth + $width}}
  111. {node}{$node}
  112. }};
  113. #local lineWidth {@math.Eval{ $lineWidth + $width }};
  114. };
  115. };
  116. };
  117. #list lines add {{
  118. {text}{$line}
  119. {buttons}{$buttons}
  120. }};
  121. #class xiaoyao.Map kill;
  122. #class xiaoyao.Map open;
  123. #local lineNo {1};
  124. #loop {1} {&lines[]} {lineNo} {
  125. #echo {%s} {$lines[$lineNo][text]};
  126. #local button {};
  127. #foreach {$lines[$lineNo][buttons][]} {button} {
  128. #local row {@math.Eval{$lineNo - 4 - &lines[] - $prompt-bot-max-line}};
  129. #line sub var #button {$row;$button[begin];$row;$button[end]} {
  130. #class xiaoyao.Map kill;
  131. #buffer lock off;
  132. #buffer end;
  133. xiaoyao.Goto $button[node];
  134. };
  135. };
  136. };
  137. #line oneshot #event {RECEIVED INPUT CHARACTER} {
  138. okLog 你略作观察后收起了地图继续赶路。;
  139. #class xiaoyao.Map kill;
  140. #buffer end;
  141. };
  142. #class xiaoyao.Map close;
  143. okLog 共包含 &map.xiaoyao.map[] 个节点,$bigAreaCount 个大区,$areaCount 个区域。;
  144. #buffer lock on;
  145. };
  146. #alias {xiaoyao.Map} {
  147. #local retry {@defaultNum{%1;0}};
  148. #local args {%2};
  149. #if { "$args" != "" } {
  150. xtt.Send {map $args};
  151. #return;
  152. };
  153. #local retry {@defaultNum{%1;0}};
  154. #if { $retry == 0 &&
  155. ( "$gMapRoom[node]$gMapRoom[dock]" == ""
  156. || &gMapRoom[area][] == 0
  157. || "$gMapRoom[area][RESOLVED]" == "" )
  158. } {
  159. event.HandleOnce map/GotArea {xiaoyao/Map} {map} {xiaoyao.Map {@math.Eval{$retry + 1}} $args};
  160. map.Here;
  161. #return;
  162. };
  163. #local here {@xiaoyao.locate{}};
  164. #if { "$here" == "" } {
  165. xtt.Send {map};
  166. #return;
  167. };
  168. #class xiaoyao.Map open;
  169. #alias {xiaoyao.Map.open} {
  170. #class xiaoyao.Map open;
  171. #var xiaoyao.Map.lines {0};
  172. #action {^%*{|ID=map}$} {#math xiaoyao.Map.lines {$xiaoyao.Map.lines + 1}} {2.5};
  173. #sub {~{*UTF8};4;44m{\p{Han}+}} {;4;44m@mslp.Exec{xiaoyao.Map.Goto %%%1;%%%1}};
  174. #action {担子炮修订时间} {xiaoyao.Map.close} {2.0};
  175. #class xiaoyao.Map close;
  176. #if { @existsFile{var/data/map.txt} } {
  177. #scan txt var/data/map.txt;
  178. };
  179. #elseif { @existsFile{mud/$gCurrentMUDLIB/data/map.txt} } {
  180. #scan txt mud/$gCurrentMUDLIB/data/map.txt;
  181. };
  182. #elseif { @existsFile{data/map.txt} } {
  183. #scan txt data/map.txt;
  184. };
  185. #else {
  186. errLog 缺少 data/map.txt 文件。;
  187. xtt.Send {map};
  188. };
  189. };
  190. #alias {xiaoyao.Map.close} {
  191. #local lines {};
  192. #screen get rows lines;
  193. #if { $prompt-bot-max-line > 0 } {
  194. #math lines {$lines - $prompt-bot-max-line - 1};
  195. };
  196. #if { $prompt-top-max-line > 0 } {
  197. #math lines {$lines - $prompt-top-max-line - 1};
  198. };
  199. #buffer end;
  200. keyboard.LessMode;
  201. #math lines {$xiaoyao.Map.lines - $lines + 2};
  202. #if { $lines > 0 } {
  203. #buffer up $lines;
  204. };
  205. #class xiaoyao.Map kill;
  206. };
  207. okLog <560>你展开地图,发现不知为什么许多地方似乎被人涂成了蓝色。<099>;
  208. xiaoyao.Map.open;
  209. #class xiaoyao.Map close;
  210. };
  211. #alias {xiaoyao.Map.Goto} {
  212. #local node {%1};
  213. keyboard.NormalMode;
  214. #if { &map.xiaoyao.map[$node(%*)] == 1 } {
  215. #local node *map.xiaoyao.map[$node(%*)];
  216. };
  217. xiaoyao.Goto $node;
  218. };
  219. #alias {map} {
  220. #local width {0};
  221. #screen get cols width;
  222. #if { $width > 132 } {
  223. xiaoyao.Map 0 {%0};
  224. };
  225. #else {
  226. xiaoyao.SimpleMap;
  227. };
  228. };
  229. ///=== {
  230. // ## xiaoyao.Goto <目的节点>
  231. // 逍遥行快速行走,可以从一个城市移动到另一个城市。支持自动坐船、自动过河。
  232. //
  233. // 逍遥行底层采用的是系统 walk 命令,这要求你必须站在逍遥行节点才能使用本别名。
  234. // 但是本别名<169>可以自动连续 walk<299>,达到长途行走的目的。
  235. //
  236. // 为避免重复,完整的逍遥行节点名称采用「<169>节点名(区域的房间名)<299>」格式表达。
  237. // 目的地暂时仅支持中文,但允许模糊查询。举例来说,假如你想前往「全真派(全真教的宫门)」,
  238. // 那么你输入「全真派」、「全真教」、「宫门」、「全真」、甚至「教的宫」都是可以的。
  239. //
  240. // 本别名也可简写为 <139>xy<299>。许多用户可能喜欢重设为 <139>gt<299>,请自行设定。
  241. //
  242. // 关于 walk 命令的细节可以参考 help walk。
  243. // };
  244. #alias {xiaoyao.Goto} {
  245. #local target {%1};
  246. #local hook {%2};
  247. #local retry {@defaultNum{%3;0}};
  248. #if { "%1" == "" } {
  249. xtt.Usage xiaoyao.Goto {<169>这里是 PaoTin++ 逍遥行};
  250. #return;
  251. };
  252. #if { &map.xiaoyao.map[] == 0 } {
  253. errLog 加载逍遥行节点数据文件失败。;
  254. okLog 请确保逍遥行数据文件 var/data/map-xiaoyao.tin 或 data/map-xiaoyao.tin 正确无误。;
  255. #return;
  256. };
  257. #if { $retry > 1 } {
  258. errLog 请先前往逍遥行节点。所有的码头、walk 节点均为逍遥行节点。;
  259. #return;
  260. };
  261. #if { "$hook" == "" } {
  262. event.HandleOnce map/walk/continue {xiaoyao.walk-end} {xiaoyao} {xiaoyao.walk-end};
  263. #local hook {xiaoyao.walk-end};
  264. };
  265. #if { "$gMapRoom[node]$gMapRoom[dock]" == ""
  266. || &gMapRoom[area][] == 0
  267. || "$gMapRoom[area][RESOLVED]" == ""
  268. } {
  269. event.HandleOnce map/GotArea {xiaoyao/Goto} {xiaoyao} {xiaoyao.Goto {$target} {$hook} {@math.Eval{$retry + 1}}};
  270. #var map.Locate.mode {CarefulOnce};
  271. look;
  272. #return;
  273. };
  274. #local here {@xiaoyao.locate{}};
  275. #if { "$here" == "" } {
  276. errLog 请先前往逍遥行节点。所有的码头、walk 节点均为逍遥行节点。;
  277. #return;
  278. };
  279. #if { "$here" == "$target" } {
  280. #if { "$hook" != "" } {
  281. event.DelayEmit map/walk/continue {$hook};
  282. };
  283. #return;
  284. };
  285. infoLog 计算从<129>$here<299>到<139>$target<299>的路径。;
  286. #local target {@xiaoyao.findPath{$here;"NODE" == "%*$target%*"}};
  287. #if { "$target" == "" } {
  288. errLog 找不到路径。;
  289. #return;
  290. };
  291. #if { "$target[path]" == "" } {
  292. okLog 你已经来到了 $target[room];
  293. #return;
  294. };
  295. okLog 计算结果: {$target[path]};
  296. #replace {target[route]} {(%*)} {};
  297. okLog 途经节点 $target[route];
  298. map.WalkNodes {$target[path]} {$hook};
  299. };
  300. #alias {xiaoyao.walk-end} {
  301. okLog 行走完成。;
  302. map.Here;
  303. };
  304. #func {xiaoyao.locate} {
  305. #local room {$gMapRoom[name]};
  306. #local area {@default{$gMapRoom[area][RESOLVED];%*}};
  307. #local node {@default{$gMapRoom[node];%*}};
  308. #local dock {$gMapRoom[dock]};
  309. #local location {};
  310. #if { @slist.Contains{{$gMapRoom[items]};{<node>}} } {
  311. #nop 节点以 walk 节点名称标记;
  312. #local location {$node($area的$room)};
  313. };
  314. #elseif { "$dock" != "" } {
  315. #nop 没有节点的码头以区域名称加码头标记。;
  316. errLog 这是个码头,但没有设置 walk 节点。;
  317. #local location {$area码头($area的$room)};
  318. };
  319. #else {
  320. errLog 此处既非码头,也非节点,逍遥行无法定位。;
  321. #return {};
  322. };
  323. #nop 如果已经有区域信息,则不用查数据库。;
  324. #if { "$gMapRoom[area][RESOLVED]" != "" } {
  325. #return {$location};
  326. };
  327. #nop 否则参考数据库来确定,当且仅当数据库中只有一条匹配记录时,才能断定;
  328. #if { &map.xiaoyao.map[$location][] != 1 } {
  329. #return {};
  330. };
  331. #foreach {*map.xiaoyao.map[$location]} {location} {
  332. #return {$location};
  333. };
  334. };
  335. #nop 计算路径;
  336. #func {xiaoyao.findPath} {
  337. #local src {%1};
  338. #local cond {%2};
  339. #local dst {};
  340. #replace cond {NODE} {\$node};
  341. #replace cond {LINK} {\$map.xiaoyao.map[\$node]};
  342. #local routeMap {
  343. {$src}{START}
  344. };
  345. #local checkList {{1}{$src}};
  346. #while {1} {
  347. #if { &checkList[] == 0 || ( "$dst" != "" && "$routeMap[$dst]" != "" ) } {
  348. #break;
  349. };
  350. #nop 遍历所有新发现的节点;
  351. #local nodes {$checkList};
  352. #local checkList {};
  353. #local node {};
  354. #foreach {$nodes[]} {node} {
  355. #local next {};
  356. #local c {};
  357. #line sub {var;functions;escapes} #format c {%s} {$cond};
  358. #if { $c } {
  359. #nop 满足条件的节点。;
  360. #local dst {$node};
  361. #break;
  362. };
  363. #foreach {*map.xiaoyao.map[$node][]} {next} {
  364. #if { "$routeMap[$next]" != "" } {
  365. #nop 已经检索过的节点。;
  366. #continue;
  367. };
  368. #local link {$map.xiaoyao.map[$node][$next][link]};
  369. #if { "$link" == "" } {
  370. #nop BUG: 不完整的连接。;
  371. #continue;
  372. };
  373. #list {checkList} {add} {$next};
  374. #local routeMap[$next] {$node};
  375. };
  376. };
  377. };
  378. #if { "$dst" == "" || "$routeMap[$dst]" == "" } {
  379. #return {};
  380. };
  381. #local route {$dst};
  382. #local path {};
  383. #local node {$dst};
  384. #while { "$node" != "$src" } {
  385. #local prev {$routeMap[$node]};
  386. #local link {$map.xiaoyao.map[$prev][$node][link]};
  387. #local action {$map.xiaoyao.map[$prev][$node][action]};
  388. #local node {$prev};
  389. #format route {%s-%s} {$node} {$route};
  390. #if { "$link" == "WALK" } {
  391. #list path insert 1 {$action};
  392. };
  393. #elseif { "$link" == "PATH" } {
  394. #list path insert 1 {PATH/{$action}};
  395. };
  396. #elseif { "$link" == "DOCK" } {
  397. #list path insert 1 {DOCK/$action};
  398. };
  399. };
  400. #list path {simplify};
  401. #return {
  402. {room}{$dst}
  403. {route}{$route}
  404. {path}{$path}
  405. };
  406. };
  407. #alias {xy} {xiaoyao.Goto};