Просмотр исходного кода

feat: 解析基本 MUD 命令的触发

dzp 3 лет назад
Родитель
Сommit
d6b9b595ba

+ 8 - 0
plugins/basic/char/__init__.tin

@@ -0,0 +1,8 @@
+#nop 不要删除本行,TinTin 语法要求文件必须以井号开始;
+
+load-module {basic/char/hp};
+load-module {basic/char/skills};
+load-module {basic/char/status};
+load-module {basic/char/i2};
+load-module {basic/char/sachet};
+load-module {basic/char/score};

+ 346 - 0
plugins/basic/char/hp.tin

@@ -0,0 +1,346 @@
+#nop 角色生命值信息解析模块;
+
+load-lib event;
+
+event.define {char/hp}       {无参}  {char/hp} {已经获取到 hp 命令输出结果,并更新 char[HP]。};
+event.define {char/hpbrief}  {无参}  {char/hp} {已经获取到 hpbrief 命令输出结果,并更新 char[HP]。};
+
+#function {basic_char_hp.Init} {
+    #class char open;
+    #var char[HP]           {};
+    #var char[HP][经验]     {};
+    #var char[HP][经验显示] {};
+    #var char[HP][潜能]     {};
+    #var char[HP][潜能显示] {};
+    #var char[HP][上次内力] {0};
+    #var char[HP][当前内力] {};
+    #var char[HP][最大内力] {};
+    #var char[HP][加力]     {};
+    #var char[HP][内力百分比] {};
+    #var char[HP][上次精力] {0};
+    #var char[HP][当前精力] {};
+    #var char[HP][最大精力] {};
+    #var char[HP][精力百分比] {};
+    #var char[HP][上次气血] {0};
+    #var char[HP][当前气血] {};
+    #var char[HP][有效气血] {};
+    #var char[HP][最大气血] {};
+    #var char[HP][气血百分比] {};
+    #var char[HP][上次精神] {0};
+    #var char[HP][当前精神] {};
+    #var char[HP][有效精神] {};
+    #var char[HP][最大精神] {};
+    #var char[HP][精神百分比] {};
+    #var char[HP][上次真气] {0};
+    #var char[HP][当前真气] {};
+    #var char[HP][最大真气] {};
+    #var char[HP][真气减伤] {};
+    #var char[HP][真元]     {};
+    #var char[HP][食物]     {};
+    #var char[HP][最大食物] {};
+    #var char[HP][饥饿]     {};
+    #var char[HP][饮水]     {};
+    #var char[HP][最大饮水] {};
+    #var char[HP][口渴]     {};
+    #var char[HP][气势]     {};
+    #var char[HP][状态]     {};
+    #var char[HP][毒]       {};
+    #var char[HP][上次更新] {0};
+    #var char[HP][更新时间] {};
+    #var char[HP][状态更新] {};
+    #class char close;
+
+    set hpbrief long,report;
+
+    #return true;
+};
+
+#nop hp 有两种格式,非战斗状态:
+#nop ┌───个人状态────────────┬───────────────────┐;
+#nop │【精神】 5978    / 5978     [103%]    │【精力】 12102   / 6051    (+   0)    │;
+#nop │【气血】 23372   / 23372    [101%]    │【内力】 5369    / 7063    (+   1)    │;
+#nop │【真气】 1367    / 1367     [  9%]    │【静气】 101%               [正常]    │;
+#nop │【食物】 874     / 900      [正常]    │【潜能】 7.67万                       │;
+#nop │【饮水】 874     / 900      [正常]    │【经验】 1349.88万                    │;
+#nop ├───────────────────┴───────────────────┤;
+#nop │【状态】 健康、怒、星宿火毒、星宿毒掌毒                                       │;
+#nop └──────────────────────────────北大侠客行────┘;
+#nop 战斗状态:
+#action {^╭───个人状态────────────┬───────────────────╮$} {
+    #class char-hp-parse-hp open;
+    #action {^│【精神】%s%d%s/%s%d%s[%s%d\%]%!s│【精力】%s%d%s/%s%d%s(+%s%d)%!s│$} {
+        #var char[HP][当前精神] {%%2};
+        #var char[HP][有效精神] {%%5};
+        #var char[HP][当前精力] {%%10};
+        #var char[HP][最大精力] {%%13};
+    };
+	#action {^│【气血】%s%d%s/%s%d%s[%s%d\%]%!s│【内力】%s%d%s/%s%d%s(+%s%d)%!s│$} {
+        #var char[HP][当前气血] {%%2};
+        #var char[HP][有效气血] {%%5};
+        #var char[HP][当前内力] {%%10};
+        #var char[HP][最大内力] {%%13};
+        #var char[HP][加力]     {%%16};
+	};
+	#action {^│【真气】%!s%d%!s/%!s%d%!s[%!s%d\%]%!s│【%!*】%!s%!d\%%!s[%!*]%!s│$} {
+        #var char[HP][当前真气] {%%1};
+        #var char[HP][最大真气] {%%2};
+        #var char[HP][真气减伤] {%%3};
+	};
+    #action {^│【食物】%s%d%s/%s%d%s[%S]%!s│【潜能】%s%S%!s│$} {
+        #var char[HP][食物]     {%%2};
+        #var char[HP][最大食物] {%%5};
+        #var char[HP][饥饿]     {%%7};
+        #var char[HP][潜能显示] {%%9};
+    };
+    #action {^│【饮水】%s%d%s/%s%d%s[%S]%!s│【经验】%s%S%!s│$} {
+        #var char[HP][饮水]     {%%2};
+        #var char[HP][最大饮水] {%%5};
+        #var char[HP][口渴]     {%%7};
+        #var char[HP][经验显示] {%%9};
+    };
+    #action {^│【气势】%s%d%s\%%s 【平衡】%s%d%s\%%!s│$} {
+        #var char[HP][气势]     {%%2};
+    };
+    #action {^├───────────────────────────────────┤$} {
+        #nop;
+    };
+    #action {~【状态】%*│} {
+        #local status {%%1};
+        #replace status { } {};
+        #replace status {{\033\[[0-9;]+m}} {};
+        #replace status {、} {;};
+        #var char[HP][状态] {$status};
+        #local item {};
+        #local poison {};
+        #foreach {$status} {item} {
+            #if { "$item" == "{.*毒|火焰刀焚伤|生死符}" } {
+                #local poison {$poison$item;};
+            };
+        };
+        #replace poison {;$} {};
+        #var char[HP][毒] {$poison};
+    };
+	#action {^╰─────────────{(─)*}%S────╯{|ID=char.hp}$} {
+    	#class char-hp-parse-hp kill;
+        event.emit char/hp;
+	};
+    #class char-hp-parse-hp close;
+};
+
+#nop hp -neili 格式:
+#nop ┌──内力显示─────────────────────────────┐
+#nop │□太极神功 (taiji-shengong)                   -   2117/  5109(6040)  │
+#nop ├──其他信息───────────┬─────────────────┤
+#nop │【走火入魔】 -41.50%              │【极限内力】 6040                 │
+#nop └─────────────────┴────────◎北大侠客行◎──┘
+#nop 
+#nop hpbrief 格式:
+#nop 第一行: 经验,潜能,最大内力,当前内力,最大精力,当前精力
+#nop 第二行: 最大气血,有效气血,当前气血,最大精神,有效精神,当前精神
+#nop 第三行: 真气,真元,食物,饮水,是否战斗,是否busy
+#nop #69407,853,992,992,844,1398
+#nop #771,776,776,397,397,397
+#nop #0,0,30,43
+#nop;
+
+#nop 第一行: 经验,潜能,最大内力,当前内力,最大精力,当前精力;
+#nop 第二行: 最大气血,有效气血,当前气血,最大精神,有效精神,当前精神;
+#action {^{|>|> }#%1,%2,%3,%4,%5,%6$} {
+    #if { "${char.parsingHP}" == "" } {
+        #var char[HP][经验显示] {%1};
+        #var char[HP][经验]     {@__char_hp_expandBigNumber__{%1}};
+        #var char[HP][潜能显示] {%2};
+        #var char[HP][潜能]     {@__char_hp_expandBigNumber__{%2}};
+        #var char[HP][最大内力] {@__char_hp_expandBigNumber__{%3}};
+        #var char[HP][上次内力] {$char[HP][当前内力]};
+        #var char[HP][当前内力] {@__char_hp_expandBigNumber__{%4}};
+        #var char[HP][最大精力] {@__char_hp_expandBigNumber__{%5}};
+        #var char[HP][上次精力] {$char[HP][当前精力]};
+        #var char[HP][当前精力] {@__char_hp_expandBigNumber__{%6}};
+
+        #math char[HP][内力百分比] { $char[HP][当前内力] * 50 / $char[HP][最大内力] };
+        #math char[HP][精力百分比] { $char[HP][当前精力] * 50 / $char[HP][最大精力] };
+
+        #var char.parsingHP     {true};
+        #line gag;
+    };
+    #else {
+        #var char[HP][最大气血] {@__char_hp_expandBigNumber__{%1}};
+        #var char[HP][有效气血] {@__char_hp_expandBigNumber__{%2}};
+        #var char[HP][上次气血] {$char[HP][当前气血]};
+        #var char[HP][当前气血] {@__char_hp_expandBigNumber__{%3}};
+        #var char[HP][最大精神] {@__char_hp_expandBigNumber__{%4}};
+        #var char[HP][有效精神] {@__char_hp_expandBigNumber__{%5}};
+        #var char[HP][上次精神] {$char[HP][当前精神]};
+        #var char[HP][当前精神] {@__char_hp_expandBigNumber__{%6}};
+
+        #math char[HP][精神百分比] { $char[HP][当前精神] * 100 / $char[HP][最大精神] };
+        #math char[HP][气血百分比] { $char[HP][当前气血] * 100 / $char[HP][最大气血] };
+
+        #unvar char.parsingHP;
+        #line gag;
+    };
+} {2.1};
+
+#nop 第三行: 真气,真元,食物,饮水;
+#action {^#%1,%2,%3,%4,{0|1},{0|1}$} {
+    #var char[HP][上次真气]  {$char[HP][当前真气]};
+    #var char[HP][当前真气]  {@__char_hp_expandBigNumber__{%1}};
+    #var char[HP][当前真元]  {@__char_hp_expandBigNumber__{%2}};
+    #var char[HP][食物]      {@__char_hp_expandBigNumber__{%3}};
+    #var char[HP][饮水]      {@__char_hp_expandBigNumber__{%4}};
+    #var char[HP][战斗中]    {false};
+    #var char[HP][忙]        {false};
+
+    #if { "%5" == "1" } {
+        #var char[HP][战斗中] {true};
+    };
+
+    #if { "%6" == "1" } {
+        #var char[HP][忙] {true};
+    };
+
+    #var char[HP][上次更新] {$char[HP][更新时间]};
+    #format now {%T};
+    #var char[HP][更新时间] {$now};
+
+    #unvar char.parsingHP;
+    #line gag;
+    #delay {char.hp.summarize} {char.hp.summarize} {0};
+} {2.0};
+
+#alias {char.hp.summarize} {
+    #local color    {<160>};
+    #local combat   {};
+    #if { "$char[HP][战斗中]" == "true" } {
+        #format color   {<110>};
+        #format combat  { <110>战斗中<070>};
+    };
+
+    #if { "$char[HP][忙]" == "true" } {
+        #format color   {<110>};
+        #format combat  {$combat <130>你正忙<070>};
+    };
+
+    #local 每秒气血变化 {};
+    #math 每秒气血变化 {($char[HP][当前气血] - $char[HP][上次气血]) / ($char[HP][更新时间] - $char[HP][上次更新])};
+    #if { ${每秒气血变化} > 0 } {
+        #local 每秒气血变化 {(<120>${每秒气血变化}<070>)};
+    };
+    #elseif { ${每秒气血变化} < 0 } {
+        #local 每秒气血变化 {(<110>${每秒气血变化}<070>)};
+    };
+    #else {
+        #local 每秒气血变化 {};
+    };
+
+    #local 每秒精神变化 {};
+    #math 每秒精神变化 {($char[HP][当前精神] - $char[HP][上次精神]) / ($char[HP][更新时间] - $char[HP][上次更新])};
+    #if { ${每秒精神变化} > 0 } {
+        #local 每秒精神变化 {(<120>${每秒精神变化}<070>)};
+    };
+    #elseif { ${每秒精神变化} < 0 } {
+        #local 每秒精神变化 {(<110>${每秒精神变化}<070>)};
+    };
+    #else {
+        #local 每秒精神变化 {};
+    };
+
+    #local 每秒内力变化 {};
+    #math 每秒内力变化 {($char[HP][当前内力] - $char[HP][上次内力]) / ($char[HP][更新时间] - $char[HP][上次更新])};
+    #if { ${每秒内力变化} > 0 } {
+        #local 每秒内力变化 {(<120>${每秒内力变化}<070>)};
+    };
+    #elseif { ${每秒内力变化} < 0 } {
+        #local 每秒内力变化 {(<110>${每秒内力变化}<070>)};
+    };
+    #else {
+        #local 每秒内力变化 {};
+    };
+
+    #local 每秒精力变化 {};
+    #math 每秒精力变化 {($char[HP][当前精力] - $char[HP][上次精力]) / ($char[HP][更新时间] - $char[HP][上次更新])};
+    #if { ${每秒精力变化} > 0 } {
+        #local 每秒精力变化 {(<120>${每秒精力变化}<070>)};
+    };
+    #elseif { ${每秒精力变化} < 0 } {
+        #local 每秒精力变化 {(<110>${每秒精力变化}<070>)};
+    };
+    #else {
+        #local 每秒精力变化 {};
+    };
+
+    #local {气血受损率} {};
+    #math {气血受损率} { $char[HP][有效气血] * 100 / $char[HP][最大气血] };
+
+    #nop 气血恢复的数值展示为每分钟可以恢复的最大血量的倍数(以百分比形式);
+    #local {气血恢复} {};
+    #math {气血恢复} { $char[STATUS][气血恢复] * 100 * 60 / $char[HP][最大气血] };
+
+    #nop 气血治疗的数值展示为每分钟可以治疗的最大血量的倍数(以百分比形式);
+    #local {气血治疗} {};
+    #math {气血治疗} { $char[STATUS][气血治疗] * 100 * 60 / $char[HP][最大气血] };
+
+    #local summarize {};
+    #format summarize {$color【HP摘要】<070>气血: %s%s/%s 内力: %s%s 气血恢复: %s/%s 精神: %s%s 精力: %s%s 食物: %s 饮水: %s$combat}
+        {@__char_hp_colorit__{$char[HP][气血百分比]}} {${每秒气血变化}} {@__char_hp_colorit__{${气血受损率}}}
+        {@__char_hp_colorit__{$char[HP][内力百分比]}} {${每秒内力变化}}
+        {@__char_hp_colorit__{${气血恢复}}} {@__char_hp_colorit__{${气血治疗}}}
+        {@__char_hp_colorit__{$char[HP][精神百分比]}} {${每秒精神变化}}
+        {@__char_hp_colorit__{$char[HP][精力百分比]}} {${每秒精力变化}}
+        {$char[HP][食物]} {$char[HP][饮水]};
+
+    #showme $summarize;
+
+    event.emit char/hpbrief;
+};
+
+#function {__char_hp_expandBigNumber__} {
+    #local number {%1};
+    #replace number {K} {*1000};
+    #replace number {M} {*1000000};
+    #math number {$number};
+    #return $number;
+};
+
+#function {__char_hp_colorit__} {
+    #local p {%1};
+    #if { $p < 15 } {
+        #return {<010>$p%<070>};
+    };
+    #elseif { $p < 30 } {
+        #return {<110>$p%<070>};
+    };
+    #elseif { $p < 60 } {
+        #return {<030>$p%<070>};
+    };
+    #elseif { $p < 90 } {
+        #return {<130>$p%<070>};
+    };
+    #elseif { $p <= 100 } {
+        #return {<120>$p%<070>};
+    };
+    #else {
+        #return {<160>$p%<070>};
+    };
+};
+
+#alias {char.GetHP}     {hpbrief;hp};
+
+#alias {hpbrief2} {
+    #class char-hpbrief open;
+    #action {@SyncMessage{hpbrief-end}} {
+        #class char-hpbrief kill;
+        #line gag;
+        hpbrief;
+    };
+    #alias {char.hpbrief.done} {
+        #class char-hpbrief kill;
+        #line gag;
+    };
+    #class char-hpbrief close;
+
+    event.handleOnce {char/hpbrief} {char/hp} {char/hp} {char.hpbrief.done};
+    #send hpbrief;
+    SyncMessage hpbrief-end;
+};

