跳至正文

基础物品——消耗品

“消耗品啊,最终都会变成不消耗的”   ——辅助mod
Item.consumable = true; // 标记为消耗品,物品介绍会多一行“消耗品”

如果你想让一个物品变成消耗品,把上面那行扔进 SetDefaults 就完事了。

与物品消耗弹药基本是一样的,这里介绍一些更高级的写法。

重写函数

你可以使用一些重写函数来控制消耗物品时的行为。

ConsumeItem

使用这个函数来控制是否消耗物品。前提是 Item.consumable = true

嗯你可以让这个物品跟巨兽鲨33%概率不消耗子弹那样的。

public override bool ConsumeItem(Player player)
{
    return true; // true是消耗,false不消耗
}

OnConsumeItem

这是当成功消耗物品时执行的函数,如果上边那个函数返回值是 false ,这个函数就不会执行了。

public override void OnConsumeItem(Player player)
{
    // 键入你想要的效果
}

注意很多辅助mod都会在一定条件下让上边那个玩意返回 true ,导致这里没效果。

那咋办捏,你可以把效果写到之前介绍过的重写函数 CanUseItem 去。

经典消耗品

下面介绍一些经典消耗品的写法。

药剂

药剂可以说是贯穿整个流程,来看看怎么写吧。熟悉的 SetDefaults 环节:

public override void SetDefaults()
{
    // 基础设定
    Item.width = 22;
    Item.height = 22;
    Item.rare = ItemRarityID.Yellow;
    Item.value = Item.sellPrice(0, 5, 0, 0);

    // 使用属性
    Item.useStyle = ItemUseStyleID.DrinkLiquid;
    Item.useAnimation = 17;
    Item.useTime = 17;
    Item.UseSound = SoundID.Item3;

    // 药剂的设定
    Item.consumable = true; // 这是消耗品
    Item.buffType = BuffID.ManaRegeneration; // 药剂的buff类型,这个是魔力再生药水的效果
    Item.buffTime = 7200; // 药效持续时间,7200帧即2分钟
}

注意,写了 Item.buffTime 会让物品显示持续时间,但是药剂喝了是什么buff要自己往描述 Tooltip 里写。

如果嫌这个只能加一个buff,你可以到 CanuseItem 或者 OnConsumeItem ,想加多少加多少,就用那个 AddBuff(int BuffID,int buffTime) 的玩意儿,NPC也用这个。

这里就不得不来一下自定义Buff了!

这个和物品不太一样倒是,不过也是从基础设定开始。这里继承的就不是 ModItem ,而是 ModBuff 了。

自定义Buff

这样TR才会知道这是一个buff,同时你也可以使用它的重写函数。

Buff需要一个32*32的贴图嗷~

继承的类变了

那么,直接来吧!Buff没有 SetDefaults ,只有SSD,因为它只有一个实例。

SetStaticDefaults

用这个来设定基础属性吧。

//Buff的本地化格式
Buffs: {
    ClassName: {
        DisplayName: Buff名
        Description: Buff描述
    }
}
public override void SetStaticDefaults()
{
    // 因为buff严格意义上不是一个TR里面自定义的数据类型,所以没有像buff.XXXX这样的设置属性方式了
    // 我们需要用另外一种方式设置属性

    // 这个属性决定buff在游戏退出再进来后会不会仍然持续,true就是不会,false就是会
    Main.buffNoSave[Type] = false;

    // 用来判定这个buff算不算一个debuff,如果设置为true会得到TR里对于debuff的限制,比如无法取消
    Main.debuff[Type] = true;

    // 决定这个buff能不能被被护士治疗给干掉,true是不可以,false则可以取消
    BuffID.Sets.NurseCannotRemoveDebuff[Type] = true;

    // 决定这个buff是不是照明宠物的buff,以后讲宠物和召唤物的时候会用到的,现在先设为false
    Main.lightPet[Type] = false;

    // 决定这个buff会不会显示持续时间,false就是会显示,true就是不会显示,一般宠物buff都不会显示
    Main.buffNoTimeDisplay[Type] = false;

    // 决定这个buff在专家模式会不会持续时间加长,false是不会,true是会
    // 这个持续时间,专家翻倍,大师三倍
    //BuffID.Sets.LongerExpertDebuff[Type] = false;

    // 如果这个属性为true,pvp的时候就可以给对手加上这个debuff/buff
    Main.pvpBuff[Type] = true;
    
    // 死亡后是否不清除buff,true为不清除,false清除,默认清除
    Main.persistentBuff[Type] = false;

    // 决定这个buff是不是一个装饰性宠物,用来判定的,比如消除buff的时候不会消除它
    Main.vanityPet[Type] = false;
}

