Skip to content

Commit 136ac22

Browse files
author
REME
committed
2026-04-02 sync
1 parent 884d5d6 commit 136ac22

18 files changed

Lines changed: 1536 additions & 836 deletions

_config.kira.yml

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,57 @@ docsTree:
3232
[
3333
{ title: 01 环境配置, path: /docs/01-env-setup/ },
3434
{
35-
title: 02 安装、看源码、修改,
35+
title: 02 常见问题,
3636
path: /docs/02-install-view-source-and-patch/,
3737
},
38-
{ title: 03 BaseLib, path: /docs/03-baselib/ },
38+
{
39+
title: 03 BaseLib,
40+
open: true,
41+
children:
42+
[
43+
{ title: 00 总览, path: /docs/03-baselib/ },
44+
{
45+
title: 01 添加卡牌,
46+
path: /docs/03-01-add-card/,
47+
},
48+
{
49+
title: 02 自定义模组配置,
50+
path: /docs/03-02-mod-config/,
51+
},
52+
{
53+
title: 03 添加新遗物,
54+
path: /docs/03-03-add-relic/,
55+
},
56+
{
57+
title: 04 添加卡牌属性,
58+
path: /docs/03-04-card-properties/,
59+
},
60+
{
61+
title: 05 添加新能力,
62+
path: /docs/03-05-add-power/,
63+
},
64+
{
65+
title: 06 添加新药水,
66+
path: /docs/03-06-add-potion/,
67+
},
68+
{
69+
title: 07 添加先古之民,
70+
path: /docs/03-07-add-ancient/,
71+
},
72+
{
73+
title: 08 添加充能球,
74+
path: /docs/03-08-add-orb/,
75+
},
76+
{
77+
title: 09 局内保存,
78+
path: /docs/03-09-run-save/,
79+
},
80+
{
81+
title: 10 mod联动,
82+
path: /docs/03-10-mod-integration/,
83+
},
84+
],
85+
},
3986
{ title: 04 添加新人物, path: /docs/04-add-new-character/ },
4087
{
4188
title: 05 变量与描述,

source/_posts/01-env-setup.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,4 +177,8 @@ public class Entry
177177

178178
## 运行并验证
179179

180-
运行游戏。第一次会提示是否开启mod,选择是,然后游戏会关闭,打开第二次即可,如果右下角显示“已加载模组”即加载成功。如果发现存档丢失,看下一章。
180+
运行游戏。第一次会提示是否开启mod,选择是,然后游戏会关闭,打开第二次即可,如果右下角显示“已加载模组”即加载成功。如果发现存档丢失,看下一章。
181+
182+
## 不启动Godot打包(可选)
183+
184+
Godot支持命令行导出pck(首先你需要添加一个导出配置),例如使用终端命令:`"{你的godot.exe的路径}" --headless --export-pack "{你的导出配置的名字,例如Windows Desktop}" "{杀戮尖塔根目录}/mods/{你的modid}/{你的modid}.pck"`,参考 https://docs.godotengine.org/zh-cn/4.x/tutorials/editor/command_line_tutorial.html#exporting 。你可以把这个命令保存成一个cmd或者csproj里的target,自行搜索相关配置说明。

source/_posts/02-install-view-source-and-patch.md

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ https://github.com/GDRETools/gdsdecomp
5353

5454
开启了模组,按下`~`(tab上方那个键)即可打开控制台。输入`help`即可查看命令。例如`card SURVIVOR`是把一张生存者加入手中。
5555

56+
你可以查询一个命令的帮助,使用`help card`等。
57+
5658
## DEBUG
5759

5860
尖塔根目录有许多`launch_xxx.bat`,选择一个合适的,右键记事本编辑,在其中加一个`--log`,例如`@echo off
@@ -62,4 +64,20 @@ https://github.com/GDRETools/gdsdecomp
6264

6365
## 本地联机测试
6466

65-
复制出两个新的`bat`,其中一个添加`--fastmp=host`参数,作为主机,另一个添加`--fastmp=join -clientId=1001`参数,作为非主机玩家。当然你可以添加更多,记得修改`clientId`
67+
复制出两个新的`bat`,其中一个添加`--fastmp=host`参数,作为主机,另一个添加`--fastmp=join -clientId=1001`参数,作为非主机玩家。当然你可以添加更多,记得修改`clientId`
68+
69+
如果你打完一层遇到保存问题,记得以管理员模式启动bat。
70+
71+
## 项目改名
72+
73+
<b>以下修改的都建议使用一个名字</b>。
74+
75+
* 打开`project.godot`,修改`config/name`以及`project/assembly_name`
76+
77+
*`{modid}.csproj`的名字修改成你想要的。
78+
79+
*`{modid}.json`的名字修改成你想要的。以及里面的`id`部分。
80+
81+
*`{modid}.sln`的名字修改成你想要的。
82+
83+
* 然后重新打包。不要忘记把你之前名字的mod删了。

source/_posts/03-01-add-card.md

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
---
2+
title: 03-01 添加卡牌
3+
date: 2026-04-02 00:00:00
4+
permalink: docs/03-01-add-card/
5+
categories:
6+
- Basics
7+
---
8+
## 代码
9+
10+
创建一个新的`Cards`文件夹方便管理,并创建新的`cs`文件,例如`TestCard.cs`
11+
12+
```csharp
13+
using BaseLib.Abstracts;
14+
using BaseLib.Utils;
15+
using MegaCrit.Sts2.Core.Commands;
16+
using MegaCrit.Sts2.Core.Entities.Cards;
17+
using MegaCrit.Sts2.Core.GameActions.Multiplayer;
18+
using MegaCrit.Sts2.Core.Localization.DynamicVars;
19+
using MegaCrit.Sts2.Core.Models.CardPools;
20+
using MegaCrit.Sts2.Core.ValueProps;
21+
22+
namespace Test.Scripts.Cards;
23+
24+
// 加入哪个卡池
25+
[Pool(typeof(ColorlessCardPool))]
26+
public class TestCard : CustomCardModel
27+
{
28+
// 基础耗能
29+
private const int energyCost = 1;
30+
// 卡牌类型
31+
private const CardType type = CardType.Attack;
32+
// 卡牌稀有度
33+
private const CardRarity rarity = CardRarity.Common;
34+
// 目标类型(AnyEnemy表示任意敌人)
35+
private const TargetType targetType = TargetType.AnyEnemy;
36+
// 是否在卡牌图鉴中显示
37+
private const bool shouldShowInCardLibrary = true;
38+
39+
// 卡牌的基础属性(例如这里是12点伤害)
40+
protected override IEnumerable<DynamicVar> CanonicalVars => [new DamageVar(12, ValueProp.Move)];
41+
42+
public TestCard() : base(energyCost, type, rarity, targetType, shouldShowInCardLibrary)
43+
{
44+
}
45+
46+
// 打出时的效果逻辑
47+
protected override async Task OnPlay(PlayerChoiceContext choiceContext, CardPlay cardPlay)
48+
{
49+
await DamageCmd.Attack(DynamicVars.Damage.BaseValue) // 造成伤害,数值来源于卡牌的基础伤害属性
50+
.FromCard(this) // 伤害来源于这张卡牌
51+
.Targeting(cardPlay.Target) // 伤害目标是玩家选择的目标
52+
.Execute(choiceContext);
53+
}
54+
55+
// 升级后的效果逻辑
56+
protected override void OnUpgrade()
57+
{
58+
DynamicVars.Damage.UpgradeValueBy(4); // 升级后增加4点伤害
59+
}
60+
}
61+
```
62+
63+
* `CanonicalVars`翻译是“规范值”,指卡牌的基础数值。添加一个`DamageVar`意为指定卡牌的基础伤害是多少,例如这里是`12`
64+
65+
* `ValueProp`表示数值的属性,例如`ValueProp.Move`表示是通过卡牌造成的伤害/格挡,`ValueProp.Unpowered`表示不受修正影响(如力量等),`ValueProp.Unblockable`表示伤害不可被格挡,`ValueProp.SkipHurtAnim`表示跳过受伤动画。这是一个bitflag类型的枚举,你可以进行组合,例如`ValueProp.Unblockable | ValueProp.Unpowered`,不可被格挡也不受修正影响。
66+
67+
* 尖塔2使用了`async``await`来控制效果逻辑顺序执行,比如选择一张牌时就一直`await`不让后续代码执行,和尖塔1的`action`类似的生态位。此处的`OnPlay`中写了一个造成单体伤害的指令。
68+
69+
* 想做什么样的卡牌,看原版代码哪张有类似的效果,参考即可。
70+
71+
* 添加一个`Pool`的attribute,并指定要添加的颜色卡池,然后会自动注册。
72+
* 继承`CustomCardModel`而不是`CardModel`
73+
* <b>注意</b>:通过`baselib`添加卡牌,其id会变成`{命名空间第一段大写}-{原卡牌id}`,例如`namespace Test.Scripts;``TEST`,原始卡牌id为`TEST-CARD`,是`TestCard`的大写snake-case,最后变成`TEST-TEST_CARD`
74+
75+
## 卡图
76+
77+
可以通过在卡牌类中添加一个表达式属性来添加卡牌,这样的话可以任意指定位置:`public override string PortraitPath => $"res://{modid}/images/cards/{Id.Entry.ToLowerInvariant()}.png";`
78+
如果这样,那么路径就是`test/images/cards/test-test_card.png`(是你类名的`snake_case`命名风格加前缀,例如`TestCard`即为`test-test_card`)。当然按你的喜好组织资源路径也可。
79+
80+
> 或者你也可以使用`public override string PortraitPath => $"res://{modid}/images/cards/{nameof(TestCard)}.png";`,这样更方便,卡图名字设置为`TestCard.png`就行。
81+
82+
`modId`即为你`{modId}.json`中填写的。<b>不是你的根目录,而是一个新文件夹。</b>
83+
84+
85+
卡图任意尺寸都可,且不需要裁剪,官方使用的尺寸是普通卡1000x760,先古卡606x852。
86+
87+
```csharp
88+
public class TestCard : TestCardModel
89+
{
90+
private const int energyCost = 1;
91+
private const CardType type = CardType.Attack;
92+
private const CardRarity rarity = CardRarity.Common;
93+
private const TargetType targetType = TargetType.AnyEnemy;
94+
private const bool shouldShowInCardLibrary = true;
95+
96+
protected override IEnumerable<DynamicVar> CanonicalVars => [new DamageVar(12, ValueProp.Move)];
97+
98+
// 添加这一行,指定卡牌立绘路径,这里是test/images/cards/TestCard.png
99+
public override string PortraitPath => $"res://test/images/cards/{nameof(TestCard)}.png";
100+
101+
public TestCard() : base(energyCost, type, rarity, targetType, shouldShowInCardLibrary)
102+
{
103+
}
104+
}
105+
```
106+
107+
![示例卡图](../../images/image10.png)
108+
109+
你也可以通过新增一个`abstract`类,避免每张卡都写一遍卡图路径,并且方便管理一些自定义功能。
110+
111+
```csharp
112+
public abstract class TestCardModel : CardModel
113+
{
114+
public override string PortraitPath => $"res://test/images/cards/{GetType().Name}.png";
115+
116+
public TestCardModel(int energyCost, CardType type, CardRarity rarity, TargetType targetType, bool shouldShowInCardLibrary) : base(energyCost, type, rarity, targetType, shouldShowInCardLibrary)
117+
{
118+
}
119+
}
120+
121+
public class TestCard : TestCardModel {}
122+
```
123+
124+
## 文本
125+
126+
此外还需要本地化文件。创建一个`{modId}/localization/{Language}/cards.json`
127+
* `modId`即为你`{modId}.json`中填写的。<b>不是你的根目录,而是一个新文件夹。</b>
128+
* `Language`可以写`zhs`表示简体中文。填写`{CardId}.title`(卡牌名)和`{CardId}.description`(卡牌描述):
129+
130+
```json
131+
{
132+
"TEST-TEST_CARD.title": "测试卡牌",
133+
"TEST-TEST_CARD.description": "造成{Damage:diff()}点伤害。"
134+
}
135+
```
136+
137+
编译打包`dll``pck`后打开游戏。如果你在对应池子中看到卡牌说明成功了。如果没有任何卡牌(或者一张在左上角的卡牌)说明出问题了。
138+
139+
`~`打开控制台输入`card TEST-TEST_CARD`获得这张卡。
140+
141+
![示例卡牌](../../images/image11.png)
142+
143+
## 最终项目参考
144+
145+
如果报错,回头看看。最终项目结构参考:
146+
147+
```
148+
Test (你的项目文件夹)
149+
├── Scripts (你的脚本文件夹,随意)
150+
│ ├── TestCard.cs
151+
│ └── Entry.cs
152+
└── Test (不要忘了这一层文件夹,是你的modid)
153+
├── images
154+
│ └── cards
155+
│ └── test-test_card.png
156+
└── localization
157+
└── zhs
158+
└── cards.json
159+
```
160+

source/_posts/03-02-mod-config.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
---
2+
title: 03-02 自定义模组配置
3+
date: 2026-04-02 00:00:00
4+
permalink: docs/03-02-mod-config/
5+
categories:
6+
- Basics
7+
---
8+
* 要使用此功能,需要先放一张图片到`{modId}\mod_image.png`作为mod图标,尺寸任意,否则会由于报错不显示配置。
9+
* 添加一个继承`SimpleModConfig`(或者是`ModConfig`如果你想要更复杂的设置)的类,在其中添加`public static bool`变量。支持`bool``double``enum``int``string`
10+
* 在初始化函数调用`ModConfigRegistry.Register`。字符串写你的`modId`
11+
12+
```csharp
13+
[ModInitializer("Init")]
14+
public class Entry
15+
{
16+
public static void Init()
17+
{
18+
ModConfigRegistry.Register("test", new ModConfig());
19+
}
20+
}
21+
22+
public class ModConfig : SimpleModConfig
23+
{
24+
public static bool Test1 { get; set; } = true;
25+
public static bool Test2 { get; set; } = false;
26+
public static bool Test3 { get; set; } = true;
27+
}
28+
```
29+
30+
![示例配置](../../images/image12.png)
31+
32+
更多请参考`baselib``BaseLibConfig`类。
33+

source/_posts/03-03-add-relic.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
---
2+
title: 03-03 添加新遗物
3+
date: 2026-04-02 00:00:00
4+
permalink: docs/03-03-add-relic/
5+
categories:
6+
- Basics
7+
---
8+
和添加卡牌类似。先新建一个类。
9+
10+
```csharp
11+
// 加入哪个遗物池,此处为通用
12+
[Pool(typeof(SharedRelicPool))]
13+
public class TestRelic : CustomRelicModel
14+
{
15+
// 稀有度
16+
public override RelicRarity Rarity => RelicRarity.Common;
17+
18+
// 遗物的数值。替换本地化中的{Cards}。
19+
protected override IEnumerable<DynamicVar> CanonicalVars => [new CardsVar(1)];
20+
21+
// 小图标
22+
public override string PackedIconPath => $"res://test/images/relics/{Id.Entry.ToLowerInvariant()}.png";
23+
// 轮廓图标
24+
protected override string PackedIconOutlinePath => $"res://test/images/relics/{Id.Entry.ToLowerInvariant()}.png";
25+
// 大图标
26+
protected override string BigIconPath => $"res://test/images/relics/{Id.Entry.ToLowerInvariant()}.png";
27+
28+
public override async Task AfterPlayerTurnStart(PlayerChoiceContext choiceContext, Player player)
29+
{
30+
// 这里的DynamicVars.Cards.IntValue为上面设置的CardsVar的数值。
31+
await CardPileCmd.Draw(choiceContext, DynamicVars.Cards.IntValue, player);
32+
}
33+
}
34+
```
35+
36+
然后放一张图片`test/images/relics/test_relic.png`。路径不一定是`test`,组织风格自定义,参考上面卡图部分。这里偷懒三张图片用了一样的,可以自己修改。
37+
38+
![示例遗物](../../images/image13.png)
39+
40+
然后写一个本地化文件,`{modId}/localization/{Language}/relics.json`
41+
42+
```json
43+
{
44+
"TEST-TEST_RELIC.title": "测试遗物",
45+
"TEST-TEST_RELIC.description": "每回合开始时,抽[blue]{Cards}[/blue]张牌。",
46+
"TEST-TEST_RELIC.flavor": "觉得很眼熟?"
47+
}
48+
```
49+

0 commit comments

Comments
 (0)