+ 206 - 0
plugins/basic/char/i2.tin

@@ -0,0 +1,206 @@
+#nop i2 格式:
+#nop 你身上带著下列这些东西(负重 27%):
+#nop 九十一两白银(Silver)
+#nop 二个竹壶(Zhuhu)
+#nop 三块干粮(Gan liang)
+#nop 大砍刀(Dakan dao)
+#nop 青锋剑(Qingfeng sword)
+#nop 北侠战袍(Pkuxkx zhanpao)
+#nop 北侠战甲(Pkuxkx zhanjia)
+#nop 北侠战衣(Pkuxkx zhanyi)
+#nop 北侠战盔(Pkuxkx zhankui)
+#nop 北侠战靴(Pkuxkx zhanxue)
+#nop 锦囊(Jin nang)
+#nop
+#nop -------------------------------------------
+#nop 你左手拿着:大砍刀(Dakan dao)
+#nop 你右手拿着:青锋剑(Qingfeng sword)
+#nop
+#nop -------------------------------------------
+#nop 你身上穿着:
+#nop 北侠战袍(Pkuxkx zhanpao)
+#nop 北侠战甲(Pkuxkx zhanjia)
+#nop 北侠战衣(Pkuxkx zhanyi)
+#nop 北侠战盔(Pkuxkx zhankui)
+#nop 北侠战靴(Pkuxkx zhanxue)
+#nop 锦囊(Jin nang)
+#nop;
+
+#function {basic_char_i2.Init} {
+    char.reset.i2;
+    char.reset.bag;
+    char.reset.sachet;
+    #return true;
+};
+
+#alias {char.reset.i2} {
+    #class char open;
+    #nop 随身物品;
+    #var char-Item      {};
+    #nop 穿戴;
+    #var char-Wear      {};
+    #nop 武器;
+    #var char-Wield     {};
+    #nop 装备;
+    #var char-Equip     {};
+    #class char close;
+};
+
+#alias {char.reset.bag} {
+    #class char open;
+    #nop 包袱;
+    #var char-Bag       {};
+    #class char close;
+};
+
+#alias {char.reset.sachet} {
+    #class char open;
+    #nop 宝石袋;
+    #var char-Sachet    {};
+    #class char close;
+};
+
+#action {^你身上带著下列这些东西(负重 %1%):$} {
+    #class {ParseItems} open;
+
+    #var char-Item.currentType {随身};
+    char.reset.i2;
+
+    #nop 你左手拿着:大砍刀(Dakan dao);
+    #nop 你右手拿着:青锋剑(Qingfeng sword);
+    #action {^你{左手|右手}拿着:%%2(%%3)$} {
+        #local hand     {%%1};
+        #local item     {%%2};
+        #local id       {@toLower{%%3}};
+        #class char open;
+        #var char-Wield.$hand {
+            {item}{$item}
+            {id}{$id}
+        };
+        #class char close;
+    } {4};
+
+    #action {^你身上穿着:$} {
+        #var char-Item.currentType {装备};
+    };
+
+    #nop 九十一两白银(Silver);
+    #action {^{(零|一|二|三|四|五|六|七|八|九|十|百|千|万|亿)+}{两|文|张}{黄金|白银|铜板|一千两银票}(%*)$} {
+        #local amount   {@c2d{%%1}};
+        #local unit     {%%3};
+        #local item     {%%4};
+        #local id       {@toLower{%%5}};
+
+        #class char open;
+        #var {char-Item.$item} {
+            {id}{@toLower{$id}}
+            {amount}{@c2d{$amount}}
+        };
+        #class char close;
+    } {4};
+
+    #local 武器等级 {沉水|赤焰|荡寇|彗月|照夜|追日|断阙|刑天};
+    #local 武器种类 {剑|刀|杖|鞭|斧|枪|锤|戟|匕|针|萧|钩};
+
+    #local 装备等级 {机杼|苍野|青幽|百战|鬼烈|巨灵|深罡|九日};
+    #local 装备种类 {铠甲|靴|袍|手套|盔|盾|披风|腰带|护腕};
+
+    #local 饰品等级 {恶来|玄狐|洛神|盘瓠|儵忽|帝江|烛阴|盘古};
+    #local 饰品种类 {戒指|项链};
+
+    #local 职业等级 {(..)+};
+    #local 职业部位 {盔|护腕|披风|护手|袍|腰带|盾|靴|项链|戒指|(板|布|鳞|皮)甲|面具|护心|护肩|腿甲};
+
+    #local 汉字数词 {(?:零|一|二|三|四|五|六|七|八|九|十|百|千|万|亿)+};
+    #local 汉字量词 {(?:本|块|碗|件|册|柄|把|根|枚|个)+};
+    #local 词缀修饰 {(?:[^ ][^ ])+};
+
+    #nop 火锅装;
+    #nop 八件百战手套(Hands);
+    #action {^{?:(${汉字数词})件|}{?:(${词缀修饰})的|}{?:(${装备等级})(${武器种类}|${装备种类}|${饰品种类})}(%S)$} {
+        #local amount   {@c2d{%%1}};
+        #local modifier {%%2};
+        #local level    {%%3};
+        #local kind     {%%4};
+        #local id       {@toLower{%%5}};
+        #if { $amount == 0 } {
+            #local amount {1};
+        };
+        #echo {amount [$amount] modifier [$modifier] level [$level] kind [$kind] id [$id]};
+    } {4};
+
+    #nop 职业装和随机装;
+    #nop 二件玄铁之护手(Gauntlet);
+    #nop 玄铁之板甲(Armor);
+    #nop 天兵华彩 巨灵之手套(Hands);
+    #action {^{((零|一|二|三|四|五|六|七|八|九|十|百|千|万|亿)+件)?}{(([^ ]+)[ ])?}%S之%S(%S)$} {
+        #local amount   {%%3};
+        #local title    {%%6};
+        #local rank     {%%7};
+        #local item     {%%8};
+        #local id       {@toLower{%%9}};
+
+        #if { "${char-Item.currentType}" == "装备" } {
+            #return;
+        };
+
+        #if { "$amount" == "" } { #format amount {%s} {一} };
+        #format amount {%s} {@c2d{$amount}};
+
+        #if { "${char-Equip.$id}" != "" } {
+            #math amount { ${char-Equip.$id} + $amount };
+        };
+
+        #class char open;
+        #var {char-Equip.$id} {$amount};
+        #class char close;
+    } {4};
+
+    #nop 二把竹剑(Zhujian);
+    #action {^{(零|一|二|三|四|五|六|七|八|九|十|百|千|万|亿)+}{本|块|碗|件|册|柄|把|根|枚|个}%S(%*)$} {
+        #local amount   {@c2d{%%1}};
+        #local unit     {%%3};
+        #local item     {%%4};
+        #local id       {@toLower{%%5}};
+        #class char open;
+        #var {char-Item.$item} {
+            {id}{$id}
+            {amount}{$amount}
+        };
+        #class char close;
+    };
+
+    #nop 大砍刀(Dakan dao);
+    #nop 青锋剑(Qingfeng sword);
+    #action {^%%1(%%2)$} {
+        #local item {%%1};
+        #local id   {@toLower{%%2}};
+        #if { "${char-Item.currentType}" == "装备" } {
+            #class char open;
+            #var {char-Wear.$item} {{id}{$id}};
+            #class char close;
+        };
+        #elseif { "${char-Item.currentType}" == "随身" } {
+            #class char open;
+            #var {char-Item.$item} {{id}{$id}};
+            #class char close;
+        };
+        #elseif { "${char-Item.currentType}" == "包袱" } {
+            #class char open;
+            #var {char-Bag.$item} {{id}{$id}};
+            #class char close;
+        };
+        #elseif { "${char.-currentType}" == "宝石袋" } {
+            #class char open;
+            #var {char-Sachet.$item} {{id}{$id}};
+            #class char close;
+        };
+    } {9};
+
+    #delay 3 {
+        #unvar char-Item.currentType;
+        #class {ParseItems} kill;
+    };
+
+    #class {ParseItems} close;
+};

