跳至正文

基础物品 — 装备

饰品

饰品也是很简单滴。

它除了需要一个基本物品的属性之外,也就多那么点东西。以下都在 SetDefaults 中:

Item.accessory = true; // 将物品标记为饰品,会让这个物品可以装备在饰品栏,同时物品的介绍上也会显示“可装备”字样
Item.defense = 10; // 装备了可以增加10点防御力,这一般是盾牌类型的才写

// Item.expert = true; 物品是专家模式及以上独有的,会改变物品的稀有度变成专家稀有度(彩虹渐变色)
// Item.expertOnly = true; 饰品在专家难度以下不会生效,这不影响使用只影响装备效果,你在经典模式装备该饰品就会有一个红叉号并且属性无效
// Item.master = true; 大师独有,改变稀有度为大师(金红渐变色)
// Item.masterOnly = true; 仅大师难度以上生效
饰品不生效

好的饰品写完了!本篇结束了!

咳,如果只是如此,那这个饰品也太单调了。

再来加些东西吧。

UpdateAccessory

饰品的核心函数,在装备时触发,它提供玩家实例和一个叫 hideVisualbool 参数,是说你是否关掉了饰品可见性。你可以用这个重写函数来给玩家写加成,或者是减益?

public override void UpdateAccessory(Player player, bool hideVisual)
{
    player.lifeRegen += 10; // 玩家生命回复增加 10 / 2 = 5点每秒
    player.GetDamage(DamageClass.Generic) += 0.1f; // 玩家全伤害增加10%
    player.GetAttackSpeed(DamageClass.Melee) -= 0.1f; // 玩家近战攻速减少10%
    if (hideVisual) player.GetCritChance(DamageClass.Magic) += 20f; // 玩家魔法暴击率增加20%,当关掉饰品可见性时
}

Wow,你应该注意到这些Get的方法了,它们的参数是伤害类型。

玩家部分属性

玩家的属性有很多,教程中无法一一列举出来,这里就放出一些常用的属性。你们应该熟练运用vs的自动补全并且靠着英文意思和实际测试去探索更多的属性。

字段名值类型描述
statLifeint玩家当前生命值
statLifeMaxint生命上限的基准,生命水晶和生命果加的是这个
statLifeMax2int临时的生命上限,生命力药水和饰品效果用这个
lifeRegenint每两秒的生命回复量
lifeRegenTimeint开始生命回复的速率,加的越多就越快开始生命回复
statDefenseint玩家防御力
endurancefloat玩家伤害减免,蠕虫围巾是 += 0.17f,增加17%
statManaint玩家当前魔力
statManaMaxint 魔力上限基准,@魔力水晶
statManaMax2int 魔力临时上限
manaRegenint每两秒的魔力回复量
manaCostfloat魔力消耗率, += 0.05f 就是增加5%魔力消耗
noKnockbackbool为true则玩家不会被击退 @钴蓝盾
noFallDmgbool为true则玩家不会受到摔落伤害 @马蹄铁
moveSpeedfloat玩家水平移速
maxRunSpeedfloat 玩家水平移速上限
runAccelerationfloat 玩家水平移动加速度
runSlowdownfloat 玩家不控制水平移动的减速度
maxMinionsint玩家的最大召唤栏
numMinionsint玩家召唤了多少个召唤物
slotsMinionsfloat玩家使用了多少召唤栏(双子魔眼2个占1栏)
你可以试试对着它们一通瞎改会发生什么

有关生命再生与魔力再生的机制,请参阅:生命再生魔力再生

翅膀

翅膀是比较特殊的饰品,参数也多,贴图要两份,还得给它打标()

一个翅膀需要准备的
物品图
翅膀帧图

先按着之前学过的知识来创建一个翅膀饰品的文件吧。

你应该注意到不一样的东西了—— [AutoloadEquip(EquipType.Wings)]

Attribute

