本篇教程由作者设定使用 CC BY-NC 协议。
· 前言
这是笔者在出匠魂2的自定义匠魂特性教程时遇见的一个问题:关于匠魂2工具增伤特性的结算顺序。笔者承诺在写完基础的特性自定义教程后会进行相关测试研究(然而教程已经出到了高级讲解部分这个坑仍然没填()在笔者参考了一些站内教程后,笔者大胆给出猜想:匠魂增伤特性结算是按照特性列表自上而下进行结算。本篇教程便是对这个猜想进行研究测试。笔者才疏学浅,如有不足之处,欢迎各位读者大佬指正!
· 正文部分
为了研究匠魂增伤特性的结算顺序,笔者编写了一个自定义测试材料和两个自定义测试特性,使用模组为CrT、CoT、匠魂2和匠魂盔甲(调用了匠魂盔甲和CoT联动的自定义材料接口),相关源代码如下:(关于自定义匠魂材料请参考CoT教程区相关教程,关于自定义匠魂特性请参考CoT蕉城区相关教程或是笔者的教程:Click Here,此处不对自定义过程进行解释)
#loader contenttweaker
#modloaded tconstruct
import mods.contenttweaker.tconstruct.TraitBuilder;
import crafttweaker.player.IPlayer;
import mods.contenttweaker.conarm.ExtendedMaterialBuilder;
import mods.contenttweaker.tconstruct.MaterialBuilder;
val aTrait = TraitBuilder.create("a_trait");
aTrait.color = 0xb06aff;
aTrait.localizedName = "测试特性A" ;
aTrait.localizedDescription = "这是个测试特性!\n增加200%伤害,结算攻击时输出基础伤害和该特性修改前伤害" ;
aTrait.calcDamage = function(trait, tool, attacker, target, originalDamage, newDamage, isCritical) {
if(!attacker.world.remote){
if(attacker instanceof IPlayer){
var player as IPlayer = attacker;
player.sendChat("A特性触发!");
player.sendChat("初始伤害为:" ~ (originalDamage as string));
player.sendChat("截至触发到该条特性时伤害为:" ~ (newDamage as string));
player.sendChat("该特性修改后伤害为:" ~ (newDamage*3.0f as string));
}
}
return (newDamage*3.0f);
};
aTrait.register();
val bTrait = TraitBuilder.create("b_trait");
bTrait.color = 0xb06aff;
bTrait.localizedName = "测试特性B" ;
bTrait.localizedDescription = "这是个测试特性!\n增加99点攻击,结算攻击时输出基础伤害和该特性修改前伤害" ;
bTrait.calcDamage = function(trait, tool, attacker, target, originalDamage, newDamage, isCritical) {
if(!attacker.world.remote){
if(attacker instanceof IPlayer){
var player as IPlayer = attacker;
player.sendChat("B特性触发!");
player.sendChat("初始伤害为:" ~ (originalDamage as string));
player.sendChat("截至触发到该条特性时伤害为:" ~ (newDamage as string));
player.sendChat("该特性修改后伤害为:" ~ (newDamage + 99.0f as string));
}
}
return (newDamage + 99.0f);
};
bTrait.register();
var testMaterial = ExtendedMaterialBuilder.create("test_material");
testMaterial.color = 0x00ffff;
testMaterial.craftable = true;
testMaterial.castable = false;
testMaterial.localizedName = "测试材料";
testMaterial.representativeItem = <item:minecraft:apple>;
testMaterial.addItem(<item:minecraft:apple>);
testMaterial.addHeadMaterialStats(1000,10,8,4);
testMaterial.addHandleMaterialStats(2.0,100);
testMaterial.addExtraMaterialStats(500);
testMaterial.addProjectileMaterialStats();
testMaterial.addMaterialTrait("a_trait","head");
testMaterial.addMaterialTrait("b_trait","handle");
testMaterial.itemLocalizer = function(thisMaterial, itemName) {
return "测试 " + itemName;
};
testMaterial.register();
以下是游戏内自定义效果截图:(请原谅我写错了红色的RGB颜色代码www)
两个测试特性效果详解:
· 测试特性A:在攻击实体前、计算伤害时触发调用,会向玩家聊天栏内发送“A特性触发!”、“初始伤害为:”+武器未经过特性修改时的攻击力、"截至触发到该条特性时伤害为:"+截至到该特性前所有增伤特性结算后的伤害、“该特性修改后伤害为:”+该特性修改后的伤害,并使伤害提升200%。
· 测试特性B:在攻击实体前、计算伤害时触发调用,会向玩家聊天栏内发送“B特性触发!”、“初始伤害为:”+武器未经过特性修改时的攻击力、"截至触发到该条特性时伤害为:"+截至到该特性前所有增伤特性结算后的伤害、“该特性修改后伤害为:”+该特性修改后的伤害,并使伤害提升99点。
此处笔者使用该材料制作了一把西洋剑,如下:
笔者使用(和自定义特性教程一样的)血量被修改后的极光幽境boss皎月女王进行测试,攻击前后效果如下:
攻击前:600点血
攻击后:487.46点血
可以看到左下角输出信息是B特性触发、修改伤害后再由A特性触发修改伤害,换言之B特性的99伤害增加吃到了A特性的200%增伤,导致伤害来到了300点。不过由于匠魂源代码内部伤害衰减机制的存在(具体可以参考此篇教程:Click Here)和怪物防御的存在,导致最后怪物被扣了112.45点血。
接下来笔者另外锻造了一把西洋剑,利用刻印将测试特性A放在了测试特性B上,如下:
同样使用这把剑攻击攻击皎月女王,测试效果如下:
攻击前:600点血
攻击后:525.87点血
可以很明显地看到,该武器的伤害经过A特性的调整达到了16.2点,再经由B特性的调整达到了115.2点,不过由于伤害衰减和怪物防御,最后怪物掉了74.13点血。
总结:匠魂工具特性触发顺序是从上至下依次结算触发。这一点在对某些整体乘算特性和加算特性混合时进行材料排布以追求伤害最大化有着很重要的指导意义。
接下来测试其他相关增伤特性的增伤机制,为此笔者将测试特性A和B的增伤效果去除并删掉最后一段调试信息,同时自定义新特性“测试特性C”使其代码和A、B部分除输出外完全相同并将其添加进测试材料的“其他部件”中,其余代码部分不变,代码如下:
(P.S.此段代码可供读者随意复制粘贴修改以进行测试而无需署名备注,复制前请先下载CrT、CoT和匠魂2模组以及其所有前置模组,然后将这段代码复制粘贴在.txt文本格式里改后缀为.zs并放入.minecraft\scripts文件夹中即可,完整的魔改教程请去CrT/CoT教程分区寻找)
#loader contenttweaker
#modloaded tconstruct
import mods.contenttweaker.tconstruct.TraitBuilder;
import crafttweaker.player.IPlayer;
import mods.contenttweaker.conarm.ExtendedMaterialBuilder;
import mods.contenttweaker.tconstruct.MaterialBuilder;
val aTrait = TraitBuilder.create("a_trait");
aTrait.color = 0xb06aff;
aTrait.localizedName = "测试特性A" ;
aTrait.localizedDescription = "这是个测试特性!\n结算攻击时输出基础伤害和截至触发到该条特性时的伤害" ;
aTrait.calcDamage = function(trait, tool, attacker, target, originalDamage, newDamage, isCritical) {
if(!attacker.world.remote){
if(attacker instanceof IPlayer){
var player as IPlayer = attacker;
player.sendChat("A特性触发!");
player.sendChat("初始伤害为:" ~ (originalDamage as string));
player.sendChat("截至触发到该条特性时伤害为:" ~ (newDamage as string));
}
}
return newDamage;
};
aTrait.register();
val bTrait = TraitBuilder.create("b_trait");
bTrait.color = 0xb06aff;
bTrait.localizedName = "测试特性B" ;
bTrait.localizedDescription = "这是个测试特性!\n结算攻击时输出基础伤害和截至触发到该条特性时的伤害" ;
bTrait.calcDamage = function(trait, tool, attacker, target, originalDamage, newDamage, isCritical) {
if(!attacker.world.remote){
if(attacker instanceof IPlayer){
var player as IPlayer = attacker;
player.sendChat("B特性触发!");
player.sendChat("初始伤害为:" ~ (originalDamage as string));
player.sendChat("截至触发到该条特性时伤害为:" ~ (newDamage as string));
}
}
return newDamage;
};
bTrait.register();
val cTrait = TraitBuilder.create("c_trait");
cTrait.color = 0xb06aff;
cTrait.localizedName = "测试特性C" ;
cTrait.localizedDescription = "这是个测试特性!\n结算攻击时输出基础伤害和截至触发到该条特性时的伤害" ;
cTrait.calcDamage = function(trait, tool, attacker, target, originalDamage, newDamage, isCritical) {
if(!attacker.world.remote){
if(attacker instanceof IPlayer){
var player as IPlayer = attacker;
player.sendChat("C特性触发!");
player.sendChat("初始伤害为:" ~ (originalDamage as string));
player.sendChat("截至触发到该条特性时伤害为:" ~ (newDamage as string));
}
}
return newDamage;
};
cTrait.register();
//如果没有装匠魂盔甲则需要把下边代码第一行的“ExtendedMaterialBuilder”
//改成“MaterialBuilder”
var testMaterial = ExtendedMaterialBuilder.create("test_material");
//你可以在这里修改颜色来改掉万恶的蓝色(格式:“0x”+不区分大小写的RGB颜色代码)
testMaterial.color = 0x00ffff;
testMaterial.craftable = true;
testMaterial.castable = false;
testMaterial.localizedName = "测试材料";
//这里改匠魂书中材料的“代表性原材料”(和直接制作部件的材料无关!)
//只需要把下边“minecraft:apple”换成你想要的物品id即可(id可用F3+H查看)
testMaterial.representativeItem = <item:minecraft:apple>;
//这里才是关乎实际部件台上制作部件的原材料,修改方法同上
testMaterial.addItem(<item:minecraft:apple>);
//各个部分数据,你可以自行修改摸索
testMaterial.addHeadMaterialStats(1000,10,8,4);
testMaterial.addHandleMaterialStats(2.0,100);
testMaterial.addExtraMaterialStats(500);
testMaterial.addProjectileMaterialStats();
testMaterial.addMaterialTrait("a_trait","head");
testMaterial.addMaterialTrait("b_trait","handle");
testMaterial.addMaterialTrait("c_trait","extra");
testMaterial.itemLocalizer = function(thisMaterial, itemName) {
return "测试 " + itemName;
};
testMaterial.register();
重新加载游戏后我们有:
这里笔者测试了骨头的碎骨、地狱岩的好暑和炼狱、玛玉灵的冷血、熔岩史莱姆的过热和暮色森林系列材料的暮光,有以下结论:(本来笔者想测试炼狱吃到和吃不到玛玉灵的百分比增伤结果测试后发现与猜想的机制不符)
1.玛玉灵的冷血加成仅仅只是提升基础面板攻击力50%的伤害量,熔岩史莱姆同理;
2.地狱岩的好暑会对武器伤害造成影响,炼狱是类似于未调整前的测试特性B增伤;
3.骨头的碎骨加成是在武器面板上;
4.暮色森林系列的暮光加成方式和炼狱相同;
由于测试过程较长,此处便不放图了。
最后我们来说一说匠魂的特性排布顺序:特性排布顺序和特性本身在材料中的排布顺序、武器=制作时组件预定顺序有关,例如(警告:该材料存在重度魔改!):
此材料特性排布顺序便是“老成-极光之赐-月光凝晶-夜幕的向往-力量”;
大剑的组件预定顺序为“手柄-剑刃-宽护手”,我们用带有“暮光-同调(重置)”特性的钢叶手柄,带有“冷血”的玛玉灵宽护手和上述极光钢剑刃打造这把武器,则其预期特性排布如下:暮光-同调(重置)-老成-极光之赐-月光凝晶-夜幕的向往-力量-冷血。这里放出实际所得武器特性截图:
和预期完全一致。
最后作一个总结:
1.匠魂特性触发顺序为从上到下依次结算(若非相关结算特性则跳过);
2.冷血、过热的百分比增伤是基于武器面板乘算加成而非整体乘算,碎骨的增伤加成作用在武器的基础伤害数值上,炼狱和暮光的伤害加成是额外数值加成;
3.武器的特性排布顺序和(1)材料的预定特性排布顺序(2)武器制作的组件预定顺序有关(相同特性高位会覆盖地位)。