+ 67 - 0
plugins/basic/char/sachet.tin

@@ -0,0 +1,67 @@
+#nop ┌────────────────────────────────────────┐;
+#nop │锦囊 (97/101)                                                                   │;
+#nop ├───五行宝石─────────────┬───────────────────┤;
+#nop │[J5A]雷☆精金*12                        │[B4A]风☆玄冰*30                      │;
+#nop ├───日月及中性五行宝石────────┴───────────────────┤;
+#nop │[S5C]雷◎玉髓*1                                                                 │;
+#nop ├───四灵宝石──────┬─────────────┬────────────┤;
+#nop │[G4A]风☆神龙骨*11        │[F4A]风☆凤凰羽*5         │[X4B]风★玄武甲*7       │;
+#nop │[G4B]风★神龙骨*8         │[F4B]风★凤凰羽*4         │[X4A]风☆玄武甲*7       │;
+#nop │                          │                          │[X3A]水☆玄武甲*7       │;
+#nop │                          │                          │[X3B]水★玄武甲*5       │;
+#nop └─────────────┴─────────────┴───北大侠客行────┘;
+#nop ;
+
+#list char[锦囊] create {};
+
+#action {^%S(%S %S) [%1/%2]$E} {
+    #list char[锦囊] create {};
+
+    #class char-parse-sachet open;
+
+    #local level    {地|山|水|风|雷|火|泽|天};
+    #local type     {☆|★|◎};
+    #local wuxing   {精金|木灵|玄冰|炎晶|玉髓};
+    #local beast    {玄武甲|神龙骨|凤凰羽|麒麟角};
+    #local special  {日魂|月魄};
+    #local pattern  {\(\s*(\d+)\)($level)($type)($wuxing|$beast|$special)\*(\d+)\s+};
+
+    #action {^├───%*宝石───────┴─────────┴──────────┤$} {
+        #nop;
+    };
+
+    #action {^│%*│$} {
+        #local line {%%1};
+        #replace line {│} {;};
+        #local item {};
+        #foreach {$line} {item} {
+            #if { "$item" == "" } {
+                #continue;
+            };
+            #nop {( 1)山★ 玄武甲*12};
+            #local item {@__char_sachet_parse__{{$item}}};
+            #var char[锦囊] {$char[锦囊]{$item[序号]}{$item}};
+        };
+    };
+
+    #action {^╰─────────┴─────────┴─────────┴─%S────╯{|ID=char.sachet}$} {
+        #delay tmp {};
+        #class char-parse-sachet kill;
+    };
+
+    #class char-parse-sachet close;
+};
+
+#function {__char_sachet_parse__} {
+    #local item {%1};
+
+    #replace {item} {[%S]%*{☆|★|◎}%**%d} {
+        {序号}{&1}
+        {等级}{&2}
+        {阴阳}{&3}
+        {种类}{&4}
+        {数量}{&5}
+    };
+
+    #return {$item};
+};

