跳转至

OlivaStory For OlivOS 自定义故事路线图编写指南

For Ver.3.3.24(1074)

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

开始使用

OlivaStoryCore是在OlivaDice3.3.24版本中同步发布的新一代文游引擎,它的设计初衷是为了让骰主能够更加方便地进行文游的设计,以文游的方式进行带团,以及游玩一些类似向火独行的文游,为骰主提供了更多的自由度。
该模块需要加载一种故事路线图扩展文件,这种文件通常使用Json或者Json5编写。

指令设计

OlivaStoryCore提供了以下两个指令,可以用于故事的基础启动和结束:

  • .story [故事名称] 用于启动一个故事。如:.story 向火独行
  • .story end 用于结束当前故事。

此外,你还可以在有对应故事选项的前提下,直接输入对应序号来选择选项,如:

Bot:
你勇敢地抵抗,但这男人的块头和决心还是压服了你。最后他打出一记重拳,你摔倒在地,眼前顿时一片黑暗。

选项如下:
1 - 继续
2 - 就此放弃

用户:
2

加载地址

对于一般使用,你只需要将你编写或者收集的故事路线图文件放到plugin\data\OlivaStory\unity\extend\story目录下即可,这个目录会在你第一次运行时生成,重载插件后将会将你的文件加载进去。

故事路线图

一个简单的故事路线图的文件格式如下

{
    {
        "name": "故事名称",
        "author": "lunzhiPenxil",
        "version": "1.0.0",
        "svn": 1,
        "ingress": "1",
        "description": "故事描述",
        "story": [
            {
                "flag": "1",
                "text": "节点故事描述",
                "type": null,  // 节点类型,null为普通节点,没有此项时默认为null
                "selection": [
                    {
                        "text": "选项1",
                        "toType": "jump",
                        "to": "2"
                    },
                    {
                        "text": "选项2",
                        "toType": "jump",
                        "to": "3",
                        "hideNote": "知晓秘密"  // 隐藏选项条件
                    }

                    // ...  各个选项
                ]
            }

            // ...  各个故事节点
        ]
    }
}

基本信息

可以看到,故事路线图文件是一个object,主要由两部分组成:故事信息故事节点,其中除了story以外的内容都是故事信息,具体对照如下:

名称 类型 说明
name string 故事名称
author string 作者
version string 版本号
svn number svn版本号
一个递增的整数版本号
用于识别更新递进关系
ingress string 入口节点
开始故事时将会从这个节点开始
对应节点的flag
description string 故事描述
story array 故事节点
详情请看后文

故事节点

story是一个array,里面包含了所有的故事节点,每一个故事节点都是一个object,其中有如下:

名称 类型 说明
flag string 节点标识
用于标识该节点
它应当在众多节点之间保持唯一
PS: 在selection中使用toType:jump时,to的值就是这个
text string 节点故事描述
type string 节点类型
默认为nullnull为普通节点
其它值请看后文
selection array 节点选项
详情请看后文

各节点类型

type字段用于标识节点的类型,目前支持的类型有:

名称 说明
null 普通节点
"end" 结局节点
当玩家选择了这个选项时,故事将会结束
"ra" 检定节点
这种类型的节点要求玩家使用一次ra指令才能继续
将会根据检定结果选择selection中的选项

null | 普通节点

这是最基本的节点类型,它没有任何特殊的功能,只是一个普通的节点,当玩家选择了这个选项时,将会向玩家提供你所列出的选项,当玩家选择了某个选项,故事将会继续进行。

{
    "flag": "节点2",
    "text": "你勇敢地抵抗,但这男人的块头和决心还是压服了你。最后他打出一记重拳,你摔倒在地,眼前顿时一片黑暗。",
    "selection": [
        {
            "text": "继续",
            "toType": "jump",
            "to": "节点108"
        },
        {
            "text": "就此放弃",
            "toType": "jump",
            "to": "节点456"
        }
    ]
}

回显如下:

你勇敢地抵抗,但这男人的块头和决心还是压服了你。最后他打出一记重拳,你摔倒在地,眼前顿时一片黑暗。

选项如下:
1 - 继续
2 - 就此放弃

"end" | 结局节点

这种节点是整个故事的结局,可以有很多个,所以它将没有selection
此外,你可以使用endFlag字段来唯一的标识这个结局。
额外的,如果你写了一个type:null的普通节点,但是缺少selection或为空,那么这个节点也将被视为结局节点。

{
    "flag": "节点65",
    "text": "火舌舔上你的双腿。你的眼中充满泪水。你被烟幕笼罩了;\n\
火焰先你一步,你失去意识,被烈焰烧死!【剧终】。",
    "type": "end",
    "endFlag": "bad_end_1"
}

回显如下:

火舌舔上你的双腿。你的眼中充满泪水。你被烟幕笼罩了;
火焰先你一步,你失去意识,被烈焰烧死!【剧终】。

道路的尽头

"ra" | 检定节点

这种节点要求玩家使用一次ra指令才能继续,而不是直接选择选项,它将会根据检定结果选择selection中的选项。
你依然可以使用selection列出这个节点可以跳转的选项。
但是这些选项需要跟随raMap所列出的条件,当条件满足时,将会自动选择这个条件对应的选项。
raMap是一个array,里面包含了所有的检定条件,每一个检定条件都是一个object,其中有如下:

名称 类型 说明
para string 检定条件
使用{raRollValue}表示检定结果
使用{raSkillValue}表示技能值
selection number 选项序号
当检定条件满足时,将会自动选择这个选项
序号从0开始

其中para字段的值是一个string,它是一个python的表达式(使用eval函数实现),你可以使用以下变量{变量名}的方式引入变量,可以使用的变量有如下:

名称 类型 说明
raRollValue number 检定掷骰结果值
raSkillValue number 技能值

当正常情况下,para表达式应当返回一个bool类型的值,判断将会从上往下依次进行,当这个值为True时,它将会选择selection中对应的选项,并且忽略它以下的判定条件,所以建议将最可能发生的情况放在最前面,并且在最后放置一个True条件,以防止所有条件都不满足时的情况。

此外需要注意,raMap中的节点的selection是对应实际的selection中的自上而下顺序,并且是从0开始的。

{
    "flag": "节点65-2",
    "text": "火舌舔上你的双腿。你的眼中充满泪水。你被烟幕笼罩了;\n\
也许是你的想象,但你认为你感觉到铁链有一点点松动。\n\
你用尽全力挣扎,全然不顾铁链在你的手腕上拴得有多么牢固。\n\
进行一次“力量”检定。\n\
使用[.ra 力量]进行检定,请确保使用该指令前已经录入该技能……",
    "type": "ra",
    "raSkillName": "力量",
    "raMap": [
        {
            "para": "{raRollValue}<={raSkillValue}",
            "selection": 0
        },
        {
            "para": "True",
            "selection": 1
        }
    ],
    "selection": [
        {
            "text": "成功",
            "toType": "jump",
            "to": "节点93"
        },
        {
            "text": "失败",
            "toType": "jump",
            "to": "节点77"
        }
    ]
},

回显如下:

火舌舔上你的双腿。你的眼中充满泪水。你被烟幕笼罩了;
也许是你的想象,但你认为你感觉到铁链有一点点松动。
你用尽全力挣扎,全然不顾铁链在你的手腕上拴得有多么牢固。
进行一次“力量”检定。
使用[.ra 力量]进行检定,请确保使用该指令前已经录入该技能……。

使用[.ra]指令完成检定以继续

节点选项

selection是一个array,里面包含了所有的节点选项,每一个节点选项都是一个object,其中有如下:

名称 类型 说明
text string 选项描述
toType string 选项跳转类型
目前仅有jump,为跳转到指定节点
to string 选项跳转目标
toTypejump时有效,表示选择该选项时跳转到的下一个节点
{
    "text": "哼哼哼啊啊啊啊啊啊啊啊啊",
    "toType": "jump",
    "to": "节点666"
}

隐藏选项

你可以使用hideNote字段来隐藏某个选项,当玩家满足了这个条件时,这个选项将会被解除隐藏,否则即使玩家知道这个选项,也无法选择它。

在故事节点中使用

在故事节点中使用hideNote字段,那么玩家在经过这个节点后,就会在本轮故事中携带着这个字段中所标示的所有线索了,这将会影响到后续玩家面对选择时的效果。

{
    "flag": "节点159",
    "text": "杰哥在阴影中停顿了一下:“你有以前那些人没有过的东西。也许你能挺过去。如果你想知道更多,今天晚上再来找我。九点钟。”他举起一根枯瘦的手指。“不要被人跟踪了。”\n\
杰哥又用袖子抹了抹鼻子。“走吧。他们一直监视着我。还有,阿伟?别想着逃走。你成功不了的。”\n\
你退回阳光下。阳光刺目,你十分地动摇。\n\
你发现了一个秘密。今天晚些时候,会有文字提示你去继续之前的约定。到那时,你可以前往。",
    "hideNote": ["与杰哥的约定","你心神不宁"],
    "selection": [
        {
            "text": "继续",
            "toType": "jump",
            "to": "节点160"
        }
    ]
}

同时,回显不会有任何变化,如果有需要,请在文本中提示玩家,他们现在获得了线索。

在节点选项中使用

在节点选项中使用hideNote字段,如果玩家携带着对应的线索,那么这个选项将不会被隐藏,否则玩家看不到这个选项,即使玩家知道这个选项,也无法选择它。

{
    "flag": "节点180",
    "text": "天色渐晚,你回到自己家,简单地吃了一顿晚饭。你反常地沉默。吃饭时,似乎有一种你难以理解的急迫感。\n\
如果你之前和人有约,现在是时候赴约了。\n\
你想要……",
    "selection": [
        {
            "text": "到外面眺望星空",
            "toType": "jump",
            "to": "节点131"
        },
        {
            "text": "[秘密]赴约",
            "hideNote": "与杰哥的约定",
            "toType": "jump",
            "to": "节点200"
        },
        {
            "text": "[秘密]发疯",
            "hideNote": "你心神不宁",
            "toType": "jump",
            "to": "节点220"
        }
    ]
}

那么当玩家没有经历过节点159时,将会看到如下回显:

天色渐晚,你回到自己家,简单地吃了一顿晚饭。你反常地沉默。吃饭时,似乎有一种你难以理解的急迫感。
如果你之前和人有约,现在是时候赴约了。
你想要……

选项如下:
1 - 到外面眺望星空

而当玩家确实经历过节点159时,他们将携带对应的线索,将会看到如下回显:

天色渐晚,你回到自己家,简单地吃了一顿晚饭。你反常地沉默。吃饭时,似乎有一种你难以理解的急迫感。
如果你之前和人有约,现在是时候赴约了。
你想要……

选项如下:
1 - 到外面眺望星空
2 - [秘密]赴约
3 - [秘密]发疯

建议不要将hideNote用于type:ra的节点,因为这样会导致玩家无法进行检定,从而无法继续游戏。

同时,如果在一次故事中,玩家的故事运行到这个节点时,你的选项中没有任何一个选项在玩家当前所持有的线索下可以被显示,那么这个节点将会被视为type:end的节点,玩家的故事也会直接结束,请好好利用这个特性。