差不多是这些,比较常用。普通写个debuff只要设置是否会保存和标记为debuff就行了。

然后是buff的效果:

Update

这里有两个,一个是对玩家生效,一个是对npc。

目标被挂上buff后执行的哦。

// 这里给的第二个buffIndex是buff在玩家身上的索引
public override void Update(Player player, ref int buffIndex)
{
    // 每帧1/3的概率让玩家散发绿色粒子(其实是诅咒焰那个粒子)
    if (Main.rand.NextBool(3))
    {
        Dust d = Dust.NewDustDirect(player.position, player.width, player.height, DustID.GreenFairy);
        d.velocity *= 0.5f;
    }

    // 把玩家的所有生命回复清除
    if (player.lifeRegen > 0)
    {
        player.lifeRegen = 0;
    }
    player.lifeRegenTime = 0;

    // 让玩家的减血速率随着时间而减少
    // player.buffTime[buffIndex]就是这个buff的剩余时间
    player.lifeRegen -= player.buffTime[buffIndex];
    // cool,如果这是一个一分钟的buff,那么获得buff的第一帧你的生命回复速率就是-3600了
    // 这意味着下一帧你就寄了
}
public override void Update(NPC npc, ref int buffIndex)
{
    // npc也有liferegen,你们可以自己试着写
}

不过其实在buff中写 liferegen 是不太规范的,之后会讲正经写法。

还有一件事儿,嗯。

ReApply

这个是目标已经有这个buff了但又被添这个buff的那一帧执行的。

// return false以使用原版效果,即再次被添加时重置时间为新的时间,即参数中给的time(如果剩的比新的短)
// return true以禁用原版效果,这里的改动是再次添加时让buff剩余时间增加这个上buff的时间
public override bool ReApply(Player player, int time, int buffIndex)
{
    player.buffTime[buffIndex] += time;
    return true;
}

到此一个ModBuff就基本写好了,使用 ModContent.BuffType<你的ModBuff类>() 来获取id并使用吧。

弹药

要让物品被识别为弹药,就要在 SetDefaults 中给这个字段赋值:

Item.ammo = AmmoID.Arrow; // 这个物品被标记为弹药且介绍内会出现“弹药”字样
// 这里标记的是作为箭矢
Item.shoot = ProjectileID.FireArrow; // 物品射出的弹幕type是烈焰箭,会导致消耗这个物品作为弹药时射出弹幕变成这个

虽然但是,弹药不用写那个 consumale = true

你也可以将物品的弹药类型标记为自身,使用 Item.ammo = Type ,之后把武器的 useAmmo 也改成这个物品的 type 即可。

Boss/事件 召唤物

不过是在使用的函数里写一写判定:

public override bool CanUseItem(Player player)
{
    if(Main.dayTime)
    {
        return false; // 如果是白天就告辞
    }

    // 遍历当前npc,有存活的克苏鲁之眼则物品无法使用(没有使用动画啥的了)
    foreach (NPC npc in Main.npc)
    {
        if (npc.active && npc.type == NPCID.EyeofCthulhu)
        {
            return false;
        }
    }
    // 上面的return false会直接离开这个方法,所以没找到npc下面才会执行

    // 生成一个在玩家300像素到800像素之内的坐标
    Vector2 pos = player.Center;
    while (Vector2.Distance(pos, player.Center) is < 300 or > 800)
    {
        pos = player.Center + new Vector2(Main.rand.Next(-800, 800), Main.rand.Next(-800, 800));
    }
    // 在这个坐标召唤克苏鲁之眼,四个参数分别是生成的横、纵坐标,npc的type,它的目标玩家的索引
    // 这个方法会在执行的时候自动发送“xxx已苏醒!”的消息
    NPC.SpawnBoss((int)pos.X, (int)pos.Y, NPCID.EyeofCthulhu, player.whoAmI);
    return true; // 可以使用物品

    // 想一想,如果要既有使用动画又不会召唤boss要怎么写?
}