+ 156 - 0
plugins/basic/char/score.tin

@@ -0,0 +1,156 @@
+#nop 人物档案解析模块;
+
+/*
+╭───人物详情────────────────────────┬───────╮
+│ 武当派真人 马后炮(Mhp)                                       │ ▂▃▅▃▂   │
+│ 膂力:[  69]  悟性:[  47]  根骨:[  83]  身法:[  79]       │    -  -      │
+│ 福缘:[  23]  容貌:[  39]  灵性:[  39]  胆识:[   ?]       │   ▂  ▂     │
+│ 距离上榜还需增加206218点经验。                               │     32/32    │
+├───────────────────┬───────────┴───────┤
+│个人信息                              │门派履历                              │
+│国籍:无国籍                          │门派:武当派                          │
+│年龄:三十四岁                        │师承:张三丰                          │
+│性别:男性                            │门忠:7195                            │
+│生日:己亥年一月三十一日申时七刻      │出师:无                              │
+│婚姻:未婚                            │叛师:无                              │
+├────────────┬──────┴─────┬─────────────┤
+│杀生:0人               │职业:甲士              │存款:527金条 21713黄金   │
+│被杀:1次               │道德:100.88万          │武学点:0                 │
+│死亡:4次               │声望:322.77万          │国家积分:0               │
+│杀气:正常              │愿望:150               │实战经验:一甲子余年      │
+├───休闲任务─────┼────────────┼─────────────┤
+│高级任务:0次           │低级任务:6次           │劫匪掉宝:0次             │
+╰────────────┴────────────┴────北大侠客行────╯
+*/
+
+#action {^╭───人物详情────────────────────────┬───────╮$} {
+    #class char-score-parser open;
+
+    #var char-score-parser-lineNo {0};
+    #action {^│%*│%*│$} {
+        #math char-score-parser-lineNo {${char-score-parser-lineNo} + 1};
+        #switch {"${char-score-parser-lineNo}"} {
+            #case {"1"} {
+                #local obj {@ParseTitle{@trim{%%1}}};
+                #var char[档案][头衔] {$obj[title]};
+                #var char[档案][大名] {$obj[name]};
+                #var char[档案][账号] {$obj[id]};
+            };
+            #case {"2"} {
+                #local level {@trim{%%2}};
+                #replace level {%d/%d} {{cur}{&1}{max}{&2}};
+                #local level {$level};
+                #var char[档案][人物等级] {$level[cur]};
+                #var char[档案][最大等级] {$level[max]};
+            };
+            #default {
+                #nop;
+            };
+        };
+    } {6};
+
+#nop │ 膂力:[  69]  悟性:[  47]  根骨:[  83]  身法:[  79]       │    -  -      │;
+    #action {~^\e[0m│\e[2;37;0m 膂力:[%+]  悟性:[%+]  根骨:[%+]  身法:[%+]%+│%+│} {
+        #local str {%%1};
+        #local int {%%2};
+        #local con {%%3};
+        #local dex {%%4};
+
+        #local key {先天};
+        #if { "$str$int$con$dex" == "%*[1;33m%*" } {
+            #local key {天赋};
+        };
+        #elseif { "$str$int$con$dex" == "%*[36m%*" } {
+            #local key {初始};
+        };
+
+        #replace str {{\x1b\[[0-9;\\]+m}} {};
+        #replace int {{\x1b\[[0-9;\\]+m}} {};
+        #replace con {{\x1b\[[0-9;\\]+m}} {};
+        #replace dex {{\x1b\[[0-9;\\]+m}} {};
+
+        #var char[档案][$key][膂力] {@trim{$str}};
+        #var char[档案][$key][悟性] {@trim{$int}};
+        #var char[档案][$key][根骨] {@trim{$con}};
+        #var char[档案][$key][身法] {@trim{$dex}};
+    };
+#nop │ 福缘:[  23]  容貌:[  39]  灵性:[  39]  胆识:[   ?]       │   ▂  ▂     │;
+    #action {^│ 福缘:[%+]  容貌:[%+]  灵性:[%+]  胆识:[%+]%*│%*│$} {
+        #var char[档案][天赋][福缘] {@trim{%%1}};
+        #var char[档案][天赋][容貌] {@trim{%%2}};
+        #var char[档案][天赋][灵性] {@trim{%%3}};
+    };
+
+#nop │国籍:大理        性别:男性          │门派:神龙教                          │;
+#nop │身高:七尺六寸    体重:约一百一十斤  │师承:洪安通                          │;
+#nop │体型:匀称        姻缘:未遇良人      │门忠:2940                            │;
+    #action {^│%+:%* %+:%+ │%+:%*│$} {
+        #var char[档案][%%1] {@trim{%%2}};
+        #var char[档案][@trim{%%3}] {@trim{%%4}};
+        #var char[档案][%%5] {@trim{%%6}};
+    } {5.1};
+
+#nop │年龄:十八岁二个月                    │出师:无                              │;
+#nop │生日:辛丑年十二月五日亥时八刻        │叛师:无                              │;
+    #action {^│%+:%*│%+:%*│$} {
+        #var char[档案][%%1] {@trim{%%2}};
+        #var char[档案][%%3] {@trim{%%4}};
+    } {5.2};
+
+#nop │杀生:0人               │职业:甲士              │存款:527金条 21713黄金   │;
+#nop │被杀:1次               │道德:100.88万          │武学点:0                 │;
+#nop │死亡:4次               │声望:322.77万          │国家积分:0               │;
+#nop │杀气:正常              │愿望:150               │实战经验:一甲子余年      │;
+#nop ├───休闲任务─────┼────────────┼─────────────┤;
+#nop │高级任务:0次           │低级任务:6次           │劫匪掉宝:0次             │;
+    #action {^│%+:%*│%+:%*│%+:%*│$} {
+        #var char[档案][%%1] {@trim{%%2}};
+        #var char[档案][%%3] {@trim{%%4}};
+        #var char[档案][%%5] {@trim{%%6}};
+    };
+
+    #nop 白驼山    你是白驼山第二代弟子,师承欧阳锋。;
+    #nop 星宿派    你是星宿派第三代弟子,师承摘星子。;
+    #nop 古墓派    你是古墓派第四代弟子,师承杨过。;
+    #nop 天龙寺    你是天龙寺第十五代弟子,师承枯荣大师。;
+    #nop 大轮寺    你是大轮寺第十一代弟子,师承鸠摩智。;
+    #nop 峨嵋派    你是峨嵋派第四代弟子,师承灭绝师太。;
+    #nop 丐帮      你是丐帮第十八代弟子,师承洪七公。;
+    #nop 华山派    你是华山派第十八代弟子,师承风清扬。;
+    #nop 灵鹫宫    你是灵鹫宫第二代弟子,师承天山童姥。;
+    #nop 雪山派    你是雪山派第六代弟子,师承白自在。;
+    #nop 明教      你是明教第二十二代弟子,师承颜垣。;
+    #nop 姑苏慕容  你是姑苏慕容第二代弟子,师承慕容博。;
+    #nop 全真派    你是全真派第四代弟子,师承尹志平。;
+    #nop 日月神教  你是日月神教第二十代弟子,师承东方不败。;
+    #nop 少林派    你是少林派第三十七代弟子,师承玄悲大师。;
+    #nop 神龙教    你是神龙教第二代弟子,师承洪安通。;
+    #nop 桃花岛    你是桃花岛第二代弟子,师承黄药师。;
+    #nop 天地会    你是天地会第四代弟子,师承徐天川。;
+    #nop 武当派    你是武当派第二代弟子,师承张三丰。;
+    #nop 五毒教    你是五毒教第十代弟子,师承齐云琳。;
+    #action {^ 你是%*第%*代弟子,师承%*。$} {
+        #var char[档案][门派] {%%1};
+        #var char[档案][辈分] {@c2d{%%2}};
+        #var char[档案][师父] {%%3};
+    };
+    
+    #nop 朝廷      你是朝廷四品官员,师承孟珙。;
+    #action {^ 你是朝廷%*品官员,师承%*。$} {
+        #var char[档案][门派] {朝廷};
+        #var char[档案][辈分] {@c2d{%%1}};
+        #var char[档案][师父] {%%2};
+    };
+
+    #action {^╰────────────┴────────────┴────%S────╯{|ID=char.score}$} {
+        #class char-score-parser kill;
+        #replace char[档案][年龄] {岁} {};
+        #var char[档案][年龄] {@c2d{$char[档案][年龄]}};
+    };
+
+    #class char-score-parser close;
+};
+    
+load-module {basic/title};
+
+score;

