“消耗品啊,最终都会变成不消耗的” ——辅助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都会在一定条件下让上边那个玩意返回 false
,导致这里不被调用(没效果)。
那咋办捏,你可以把效果写到之前介绍过的重写函数 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)); }
练习
基础
- 如何写一个跟武器灌注一样的buff答案写在
SetStaticDefaults
Main.meleeBuff[Type] = true;// 设为true后将会与原版武器灌注冲突(只会存在一种武器灌注) Main.persistentBuff[Type] = true;// 死亡后不会清除buff
- 如何做一个永远不会结束的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%概率掉落打折卡
练习,写得不好,看看就行了 https://paste.ubuntu.com/p/HjzWhpdp9K/
非常好
Pingback: Global系列-全局操作 - 裙中世界