另外这里还有个标记,是写在SSD中的:

ItemID.Sets.SortingPriorityBossSpawns[Type] = 13; //这是一个boss召唤物

摸彩袋

啊?摸彩袋是啥?

其实就是那些boss袋子,钓鱼的匣子,还有草药袋蠕虫罐头什么的。

与上面的消耗品不同的是,摸彩袋是在背包中右键来使用。

CanRightClick

把这个重写函数的返回值改成 true 来允许这个物品在背包中的右键效果,它默认是 false 的。

游戏中会告诉你这个玩意“右键点击可打开”。

public override bool CanRightClick()
{
    return true;
}

现在ok了,来看发动效果的重写函数:

RightClick

这是在背包中右击物品时执行的函数。

你可以在这边写奇奇怪怪的效果,比如干掉玩家。

public override void RightClick(Player player)
{
    // 这会在玩家头上直接给你扔一个物品出来,这里是猪鲨翅膀,这个方法的参数是生成源,物品id,物品数量(不写默认1个)
    player.QuickSpawnItemDirect(player.GetSource_ItemUse(Item), ItemID.FishronWings);
}

以上是不规范写法。下面有请函数:

ModifyItemLoot

这是规范写法,你们以后在npc那儿也会看见的。

规范写的话,你甚至可以用Mod更好的体验看到摸彩袋的战利品表。

有关掉落规则,详见此处

这里提供简单案例:

// 这个函数的执行条件跟上面的RightClick是一致的
public override void ModifyItemLoot(ItemLoot itemLoot)
{
    // 给战利品池子添加:不受玩家幸运影响的有1/7概率掉落的猪鲨翅膀,这个方法有四个参数,物品id,掉率分母,也就是1/分母的掉率
    // 最小掉落数量,默认1,最大掉落数量,默认1
    itemLoot.Add(ItemDropRule.NotScalingWithLuck(ItemID.FishronWings, 7));
    // 添加:受玩家幸运影响的,1 / 2 = 50%概率掉落(这个概率将被幸运修正提高)的绿藻矿,30~60个
    itemLoot.Add(ItemDropRule.Common(ItemID.ChlorophyteOre, 2, 30, 60));
    // 添加:掉落基于世纪之花价值的钱币
    itemLoot.Add(ItemDropRule.CoinsBasedOnNPCValue(NPCID.Plantera));
}

练习

基础

  1. 如何写一个跟武器灌注一样的buff答案
    写在SetStaticDefaults
    Main.meleeBuff[Type] = true;// 设为true后将会与原版武器灌注冲突(只会存在一种武器灌注)
    Main.persistentBuff[Type] = true;// 死亡后不会清除buff
    
  2. 如何做一个永远不会结束的buff答案
    SetStaticDefaults里面
    Main.buffNoTimeDisplay[Type] = true;// buff不显示持续时间
    Main.debuff[Type] = true;// 将其设为debuff,这将会有多种影响
    BuffID.Sets.NurseCannotRemoveDebuff[Type] = true;// 无法被护士清除(一般debuff可以被护士清除,所以要阻止)
    Main.buffNoSave[Type] = false;// 退出世界不会取消buff
    Main.persistentBuff[Type] = true;// 死亡后不会清除buff

    Update里面

    player.buffTime[buffIndex] = 2;

    这下你就只能通过一些特殊手段取消它了(笑)

劝退

写一个战利品池:

  • 在玩家处于血腥地时
  • 在玩家处于地下时
  • 在玩家满血时
  • 在玩家拿着鱼竿时
  • 在玩家装备职业徽章时
  • 在上述条件满足3条,血月时满足两条时
  • 有75%概率掉落水晶蛇
  • 在水晶蛇不掉落时25%掉落大师鱼饵
  • 在大师鱼饵不掉落时35%概率掉落海草
  • 在海草和水晶蛇不同时掉落时40%概率掉落1铂金币
  • 在大师鱼饵与铂金币同时掉落时80%概率掉落打折卡
标签:

《基础物品——消耗品》有3个想法

  1. Pingback: Global系列-全局操作 - 裙中世界

发表回复