LootModifierManager 管理了所有的战利品表修饰器,前两章的修改最终都是调用这里才做到修改的。你可以直接使用 loot.modifiers
获取 LootModifierManager。从这里注册的战利品表修饰器是全局的,往往需要战利品条件来确定是否生效。
无条件战利品表修饰器,则代表它会影响所有战利品表。
import crafttweaker.api.loot.modifiers.CommonLootModifiers;
import crafttweaker.api.item.IngredientAny;
import crafttweaker.api.item.IItemStack;
// loot.modifiers.registerUnconditional(name as string, modifier as ILootModifier)
// 将删除所有战利品表抽奖结果,也就是删除所有了生物、方块掉落物和地牢生成。
loot.modifiers.registerUnconditional("loot_nuke", CommonLootModifiers.clearLoot());
// 删除在所有战利品表内在热力系列模组的物品
// 再提一遍,这里包括了方块、实体掉落物,该脚本同时会使热力系列的方块均无掉落物!
loot.modifiers.registerUnconditional("remove_thermal_items", CommonLootModifiers.remove(
IngredientAny.getInstance().onlyIf("thermal_only", (stack as IItemStack) => stack.owner == "thermal")
));
你可以使用战利品条件来确定什么时候执行以下的战利品修饰器,可使用以下方法。
loot.modifiers.register(name as string, conditions as ILootCondition[], modifier as ILootModifier)
loot.modifiers.register(name as string, builder as LootConditionBuilder, modifier as ILootModifier)
ILootCondition 是 LootContext 为参数,boolean 为返回值的函数式接口,用于确定何时执行修饰器。上面的第一个方法的 ILootCondition 数组为「与」操作,即当所给所有的战利品条件均满足后才会执行。本教程不会对这个函数式接口再进行更多介绍,因为你更应该用第二个接受 LootConditionBuilder 参数的方法。
ILootConditionTypeBuilder 用于构建单个 ILootCondition。CrT 提供了大量 ILootConditionTypeBuilder 的实现类,有用于检测某一类型的,有用于逻辑判断的 CrT 提供的特殊类型。
LootConditionBuilder 则用于连接多个 ILootConditionTypeBuilder,进而构建出所需的 ILootCondition
数组。
一般而言,我们需要创建一个 LootConditionBuilder,往其添加一个或多个 ILootConditionTypeBuilder,最后将其传入上文的 register
方法完成操作。
是不是觉得有些套娃?这采用了抽象工厂模式 (Abstract Factory Pattern)
你可以调用以下方法来创建 LootConditionBuilder
import crafttweaker.api.loot.conditions.LootConditionBuilder;
import crafttweaker.api.loot.conditions.crafttweaker.And;
import crafttweaker.api.loot.conditions.crafttweaker.Or;
// LootConditionBuilder.create();
// 添加一个空的 LootConditionBuilder
// LootConditionBuilder.createForSingle<T extends ILootConditionTypeBuilder>(lender as Consumer<T>)
// 添加后并加入一个 ILootConditionTypeBuilder
// LootConditionBuilder.createInAnd(lender as Consumer<And>)
// 你可以在 lender 函数内可以添加多个 ILootConditionTypeBuilder,这些为与操作
// LootConditionBuilder.createInOr(lender as Consumer<Or>)
// 你可以在 lender 函数内可以添加多个 ILootConditionTypeBuilder,这些为或操作
在创建 LootConditionBuilder 后,你可以使用 add
方法来添加更多的 ILootConditionTypeBuilder。
该方法是一个泛型方法。
// builder.add<T extends ILootConditionTypeBuilder>(lender as Consumer<T>) as LootConditionBuilder
尖括号内填所需的 ILootConditionalTypeBuilder 的类名,而括号内的 lender 则为以所给泛型的实例为参数,无返回值的 lambda 表达式,用于设定一些数值。
这个方法返回 LootConditionBuilder 本身,则允许你 链性调用 多个 add
方法,来添加多个 ILootConditionTypeBuilder。
import crafttweaker.api.loot.conditions.LootConditionBuilder;
import crafttweaker.api.loot.conditions.vanilla.LootTableId;
import crafttweaker.api.loot.conditions.vanilla.RandomChance;
import crafttweaker.api.loot.modifiers.CommonLootModifiers;
var lcb = LootConditionBuilder.create() // 创建一个空的
// 添加一个 ILootConditionBuilder,为 LootTableId,
// 用于限定作用于哪个战利品表,例子为沙漠神殿
// 尖括号泛型为 LootTableId,则 lambda 表达式的参数为 LootTableId 对象
// 等等,你说战利品表 ID 从哪看?输入 `/ct dump loot_tables` 可以查看游戏内所有战利品表 ID
// 例子调用 LootTableId 类的 withTableId 方法设定这个条件指定的战利品表
.add<LootTableId>(condition => {
condition.withTableId(<resource:minecraft:chests/desert_pyramid>);
})
// 同理,再添加 ILootConditionBuilder,为 RandomChance
// 这里的 lambda 表达式参数即为 RandomChance
// 调用 RandomChance#withChance 方法,来设定生效几率
.add<RandomChance>(condition => {
condition.withChance(0.7);
});
// 注册战利品修饰符,这个修饰符只有战利品表是沙漠神殿和 70% 几率生效,效果是添加一本书。
loot.modifiers.register("add_book", lcb, CommonLootModifiers.add(<item:minecraft:book>));
铁矿在下雨的时候将直接会掉落铁锭,并排除精准采集的情况。
import crafttweaker.api.loot.conditions.LootConditionBuilder;
import crafttweaker.api.loot.conditions.vanilla.MatchTool;
import crafttweaker.api.loot.conditions.vanilla.WeatherCheck;
import crafttweaker.api.loot.conditions.crafttweaker.Not;
import crafttweaker.api.loot.conditions.vanilla.BlockStateProperty;
import crafttweaker.api.loot.modifiers.CommonLootModifiers;
loot.modifiers.register(
"drop_iron_ingot",
LootConditionBuilder.create()
// 下雨
.add<WeatherCheck>(condition => {
condition.withRain();
})
// 指定只作用于原版铁矿石
.add<BlockStateProperty>(condition => {
// 这里填的是 MCBlock
condition.withBlock(<block:minecraft:iron_ore>);
})
// 对下面的条件取非
// 我们需要跳过精准采集,即为给下面匹配精准采集的条件取非
.add<Not>(not => {
not.withCondition<MatchTool>(condition => { // 匹配工具
condition.withPredicate(predicate => { // 设置工具需要满足的条件
// 工具需要精准采集附魔
// 对于其他附魔,可以在后面的 lambda 表达式中设置所需等级等信息
predicate.withEnchantmentPredicate(<enchantment:minecraft:silk_touch>, it => {});
});
});
}),
// 将原有铁矿石掉落替换为铁锭
CommonLootModifiers.replaceWith(<tag:items:forge:ores/iron>, <item:minecraft:iron_ingot>)
);
是的,就像上文例子那样,你基本不需要自己重新用 lambda 写一个 ILootCondition 或 ILootModifier。通过组合内置战利品条件和战利品修饰符,你就能满足 90% 的需求。
在官方文档的 Vanilla/Api/Loot/Conditions/Vanilla
和 Vanilla/Api/Loot/Conditions/CraftTweaker
章节你可以看见所有提供的 ILootConditionTypeBuilder。
其他模组可能也会注册自己的战利品修饰器。比起添加,删除则相当简单,毕竟它只需要填入想要删除的 ID 即可...
你可以通过 /ct dump loot_modifiers
指令查看游戏内所有战利品修饰器。
loot.modifiers.removeAll(); // 删除所有
loot.modifiers.removeByModId(modid as string); // 删除特定模组的
loot.modifiers.removeByName(name as string); // 删除指定 ID 的
loot.modifiers.removeByRegex(regex as string); // 删除所有 ID 匹配所给正则的