#nop vim: set filetype=tt:; /* 本文件属于 PaoTin++ 的一部分 =========== PaoTin++ © 2020~2023 的所有版权均由担子炮(dzp ) 享有并保留一切法律权利 你可以在遵照 GPLv3 协议的基础之上使用、修改及重新分发本程序。 =========== */ #pathdir {n} {s} {1}; #pathdir {e} {w} {2}; #pathdir {s} {n} {4}; #pathdir {w} {e} {8}; #pathdir {u} {d} {16}; #pathdir {d} {u} {32}; #pathdir {ne} {sw} {3}; #pathdir {nw} {se} {9}; #pathdir {se} {nw} {6}; #pathdir {sw} {ne} {12}; #pathdir {nu} {sd} {17}; #pathdir {eu} {wd} {18}; #pathdir {su} {nd} {20}; #pathdir {wu} {ed} {24}; #pathdir {nd} {su} {33}; #pathdir {ed} {wu} {34}; #pathdir {sd} {nu} {36}; #pathdir {wd} {eu} {40}; #pathdir {out} {enter} {19}; #pathdir {enter} {out} {44}; VAR {当前路径} map.path.current {}; event.HandleOnce {map/init} {map/path} {map} {map.path.Init}; #alias {map.path.Init} { event.Handle {map/GotRoomInfo} {path.Hint} {map/path} {path.Hint}; storage.Load map-path map.path.list; }; ///=== { // ## path.Trace [<是否可翻转>] [<是否可压缩>] // 开始为本房间录制路径。 // 两个参数指定了本次即将录制的路径特点,并会在录制完成时真正运用。 // 如果省略参数,则默认为可翻转、可压缩。 // 在录制完成之前,你仍然可以随时用 path.SetType 来重新设置。 // }; #alias {path.Trace} { #local reversible {@default{%1;true}}; #local compact {@default{%2;true}}; #if { @path.isTracing{} } { errLog 录制路径工作正在进行中。; #return; }; #local area {@map.GetArea{}}; #if { "$area" == "" } { event.HandleOnce {map/GotArea} {path.Trace} {map/path} {path.Trace}; #delay map.Trace.retry {map.GetArea} 1; #return; }; #var map.path.current { {from} {@map.Room.CID{}} {to} {} {reversible} {$reversible} {compact} {$compact} }; event.Handle {GMCP.Move} {path.Trace} {map/path} {path.response}; #path create; path.message 开始录制路径。; option.Enable KeypadWalk; ui.walk.SetCmd path.ui.move; }; ///=== { // ## path.SetType [<是否可翻转>] [<是否可压缩>] // 重新设置当前正在录制的路径特点。 // 两个参数指定了此时正在录制的路径特点,并会在录制完成时真正运用。 // 如果省略参数,则默认为前值,不予改变。 // 在录制完成之前,你仍然可以随时用 path.SetType 来重新设置。 // }; #alias {path.SetType} { #if { "%0" == "" } { xtt.Usage %90; #return; }; #if { ! @path.isTracing{} } { errLog 尚未开始录制。; #return; }; #local reversible {@default{%1;$map.path.current[reversible]}}; #local compact {@default{%2;$map.path.current[compact]}}; #var map.path.current[reversible] {$reversible}; #var map.path.current[compact] {$compact}; }; #alias {path.ui.move} { #local dir {%1}; #local short {@dir.Short{%1}}; #path insert {$short}; go $dir; }; #alias {path.response} { #local cmd {@ga.ThisCmd{}}; #if { @isFalse{$gGMCP[Move][成功]} } { #if { "$cmd" == "go %+" } { #path delete; }; #return; }; #if { @dir.IsDir{$cmd} } { #local short {@dir.Short{$cmd}}; #if { "$cmd" !== "$short" } { #path insert {$cmd}; }; }; #elseif { "$cmd" != "go %*" } { warnLog 未知的移动方式,无法识别,请手动维护路径。; path.Mark {$gMapRoom[name]/$cmd}; #return; }; #local length {}; #path get length length; path.message 路径录制中,{<139>$cmd<159>} 已添加,目前长度: $length; }; ///=== { // ## path.BotStep <机器人名称> [<机器人参数> ...] // 插入一个机器人行走步骤。 // 接到本指令时,PaoTin++ 会进行如下处理: // - 1: 暂停路径录制; // - 2: 在路径中插入一个机器人步骤; // - 3: 自动调用机器人行走; // - 4: 机器人行走完成后,自动恢复录制。 // 按照约定,符合本规范的机器人必须发射以下事件之一: // - map/walk/continue: 代表机器人成功结束运行,通过该区域 // - map/walk/failed: 代表机器人遇到了无法逾越的障碍,放弃行走 // 本命令会监听以上事件并做相应处理。 // }; #alias {path.BotStep} { #local bot {%1}; #info arguments save; #local args {$info[ARGUMENTS]}; #unvar info[ARGUMENTS]; #unlocal args[0]; #if { "$bot" == "" } { xtt.Usage %90; #return; }; #if { ! @path.isTracing{} } { errLog 路径录制尚未开始。; #return; }; #if { !@existsAlias{map.$bot} } { errLog 不存在机器人 $bot,请检查是否拼写错误。; #return; }; #class path.BotStep open; #alias {path.BotStep.done} { path.BotStep.end; path.message 机器人运行完成,继续录制路径。; }; #line sub var #alias {path.BotStep.failed} { path.BotStep.end; path.message 机器人运行出错,姑且继续录制,如有不脱请取消录制。; }; #line sub var #alias {path.BotStep.end} { #class path.BotStep kill; #path start; event.Handle {GMCP.Move} {path.Trace} {pathdir} {path.response}; path.message <129>录制路径中…… <299>; }; event.ClassHandleOnce {map/walk/continue} {map.$bot} {pathdir} {path.BotStep.done}; event.ClassHandleOnce {map/walk/failed} {map.$bot} {pathdir} {path.BotStep.failed}; #class path.BotStep close; event.UnHandle {GMCP.Move} {path.Trace} {pathdir}; #local step {$bot}; #local count {&args[]}; #if { $count > 1 } { #local idx {}; #loop 2 {$count} {idx} { #local arg {$args[$idx]}; #if { "$arg" == "%*;%*" } { #cat {step} {/{$arg}}; }; #else { #cat {step} {/$arg}; }; }; }; #path stop; #path insert {$step} {$step}; path.message 已经暂停路径录制,将会在机器人运行结束后自动继续。; map.%0; }; ///=== { // ## path.Mark [<记号>] // 在录制路径的过程中,插入一个记号,方便将来手动编辑路径。 // 如果省略记号,默认为当前房间名。 // }; #alias {path.Mark} { #local mark {@default{%1;$gMapRoom[name]}}; #if { ! @path.isTracing{} } { errLog 路径录制尚未开始。; #return; }; #path insert {Mark/$mark} {Mark/$mark}; }; #alias {map.Mark} { #local mark {%1}; okLog 这里有一个记号:「$mark」。; map.BotReturn map.Mark; }; ///=== { // ## path.Cancel // 取消当前正在进行的录制路径工作。 // }; #alias {path.Cancel} { #if { ! @path.isTracing{} } { errLog 路径录制尚未开始。; #return; }; #var map.path.current {}; #path destroy; event.UnHandle {GMCP.Move} {path.Trace}; path.message 放弃了本次路径录制工作。; }; ///=== { // ## path.Finish // 完成录制。 // }; #alias {path.Finish} { #local area {@map.GetArea{}}; #if { "$area" == "" } { event.HandleOnce {map/GotArea} {path.Finish} {map/path} {path.Finish}; #delay map.Finish.retry {map.GetArea} 1; #return; }; #local here {@map.Room.CID{}}; #var map.path.current[to] {$here}; #path stop; event.UnHandle {GMCP.Move} {path.Trace}; #local fpath {}; #path save forward fpath; #local bpath {}; #path save backward bpath; #if { "$map.path.current[from]" == "$map.path.current[to]" } { okLog 检测到遍历路径。; #local length {}; #path get length length; #local pathName {${here}-遍历${area}-$length}; #var map.path.list[$pathName] {$fpath}; }; #else { #if { @isTrue{$map.path.current[compact]} } { #local fpath {@path.Simplify{$fpath}}; }; okLog 正向路径: {#$fpath#}; #local pathName {${map.path.current[from]}-${map.path.current[to]}}; #var map.path.list[$pathName] {$fpath}; #if { @isTrue{$map.path.current[reversible]} } { #if { @isTrue{$map.path.current[compact]} } { #local bpath {@path.Simplify{$bpath}}; }; okLog 反向路径: {#$bpath#}; #local pathName {${map.path.current[to]}-${map.path.current[from]}}; #var map.path.list[$pathName] {$bpath}; }; }; #var map.path.current {}; #path destroy; path.message 路径录制结束。你可以使用 {@mslp.Exec{path.List;path.List}} 命令查看本房间的关联路径。; path.Hint; storage.Save map-path map.path.list; }; ///=== { // ## path.Hint // 如果此处有路径,则提醒玩家。 // }; #alias {path.Hint} { #nop 录制路径的过程中,提示以录制为主。; #if { @path.isTracing{} } { #return; }; #local area {@map.GetArea{}}; #if { "$area" == "" } { #local here {@xiaoyao.Locate{}}; #if { "$here" == "" } { path.hint; #return; }; }; #local here {@map.Room.CID{}}; #local path {@table.Keys{map.path.list; {${here}-%*}}}; #local count {@slist.Size{$path}}; #if { $count > 0 } { #local path {@fp.Transform{{$path};\@str.Replace{VALUE;{%*-%*};{&2}}}}; #local path {@fp.Transform{{$path};\@mslp.Exec{{path.Walk ${here}-VALUE};<139>\@str.Replace{VALUE;{$area的};{}}<299>}} }; path.hint $path; }; #else { path.hint; }; }; ///=== { // ## path.List // 查看本房间都有哪些关联路径,类似于北侠 node 或者 walk 命令。 // }; #alias {path.List} { #local area {@map.GetArea{}}; #if { "$area" == "" } { event.HandleOnce {map/GotArea} {path.List} {map/path} {path.List}; #delay map.List.retry {map.GetArea} 1; #return; }; #local here {@map.Room.CID{}}; #local count {0}; #local name {}; #foreach {*map.path.list[]} {name} { #if { "$name" == "${here}-%*" } { #local path {$map.path.list[$name]}; #local size {@slist.Size{$path}}; #echo {%s(<129>$size<299>): %s} {@mslp.Exec{{path.Walk $name};<139>$name<299>}} {<169>$path<099>}; #math count {$count + 1}; }; }; #if { $count > 0 } { okLog 共列出 $count 条关联路径。; }; #else { warnLog 尚未找到本房间的关联路径。; }; path.message 为本房间录制更多路径请使用 {@mslp.Exec{path.Trace;path.Trace}}。; }; ///=== { // #@ path.Get <路径名称> // 查询并返回路径。 // }; #func {path.Get} { #local name {%0}; #if { "$name" == "" } { #return {}; }; #return {$map.path.list[$name]}; }; VAR {千里通步进推进器} {path.Walk.Stepper} {}; ///=== { // ## path.Walk.SetStepper <步进推进器> // 设置路径行走的步进推进器。如果设置了步进推进器,则千里通将进入步进推进模式。 // 你推一步,它就走一步,不推就不走。 // 你可以用 path.Walk.Resume 来推动千里通继续前进,一次一步。 // 注意,步进推进器仅在下一次行走任务中生效。一旦行走结束,无论成功失败,步进推进器设置将被清空。 // }; #alias {path.Walk.SetStepper} { #local stepper {%21}; #if { "$stepper" == "" } { xtt.Usage %90; #return; }; #var path.Walk.Stepper {$stepper}; }; ///=== { // ## path.Walk <路径名称> [<回调代码>] // 沿着指定的路径名称执行行走任务。行走完成后,执行回调代码。 // 如果省略回调代码,用户仍可通过订阅 map/walk/continue 事件获得回调机会。 // 注意约定的回调钩子名称为 map/path/end。 // }; #alias {path.Walk} { #local name {%1}; #local callback {%22}; #local path {$map.path.list[$name]}; #if { "$name" == "" } { xtt.Usage %90; #return; }; #if { "$callback" != "" } { #line sub {escapes;var} event.HandleOnce map/walk/continue {map/path/end} {map/path} {$callback}; }; path.WalkSteps {$path}; }; ///=== { // ## path.WalkSteps <路径> [<回调代码>] // 走一个自定义路径。行走完成后,执行回调代码。 // }; #alias {path.WalkSteps} { #local path {%1}; #local callback {%22}; #local len {@slist.Size{$path}}; #if { $len == 0 } { xtt.Usage %90; #return; }; #local path {@fp.Transform{{$path};path.step {VALUE}}}; #if { $len > 1 } { env.Set brief 3; #local path {@slist.Insert{{$path};$len;path.last-step}}; }; #if { "$callback" != "" } { #line sub {escapes;var} event.HandleOnce map/walk/continue {map/path/end} {map/path} {$callback}; }; #path load {$path;path.end}; sync.Wait {#path walk}; }; #alias {path.step} { #class path.step open; #local cmd {@dir.Long{%1}}; #if { "$path.Walk.Stepper" === "" } { event.HandleOnce {map/walk/continue} {map/step} {map/path} {path.step.next}; }; #else { #line sub {escapes;var} event.HandleOnce {map/walk/continue} {map/step} {map/path} {$path.Walk.Stepper}; }; event.HandleOnce {map/walk/failed} {map/step} {map/path} {#path destroy; path.last-step; path.end}; map.step.Try {} {$cmd} {}; }; VAR {停止走路标志} path.walk.stop {0}; #alias {path.Walk.Stop} { #var path.walk.stop 1; }; #alias {path.Walk.Resume} { #var path.walk.stop 0; path.step.next; }; #alias {path.Walk.Reset} { #var path.walk.stop 0; #path destroy; }; #alias {path.step.next} { #if { ! $path.walk.stop } { #path walk; }; }; #alias {path.last-step} { env.UnSet brief; #path walk; }; #alias {path.end} { okLog 行走完成。; #local path {}; #path get info {path}; #if { $path[position] <= $path[length] } { sync.Wait { #path run; }; }; #var path.Walk.Stepper {}; event.Emit {map/walk/continue} {map/path/end}; event.HandleOnce {map/GotArea} {path/end} {map/path} {path.Hint}; map.GetArea; }; #func {path.isTracing} { #if { &map.path.current[] > 0 } { #return 1; }; #else { #return 0; }; }; #alias {path.message} { #local msg {%0}; #local trace {@mslp.Exec{path.Trace;<159>path.Trace<299>}}; #local cancel {@mslp.Exec{path.Cancel;<119>path.Cancel<299>}}; #local finish {@mslp.Exec{path.Finish;<129>path.Finish<299>}}; #if { @path.isTracing{} } { infoLog <159>$msg<299> 取消录制请使用 {$cancel},完成录制请使用 {$finish}。<299>; }; #else { infoLog <159>$msg<299> 要想录制新路径,请使用 {$trace}。<299>; }; path.hint %0; }; VAR {map/path 模块提醒内容} {path-hint} {NOTHING}; #alias {path.hint} { #local hint {%0}; #if { "$path-hint" == "$hint" } { #return; }; #var path-hint {$hint}; #local trace {【@mslp.Exec{path.Trace;<159>开始录制<299>}】}; #local cancel {【@mslp.Exec{path.Cancel;<119>取消录制<299>}】}; #local finish {【@mslp.Exec{path.Finish;<129>完成录制<299>}】}; #if { @path.isTracing{} } { #local hint {$finish $cancel <159>$hint<299>}; }; #else { #local hint {$trace <159>$hint<299>}; }; prompt.Set {{path}{$hint}}; };