泰拉瑞亚mod开发笔记 1
在开发mod之前,请务必保证你有以下辅助性资源,否则开发的过程将异常困难:
- 官方的Wiki教程
- 按照官方教程得到了一份源代码
- 官方给出的mod样例ExampleMod
方法论
首先肯定是要按照官方文档过一遍,Wiki介绍了很多基本的修改方式,但是没有详尽列举所有可拓展部分。应该把Wiki教程作为方法论,它告诉哦我们应该如何去修改,大致在那个范围修改,但是具体执行修改还是需要去看源码,去看接口和Hook是如何定义的。
接着就是查看官方的ExampleMod,大部分能拓展的模块它都给出了一个实际的样例。具体的mod内容继承自ModXXX对象(ModItem、ModNPC等)开发的,ExampleMod则给出了一个继承的实例来补充了文档中没有提到的细节。
借助AI工具的辅助,我们可以比较轻松的找出原版代码实现某个机制的具体代码,这对于实现我们设计的机制而言非常有用。
讲完了方法论,我们来针对具体的模块来给出经验之谈。
本地化
这将是花费很多时间的板块,即使你的mod只支持中文,因为必须将文本和代码分离以解耦,否则既不便于多处调用同一段文本,也让代码变得很难看。
**硬广:**如果想要有方便的图形化界面同步编辑多个语言文件,可以使用LocalizationEditor
对于本地化文件的结构划分,应该遵循一个原则:能复用的文本尽量复用,不要让相同的文本在多处重复出现,使用换元来解决。比如说下面这样一个简单的饰品:
A_Gear: {
Tooltip:
'''
缓慢再生生命
强化技能 ‘6767’
[c/746f6f:啊吧啊吧]
[c/746f6f:这是背景故事]
'''
DisplayName: 洁白的头饰
}
其中可以拆分出来的单元很多,比如说“缓慢再生生命”,“强化技能”,6767,以及[]包围的两行都可以也最好拆分成为独立键,如果“洁白的头饰”这一文本会在其他地方被引用到,那么也要将其设置为单独的Key,比如:
EffectRegen: 缓慢再生生命
SkillEnhance: 强化技能
A: {
SkillName: 6767
GearDesc:
'''
[c/746f6f:啊吧啊吧]
[c/746f6f:这是背景故事]
'''
GearName: 洁白的头饰
}
# 假设你的mod名字叫做XMod
A_Gear: {
Tooltip:
'''
{$Mods.XMod.EffectRegen}
{$Mods.XMod.SkillEnhance} ‘{$Mods.XMod.A.SkillName}’
{$Mods.XMod.A.GearDesc}
'''
DisplayName: {$Mods.XMod.A.GearName}
}
如果我们发现,不同的Gear饰品之间的Tooltip格式都是一样的,区别就是A替换成为了B,C,D,那么更极端一点的做法就是:
EffectRegen: 缓慢再生生命
SkillEnhance: 强化技能
A: {
SkillName: 6767
GearEffect: "{$Mods.XMod.EffectRegen}"
GearDesc:
'''
[c/746f6f:啊吧啊吧]
[c/746f6f:这是背景故事]
'''
GearName: 洁白的头饰
}
# 假设你的mod名字叫做XMod
Tooltip:
'''
{0}{$Mods.XMod.SkillEnhance} ‘{1}’
{2}
'''
然后在代码里面格式化LocalizaedText,从而完全不需要每多出一个Item就手动拼接一次,最大程度减少重复。
货币系统
护卫奖章是原版的特殊货币,是独立于原版四币的货币系统,tmodloader自带提供了一个方便的实现CustomCurrencySingleCoin,用于支持单币种货币系统。但是显然,如果想要拓展到多币种系统,或者想要修改货币的显示方式,还是需要自己动手,这就需要继承CustomCurrencySystem。为了到达原版的效果,我们至少要做以下内容:
- 货币不能作为可交易物品
- 货币不能显示交易价格
- 购买时扣钱应该尽量保持货币物体的槽位不变
第一点,通过查看源代码得知,在出售物品之前,ModPlayer.CanSellItem接口将检测这个物体是否能被出售,只需在这一层拦截,实现如下:
public override bool CanSellItem(NPC vendor, Item[] shopInventory, Item item)
{
if (item.ModItem is Currency) return false;
return base.CanSellItem(vendor, shopInventory, item);
}
第二点,需要修改货币Item对应的Tooltip显示,在显示之前ModItem.ModifyTooltips接口将给出自定义Tooltip的操作空间,这也是最好的拦截接口,实现如下:
public override void ModifyTooltips(List<TooltipLine> tooltips)
{
var ptl = tooltips.FirstOrDefault(tl => tl.Name == "Price");
if (ptl != null) ptl.Hide();
}
第三点,需要修改货币交易时的操作接口,CustomCurrencySystem.TryPurchase接口负责具体的货币交易,这里的实现比较复杂,但是逻辑很简单,就是先尽可能地从已有的而货币中扣款,不涉及到进位。如果这一轮之后还有余款,则破开一个比余款多的货币,然后执行找零。