+ 188 - 0
plugins/basic/char/skills.tin

@@ -0,0 +1,188 @@
+#nop ╭───技能列表(共十六项)─┬─────────────┬──────┬──────┬──────╮
+#nop │名称                      │ID                        │描述        │级别        │最大级别    │
+#nop ├───一项职业技能────┼─────────────┼──────┼──────┼──────┤
+#nop │  占卜之术                │divination                │不足挂齿    │82.0        │387         │
+#nop ├───六项基本知识────┼─────────────┼──────┼──────┼──────┤
+#nop │  禅宗心法                │buddhism                  │半生不熟    │153.0       │-           │
+#nop │  鉴定之术                │identification            │初窥门径    │54.0        │-           │
+#nop │  读书写字                │literate                  │半生不熟    │152.0       │-           │
+#nop │  医术                    │medical-skill             │新学乍用    │30.0        │-           │
+#nop │  妙手空空                │stealing                  │新学乍用    │10.0        │-           │
+#nop │  道家养生术              │taoism                    │深不可测    │948.23      │-           │
+#nop ├───六项基本功夫────┼─────────────┼──────┼──────┼──────┤
+#nop │  基本拳法                │cuff                      │半生不熟    │386.0       │387         │
+#nop │  基本轻功                │dodge                     │半生不熟    │386.0       │387         │
+#nop │  基本内功                │force                     │半生不熟    │386.0       │387         │
+#nop │  基本招架                │parry                     │半生不熟    │386.0       │387         │
+#nop │  基本剑法                │sword                     │半生不熟    │386.0       │387         │
+#nop ├───四项特殊功夫────┼─────────────┼──────┼──────┼──────┤
+#nop │□太极剑法                │taiji-jian                │半生不熟    │386.0       │387         │
+#nop │□太极拳                  │taiji-quan                │半生不熟    │386.0       │387         │
+#nop │□太极神功                │taiji-shengong            │第五重楼    │387.0       │387         │
+#nop │□梯云纵                  │tiyunzong                 │半生不熟    │386.0       │387         │
+#nop ╰─────────────┴─────────────┴──────┴────北大侠客行────╯
+#nop;
+
+#function {basic_char_skills.Init} {
+    #class char open;
+    #var char[Skills] {};
+    #class char close;
+    #return true;
+};
+
+#action {^╭───技能列表(共%*项){(─|┬)*}──╮$} {
+    #class {ParseSkills} open;
+
+    #var char[Skills][currentType] {};
+
+    #gag {^│名称};
+
+    #action {^├───%%1项%%2──} {
+        #var char[Skills][currentType] {%%2};
+    };
+
+    #local RST      {\e[0m};
+    #local RST__    {\e[2;37;0m};
+    #local __I__    {$RST__│};
+
+    #action {~^$RST│%*│%*│%*│%*│%*│{|ID=char.skills}} {
+        #local line     {%%0};
+        #local code     {%%2};
+        #local level    {%%4};
+        #local limit    {%%5};
+        #replace {code}   {\x1b[2;37;0m} {};
+        #replace {level}  {\x1b[2;37;0m} {};
+        #replace {limit}  {\x1b[2;37;0m} {};
+
+		#replace level {+} {};
+
+        #if { "$limit" == "%s%d%s" } {
+            #math limit {$limit + 0};
+        };
+        #else {
+            #local limit {0};
+        };
+
+        #if { $limit > 0 } {
+            #nop 给技能加上彩色进度条,用来表示当前级别距离上限的程度;
+            #local newCode {@__char_skills_colorit__{{$code};$level;$limit}};
+            #replace code { } {};
+            #replace line {$code\x1b[2;37;0m%s} {$newCode\e[0m};
+            #echo {%s} {@Beautify{{$line}}};
+            #local line {Skill/%%1/%%2/%%3/%%4/$limit};
+            #replace line { } {};
+            #showme {$line};
+            #line gag;
+        };
+    };
+
+    #action {^Skill/{□|Θ|}%%2/%%3/%%4/%%5/%%6$} {
+        #local type ${char[Skills][currentType]};
+        #local enabled  {%%1};
+        #local name     {%%2};
+        #local code     {%%3};
+        #local rank     {%%4};
+        #local level    {%%5};
+        #local limit    {%%6};
+
+        #replace name { } {};
+
+        #if { "$enabled" == "□" } {
+            #format enabled {true};
+        };
+        #else {
+            #format enabled {false};
+        };
+
+        #local key {};
+        #format key {char[Skills][%s]} {$name};
+
+        #class char open;
+        #var {$key} {
+            {name}{$name}
+            {type}{$type}
+            {enabled}{$enabled}
+            {code}{$code}
+            {rank}{$rank}
+            {level}{$level}
+            {limit}{$limit}
+        };
+        #class char close;
+
+        #line gag;
+    };
+
+    #action {^╰───{(┴|─)*}┴────%S────╯{|ID=char.skills}$} {
+        #unvar char[Skills][currentType];
+        #class {ParseSkills} kill;
+    };
+
+    #action {^你不是查看过吗?{|ID=char/skills}$} {
+        #class {ParseSkills} kill;
+    };
+
+    #delay 5 {
+        #class {ParseSkills} kill;
+    };
+
+    #class {ParseSkills} close;
+};
+
+#function {__char_skills_colorit__} {
+    #local code     {%1};
+    #local level    {%2};
+    #local limit    {%3};
+
+    #local p {};
+    #math p {$level * 100 / $limit};
+    #format p {%d} {$p};
+
+    #local color {};
+
+    #if { $p < 15 } {
+        #format color {%s} {<071>};
+    };
+    #elseif { $p < 30 } {
+        #format color {%s} {<171>};
+    };
+    #elseif { $p < 60 } {
+        #format color {%s} {<003>};
+    };
+    #elseif { $p < 90 } {
+        #format color {%s} {<074>};
+    };
+    #elseif { $p < 100 } {
+        #format color {%s} {<134>};
+    };
+    #elseif { $p == 100 } {
+        #format color {%s} {<132>};
+    };
+    #elseif { $p > 100 } {
+        #format color {%s} {<506>};
+    };
+
+    #local len {};
+    #local len2 {};
+    #local len3 {};
+    #format {len} {%L} {$code};
+    #format {code} {%p} {$code};
+    #format {len2} {%L} {$code};
+    #math len3 {$len - $len2};
+    #format {code} {%s%${len3}s} {$code} {$p%};
+    #local leftLen {};
+    #math leftLen {$len * $level / $limit};
+    #format leftLen {%d} {$leftLen};
+    #local left {};
+    #format {left} {${color}%.${leftLen}s<070>} {$code};
+
+    #local right {};
+    #local rightLen {};
+    #math rightLen {$len - $leftLen};
+    #format {right} {%r} {$code};
+    #format {right} {%.${rightLen}s} {$right};
+    #format {right} {<g08>%r} {$right};
+
+    #return {$left$right};
+};
+
+#alias {char.GetSkills} {skills};