这个其实是一个C#里面叫做 Attribute 的东西,我们可以理解为给这个类打上一个标记,这样TML读到这个类的时候就会知道这是个翅膀。注意到我们之前的那个帧图贴图了吗,为什么它要有一个后缀_Wings,就是因为打了Wings标记的类需要一个Wings帧图,而且这个帧图名字必须匹配且必须有正好4帧。

有关翅膀,在 SetDefaults 中跟其他饰品没有区别,但是 UpdateAcc 中要多写一个属性:

public override void UpdateAccessory(Player player, bool hideVisual)
{
    player.wingTimeMax = 180; // 玩家的最大飞行时间,3s
    // player.wingTime = player.wingTimeMax; 这样写会导致每帧你的剩余飞行时间都被重置为最大值,然后你就无限飞行了
}

写了就能飞,不过这个最大飞行时间不等于实际飞行时间,因为飞行时间的消耗速率在某些情况下不一样。

嗯,其实就是悬停消耗减半啦,然后喷气背包按住上升时是双倍消耗率。反正跟咱们没关系。

飞行参数

// 控制垂直飞行的函数
public override void VerticalWingSpeeds(Player player, ref float ascentWhenFalling, ref float ascentWhenRising, ref float maxCanAscendMultiplier, ref float maxAscentMultiplier, ref float constantAscend) { }

// 控制水平飞行的函数
public override void HorizontalWingSpeeds(Player player, ref float speed, ref float acceleration) { }

这两个重写函数的参数比较多,它们是玩家在飞时每帧更新的。

先看 VerticalWingSpeeds 这个函数,Player就不说了,

ascentWhenFalling 这个属性是控制玩家在下落的时候开启翅膀的下落减速度(下落时爬升率),如果设为0那么下落的时候就需要比较长的时间才能上去;

ascentWhenRising 是玩家切换到上升状态时的爬升率;

maxCanAscendMultiplier 是,当 玩家上升速度玩家跳跃速度*这个值 的时候,使用那个上升爬升率;

maxAscentMultiplier 是玩家可以到达的最大爬升率;

constantAscend 是正常飞行时翅膀的爬升率;

然后就是 HorizontalWingSpeeds 这个函数,speed 就是你一直按着方向键能到多快,acceleration 就是加速度啦。

不过水平速度上的控制还有另一种写法,同时这种写法也可以选择让翅膀是否能悬停。

WingStats

噢,IDSet要来力!注意,因为是写在SSD,所以这个玩意是不会像上面两个函数一样每帧更新的。

public override void SetStaticDefaults()
{
    // 物品名和描述你们自己记得
    ArmorIDs.Wing.Sets.Stats[Item.wingSlot] = new WingStats( /*键入参数*/ );
}

WingStats,这是一个结构体,来看看它的构造方法。

呃啊,又是一堆参数

前三个参数分别是,飞行时间,水平最大速度,水平加速度。

后面三个是重点,它们分别是:可否悬停,平飞最大速度,平飞加速度。想想星盘,它用平飞那真不是一般的快。

// eg.
// ArmorIDs.Wing.Sets.Stats[Item.wingSlot] = new WingStats(180, 8, 4.5f, true, 16, 16);
// 这样这个翅膀的水平机动力就和天界星盘的水平机动力一致了
名称平飞最大速度平飞加速度
悬浮板1010
双足翼龙之翼1212
星云斗篷1212
星旋强化翼1212
天界星盘1616
悬停数据参考

这里是原版翅膀的数据,拿去参考吧,这里边就没有悬停的数据了。

盔甲

盔甲是更复杂的可装备物。嗯,我说的是噩梦一般的帧图

瞧瞧这个贴图量

它分为头身腿三个部位,记得打标。这次的就不是 Wings 了:头盔 Head ,胸铠 Body ,腿甲 Legs

写上以上 Attribute ,TML会自动识别它们的类型,并让它们可装备

还要记得要 在SetDefaults 中写上防御力嗷~

