编写自定义回复
编写自定义回复
本节内容
本节将展示自定义回复编写的进阶部分,请善用侧边栏和搜索,按需阅读文档。
在部分内容中,我们假定你了解海豹变量机制和正则表达式。如果你对正则表达式还很陌生,可以阅读以下教程或在互联网自行搜索学习。
第一个自定义回复
首先我们打开「自定义回复」页,新建一项自定义回复。
使用 .text 帮助测试
.text <文本>
将是你的一大助力,它会输出后面文本的执行结果,你可以将它看成不需要触发词的自定义回复。
当然,在采用 .text
指令进行 debug 时,可能出现因为测试的内容对变量造成影响,而不得不频繁复制黏贴清空指令的情况。此时建议专门开一个一两个字即可触发的自定义回复,用来测试。
嵌入 CQ 码
返回内容可以嵌入 CQ 码。CQ 码文档见 CQ 码列表。
自定义回复中分「条件」和「结果」两个部分。在 配置 - 自定义回复 中,我们已经了解了一些简单的回复编写,下面将补充介绍进阶内容。
触发条件
文本匹配:模糊匹配
模糊匹配将比较收到的消息与指定文本,内容相似时触发。
比较定义在 dice/ext_reply_logic.go
中,内容 jaro 和 hamming 平均值高于阈值(0.7)被认为是相似:
func strCompare(a string, b string) float64 {
va := strsim.Compare(a, b, strsim.Jaro())
vb := strsim.Compare(a, b, strsim.Hamming())
return (va + vb) / 2
}
模糊匹配未命中
模糊匹配可能出现感觉能匹配上,但实际上没办法匹配上的情况。我们更建议你使用「包含文本」或「正则匹配」。
文本匹配:正则匹配
使用正则匹配时,直接在要匹配的文本一栏中写入正则表达式即可。
正则匹配可以将回复中的一部分存入变量中以备调用:
正则匹配:^购买(.+)
输出文本:{$t玩家}购买了{$t1}
示例
正则匹配会将满足匹配的整条消息存入 $t0
,而正则中的分组会按顺序存入 $t1
$t2
等中。在如上例子中,就是将 购买
后用括号括起来的部分存入了 $t1
中,从而可以进行调用。
如额外存在组名,如 (?P<A>cc)
,将会额外存入 $tA
。
不要使用某些前缀!
由于 .
。
/
!
等符号会作为海豹中指令的前缀,因此作为前缀时可能导致将其识别为指令而非自定义回复的情况,建议换成别的前缀。
正则中匹配 CQ 码
海豹支持用正则匹配 CQ 码,但是如果你这么做了,请在 [
]
前面进行转义。
示例:^\[CQ:xxx,xx=xxx\]
表达式为真
在「表达式为真」匹配中,只需要直接在匹配文本中写出形如 变量名 == 需要的值
的形式即可,不需要使用任何 {}
。
回复结果
在回复文本中,可以调用一些 变量,也可以嵌入 内置脚本语言。
嵌入脚本语言
示例
未赋值的变量
所有变量在未被赋值时被调用的值都为 0。
执行块
{% %}
被称为执行块。由 {% %}
括起来的部分会被作为代码执行,输出最后一个语句的结果。执行块中的两个语句之间要使用 ;
隔开。
如果想要输出字符串,则应该用 `
/ "
/ '
括上。
- 例:形如
{% \$t1="114514" %}
的式子会输出114514
。
结果中调用变量
若想在结果中调用变量,请用反引号。目前海豹只支持在反引号中调用变量。
下面是一个简单的示例,这里的第一句也是最后一句,所以它的结果会被输出。
.text {% $t测试=1 %}
if
示例:使用 {%
$t测试=1;
if $t测试==1 {$t输出="赞美木落"};
if $t测试==2 {$t输出="快点更新"};
if $t测试!=2&&$t测试!=1 {$t输出="群主女装"}
%}
{$t输出}
首先给 $t测试
赋值为 1,然后进入判断:
- 如果
$t测试
等于 1,则变量$t输出
等于"赞美木落"
; - 如果
$t测试
等于 2,则变量$t输出
等于"快点更新"
; - 如果
$t测试
既不等于 2 也不等于 1,则变量$t输出
等于"群主女装"
;
最后,输出变量 $t输出
。
容易误解的 if 使用
目前海豹语并不支持 else if
,if
和 else
是一对一匹配的。所以当形如:
if xxx {xxx};
if xxx {xxx}
else {xxx}
的语句出现时,并不是 if elseif elseif else
的关系!即使满足了第一个 if
,其结果也是执行 else
中的内容!
示例:变量运算
{%
$t0=1;
$tRand=d6;
if $t0==1 {$t0=$t0+$tRand}
%}
{$t0}
在这个例子里,我们先给 $t0
赋值为 1,然后判断 $t0
是否等于 1,若通过则 $t0
的值增加 1d6,最后输出结果。
更多示例片段
牌堆与自定义回复的结合
以养猫功能中猫好感度为例:
{%
$mCatFavor<=100 ? `#{DRAW-第一档猫好感}`,
$mCatFavor<=250 ? `#{DRAW-第二档猫好感}` ,
$mCatFavor<=600 ? `#{DRAW-第三档猫好感}` ,
$mCatFavor<=1500 ? `#{DRAW-第四档猫好感}` ,
$mCatFavor<=2500 ? `#{DRAW-第五档猫好感}` ,
1 ? `#{DRAW-第六档猫好感}`
%}
在这一脚本中,根据猫好感度 $mCatFavor
不同,需要输出不同回复的机制。
其它写法
除了形如
{%
判断1 ? `#{DRAW-牌组1}`,
判断2 ? `#{DRAW-牌组2}`,
判断3 ? `#{DRAW-牌组3}`,
1 ? `#{DRAW-牌组4}`,
%}
的写法外,还可以使用:
{%
if 判断1 {
$tRand=d6;
$t输出=$tRand==1?`内容1`,
$t输出=$tRand==2?`内容2`,
$t输出=$tRand==3?`内容3`,
$t输出=$tRand==4?`内容4`,
$t输出=$tRand==5?`内容5`,
$t输出=$tRand==6?`内容6`
};
if 判断2 {$tRand=d10;$t输出=$tRand==1?`内容1`,……};
if 判断3 {$tRand=d10;$t输出=$tRand==1?`内容1`,……};
%}
实质上没有太大区别,可根据喜好选择。
多回复行的错误使用
以踢海豹为例,这一自定义回复的多行输出实现上并不是:
{$t输出0}
{$t输出1}
{$t输出2}
{$t输出3}
而是在为四个 $t输出
变量赋值时,于内部写上 \n
,采用 {$t输出0}{$t输出1}{$t输出2}{$t输出3}
的形式。
这是因为如果某一变量可能为空时,如果采用第一种分行的写法,会出现这样的效果:
示例
可以看见,在中间会出现突兀的空行。这是因为虽然并没有在变量内部赋值 \n
,但是由于海豹读取时会按照写的格式读取,因此在应当是 $t输出2
的一行中,会照样调用 {$t输出2}
,照常空行。
所以,如果想要某个变量为空时,看不出来这里应该存在什么,就最好多做几次实验,好好规划一下换行符 \n
的位置。
限定每人/每群每天一次
海豹提供了一系列时间变量来调用,以打卡指令为例,可以采用如下两种写法中的一种(示例为每人每天一次,如要每群自行将 $m
换成 $g
):
写法 1 文本匹配:你需要的文本 表达式为真:$m变量 != $tDate
回复:{if 1 {$m变量=$tDate}}你需要的回复文本
$m变量
作为标记变量,用if
是防止它出现在回复文本中。
文本匹配:你需要的文本 表达式为真:$m变量==$tDate
- 可以不写在另一条里,选择放到相较于上一条的后面,利用海豹从上往下逐个匹配的机制达成相同效果
回复:在一天触发多次时的回复
写法 2 文本匹配:你需要的文本 回复:
{%
if $m变量!=$tDate {
$t输出=`你需要的回复文本`;
$m变量=$tDate//对其赋值,作为标记
} else {
$t输出=`在一天触发多次时的回复`
}
%}
{$t输出}
以上两种写法实现效果没有差别,具体使用哪种请自行决断。
条件语句嵌套条件算符,多条件条件语句
以石头剪刀布为例,为了实现骰子随机出招的效果,令 $tRand=d3
,然后根据 $tRand
的情况赋值 $tDicePlay
。通过骰子出招和玩家出招两个变量判断,输出游戏结果,并记录场次。
为了防止直接使用 {%%}
进行赋值导致的变量显示,需要在最外面写 if 1
,则在生成 $tRand
之后再次判断的时候,可以使用 $tDicePlay=条件算符
,或是再新开一行用条件算符或者条件语句实现。
以下给出在同一个 if
内直接赋值的写法和新开一行使用条件语句的写法:
{% //在同一个if内直接赋值。可以在赋值时使用条件算符。
if 1 {
$tRand=d3;
$tDicePlay=$tRand==1?"石头",
$tRand==2?"剪刀",
1?"布"
}
%}
{% //新开一行赋值
if 1 {
$tRand=d3;
} ;
if $tRand==1 {$tDicePlay="石头"};
if $tRand==2 {$tDicePlay="剪刀"};
if $tRand==3 {$tDicePlay="布"}
%}
两种写法实现效果相同,石头剪刀布内在这里采用了第一种,实际上没有差别。
生成骰子出招并获取玩家出招之后,就开始判断。这里除了平局可以使用 $tDicePlay==$t0
省事之外,其他的都需要在条件中用多个进行嵌套。
条件判断
豹语语法中,判断时条件中的 ||
和 &&
是从左往右计算的,如果后面有需要优先计算与或的东西,请加好括号。
if $t0==$tDicePlay {
$t输出=`那我出{$tDicePlay}!{$t玩家}出的是{$t0}啊,我们平局了。`;
$mPlayerTime=$mPlayerTime+1
};
if $t0=="剪刀"&&$tDicePlay=="石头"||($t0=="石头"&&$tDicePlay=="布")||($t0=="布"&&$tDicePlay=="剪刀") {
//后两个与需要单独计算,加上括号
$t输出=`那我出{$tDicePlay}!{$t玩家}出的是{$t0}啊,我赢了。`;
$mPlayerTime=$mPlayerTime+1;
$mPlayerLose=$mPlayerLose+1
};
if $t0=="石头"&&$tDicePlay=="剪刀"||($t0=="布"&&$tDicePlay=="石头")||($t0=="剪刀"&&$tDicePlay=="布") {
$t输出=`那我出{$tDicePlay}!{$t玩家}出的是{$t0}啊,你赢了。`;
$mPlayerTime=$mPlayerTime+1;
$mPlayerWin=$mPlayerWin+1
}
AxxxxxxxB
型文本
同时使用前缀和后缀匹配,以匹配 前缀匹配:A
后缀匹配:B
回复:怎么辉石呢
示例
随机看图

单人模组
示例
具体实现,第一段

第二段

这两段较为常规,第三段开始变形了:

{%
if $mStory == 4 { $mStory = 5 };
if $mStory == 3 { $mStory = 4 };
if $mStory == 2 { $mStory = 3 };
$mStory == 3 ? '这个村子有一户人家,门前有两棵树',
$mStory == 4 ? '一棵是函树,一棵是反函树',
$mStory == 5 ? '我讲完了。',
1 ? '?'
%}
{% if $mStory == 5 { $mStory=0 } %}