本页面将介绍零编程基础为该游戏制作mod的方法,你只需要了解如何编辑 json 即可学会制作 mod.


Edge100.png
需要校对
这篇文献的内容需要严谨校对,以免被防剿局篡改过的版本传递到更多学徒手中。你可以帮助密教模拟器中文维基来 完善它
我不会编程啊,求个大佬帮我看看我有没有写错的地方吧orz
上传mod至创意工坊的方法参见 https://weatherfactory.biz/daybreak-in-the-invisible-serapeum/
Q:我该使用什么工具呢?

如果你有一定的编程基础,那你就不用来看这个指南了,出去!你可能会某种顺手的的 IDE,在 debug 的时候会非常方便。

Q:我没有编程基础,也不想踏入编程的世界……

json 是一种储存文本信息的语法。在代码中,冒号(:)左边的叫做“字段”,右边即为字段下储存的“”,数据之间用逗号(,)分隔。除了数值和true和false之外,其他的(包括字母/汉字和这三种结合)都需要加双引号。
任何可以编辑 json 的软件都可以用来制作 mod, notepad++ 甚至记事本都可以,网络上也有不少在线的 json 编辑器,(ps. 这里比较推荐Visual Studio Code,支持中文,方便转码)可以提供格式化的校验。顺带一提, json 中的提行不是必要的,如果你愿意,完全不换行也是可以的,不过为了代码整齐好看便于调试,一般我们会按照自己的习惯分行。当然这是指图片以外的部分。你可能需要使用 Photoshop, SAI 等图片处理软件绘制、处理图片。
英文版教程:https://cultistsimulator.gamepedia.com/Modding

首先,在 "C:\Users\[你的用户名]\AppData\LocalLow\Weather Factory\Cultist Simulator\mods" 下建立你的 mod 文件夹。这个文件夹中将包含 content, images 两个子目录,以及 synopsis.json 文件和可选的cover.png。

mod 内容的 json 储存在 content 文件夹中,包括: elements, recipes, endings, legacies, decks, verbs; mod 中的图片文件则需要储存在 images 目录下,包括 elements, endings, aspects, burns, legacies, cardbacks,statusbaricons,verbs,ui。


如果你的游戏卡在主菜单的黑屏上,很可能你忘记了代码中的某个字符。最有可能的是,'','在一行代码的末尾丢失,或者括号没有用']或'}结束

现在有了报错界面,出现黑猫猫的原因可能是拼错字段名或id名(但也可能是别的错)

