本文内容整理自 tModLoader 官方 Wiki(Terraria 模组开发指南),原文:Basic Recipe

配方有三个地方可以写:ModItem.AddRecipesGlobalItem.AddRecipesModSystem.AddRecipes。放哪儿看你自己的整理习惯,不过 ModItem.CreateRecipe 并不是在哪儿都能直接用,用不了的地方就换成 Recipe.Create

一个配方由三部分组成:材料(Ingredients,合成时被消耗掉的物品)、制作站(Tiles,你得站在旁边的那些物块)和产物(Results,合成出来的物品)。

只要某个物品被至少一个配方当作材料用过,游戏就会自动给它加上“Material”(材料)提示,不用你手动加。

配方的基本结构

需要引用的命名空间

先确认 .cs 文件顶部有这几个 using,配方相关的函数都在里面:

1
2
3
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;

创建配方并指定产物

配方的第一步,是拿到一个 Recipe 类的实例,途径有两条:Recipe.Create 方法,或者 ModItem.CreateRecipe 方法。创建的时候要指定产物的类型和数量。ModItem.CreateRecipe 默认产物就是当前这个 ModItem,所以只需要给数量。数量可以不写,默认为 1:

GlobalItem 类里,得用 Recipe.Create 方法。下面几个例子分别用了原版物品和模组物品,也演示了默认数量和自定义数量:

1
2
3
4
Recipe recipe = Recipe.Create(ItemID.AlphabetStatueZ); 
Recipe recipe = Recipe.Create(ItemID.AlphabetStatueZ, 5); 
Recipe recipe = Recipe.Create(ModContent.ItemType<Content.Items.ExampleItem>());
Recipe recipe = Recipe.Create(ModContent.ItemType<Content.Items.ExampleItem>(), 10);

ModSystem 类里也是用 Recipe.Create

1
Recipe recipe = Recipe.Create(ItemID.AlphabetStatueZ);

ModItem 类里,如果产物不是这个 ModItem 本身,就用 Recipe.Create

1
2
3
4
Recipe recipe = Recipe.Create(ItemID.AlphabetStatueZ); 
// ... And we can use "CreateRecipe" directly to create a recipe that results in this ModItem. We can optionally provide a stack size:
Recipe recipe = CreateRecipe(); 
Recipe recipe = CreateRecipe(10);

添加材料

接下来往配方里加材料 —— 也就是合成时会被消耗掉的物品:

1
2
recipe.AddIngredient(ItemID.DirtBlock);
recipe.AddIngredient(ItemID.Ruby);

AddIngredient 还有一个可选参数用来指定数量:

1
recipe.AddIngredient(ItemID.Chain, 10);

上面的例子都是通过 ItemID 类来引用原版物品的。用 Visual Studio 这类趁手的 IDE 时,自动补全和智能提示会非常省事;当然你也可以在这里查 ItemID 的名字或数值

要加自己模组的物品也有好几种写法,挑顺手的用就行,第一种最干净。这些写法都能再带上数量参数。下面的例子指向的都是 ExampleMod.Content.Items 命名空间里的 ExampleItem 类:

1
2
3
4
5
recipe.AddIngredient<Content.Items.ExampleItem>();
recipe.AddIngredient<Content.Items.ExampleItem>(10);
recipe.AddIngredient(ModContent.ItemType<Content.Items.ExampleItem>());
recipe.AddIngredient(ModContent.GetInstance<Content.Items.ExampleItem>());
recipe.AddIngredient(Mod, "ExampleItem");

如果代码就写在 ModItem 类里,也可以直接把这个 ModItem 当材料用:

1
recipe.AddIngredient(this, 5);

指定制作站

接着指定制作站,写法跟加物品一样。TileID 在这里查

想让它徒手就能合成的话,这一步直接跳过。

1
2
3
4
5
6
recipe.AddTile(TileID.WorkBenches);
recipe.AddTile(TileID.Anvils);
recipe.AddTile<Content.Tiles.Furniture.ExampleWorkbench>();
recipe.AddTile(ModContent.TileType<Content.Tiles.Furniture.ExampleWorkbench>());
recipe.AddTile(ModContent.GetInstance<Content.Tiles.Furniture.ExampleWorkbench>());
recipe.AddTile(Mod, "ExampleWorkbench");

注册配方

最后告诉 tModLoader 这个配方已经写完了,把它加进游戏:

1
recipe.Register();

原版与模组材料、制作站的写法区别

小结一下:原版物品和物块用 TileIDItemID 类,模组内容用 ModContent.TileTypeModContent.ItemType 方法:

1
2
3
4
recipe.AddTile(TileID.WorkBenches); // Vanilla Tile
recipe.AddTile(ModContent.TileType<Content.Tiles.Furniture.ExampleWorkbench>()); // Modded Tile
recipe.AddIngredient(ItemID.Meowmere); // Vanilla Item
recipe.AddIngredient(ModContent.ItemType<Content.Items.ExampleItem>()); // Modded Item

完整的配方示例

先看两个简单的完整例子。第一个写在 ModSystem 类里:消耗 1 个锁链和 10 个石块,需要在工作台和铁砧旁边合成,产出 1 个 AlphabetStatueA。

1
2
3
4
5
6
Recipe recipe = Recipe.Create(ItemID.AlphabetStatueA);
recipe.AddIngredient(ItemID.StoneBlock, 10);
recipe.AddIngredient(ItemID.Chain);
recipe.AddTile(TileID.WorkBenches);
recipe.AddTile(TileID.Anvils);
recipe.Register();