在套装/装备效果里面,我们要用UpdateEquip这个重写函数来施加效果,而不是UpdateAccessory,因为装备不具备饰品的一些特性。

UpdateEquip

public override void UpdateEquip(Player player)
{
    // 免疫灼伤debuff
    player.buffImmune[BuffID.OnFire] = true;

    // 增加生命上限50
    player.statLifeMax2 += 50;

    // 增加2点生命恢复,虽然看起来不多,其实在游戏里还挺可观的
    player.lifeRegen += 2;
}

套装效果

套装效果是盔甲的一大特色,这里涉及到两个重写函数,一个用于判定,一个用于生效效果。

想想原版的神圣套,它使用头盔的类型来区分职业类型。所以,我们把套装判定写在头盔中。你应该不会想准备很多种胸铠的贴图吧?画师会掐死你的

IsArmorSet

在头盔中写上这个重写函数,用以判定玩家是否穿了套装,你们只要把判定里的物品类型改成自己的就好。

// 让头盔,胸甲,护腿全部都是模板装备的才能算是套装
public override bool IsArmorSet(Item head, Item body, Item legs)
{
    // 这里没有判定头盔类型,因为玩家要穿着这个头盔才会执行这里的判定
    return body.type == ModContent.ItemType<ExampleBreastplate>() && legs.type == ModContent.ItemType<ExampleLeggings>();
}

UpdateArmorSet

这是当上面那个 IsArmorSet 的返回值是 true 的时候才会执行的函数。

public override void UpdateArmorSet(Player player)
{
    // 套装奖励描述,就是鼠标移上去最底下显示的套装效果
    player.setBonus = "进一步增加回血速度,吸取红心范围增大\n" +
        "增加10%伤害减免";
    player.endurance += 0.1f;
    player.lifeRegen += 2;
    player.lifeMagnet = true;
    // 加点特技,你们可以试试效果
    //player.armorEffectDrawShadow = true;
}

不过这个套装效果在头盔里写一次就够了,在三个盔甲里都写会发生什么呢?三倍Ice cream!!!

练习

基础

  1. 写一个看起来很nb但实际毫无作用的套装描述来逗逗玩家吧?答案
    player.setBonus = "可装备" +
    "\n材料" +
    "\n100 防御力" +
    "\n“无论凡人或不朽,都承认你的神性”" +
    "\n暴击率设为50%" +
    "\n每次暴击提升10%" +
    "\n达到100%时所有攻击附带10%的生命偷取,增加5%伤害,增加5防御力" +
    "\n可叠加950次直到被攻击" +
    "\n额外获得:增加250%的伤害" +
    "\n增加100%的射击速度" +
    "\n增加25%的暴击率" +
    "\n暴击造成10倍伤害" +
    "\n所有武器击退翻倍并可自动连发" +
    "\n最大小黄人数量增加30" +
    "\n最大哨兵数量增加20" +
    "\n最大魔力值增加到999" +
    "\n最大生命恢复提升50%,增加40%伤害免疫,增加15生命回复" +
    "\n获得回击免疫和大部分减益" +
    "\n你会反弹所有射弹";
    // 放进UpdateArmorSet重写函数就行
    

进阶

  1. 如何实现在装备某套装后,某个武器受到影响?
  2. 试着实现一下多头盔配一套盔甲和护腿吧!
  3. 试着实现一下上面所说的(基础问题1)盔甲效果吧!(别打我)

劝退

  1. 试着写一个套装,该套装的头盔为原版全头盔的效果之和,盔甲和护腿也是如此。而套装奖励则是每分钟随机挑选十个原版的套装奖励作为套装奖励。
标签:

《基础物品 — 装备》有5个想法

  1. 现在装备特效的player.armorEffectDrawShadow = true;这玩意要写在public override void ArmorSetShadows(Player player){}里,写public override void UpdateArmorSet(Player player) {}里不起效(目移)

发表回复