+ 113 - 0
plugins/basic/char/status.tin

@@ -0,0 +1,113 @@
+#nop 角色生命值信息解析模块;
+
+load-lib event;
+
+event.define {char/status}    {无参}  {char/status} {已经获取到 status_me 命令输出结果,并更新 char[STATUS]。};
+
+#nop ╭────个人状态────┬────┬──────┬────┬──────┬────┬─────╮;
+#nop │姓名    │马后炮      │ID    │Mhp         │级别    │32          │战斗力  │104611      │;
+#nop ├───攻击属性────┼────┼──────┼────┼──────┼────┼──────┤;
+#nop │武器伤害│264         │出招速度│0.58        │外伤命中│806         │内伤命中│-2级        │;
+#nop │外伤增益│15%         │内伤增益│6%          │要害攻击│2%          │要害伤害│152%        │;
+#nop │毒伤增强│0%          │致晕命中│0级         │        │            │        │            │;
+#nop ├───防御属性────┼────┼──────┼────┼──────┼────┼──────┤;
+#nop │护甲    │597         │防御    │382         │躲闪    │818         │招架    │2846        │;
+#nop │外伤抗性│50%         │外伤绝抗│0%          │内伤抗性│45%         │内伤绝抗│0%          │;
+#nop │真气减伤│9%          │伤害吸收│0%          │外伤减伤│0           │技能防御│4级         │;
+#nop │要害抗性│1%          │毒伤抗性│50%         │致晕抗性│+3级        │        │            │;
+#nop ├───其他属性────┼────┼──────┼────┼──────┼────┼──────┤;
+#nop │臂力影响│54          │悟性影响│45          │根骨影响│75          │身法影响│59          │;
+#nop │后天身法│10点        │        │            │        │            │        │            │;
+#nop ├───技能加成────┼────┼──────┼────┼──────┼────┼──────┤;
+#nop │基本轻功│+57级       │基本招架│+40级       │基本拳法│+25级       │基本爪法│+25级       │;
+#nop │基本手法│+24级       │基本剑法│+50级       │基本刀法│+50级       │        │            │;
+#nop ├───恢复状态────┼────┼──────┼────┼──────┼────┼──────┤;
+#nop │气血基础│3381        │等级加成│1589        │高等加成│0           │其他加成│18050       │;
+#nop │精神基础│1964        │等级加成│926         │高等加成│0           │其他加成│2882        │;
+#nop │气血恢复│309.37      │气血治疗│49.79       │精神恢复│389.58      │精神治疗│49.79       │;
+#nop │内力恢复│43.05       │精力恢复│14.32       │内力精纯│100.00%     │加力减耗│0%          │;
+#nop ├───战斗信息────┴────┴──────┴────┴──────┴────┴──────┤;
+#nop │你使用「太极剑法」中的绝招「太极剑·连」攻击对手:喻永思(yu yongsi),命中(986),对方躲闪(1509 │;
+#nop │),招架(1795),最终命中概率12.00%。                                                           │;
+#nop ├───特殊状态────────────────────────────────────────┤;
+#nop │身轻如燕永久有效,躲闪几率增加10%。                                                           │;
+#nop │太极神功永久有效,最大气血 + 5100点。                                                         │;
+#nop │铜皮铁骨永久有效,防御躲闪 + 117级,护甲防御 + 235点。                                        │;
+#nop ├───健康状态────────────────────────────────────────┤;
+#nop │受伤、怒、梯云纵(127秒)、太极剑·随(11秒)、太极剑·连(4秒)、太极剑·缠(1秒)                   │;
+#nop ├───奖励状态────┬────┬──────┬────┬──────┬────┬──────┤;
+#nop │幸运值  │25          │奖励系数│115%        │识图检查│完整奖励    │        │            │;
+#nop ╰────┴──────┴────┴──────┴────┴──────┴──北大侠客行────╯;
+
+#alias {char.status_me.parse.output} {
+    #class char-parse-status-me open;
+
+    #gag {^%*$};
+
+#nop  气血恢复   340.21   气血治疗   65.47    精神恢复   605.26   精神治疗   65.47    ;
+    #action {^│气血恢复│%S%!s│气血治疗│%S%!s│精神恢复│%S%!s│精神治疗│%S%!s│$} {
+        #var char[STATUS][气血恢复] {@trim{%%1}};
+        #var char[STATUS][气血治疗] {@trim{%%2}};
+        #var char[STATUS][精神恢复] {@trim{%%3}};
+        #var char[STATUS][精神治疗] {@trim{%%4}};
+    };
+
+#nop ├───健康状态────────────────────────────────────────┤;
+#nop │ 受伤、怒、梯云纵(127秒)、太极剑· 随(11秒)、太极剑· 连(4秒)、太极剑· 缠(1秒)                   │;
+    #action {^├───健康状态──{(┴|─)+}───┤$} {
+        #line oneshot #action {~^\e[0m│%*\e[2;37;0m{?:|、\x1b\[1;36m(.*)\x1b\[2;37;0m}%s\e[2;37;0m\e[2;37;0m│\e[0m$} {
+            #var char[STATUS][健康状态] {%%%1};
+            #var char[STATUS][持续效果] {%%%2};
+        };
+    };
+
+#nop  持续效果提示     梯云纵(87秒)、太极剑· 随(37秒)                                       ;
+    #action {^ 持续效果提示     %* $} {
+        #local status {@trim{%%1}};
+    };
+
+#nop │幸运值      │2           │奖励系数    │100%        │识图检查    │需要    │;
+    #action {^│幸运值%!s│%d%!s│奖励系数%!s│%d%!.%!s│识图检查%!s│%*│$} {
+        #var char[STATUS][幸运值]   {@trim{%%1}};
+        #var char[STATUS][奖励系数] {@trim{%%2}};
+        #var char[STATUS][识图检查] {@trim{%%3}};
+    };
+
+    #class char-parse-status-me close;
+};
+
+#alias {char.GetStatusMe} {
+    #local silent {%1};
+
+    #local disableOutput {@XTTGetOption{DisableOutput}};
+    #if { "$disableOutput" == "true" } {
+        #echo {<160>命令已被抑制: <420>%p<070>} {char.GetStatusMe};
+        #return;
+    };
+
+    #class char.GetStatusMe open;
+
+#nop ╭───个人状态────┬────┬──────┬────┬──────┬────┬──────╮┐;
+    #action {^╭───个人状态──{(─|┬)+}─╮$} {
+        char.status_me.parse.output;
+    };
+
+#nop ╰────┴──────┴────┴──────┴────┴──────┴──北大侠客行────╯;
+    #action {^╰{(─|┴)+}──%S────╯{|ID=char.status}$} {
+        #class char-parse-status-me kill;
+        #class char.GetStatusMe kill;
+        #echo <120>人物状态信息已更新。<070>;
+        #line gag;
+
+        event.emit char/status;
+    };
+
+    #action {^等等,系统喘气中......$} {
+        #class char-parse-status-me kill;
+        #class char.GetStatusMe kill;
+    };
+
+    #class char.GetStatusMe close;
+
+    status_me;
+};