第二个写在 ModItem 类里:用 5 个 ExampleItem 合成 3 个该 ModItem。

1
2
3
Recipe recipe = CreateRecipe(3);
recipe.AddIngredient<Content.Items.ExampleItem>(5);
recipe.Register();

Chain Syntax

前面那些代码啰嗦得很,用链式语法可以把它们串起来,看起来清爽不少,改起来也舒服。注意只有最后一行带分号。

1
2
3
4
5
6
Recipe.Create(ItemID.AlphabetStatueA)
	.AddIngredient(ItemID.StoneBlock, 10)
	.AddIngredient(ItemID.Chain)
	.AddTile(TileID.WorkBenches)
	.AddTile(TileID.Anvils)
	.Register();

配方组

配方组(Recipe Group)允许一个材料位置由一组同类物品里的任意一个来满足,最常见的例子就是用铁锭或铅锭都能合成同一个配方。这部分内容在中级配方篇里讲。

条件

除了材料和制作站,配方还能带条件。每一个条件都满足,配方才做得出来。

水、蜂蜜、岩浆、微光

水、蜂蜜、岩浆和微光严格来说不算物块,所以想让配方要求站在这些东西旁边,得用下面这几个:

1
2
3
4
recipe.AddCondition(Condition.NearWater);
recipe.AddCondition(Condition.NearLava);
recipe.AddCondition(Condition.NearHoney);
recipe.AddCondition(Condition.NearShimmer);

注意 NearWater 对水槽(Sink)同样成立,所以别再单独把水槽这个物块加进去。

其他原版条件

其余原版条件都列在 Condition.cs 里,用法跟上面一样。

自定义条件

模组也可以定义自己的条件,见中级配方篇的自定义条件一节

一个地方写多个配方

在同一个 AddRecipes 里写多个配方时,注意别把变量名重复声明了。下面这样会报错:

1
2
3
4
Recipe recipe = Recipe.Create(ItemID.AlphabetStatueA); 
// other code
Recipe recipe = Recipe.Create(ItemID.AlphabetStatueB);
// other code

你可以把变量名起成 recipe1、recipe2 这样,但更干净的做法是干脆复用同一个变量:

1
2
3
4
Recipe recipe = Recipe.Create(ItemID.AlphabetStatueA); 
// other code
recipe = Recipe.Create(ItemID.AlphabetStatueB); 
// other code

如果你用的是链式写法,那就每个配方各起一行、照同样的方式往下写即可。

让原版物块“升级”

顺带提一个需求:你可能希望自己的 ModTile 也能被当成工作台、铁砧之类的制作站。做法是在 ModTile.SetStaticDefaults 里加上这一行:

1
AdjTiles = [TileID.WorkBenches];

完整示例

下面给两个完整例子:一个把配方写在 ModItem 类里,适合跟这个 ModItem 相关的配方;另一个写在 ModSystem 类里,适合围绕原版物品的配方。严格来说放哪儿都能跑,只是为了条理清楚,把配方放在 ModItem 类里有时更顺手。

ModItem 示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;

namespace ExampleMod.Content.Items.Accessories
{
	public class ExampleShield : ModItem
	{
		// Other methods and fields here...

		public override void AddRecipes()
		{
			// This example showcases the more modern "chaining style" for recipe creation.
			// For a simpler example, see the ModSystem code below.
			CreateRecipe()
				.AddIngredient<ExampleItem>()
				.AddTile<ExampleWorkbench>()
				.Register();
		}
	}
}

ModSystem 示例

记住在 ModSystem 里必须把配方的产物物品类型传进去。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;

namespace ExampleMod.Content
{
	public class ExampleRecipes : ModSystem
	{
		// Other methods and fields here...

		public override void AddRecipes()
		{
			// Here is an example of a recipe.
			Recipe recipe = Recipe.CreateRecipe(ItemID.Wood, 999);
			recipe.AddIngredient<Content.Items.ExampleItem>();
			recipe.Register();

			// Here we reuse 'recipe', meaning we don't need to re-declare that it is a Recipe
			recipe = Recipe.CreateRecipe(ItemID.PumpkinPie, 2);
			recipe.AddIngredient(ItemID.BlueBerries, 20);
			recipe.AddTile(TileID.WorkBenches);
			recipe.Register();
		}
	}
}

常见错误

Error CS0117 ‘ItemID’ (or TileID) does not contain a definition for ‘MyModItem’

你用了原版物品的写法去加模组物品,回头再读一遍前面的内容。

Error CS0103 The name ‘recipe’ does not exist in the current context

第一个配方忘了声明成 Recipe。代码里第一个配方得写成 Recipe recipe = ...

Error CS0128 A local variable named ‘recipe’ is already defined in this scope

看上面的「一个地方写多个配方」那节。

游戏里找不到我写的配方

检查一下 AddRecipes 方法是不是写成了 override 而不是 virtual

No suitable method to override

AddRecipes 只能在 ModModSystemModItem 里重写,别的类不行。

游戏里显示的制作站或材料和我的配方代码对不上

多半是把 ItemID 传进了 AddTile,或者把 TileID 传进了 AddIngredient。用错了 ID 类,等于引用到了另一个 ID。

相关参考

基础篇不涉及的内容

配方还有几块内容留给更进阶的指南: