跳转至

OlivaDice For OlivOS 自定义牌堆编写指南

For Ver.3.3.9(1059)

世界是属于每一个人的。要创造一个充满逻辑并尊重每一个人的世界。
——《Новый Элемент Расселения》A.D.1960 Москва

有关基础搭建的指引请参考【教程】手把手教你搭建青果骰

自定义牌堆

牌堆是一种广泛运用在骰子机器人中的,用于在限定范围的条目之中,抽取一个或多个内容的功能,这项功能除了可以使用骰子内置的牌堆以外,还可以由骰主通过添加扩展文件的方法来进行扩展,从而让骰子加载各种各样的第三方牌堆。在骰子的野蛮发展阶段,各个骰子开发者发展出了多上不互通的牌堆格式,常见的为青果 - 溯洄系/Json塔系/Yaml梨系/Excel

总体介绍

作为一个扩展文件,牌堆的格式多种多样,青果系支持了其中的大部分,接下来会为你分别介绍这些格式。
在此之前,你可以提前了解的是,无论牌堆文件本身是哪种格式,牌堆本质上是一种:单一牌堆名下打包多个牌面的内容模式,它的格式通常都是比较简单的。

青果系/Json牌堆

青果系和溯洄系在创立之初就开始使用了一种名为Json的格式,这种格式的全名为:JavaScript Object Notation, JS对象简谱,是一种起源于编程语言JavaScript的序列化数据格式,如果只是编写牌堆,你不需要对其有完整的了解,但是,相信我,跟随Json快速入门的引导,它很容易上手。

对于最原本的Json牌堆,这其实是一种非常简单的格式,它的格式通常是下面这样的:

{
    "牌堆名A": [
        "牌面A1",
        "牌面A2",
        "牌面A3",
        "牌面A4",
        "牌面A5",
        "牌面A6",
        "牌面A7"
    ],
    "牌堆名B": [
        "牌面B1",
        "牌面B2",
        "牌面B3",
        "牌面B4",
        "牌面B5"
    ],
    "牌堆名C": [
        "牌面C1",
        "牌面C2",
        "牌面C3"
    ],
}

可以看到,牌堆的格式为一系列以牌堆名为键,以牌面组成的数组为值的字典所组成,实际抽取时,用户将会使用.draw 牌堆名B来从牌面B1牌面B5的5个牌堆中抽取一个。
在加载牌堆时,你需要将牌堆放置在deckclassic/目录,这个目录需要你查看骰主手册 - 配置文件章节进行确认;牌堆文件会在插件加载时被逐个读取,将其中的牌堆以牌堆名为单位进行读取,并在这个过程中自动生成相关的帮助文档;重名的牌堆名会遵守逐次覆盖的原则,即后一次加载的内容会覆盖前一次加载的内容。

牌堆引用

我们通常需要在一个牌堆的文本中抽取另一个牌堆,例如一些人物卡作成的场景,或是一些经过了精心排版的牌堆。
所以我们在牌堆中支持了以下两种引用的方法:

  • {牌堆名} 表示不放回抽取一个牌堆名的牌堆。
  • {%牌堆名} 表示放回抽取一个牌堆名的牌堆。

例如对于以下牌堆

{
    "牌堆名A": [
        "牌面A1{%牌堆名B}牌面A2"
    ],
    "牌堆名B": [
        "牌面B1"
    ]
}

那么,使用指令.draw 牌堆名A抽卡的结果就是:牌面A1牌面B1牌面A2

隐藏牌堆

当你已经理解了牌堆引用的用法时,你会发现,你在一些牌堆中需要用很多的琐碎且复杂的嵌套结构,通过多次的引用来组成你最终抽取到的牌堆,但这些中间过程单独使用往往是毫无意义的,你也许会产生想要隐藏它们的想法,这时候,你就需要了解隐藏牌堆的使用方法。

{
    "牌堆名A": [
        "牌面A1{%_牌堆名B}牌面A2"
    ],
    "_牌堆名B": [
        "牌面B1"
    ]
}
可以参考如上这样一个牌堆,其中的_牌堆名B,由于在开头添加了下划线,所以青果核心将会将其识别为隐藏牌堆,从而禁止用户通过.draw指令将其抽取出来。

加权牌堆

如果你已经理解了上面的这些内容,你会发现一个显而易见的问题,这些牌面被抽出的概率都是相等的,但有时你会希望它们之间有些出现概率的差异,这有可能式因为某些特定的规则书,也有可能是一些娱乐化的诉求(例如模拟明日方舟抽卡),你可能需要牌堆名2牌面B1出现的概率是80%牌面B2出现的概率是10%,而牌面B3牌面B4出现的概率是5%,常见的做法便是编写这样一个牌堆,这个牌堆中塞进了20张牌面,其中有16牌面B1,有2牌面B2,有1牌面B3,有1牌面B4,也就是如下的牌堆:

传统牌堆的概率控制
{
    "牌堆名B": [
        "牌面B1",
        "牌面B1",
        "牌面B1",
        "牌面B1",
        "牌面B1",
        "牌面B1",
        "牌面B1",
        "牌面B1",
        "牌面B1",
        "牌面B1",
        "牌面B1",
        "牌面B1",
        "牌面B1",
        "牌面B1",
        "牌面B1",
        "牌面B1",
        "牌面B2",
        "牌面B2",
        "牌面B3",
        "牌面B4"
    ]
}

但是这样编写,既不直观,也不优雅,因为我们只能看到满屏的重复牌面,后续想要修改还得数一数每种有多少个,一不小心可能还会少放几个,所以我们开发出了这样一种新的格式来实现相同的功能:

{
    "牌堆名B": [
        "::16::牌面B1",
        "::2::牌面B2",
        "::1::牌面B3",
        "::1::牌面B4"
    ]
}

这种格式下,可以通过简单的修改数字来实现不同牌面拥有不同的权重(牌数),进而实现上述效果。
进一步的,我们还将掷骰表达式引入到了这个过程中,你还可以将上述格式中表示权重的数字用表达式替代,这样就可以实现在每次抽取时实时生成概率:

{
    "牌堆名B": [
        "::2d16::牌面B1",
        "::2d3+3d4::牌面B2",
        "::1d6+2::牌面B3",
        "::1d6::牌面B4"
    ]
}

程心自定义解析

类似权重牌堆的格式,你也可以通过在牌面文本开头加上::【CCPK】::这样的前缀1,来让整个牌堆文本基于程心自定义的解析器进行解析2

{
    "牌堆名B": [
        "::【CCPK】::俺晓得了【艾特】,1+1=【计算1+1】"
    ]
}

青果系/Json5牌堆

青果系在2022年8月前后提出了一种新的Json5牌堆格式,用来解决Json格式不支持注释,并且格式比较严格的问题;总体来说,原本的传统Json格式的牌堆在新的Json5格式里也是完全兼容的,除了你在Json快速入门中看到的那些基本的规则,它还将支持Json5快速入门中提到的那些新的规则,比如说允许数组和对象中出现多余的逗号,允许注释之类的。
为了便于文本编辑器对Json5格式进行染色,所以我们也支持了.json5后缀命名的牌堆文件。

{
    "牌堆名B": [
        "::16::牌面B1",  // 16张
        "::2::牌面B2",   //  2张
        "::1::牌面B3",   //  1张
        "::1::牌面B4",   //  1张
    ]
}


  1. 出于兼容性考虑,这些前缀可以发挥相同的效果:::【CCPK】::::【EPK】::::【程心】::::【铃心】:: 

  2. 如果需要让权重牌堆与程心自定义解析共存,你需要将权重放在这个标记之前,例如::16::【CCPK】::