+ 29 - 0
plugins/basic/cmds/finger.tin

@@ -0,0 +1,29 @@
+#var gOnlineIDs {};
+
+#alias {finger} {
+    #class finger-parse open;
+
+    #var finger-state {};
+
+    #action {^《北大侠客行》$}      {#nop};
+    #action {^姓名%s帐号%s发呆$}    {#nop};
+
+    #action {^{(—)+}$}             {
+        #if { "${finger-state}" == "wait-end" } {
+            #class finger-parse kill;
+        };
+    };
+
+    #action {^%+1..S%+1..s%+1..S%+1..s%+1..ds%s$}  {
+        #if { "%%3" == "{[a-z]+}" } {
+            #if { "${finger-state}" == "" } {
+                #var finger-state {wait-end};
+            };
+            #var gOnlineIDs[%%3] {%%1};
+        };
+    };
+
+    #class finger-parse close;
+
+    #send finger;
+};

+ 81 - 0
plugins/basic/cmds/who.tin

@@ -0,0 +1,81 @@
+#var gOnlineUsers {};
+
+#alias {who-l} {
+    #class who-parse open;
+
+    #action {^【%*】%*(%w)$} {
+        #local obj {@ParseTitle{%%0}};
+        #if { "$obj[id]" == "" } {
+            #echo {解析失败: %%0};
+        };
+        #else {
+            #var gOnlineUsers[$obj[id]] {
+                $gOnlineUsers[$obj[id]]
+                $obj
+            };
+        };
+    };
+
+    who-handle-end;
+
+    #class who-parse close;
+
+    #send {who -l};
+};
+
+#alias {who-pro-l} {
+    #class who-parse open;
+
+    #action {^【%*】%*(%w)$} {
+        #local obj {@ParseTitle{%%0}};
+        #if { "$obj[id]" == "" } {
+            #echo {解析失败: %%0};
+        };
+        #else {
+            #local obj[pro] {$obj[rank]};
+            #unlocal obj[rank];
+            #var gOnlineUsers[$obj[id]] {
+                $gOnlineUsers[$obj[id]]
+                $obj
+            };
+        };
+    };
+
+    who-handle-end;
+
+    #class who-parse close;
+
+    #send {who -pro -l};
+};
+
+#alias {who-all} {
+    #class who-parse open;
+
+    #action {^%S(在线%d人)(活跃 %*%)$} {
+        #echo {%s} {LINE: %%0};
+    };
+
+    #action {^%S(%w){(\s+\S+\(\w+\))*}%s$} {
+        #echo {%s} {LINE: %%0};
+    };
+
+    who-handle-end;
+
+    #class who-parse close;
+
+    #send {who};
+};
+
+#alias {who-handle-end} {
+    #action {^{|共列出 1 位玩家。}系统负担:%S cmds/s, %S comp lines/s。$} {
+        #class who-parse kill;
+    };
+
+    #action {^请用help who查看指令格式。$} {
+        #class who-parse kill;
+    };
+
+    #action {^等等,系统喘气中......$} {
+        #class who-parse kill;
+    };
+};