(注:所有json文件均需采用utf-16编码。win7是不支持转码到utf-16的,需要依靠别的软件或一个可靠的朋友,如果你是win10当我没说

synopsis.json

synopsis.json 文件记录了关于这个 mod 的一些信息,它的格式如下:

{
    "name": " mod名 ",
    "author": " 作者 ",
    "version": " 版本号 ",

    "description": " 一段简短的描述。 ",
    "description_long": " 一段较长的描述。 "
}

这些文字将显示在游戏里的模组选择页面中。由于文字适配的原因,建议使用英文。

content

该文件夹下需要储存各种游戏内容的 json 文件,这些文件都以如下方式开头和结尾:

{" 对象名 ":
    [
        ……
    ]
}

对象名说明了这个文件里包含的都是什么类型的对象,下面会给出解释。

elements

卡牌

游戏中的卡牌属于 elements. 举个例子,想要添加一个秘史(12)工具,就叫“漫宿罗盘”好了,那么它的代码可能是这样的:

{"elements":
    [
        ……
        {
            "id": "mymod_toolsecrethistoriesf",
            "label": "漫宿罗盘",
            "description": "世界的形状在变化,但也存在永恒的东西。",
			"aspects": {
                "secrethistories":12,
                "tool":1
            },
        },
        ……
    ]
}

上面的代码中,

  • id 字段的值是需为一段独一无二的文字,以和其它对象区分;当你在其它地方引用这个对象时会用的这里的值
  • label 字段是对象的名字,它会显示在卡牌和卡牌信息框上
  • description 字段是对象的描述,它会显示在卡牌信息框上
  • aspects 字段表示卡牌具有的性相,它的值要用 {} 括起来
    • secrethistories 字段表示秘史,值12表示有12点
    • tool 字段表示工具,值1表示存在这个性相,当然也可以表示该性相有1点
    • 这里的字段用到的就是各个性相的 id, 其它性相的 id 可以
      1. 在本维基对应的性相页面查到
      2. 模块:Query/data页面查到(善用Ctrl+F页面搜索功能)
  • 更多字段参见Modding/elements

性相

游戏中的性相也属于 elements. 如果想添加一个性相,它的代码可能是这样的:

{"elements":
    [
        ……
        {
	        "id": "mymod_masterwork",
	        "label": "著作",
	        "isAspect": true,
	        "description": "大师出品。"
        }
        ……
    ]
}

与卡牌相比,性相多出了一个字段 isAspect,这个字段就是在告诉程序这个对象是一个性相。出了上面列举的字段以外,性相还可以有下面的字段:

字段名 类型 用途
noartneeded 布尔值 是否需要图片,默认为 false, 即需要图片
isHidden 布尔值 是否为隐藏性相(用于 recipe ),默认为 false, 即不隐藏
icon 字符串 图标的文件名,如果文件名和 id 一致则不需要填写

recipes

recipes是使用行动与卡牌交互的一种过程,可以实现多样化的功能

{
	"id": "dreamfunds",
	"label": "购买一剂鸦片酊",
	"actionId": "dream",
	"requirements": {
		"funds": "1"
	},
	"effects": {
		"contentment": "1",
		"funds": -1
	},
	"startdescription": "在面临特别重大的危机时,我可以拜访一个口风严实的药剂师,买一剂鸦片酊来维持我香甜的梦境。但是这只能适用于面临重大危机的情况。[这是一种昂贵而高风险的获取安逸的途径。这可能会导致生病或绝望。]",
	"description": "噢,我得到了深深的平静。但我不应该再这样做了。",
	"warmup": "30",
	"craftable": "true",
	"alt": [{
			"id": "grailinduction",
			"chance": "30",
			"additional": "true"
		}, {
			"id": "despairrisk",
			"chance": "10",
			"additional": "true"
		}, {
			"id": "presickness",
			"chance": "10",
			"additional": "true"
		}
	]

我们以此为例

  • id是recipe对象的唯一标识符
  • label是游戏中显示的文本标识,具体对recipes而言就是点开行动框后显示的文本标题
  • actionId,该recipe所使用的行动的id
  • startdescription,该recipe开始进行时行动框显示的文本
  • description则是它结束后显示的文本

{
        "recipes": [
                {
                        ...
                        "startdescription(或description)": "[前面内容]
                        @#id1|内容1
                                #id2|内容2
                                #id3|内容3
                                ...
                                #id n|内容n
                                #|默认内容@
                        [后续内容]",
                        ...
                },
                ...
        ]
}
以上内容表示在此recipe中拥有卡牌1,性相1或uniquenessgroup(见Modding/elements)1时显示内容1;否则拥有卡牌2,性相2或uniquenessgruop2时显示内容2,以此类推。当此recipe中不存在任何给出的卡牌,性相或uniquenessgroup时则显示默认内容。

  • requirements,取值格式为{element1id:数值, element2id:数值, ...},表示为了进入此recipe该行动框内需要满足的条件,element可以是卡牌或者性相,正数表示至少需要的数量,负数则表示至多,需满足所有的条件
  • effects,取值格式为{卡牌1id:数值,卡牌2id:数值,...},表示其产生(正数)/销毁(负数)对应数量的卡牌
  • alternativerecipes,满足一定条件后会取代该recipe生效的recipe(如果additional为真值则新的recipe额外进行),详见下表
  • warmup,该recipe进行的时间
  • craftable,为真时该recipe可以被玩家主动使用对应行动框触发,否则则只能通过其他方式(如其他的recipe)触发
    • 结合前面的requirements,可以看出这就代表玩家可以在入梦框内放入一张资金便可开始此recipe

更多的字段见下表

详细文档
字段名 取值类型 用途
id 字符串 对象的唯一标识符
label 字符串 点开行动框后显示的文本标题
actionId 字符串 使用的行动的id
startdescription 字符串 开始和进行时行动框显示的文本
description 字符串 结束后显示的文本
requirements {element1id:数值,
element2id:数值, ...}
表示为了进入此recipe,该行动框内需要满足的条件,element可以是卡牌或者性相,正数表示至少需要的数量,负数则表示至多,需满足所有的条件
extantreqs {element1id:数值,
element2id:数值, ...}
与requirement类似,区别在于它检测的是整个游戏中(包括其他行动框中)的element
tablereqs {element1id:数值,
element2id:数值, ...}
与requirement类似,区别在于它检测的是桌面上的element
effects {卡牌1id:数值,
卡牌2id:数值,...}
产生(正数)/销毁(负数)对应数量的卡牌。当数值为负数时,可以在卡牌id处填写性相id,表示销毁对应数量具有此性相的卡牌(若实际数量低于销毁数量,则全部销毁。)
aspects {性相1id:数值,
性相2id:数值,...}
表示recipe本身的性相,本身并不显示在性相栏中,但是会参与在"induces"和"xtrigger"的作用中
mutations [{filter: 过滤的条件id,
mutate: 需要改变的性相id,
level: 数值,
additive: 布尔值}, {}, ...]
给特定或具有特定性相的卡牌重载(additive为false时)或增加/减少(additive为true时根据level的正负)性相,且过滤条件除了性相的id也可以填写卡牌的id。mutation对性相的改变可以被继承,即使卡牌经过了xtrigger或decayto的变换,变异后的卡牌无法堆叠
alt1 [{id: "recipe id",
chance: 数值,
additional: 布尔值,
expulsion: {limit: 数值,
filter: {element1id: 数值, ...}}}, {}, ... ]
满足一定条件后会取代该recipe生效的recipe,如果additional为真值则新的recipe在对应行动框中额外进行,要注意这种情况下若该行动框已被占用,那么这次转换不会生效
  • expulsion是可选项,可以将卡牌从当前的recipe弹出供其他的recipe调用,limit表示弹出的最大卡牌数量上限,filter则给出一组element及其最小值作为条件,只需满足其一便可弹出
  • chance表示这种recipe转换发生的概率,可以使用另一种表示"challenges":{"aspect1":"base", "aspect2":"advanced", ...} base/advanced代表了一种达到要求的至少性相值与概率的对应关系,base:0-0%, 1-30%, 5-70%, 10-90%,advanced:0-0%, 5-10%, 10-30%, 15-70%, 20-90%(缺省为base)
    • 如果同时使用chance和challenges,那么成功率取其中较高值
linked1 [{id: "recipe id",
chance: number}, {}, ... ]
表示在此recipe后会概率生效的recipe,与alt类似,包括关于challenge的规则上
slots [{slot1}] recipe只能拥有一个卡槽,在其进行时会出现,见#slots
warmup 数值 该recipe进行的时间
maxexecutions 数值 该recipe可以被进行的最大次数,0即无限制
deckeffects {"deckid": 数值} 从一个对应卡组中随机抽取一定数量张牌
internaldeck {deck} 在recipe中直接定义一个卡组,见#decks
burnimage "imageid" recipe开始后环绕动作框显示的图片
ending "endingid" 通向对应结局画面
signalEndingFlavour Grand/Melancholy 改变recipe进行时行动框计时圈线的颜色,Grand:黄色/Melancholy:红色
portaleffect "id" 进入对应的漫宿之路
craftable 布尔值 为真时该recipe可以被玩家主动使用对应行动框触发,否则则只能通过其他方式(如其他的recipe)触发
hintonly 布尔值 为真时该recipe无法被实际执行,只做展示描述作用(多用于提示)
signalimportantloop 布尔值 ?目前只在时间流逝中使用,意味不明
comments 字符串 注释
1linked和alt中的recipe皆为按顺序生效,这意味着只有在前一个recipe因为概率或未满足条件失败(如果那个recipe是addtional则只需等其执行完),后一个recipe才会开始结算概率与条件,这也意味着该recipe实际生效的概率为(1-前面所有recipe实际概率之和)*其标称概率,比方说一组3个recipe按顺序分别为30%,50%,100%,那么实际就为30%,35%,35%

endings

endings即mod中的结局。 字段见下表:

字段名 取值类型 用途
id 字符串 该结局的身份标识符
label 字符串 在达成该结局时,游戏中显示的标题
description 字符串 在达成该结局时,游戏中显示的文本
image 字符串 在达成该结局时显示的图片名称
flavour 字符串 表示该结局的类型,可选“Melancholy”“Grand”或“Vile”1
anim 字符串 从某个recipe进入该结局时,显示的动画类型。可选“DramaticLightCool”“DramaticLightEvil”或“DramaticLight”2
achievement 字符串 可能决定了该结局触发的成就。如果填入“XXX”或空串则不会触发任何成就。3
1“Melancholy”代表坏结局;“Grand”代表胜利;“Vile”代表反面胜利。
2“DramaticLightCool”是胜利时显示的动画,“DramaticLightEvil”则是在坏结局时显示,“DramaticLight”在任何结局都可用。
3achievement为必填字段,但是可以填入空串。

legacies

legacies是mod中的职业,写法如下:

{"legacies": [
        {
                "id": "aspirant",
                "label": "有志青年",
                "description": "重回6月28日。",
                "startdescription": "我孤身来到这个阴冷的城市,怀揣着一纸无用的文凭和我的梦想。\n
                然后呢?我能成为人上人吗?",
                "effects": {
                        "introjob": 1
                },
                "image": "aspirant",
                "fromEnding": "default",
                "availableWithoutEndingMatch": true,
                "startingVerbId": "work"
        },
        ......
]
}

其中:

  • id是职业身份标识符;
  • label是职业名称;
  • description是职业在选择页面的介绍;
  • startdescription是该职业开局时显示的文本;
  • effects是该职业开局拥有的卡牌;
  • image代表该职业在选择页面的图片名;
  • fromEnding代表在达成此结局的情况下必定可选;
  • availableWithoutEndingMatch决定是否在未达成指定结局的情况下也可能可选;
  • startingVerbId代表该职业开局时出现的行动框。

legacie还可以拥有以下字段:

  • excludesOnEnding,代表该职业在达成列表中任意结局的情况下必定可选。
  • newstart,值为true或false,代表该职业能否在mod与dlc界面直接开始游戏(就像dlc的方式一样)。

decks

decks是mod中随机抽卡的卡池,可以写在recipe中,也可以单独写出。
语法:

{"decks": [
        {
                "id": "[卡组id]",
                "label": "[卡组名称]",
                "description": "[卡组介绍]",
                "spec": [
                        "[卡牌1id]",
                        "[卡牌2id]",
                        ......
                ],
                "defaultcard": "[卡牌id]",
                "resetonexhaustion": [true/false]
        },
        ......
]
}
  • id是身份标识符;
  • label是卡池的名称;
  • description是卡池的介绍;
  • spec是卡池包含的卡牌;
  • defaultcard是卡池里所有卡牌被抽完时默认出现的卡牌;
  • resetonexhaustion决定卡池中的卡牌是否不会减少。

verbs

verbs是mod中的行动框。

{"verbs": [
        {
                "id": "work",
                "label": "作业",
                "description": "或赚钱糊口,或施展无形之术。",
                "atStart": true,
                "slot": {
                        ......
                }
        },
        ......
]
}

字段表:

字段名 取值类型 用途
id 字符串 该行动框的身份标识符
label 字符串 该行动框的名称
description 字符串 该行动框的介绍
atStart 布尔值 不明
slot 列表 该行动框带有的唯一卡槽,详见#slots。注意,仅仅在verb中slots没有s,而且没有最外面的中括号,直接是大括号(即可写的slot只有一个)

slots

slots代表mod中的卡槽,需要直接写在recipe、卡牌或事件框中。 示例:

"slots": [{
        "id": "Work",
        "label": "作业",
        "description": "我能做的,我知道的,或者我身为的。",
        "required": {
                "ability": 1,
                "job": 1,
                "ritual": 1,
                "desire": 1,
                "benefactor": 1
        },
        "forbidden": {
                "reasonskill": 1
        }
}]

以上卡槽中,

  • id代表卡槽的身份标识符;
  • label代表卡槽显示的名称;
  • description代表玩家点开卡槽时显示的描述;(如果不填,默认为「“埏埴以为器,当其无,有器之用。”    ——老子」)
  • required代表卡槽可以容纳的性相或卡牌,其中数字表示最小数量;
  • forbidden代表卡槽不能容纳的性相或卡牌,其中数字表示最小数量。

更多字段见下表:

字段名 取值类型 用途
actionId 字符串 当卡槽写在卡牌中时,在该卡牌进入此事件框时会显示
greedy 布尔值 代表该卡槽是否会 自动吸取卡牌
cosumes 布尔值 代表进入该卡槽的卡牌是否会 消耗

extends

extends是mod中一种特殊的写法,可以修改原游戏的数据。 写法如下:

{
        "id": "[id]",
        "extends": ["[需要扩充的对象id]"],
        ...
}

再写上你要修改的数据名并写入新的内容,例如:

{
        "id": "funds",
        "extends": ["funds"],
        "description": "万能的东西。"
}

就会把资金的介绍修改为“万能的东西。”。
还有一种写法是在要更改的数据名后方添加“$”字符+关键字,功能如下表:

关键字 取值类型 作用
append 列表 在列表数据的末尾添加内容
prepend 列表 在列表数据的开头插入内容
add 字典 在字典类型数据中添加内容

deleted

在对象中添加deleted可以从游戏中移除此对象。

{
        "id": "[对象id]",
        "deleted": true
}

images

mod中的图片文件夹需要包含以下内容:

images子文件夹表
文件夹名 子文件夹名 图片大小 用途
elements 1:1 用于存储卡牌的图片
anim 1:1 用于存储卡牌的帧动画图片
endings 400x580 用于存储结局的图片
aspects 1:1 用于存储性相的图片
verbs 1:1 用于存储事件框的图片
anim 1:1 用于存储事件框的帧动画图片(大概?)
legacies 1:1 用于存储在选职业界面职业的图片
burns 任意大小 用于存储recipe中的burnimage
cardbacks 142x222 用于存储卡池的图片
statusbaricons 1:1(大概?) 用于存储下方属性栏的图片,原版是金钱和三维(大概?)
ui 未知 未知
cover.png(和images文件夹同级!) 1:1 可选,如果添加,就会生成在mod与dlc界面和创意工坊界面的预览图。

作品展示

以下是部分教主制作的Mod,各位萌新可以从此处获得参考。

  • 秘史飞升 (by 嗡嗡嗡嗡嗡嗡嗡嗡w)
  • 性别系统 (by 嗡嗡嗡嗡嗡嗡嗡嗡w)
  • (by 林孙、晨寂似水、群镜女、裂兽专家、群食尸鬼、午港某热心网友、见证者:寻七得七和见证者:寻七得六友)
5.0
2人评价
avatar
avatar
血红雪月
1

建议MOD展示加上作者和详细一点的介绍等信息!

4个月