泰拉瑞亚Mod(鸟妖勋章)物品开发日志

1、前言

        为了避免本人在游玩mod地图(来自深渊)坐牢,彻底解决鸟妖生成的问题,故而开发了本mod

2、设计思路

        项目设计之初,想要参考原版物品“皇家凝胶”,将鸟妖变成被动型生物。从结论上来说,这个设计很不幸失败了,失败的原因在于无法彻底禁止鸟妖射出羽毛(建议博主菜就多练),这可能是没有完全理解AI机制导致的。因此改换第二个思路,直接禁止鸟妖生成

3、代码核心

        以下是初版的失败代码,失败的原因在于原代码使用SpawnModificationPriority => uint.MaxValue - 1试图确保最高优先级,这是由于尝试重写不存在的父类成员(CS0115),为解决这个问题,我选择直接放弃属性控制,改为通过代码逻辑手动确保最后修改生成池。

using System;
using System.Collections.Generic;
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;

namespace HarpyGoAway.NPCs
{
    public class HarpySpawnControl : GlobalNPC
    {
        private static readonly int[] HarpyIDs = {
            NPCID.Harpy,
            NPCID.IlluminantHarpy,
            NPCID.Splinterling
        };


        public override uint SpawnModificationPriority => uint.MaxValue - 1;

        public override void EditSpawnPool(IDictionary<int, float> pool, NPCSpawnInfo spawnInfo)
        {
            try
            {
                // 使用安全导航操作符和模式匹配
                if (spawnInfo.Player?.GetModPlayer<HarpyMedallionPlayer>() is { } player 
                    && player.blockHarpySpawns
                    && spawnInfo.SpawnTileY < Main.worldSurface * 0.35)
                {
                    foreach (int id in HarpyIDs)
                    {
                        if (pool.TryGetValue(id, out _))
                        {
                            pool[id] = 0f; // 设置生成概率为0
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Mod.Logger.Warn($"生成控制异常:{ex}");
            }
        }

        // 增强防御:实时禁用NPC
        public override bool PreAI(NPC npc)
        {
            if (Array.Exists(HarpyIDs, x => x == npc.type))
            {
                if (Main.LocalPlayer.GetModPlayer<HarpyMedallionPlayer>().blockHarpySpawns)
                {
                    // 立即失效并清除
                    npc.active = false;
                    npc.netUpdate = true;
                    
                    // 防止残留逻辑执行
                    return false;
                }
            }
            return true;
        }
    }
}

4、项目结构

HARPYGOAWAY/
├── Items/                 
│   ├── HarpyMedallion.cs
│   └── HarpyMedallion.png  
├── NPCs/                
│   ├── HarpyCleaner.cs
│   └── HarpySpawnControl.png
├── Players/
     └── HarpyMedallionPlayer.cs

5、代码展示

HarpyMedallion.cs

using HarpyGoAway.Players;
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;

namespace HarpyGoAway.Items
{
    public class HarpyMedallion : ModItem
    {
        public override void SetStaticDefaults()
        {
            
        }

        public override void SetDefaults()
        {
            Item.width = 28;
            Item.height = 28;
            Item.accessory = true; // 设为饰品
            Item.rare = ItemRarityID.Pink;
            Item.value = Item.sellPrice(0, 0, 0, 0);
            Item.value = Item.buyPrice(0, 1, 0, 0);
        }

        // 饰品生效逻辑
        public override void UpdateAccessory(Player player, bool hideVisual)
        {
            player.GetModPlayer<HarpyMedallionPlayer>().blockHarpySpawns = true;
        }

        // 合成配方
        public override void AddRecipes()
        {
            CreateRecipe()
                .AddIngredient(ItemID.Feather, 1)
                .AddTile(18)
                .Register();
        }
    }
}

HarpyCleaner.cs

using HarpyGoAway.Players;
using Terraria;
using Terraria.ModLoader;

namespace HarpyGoAway.NPCs
{
    public class HarpyCleaner : GlobalNPC
    {
        public override bool PreAI(NPC npc)
        {
            if (npc.active && 
                (npc.type == 48) &&
                Main.LocalPlayer.GetModPlayer<HarpyMedallionPlayer>().blockHarpySpawns)
            {
                // 强制清除已存在的鸟妖
                npc.active = false;
                npc.netUpdate = true;
                return false;
            }
            return true;
        }
    }
}

HarpySpawnControl.cs

using System;
using System.Collections.Generic;
using System.Text;
using HarpyGoAway.Players;
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;

namespace HarpyGoAway.NPCs
{
    public class HarpySpawnControl : GlobalNPC
    {
        private static readonly int[] HarpyIDs = {
            NPCID.Harpy
        };

        public override void EditSpawnPool(IDictionary<int, float> pool, NPCSpawnInfo spawnInfo)
        {
            StringBuilder sb = new StringBuilder("当前生成池内容:\n");
            
            // 记录生成池条目总数
            sb.AppendLine($"总条目数:{pool.Count}");
            
            // 遍历所有生成条目
            foreach (var entry in pool)
            {
                string npcName = Lang.GetNPCNameValue(entry.Key);
                sb.AppendLine($"ID:{entry.Key} 名称:{npcName} 概率:{entry.Value:F2}");
            }
            
            //Main.NewText(sb.ToString());
            
            // 修改鸟妖生成概率
            foreach (int id in HarpyIDs)
            {
                if (pool.ContainsKey(id))
                {
                    float oldValue = pool[id];
                    pool[id] = 0f;
                    //Main.NewText($"已将 {Lang.GetNPCNameValue(id)} 生成概率从 {oldValue} 修改为 0");
                }
                else
                {
                    //Main.NewText($"{Lang.GetNPCNameValue(id)} 不在生成池中");
                }
            }
        }

        // 实时清除已生成的NPC
        public override bool PreAI(NPC npc)
        {
            if (Array.Exists(HarpyIDs, x => x == npc.type) &&
                Main.LocalPlayer.GetModPlayer<HarpyMedallionPlayer>().blockHarpySpawns)
            {
                npc.active = false;
                npc.netUpdate = true;
                return false;
            }
            return true;
        }
    }
}

HarpyMedallionPlayer.cs

using Terraria;
using Terraria.ModLoader;

namespace HarpyGoAway.Players
{
    public class HarpyMedallionPlayer : ModPlayer
    {
        public bool blockHarpySpawns;

        public override void ResetEffects() => blockHarpySpawns = false;

        /*
        public override void PostUpdateMiscEffects()
        {
            // 世界地表高度的35%(转换为像素)
            float skyHeightThreshold = (float)(Main.worldSurface * 0.35f * 16);
            bool inSkyLayer = Player.position.Y < skyHeightThreshold;

            blockHarpySpawns &= inSkyLayer;
        }
        */
    }
}

6、问答

        Q:为什么注释掉PostUpdateMiscEffects?

        A:这是由于博主对该mod地图不熟悉导致的,尚不清楚为什么在原版可以生效,但在mod地图中测试无法生效,因此采用了一刀切(取消了Y高度判断),在所有的Y值上都禁止生成鸟妖。

        Q:本Mod是否进行了多人联机适配?

        A:没有(博主太菜导致的,绝不是太懒

        Q:该Mod能否拓展并禁止其他生物生成?

        A:可以,你只需要在“黑名单”HarpyIDs中添加对应生物的NPCID

        Q:Mod是否会导致一辈子见不到鸟妖?

        A:不会,你只需要卸下这个物品即可正常刷新,而在戴上时会立刻杀死所有鸟妖。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值