+ 58 - 0
plugins/basic/title.tin

@@ -0,0 +1,58 @@
+#nop 开启 PCRE UTF 字符类支持。;
+#config {PCRE UTF} ON;
+
+#nop 【一代神相】江湖十大气血高手 牛肉面馆 总管事「绝对不是」天天练功 🐒 ☯️ (Marking);
+#nop 【 西  毒 】桃林书院 生员「喵喵喵喵喵喵喵喵喵喵喵喵喵喵喵喵」挖煤猫 🐎 ⭕️ (Zardc);
+#nop             朱雀 辽东大侠 胡一刀(Hu yidao) [任务发放] ◆◆ <衣钵相承>;
+#nop             丐帮第八代帮主 萧峰(Xiao feng) [任务发放] ◆;
+#nop             大善人 韩员外(Han yuanwai) [任务发放];
+#function {ParseTitle} {
+    #local obj {%0};
+
+    #nop 小技巧:replace 匹配之前不会将 &1~&99 清空,因此匹配可选项时会保留上一次的值。;
+    #nop 所以这里手动清空一下;
+    #local tmp {};
+    #replace {tmp} {%s%s%s%s%s%s%s%s%s%s} {};
+
+    #replace {obj} {^{?:(?:【(.+?)】)?(.*?)(?:「(.+?)」)?(\p{Han}+)( (?:\p{So}\S* )+)?\(([A-Z][a-z']+(?: [a-z]+)*)\)(?: <(.*?)>)?(?: \[(.*?)\])?(?: ((?:◆)+))?(?: <(衣钵相承)>)?}$} {
+        {rank}      {@trim{&1}}
+        {title}     {@trim{&2}}
+        {nick}      {@trim{&3}}
+        {name}      {&4}
+        {emoji}     {@trim{&5}}
+        {id}        {@toLower{&6}}
+        {status1}   {&7}
+        {status2}   {&8}
+        {isJobNPC}  {&9}
+        {yibo}      {&10}
+    };
+
+    #nop 注意 #replace 刚替换完时,得到的是字符串,最后还要再进行一次赋值,才能够将它结构化;
+    #local obj {$obj};
+
+    #if { "$obj[name]" == "" } {
+        #return {};
+    };
+
+    #if { "$obj[title]" == "☆%S%s%S☆" } {
+        #local partyInfo {$obj[title]};
+        #replace partyInfo {^☆%S%s%S☆$} {{party}{&1}{partyRank}{&3}};
+        #local partyInfo {$partyInfo};
+        #local obj[title] {$partyInfo[party];$partyInfo[partyRank]};
+        #local obj[party] {$partyInfo[party]};
+        #local obj[partyRank] {$partyInfo[partyRank]};
+    };
+
+    #replace obj[title] {%+1..s} {;};
+    #replace obj[emoji] {%+1..s} {;};
+    #replace obj[rank]  {%+1..s} {};
+
+    #local field {};
+    #foreach {rank;title;nick;name;emoji;id;status1;status2;isJobNPC;yibo} {field} {
+        #if { "$obj[$field]" == "" } {
+            #unlocal obj[$field];
+        };
+    };
+
+    #return {$obj};
+};