Help With Custom Town NPCs

C#:
using Microsoft.Xna.Framework;
using System;
using System.Linq;
using Terraria;
using Terraria.Audio;
using Terraria.ID;
using Terraria.Localization;
using Terraria.ModLoader;
using Terraria.Utilities;
using Terraria.GameContent.Bestiary;
using Terraria.GameContent.ItemDropRules;
using Microsoft.Xna.Framework.Graphics;
using Terraria.GameContent;
using Terraria.GameContent.Personalities;
using Terraria.DataStructures;
using System.Collections.Generic;
using ReLogic.Content;
using Terraria.ModLoader.IO;

namespace ExampleMod.Content.NPCs
{
    // [AutoloadHead] and NPC.townNPC are extremely important and absolutely both necessary for any Town NPC to work at all.
    [AutoloadHead]
    public class ExamplePerson : ModNPC
    {
        public int NumberOfTimesTalkedTo = 0;

        public override void SetStaticDefaults()
        {
            // DisplayName automatically assigned from localization files, but the commented line below is the normal approach.
            // DisplayName.SetDefault("Example Person");
            Main.npcFrameCount[Type] = 25; // The amount of frames the NPC has

            NPCID.Sets.ExtraFramesCount[Type] = 9; // Generally for Town NPCs, but this is how the NPC does extra things such as sitting in a chair and talking to other NPCs.
            NPCID.Sets.AttackFrameCount[Type] = 4;
            NPCID.Sets.DangerDetectRange[Type] = 700; // The amount of pixels away from the center of the npc that it tries to attack enemies.
            NPCID.Sets.AttackType[Type] = 0;
            NPCID.Sets.AttackTime[Type] = 90; // The amount of time it takes for the NPC's attack animation to be over once it starts.
            NPCID.Sets.AttackAverageChance[Type] = 30;
            NPCID.Sets.HatOffsetY[Type] = 4; // For when a party is active, the party hat spawns at a Y offset.

            // Influences how the NPC looks in the Bestiary
            NPCID.Sets.NPCBestiaryDrawModifiers drawModifiers = new NPCID.Sets.NPCBestiaryDrawModifiers(0)
            {
                Velocity = 1f, // Draws the NPC in the bestiary as if its walking +1 tiles in the x direction
                Direction = -1 // -1 is left and 1 is right. NPCs are drawn facing the left by default but ExamplePerson will be drawn facing the right
                               // Rotation = MathHelper.ToRadians(180) // You can also change the rotation of an NPC. Rotation is measured in radians
                               // If you want to see an example of manually modifying these when the NPC is drawn, see PreDraw
            };

            NPCID.Sets.NPCBestiaryDrawOffset.Add(Type, drawModifiers);

            // Set Example Person's biome and neighbor preferences with the NPCHappiness hook. You can add happiness text and remarks with localization (See an example in ExampleMod/Localization/en-US.lang).
            // NOTE: The following code uses chaining - a style that works due to the fact that the SetXAffection methods return the same NPCHappiness instance they're called on.
            NPC.Happiness
            .SetBiomeAffection<HallowBiome>(AffectionLevel.Love) // Example Person prefers the forest.
            .SetBiomeAffection<ForestBiome>(AffectionLevel.Love)
            .SetBiomeAffection<DesertBiome>(AffectionLevel.Like)
            .SetBiomeAffection<SnowBiome>(AffectionLevel.Like)
            .SetBiomeAffection<UndergroundBiome>(AffectionLevel.Dislike) // Example Person likes the snow.
            .SetNPCAffection(NPCID.Truffle, AffectionLevel.Like) // Loves living near the dryad.
            .SetNPCAffection(NPCID.Guide, AffectionLevel.Like) // Likes living near the guide.
            .SetNPCAffection(NPCID.Wizard, AffectionLevel.Like) // Dislikes living near the merchant.
            .SetNPCAffection(NPCID.PartyGirl, AffectionLevel.Like) // Dislikes living near the merchant.
            .SetNPCAffection(NPCID.GoblinTinkerer, AffectionLevel.Dislike) // Dislikes living near the merchant.
            .SetNPCAffection(NPCID.TaxCollector, AffectionLevel.Hate) // Hates living near the demolitionist.
            ; // < Mind the semicolon!
        }

        public override void SetDefaults()
        {
            NPC.townNPC = true; // Sets NPC to be a Town NPC
            NPC.friendly = true; // NPC Will not attack player
            NPC.width = 18;
            NPC.height = 40;
            NPC.aiStyle = 7;
            NPC.damage = 10;
            NPC.defense = 15;
            NPC.lifeMax = 250;
            NPC.HitSound = SoundID.NPCHit1;
            NPC.DeathSound = SoundID.NPCDeath1;
            NPC.knockBackResist = 0.5f;

            AnimationType = NPCID.Guide;
        }

        public override void SetBestiary(BestiaryDatabase database, BestiaryEntry bestiaryEntry)
        {
            // We can use AddRange instead of calling Add multiple times in order to add multiple items at once
            bestiaryEntry.Info.AddRange(new IBestiaryInfoElement[] {
// Sets the preferred biomes of this town NPC listed in the bestiary.
// With Town NPCs, you usually set this to what biome it likes the most in regards to NPC happiness.
BestiaryDatabaseNPCsPopulator.CommonTags.SpawnConditions.Biomes.TheHallow,

// Sets your NPC's flavor text in the bestiary.
new FlavorTextBestiaryInfoElement("Did you want some lamp- I mean torches? Rope? Bombs? It's all your's, my friend, because this guy has it."),

// You can add multiple elements if you really wanted to
// You can also use localization keys (see Localization/en-US.lang)
new FlavorTextBestiaryInfoElement("Mods.NPCMorshu.Bestiary.RubyMerchant")
});
        }

        // The PreDraw hook is useful for drawing things before our sprite is drawn or running code before the sprite is drawn
        // Returning false will allow you to manually draw your NPC
        public override bool PreDraw(SpriteBatch spriteBatch, Vector2 screenPos, Color drawColor)
        {
            // This code slowly rotates the NPC in the bestiary
            // (simply checking NPC.IsABestiaryIconDummy and incrementing NPC.Rotation won't work here as it gets overridden by drawModifiers.Rotation each tick)
            if (NPCID.Sets.NPCBestiaryDrawOffset.TryGetValue(Type, out NPCID.Sets.NPCBestiaryDrawModifiers drawModifiers))
            {
                drawModifiers.Rotation += 0.001f;

                // Replace the existing NPCBestiaryDrawModifiers with our new one with an adjusted rotation
                NPCID.Sets.NPCBestiaryDrawOffset.Remove(Type);
                NPCID.Sets.NPCBestiaryDrawOffset.Add(Type, drawModifiers);
            }

            return true;
        }

        public override void HitEffect(int hitDirection, double damage)
        {
            int num = NPC.life > 0 ? 1 : 5;

            for (int k = 0; k < num; k++)
            {
                Dust.NewDust(NPC.position, NPC.width, NPC.height, (DustID.Blood));
            }
        }

        public override bool CanTownNPCSpawn(int numTownNPCs, int money)
        { // Requirements for the town NPC to spawn.
            for (int k = 0; k < 255; k++)
            {
                Player player = Main.player[k];
                if (!player.active)
                {
                    continue;
                }

                // Player has to have either an ExampleItem or an ExampleBlock in order for the NPC to spawn
                if (player.inventory.Any(item => item.type == (ItemID.Ruby) || item.type == (ItemID.LargeRuby)))
                {
                    return true;
                }
            }

            return false;
        }


        public override ITownNPCProfile TownNPCProfile()
        {
            return new ExamplePersonProfile();
        }

        public override List<string> SetNPCNameList()
        {
            return new List<string>() {
"Morshu"
};
        }

        public override void FindFrame(int frameHeight)
        {
            /*npc.frame.Width = 40;
            if (((int)Main.time / 10) % 2 == 0)
            {
            npc.frame.X = 40;
            }
            else
            {
            npc.frame.X = 0;
            }*/
        }

        public override string GetChat()
        {
            WeightedRandom<string> chat = new WeightedRandom<string>();

            int partyGirl = NPC.FindFirstNPC(NPCID.PartyGirl);
            if (partyGirl >= 0 && Main.rand.NextBool(4))
            {
                chat.Add(Language.GetTextValue("Mods.ExampleMod.Dialogue.ExamplePerson.PartyGirlDialogue", Main.npc[partyGirl].GivenName));
            }
            // These are things that the NPC has a chance of telling you when you talk to it.
            chat.Add(Language.GetTextValue("Mods.ExampleMod.Dialogue.ExamplePerson.StandardDialogue1"));
            chat.Add(Language.GetTextValue("Mods.ExampleMod.Dialogue.ExamplePerson.StandardDialogue2"));
            chat.Add(Language.GetTextValue("Mods.ExampleMod.Dialogue.ExamplePerson.StandardDialogue3"));
            chat.Add(Language.GetTextValue("Mods.ExampleMod.Dialogue.ExamplePerson.CommonDialogue"), 5.0);
            chat.Add(Language.GetTextValue("Mods.ExampleMod.Dialogue.ExamplePerson.RareDialogue"), 0.1);

            NumberOfTimesTalkedTo++;
            if (NumberOfTimesTalkedTo >= 10)
            {
                //This counter is linked to a single instance of the NPC, so if ExamplePerson is killed, the counter will reset.
                chat.Add(Language.GetTextValue("Mods.ExampleMod.Dialogue.ExamplePerson.TalkALot"));
            }

            return chat; // chat is implicitly cast to a string.
        }

        public override void SetChatButtons(ref string button, ref string button2)
        { // What the chat buttons are when you open up the chat UI
            button = Language.GetTextValue("LegacyInterface.28");

        }
        // Not completely finished, but below is what the NPC will sell

        public override void SetupShop(Chest shop, ref int nextSlot)
        {
            shop.item[nextSlot++].SetDefaults(ItemID.Torch);
            shop.item[nextSlot++].SetDefaults(ItemID.Rope);
            shop.item[nextSlot++].SetDefaults(ItemID.Bomb);
            shop.item[nextSlot++].SetDefaults(ItemID.RopeCoil);
            shop.item[nextSlot++].SetDefaults(ItemID.DirtBomb);
            shop.item[nextSlot++].SetDefaults(ItemID.Ruby);
            shop.item[nextSlot++].SetDefaults(ItemID.Topaz);
            shop.item[nextSlot++].SetDefaults(ItemID.Diamond);
            shop.item[nextSlot++].SetDefaults(ItemID.Amethyst);
            shop.item[nextSlot++].SetDefaults(ItemID.Emerald);
            shop.item[nextSlot++].SetDefaults(ItemID.Amber);
            shop.item[nextSlot++].SetDefaults(ItemID.Sapphire);
            shop.item[nextSlot++].SetDefaults(ItemID.LargeRuby);
        }
        //
        // if (Main.LocalPlayer.HasBuff(BuffID.Lifeforce)) {
        // shop.item[nextSlot++].SetDefaults(ItemType<ExampleHealingPotion>());
        // }
        //
        // // if (Main.LocalPlayer.GetModPlayer<ExamplePlayer>().ZoneExample && !GetInstance<ExampleConfigServer>().DisableExampleWings) {
        // // shop.item[nextSlot].SetDefaults(ItemType<ExampleWings>());
        // // nextSlot++;
        // // }
        //
        // if (Main.moonPhase < 2) {
        // shop.item[nextSlot++].SetDefaults(ItemType<ExampleSword>());
        // }
        // else if (Main.moonPhase < 4) {
        // // shop.item[nextSlot++].SetDefaults(ItemType<ExampleGun>());
        // shop.item[nextSlot].SetDefaults(ItemType<ExampleBullet>());
        // }
        // else if (Main.moonPhase < 6) {
        // // shop.item[nextSlot++].SetDefaults(ItemType<ExampleStaff>());
        // }
        //
        // // todo: Here is an example of how your npc can sell items from other mods.
        // // var modSummonersAssociation = ModLoader.TryGetMod("SummonersAssociation");
        // // if (ModLoader.TryGetMod("SummonersAssociation", out Mod modSummonersAssociation)) {
        // // shop.item[nextSlot].SetDefaults(modSummonersAssociation.ItemType("BloodTalisman"));
        // // nextSlot++;
        // // }
        //
        // // if (!Main.LocalPlayer.GetModPlayer<ExamplePlayer>().examplePersonGiftReceived && GetInstance<ExampleConfigServer>().ExamplePersonFreeGiftList != null) {
        // // foreach (var item in GetInstance<ExampleConfigServer>().ExamplePersonFreeGiftList) {
        // // if (Item.IsUnloaded) continue;
        // // shop.item[nextSlot].SetDefaults(Item.Type);
        // // shop.item[nextSlot].shopCustomPrice = 0;
        // // shop.item[nextSlot].GetGlobalItem<ExampleInstancedGlobalItem>().examplePersonFreeGift = true;
        // // nextSlot++;
        // // //TODO: Have tModLoader handle index issues.
        // // }
        // // }
        // }

        public override void ModifyNPCLoot(NPCLoot npcLoot)
        {
            npcLoot.Add(ItemDropRule.Common(ItemID.BombFish));
        }

        // Make this Town NPC teleport to the King and/or Queen statue when triggered.
        public override bool CanGoToStatue(bool toKingStatue) => true;
        // Create a square of pixels around the NPC on teleport.
        public void StatueTeleport()
        {
            for (int i = 0; i < 30; i++)
            {
                Vector2 position = Main.rand.NextVector2Square(-20, 21);
                if (Math.Abs(position.X) > Math.Abs(position.Y))
                {
                    position.X = Math.Sign(position.X) * 20;
                }
                else
                {
                    position.Y = Math.Sign(position.Y) * 20;
                }

                Dust.NewDustPerfect(NPC.Center + position, (DustID.ManaRegeneration), Vector2.Zero).noGravity = true;
            }
        }

        public override void TownNPCAttackStrength(ref int damage, ref float knockback)
        {
            damage = 20;
            knockback = 6f;
        }

        public override void TownNPCAttackCooldown(ref int cooldown, ref int randExtraCooldown)
        {
            cooldown = 30;
            randExtraCooldown = 30;
        }

        // todo: implement
        // public override void TownNPCAttackProj(ref int projType, ref int attackDelay) {
        // projType = ProjectileType<SparklingBall>();
        // attackDelay = 1;
        // }

        public override void TownNPCAttackProjSpeed(ref float multiplier, ref float gravityCorrection, ref float randomOffset)
        {
            multiplier = 12f;
            randomOffset = 2f;
        }

        public override void LoadData(TagCompound tag)
        {
            NumberOfTimesTalkedTo = tag.GetInt("numberOfTimesTalkedTo");
        }

        public override void SaveData(TagCompound tag)
        {
            tag["numberOfTimesTalkedTo"] = NumberOfTimesTalkedTo;
        }
        public class ExamplePersonProfile : ITownNPCProfile
        {
            public int RollVariation() => 0;
            public string GetNameForVariant(NPC npc) => npc.getNewNPCName();

            public Asset<Texture2D> GetTextureNPCShouldUse(NPC npc)
            {
                if (npc.IsABestiaryIconDummy && !npc.ForcePartyHatOn)
                    return ModContent.Request<Texture2D>("NPCMorshu/Content/NPCs/RubyMerchant");

                if (npc.altTexture == 1)
                    return ModContent.Request<Texture2D>("NPCMorshu/Content/NPCs/RubyMerchant_Party");

                return ModContent.Request<Texture2D>("NPCMorshu/Content/NPCs/RubyMerchant");
            }

            public int GetHeadTextureIndex(NPC npc) => ModContent.GetModHeadSlot("NPCMorshu/Content/NPCs/RubyMerchant_Head");
        }
    }
}
Try to copy the code more carefully
The new code:

using Microsoft.Xna.Framework;
using System;
using System.Linq;
using Terraria;
using Terraria.ID;
using Terraria.Localization;
using Terraria.ModLoader;
using Terraria.Utilities;
using Terraria.GameContent.Bestiary;
using Terraria.GameContent.ItemDropRules;
using Microsoft.Xna.Framework.Graphics;
using Terraria.GameContent;
using Terraria.GameContent.Personalities;
using System.Collections.Generic;
using ReLogic.Content;
using Terraria.ModLoader.IO;


namespace NPCMorshu
{
// Token: 0x02000003 RID: 3
[AutoloadHead]
public class RubyMerchant : ModNPC
{

public int NumberOfTimesTalkedTo = 0;

public override void SetStaticDefaults()
{
// DisplayName automatically assigned from localization files, but the commented line below is the normal approach.
// DisplayName.SetDefault("Example Person");
Main.npcFrameCount[Type] = 25; // The amount of frames the NPC has

NPCID.Sets.ExtraFramesCount[Type] = 9; // Generally for Town NPCs, but this is how the NPC does extra things such as sitting in a chair and talking to other NPCs.
NPCID.Sets.AttackFrameCount[Type] = 4;
NPCID.Sets.DangerDetectRange[Type] = 700; // The amount of pixels away from the center of the npc that it tries to attack enemies.
NPCID.Sets.AttackType[Type] = 0;
NPCID.Sets.AttackTime[Type] = 90; // The amount of time it takes for the NPC's attack animation to be over once it starts.
NPCID.Sets.AttackAverageChance[Type] = 30;
NPCID.Sets.HatOffsetY[Type] = 4; // For when a party is active, the party hat spawns at a Y offset.

// Influences how the NPC looks in the Bestiary
NPCID.Sets.NPCBestiaryDrawModifiers drawModifiers = new NPCID.Sets.NPCBestiaryDrawModifiers(0)
{
Velocity = 1f, // Draws the NPC in the bestiary as if its walking +1 tiles in the x direction
Direction = -1 // -1 is left and 1 is right. NPCs are drawn facing the left by default but ExamplePerson will be drawn facing the right
// Rotation = MathHelper.ToRadians(180) // You can also change the rotation of an NPC. Rotation is measured in radians
// If you want to see an example of manually modifying these when the NPC is drawn, see PreDraw
};

NPCID.Sets.NPCBestiaryDrawOffset.Add(Type, drawModifiers);

// Set Example Person's biome and neighbor preferences with the NPCHappiness hook. You can add happiness text and remarks with localization (See an example in ExampleMod/Localization/en-US.lang).
// NOTE: The following code uses chaining - a style that works due to the fact that the SetXAffection methods return the same NPCHappiness instance they're called on.
NPC.Happiness
.SetBiomeAffection<HallowBiome>(AffectionLevel.Love) // Example Person prefers the forest.
.SetBiomeAffection<ForestBiome>(AffectionLevel.Love)
.SetBiomeAffection<DesertBiome>(AffectionLevel.Like)
.SetBiomeAffection<SnowBiome>(AffectionLevel.Like)
.SetBiomeAffection<UndergroundBiome>(AffectionLevel.Dislike) // Example Person likes the snow.
.SetNPCAffection(NPCID.Truffle, AffectionLevel.Like) // Loves living near the dryad.
.SetNPCAffection(NPCID.Guide, AffectionLevel.Like) // Likes living near the guide.
.SetNPCAffection(NPCID.Wizard, AffectionLevel.Like) // Dislikes living near the merchant.
.SetNPCAffection(NPCID.PartyGirl, AffectionLevel.Like) // Dislikes living near the merchant.
.SetNPCAffection(NPCID.GoblinTinkerer, AffectionLevel.Dislike) // Dislikes living near the merchant.
.SetNPCAffection(NPCID.TaxCollector, AffectionLevel.Hate) // Hates living near the demolitionist.
; // < Mind the semicolon!
}

public override void SetDefaults()
{
NPC.townNPC = true; // Sets NPC to be a Town NPC
NPC.friendly = true; // NPC Will not attack player
NPC.width = 18;
NPC.height = 40;
NPC.aiStyle = 7;
NPC.damage = 10;
NPC.defense = 15;
NPC.lifeMax = 250;
NPC.HitSound = SoundID.NPCHit1;
NPC.DeathSound = SoundID.NPCDeath1;
NPC.knockBackResist = 0.5f;

AnimationType = NPCID.Guide;
}

public override void SetBestiary(BestiaryDatabase database, BestiaryEntry bestiaryEntry)
{
// We can use AddRange instead of calling Add multiple times in order to add multiple items at once
bestiaryEntry.Info.AddRange(new IBestiaryInfoElement[] {
// Sets the preferred biomes of this town NPC listed in the bestiary.
// With Town NPCs, you usually set this to what biome it likes the most in regards to NPC happiness.
BestiaryDatabaseNPCsPopulator.CommonTags.SpawnConditions.Biomes.TheHallow,

// Sets your NPC's flavor text in the bestiary.
new FlavorTextBestiaryInfoElement("Did you want some lamp- I mean torches? Rope? Bombs? It's all your's, my friend, because this guy has it."),

// You can add multiple elements if you really wanted to
// You can also use localization keys (see Localization/en-US.lang)
new FlavorTextBestiaryInfoElement("Mods.NPCMorshu.Bestiary.RubyMerchant")
});
}

// The PreDraw hook is useful for drawing things before our sprite is drawn or running code before the sprite is drawn
// Returning false will allow you to manually draw your NPC
public override bool PreDraw(SpriteBatch spriteBatch, Vector2 screenPos, Color drawColor)
{
// This code slowly rotates the NPC in the bestiary
// (simply checking NPC.IsABestiaryIconDummy and incrementing NPC.Rotation won't work here as it gets overridden by drawModifiers.Rotation each tick)
if (NPCID.Sets.NPCBestiaryDrawOffset.TryGetValue(Type, out NPCID.Sets.NPCBestiaryDrawModifiers drawModifiers))
{
drawModifiers.Rotation += 0.001f;

// Replace the existing NPCBestiaryDrawModifiers with our new one with an adjusted rotation
NPCID.Sets.NPCBestiaryDrawOffset.Remove(Type);
NPCID.Sets.NPCBestiaryDrawOffset.Add(Type, drawModifiers);
}

return true;
}

public override void HitEffect(int hitDirection, double damage)
{
int num = NPC.life > 0 ? 1 : 5;

for (int k = 0; k < num; k++)
{
Dust.NewDust(NPC.position, NPC.width, NPC.height, (DustID.Blood));
}
}

public override bool CanTownNPCSpawn(int numTownNPCs, int money)
{ // Requirements for the town NPC to spawn.
for (int k = 0; k < 255; k++)
{
Player player = Main.player[k];
if (!player.active)
{
continue;
}

// Player has to have either an ExampleItem or an ExampleBlock in order for the NPC to spawn
if (player.inventory.Any(item => item.type == (ItemID.Ruby) || item.type == (ItemID.LargeRuby)))
{
return true;
}
}

return false;
}


public override ITownNPCProfile TownNPCProfile()
{
return new RubyMerchantProfile();
}

public override List<string> SetNPCNameList()
{
return new List<string>() {
"Morshu"
};
}

public override void FindFrame(int frameHeight)
{
/*npc.frame.Width = 40;
if (((int)Main.time / 10) % 2 == 0)
{
npc.frame.X = 40;
}
else
{
npc.frame.X = 0;
}*/
}

public override string GetChat()
{
WeightedRandom<string> chat = new WeightedRandom<string>();

int partyGirl = NPC.FindFirstNPC(NPCID.PartyGirl);
if (partyGirl >= 0 && Main.rand.NextBool(4))
{
chat.Add(Language.GetTextValue("Mods.NPCMorshu.Dialogue.RubyMerchant.PartyGirl", Main.npc[partyGirl].GivenName));
}
// These are things that the NPC has a chance of telling you when you talk to it.
chat.Add(Language.GetTextValue("Mods.NPCMorshu.Dialogue.RubyMerchant.StandardDialogue1"));
chat.Add(Language.GetTextValue("Mods.NPCMorshu.Dialogue.RubyMerchant.StandardDialogue2"));
chat.Add(Language.GetTextValue("Mods.NPCMorshu.Dialogue.RubyMerchant.StandardDialogue3"));
chat.Add(Language.GetTextValue("Mods.NPCMorshu.Dialogue.RubyMerchant.CommonDialogue"), 5.0);
chat.Add(Language.GetTextValue("Mods.NPCMorshu.Dialogue.RubyMerchant.RareDialogue"), 0.1);

NumberOfTimesTalkedTo++;
if (NumberOfTimesTalkedTo >= 10)
{
//This counter is linked to a single instance of the NPC, so if ExamplePerson is killed, the counter will reset.
chat.Add(Language.GetTextValue("Mods.NPCMorshu.Dialogue.RubyMerchant.TalkALot"));
}

return chat; // chat is implicitly cast to a string.
}

// Token: 0x06000009 RID: 9 RVA: 0x0000263B File Offset: 0x0000083B
public override void SetChatButtons(ref string button, ref string button2)
{
button = Language.GetTextValue("LegacyInterface.28");
}

// Token: 0x0600000A RID: 10 RVA: 0x00002649 File Offset: 0x00000849
public override void OnChatButtonClicked(bool firstButton, ref bool shop)
{
if (firstButton)
{
shop = true;
}
}


// Not completely finished, but below is what the NPC will sell

public override void SetupShop(Chest shop, ref int nextSlot)
{
shop.item[nextSlot++].SetDefaults(ItemID.Torch);
shop.item[nextSlot++].SetDefaults(ItemID.Rope);
shop.item[nextSlot++].SetDefaults(ItemID.Bomb);
shop.item[nextSlot++].SetDefaults(ItemID.RopeCoil);
shop.item[nextSlot++].SetDefaults(ItemID.DirtBomb);
shop.item[nextSlot++].SetDefaults(ItemID.Ruby);
shop.item[nextSlot++].SetDefaults(ItemID.Topaz);
shop.item[nextSlot++].SetDefaults(ItemID.Diamond);
shop.item[nextSlot++].SetDefaults(ItemID.Amethyst);
shop.item[nextSlot++].SetDefaults(ItemID.Emerald);
shop.item[nextSlot++].SetDefaults(ItemID.Amber);
shop.item[nextSlot++].SetDefaults(ItemID.Sapphire);
shop.item[nextSlot++].SetDefaults(ItemID.LargeRuby);


if (Main.moonPhase < 2)
{
shop.item[nextSlot++].SetDefaults(ItemID.GoldCrown);
}

}
// else if (Main.moonPhase < 4) {
// // shop.item[nextSlot++].SetDefaults(ItemType<ExampleGun>());
// shop.item[nextSlot].SetDefaults(ItemType<ExampleBullet>());
// }
// else if (Main.moonPhase < 6) {
// // shop.item[nextSlot++].SetDefaults(ItemType<ExampleStaff>());
// }
//
// // todo: Here is an example of how your npc can sell items from other mods.
// // var modSummonersAssociation = ModLoader.TryGetMod("SummonersAssociation");
// // if (ModLoader.TryGetMod("SummonersAssociation", out Mod modSummonersAssociation)) {
// // shop.item[nextSlot].SetDefaults(modSummonersAssociation.ItemType("BloodTalisman"));
// // nextSlot++;
// // }
//
// // if (!Main.LocalPlayer.GetModPlayer<ExamplePlayer>().examplePersonGiftReceived && GetInstance<ExampleConfigServer>().ExamplePersonFreeGiftList != null) {
// // foreach (var item in GetInstance<ExampleConfigServer>().ExamplePersonFreeGiftList) {
// // if (Item.IsUnloaded) continue;
// // shop.item[nextSlot].SetDefaults(Item.Type);
// // shop.item[nextSlot].shopCustomPrice = 0;
// // shop.item[nextSlot].GetGlobalItem<ExampleInstancedGlobalItem>().examplePersonFreeGift = true;
// // nextSlot++;
// // //TODO: Have tModLoader handle index issues.
// // }
// // }
// }

public override void ModifyNPCLoot(NPCLoot npcLoot)
{
npcLoot.Add(ItemDropRule.Common(ItemID.BombFish));
}

// Token: 0x0600000C RID: 12 RVA: 0x000028A8 File Offset: 0x00000AA8
public override bool CanGoToStatue(bool toKingStatue)
{
return true;
}
// Make something happen when the npc teleports to a statue. Since this method only runs server side, any visual effects like dusts or gores have to be synced across all clients manually.


// Create a square of pixels around the NPC on teleport.
public void StatueTeleport()
{
for (int i = 0; i < 30; i++)
{
Vector2 position = Main.rand.NextVector2Square(-20, 21);
if (Math.Abs(position.X) > Math.Abs(position.Y))
{
position.X = Math.Sign(position.X) * 20;
}
else
{
position.Y = Math.Sign(position.Y) * 20;
}

Dust.NewDustPerfect(NPC.Center + position, (DustID.ManaRegeneration), Vector2.Zero).noGravity = true;
}
}

public override void TownNPCAttackStrength(ref int damage, ref float knockback)
{
damage = 20;
knockback = 6f;
}

public override void TownNPCAttackCooldown(ref int cooldown, ref int randExtraCooldown)
{
cooldown = 30;
randExtraCooldown = 30;
}

// todo: implement
// public override void TownNPCAttackProj(ref int projType, ref int attackDelay) {
// projType = ProjectileType<SparklingBall>();
// attackDelay = 1;
// }

public override void TownNPCAttackProjSpeed(ref float multiplier, ref float gravityCorrection, ref float randomOffset)
{
multiplier = 12f;
randomOffset = 2f;
}

public override void LoadData(TagCompound tag)
{
NumberOfTimesTalkedTo = tag.GetInt("numberOfTimesTalkedTo");
}

public override void SaveData(TagCompound tag)
{
tag["numberOfTimesTalkedTo"] = NumberOfTimesTalkedTo;
}
}


namespace RubyMerchant
{
// Token: 0x02000004 RID: 4
public class RubyMerchantProfile : ITownNPCProfile
{
// Token: 0x06000012 RID: 18 RVA: 0x000028E3 File Offset: 0x00000AE3
public int RollVariation()
{
return 0;
}

// Token: 0x06000013 RID: 19 RVA: 0x000028E6 File Offset: 0x00000AE6
public string GetNameForVariant(NPC npc)
{
return npc.getNewNPCName();
}

// Token: 0x06000014 RID: 20 RVA: 0x000028EE File Offset: 0x00000AEE
public Asset<Texture2D> GetTextureNPCShouldUse(NPC npc)
{
if (npc.IsABestiaryIconDummy && !npc.ForcePartyHatOn)
{
return ModContent.Request<Texture2D>("NPCMorshu/Content/NPCs/RubyMerchant/RubyMerchant");
}
int altTexture = npc.altTexture;
return ModContent.Request<Texture2D>("NPCMorshu/Content/NPCs/RubyMerchant/RubyMerchant_Party");
}

// Token: 0x06000015 RID: 21 RVA: 0x00002920 File Offset: 0x00000B20
public int GetHeadTextureIndex(NPC npc)
{
return ModContent.GetModHeadSlot("NPCMorshu/Content/NPCs/RubyMerchant/RubyMerchant_Head");
}
}
}
}
 
C#:
using Microsoft.Xna.Framework;
using System;
using System.Linq;
using Terraria;
using Terraria.Audio;
using Terraria.ID;
using Terraria.Localization;
using Terraria.ModLoader;
using Terraria.Utilities;
using Terraria.GameContent.Bestiary;
using Terraria.GameContent.ItemDropRules;
using Microsoft.Xna.Framework.Graphics;
using Terraria.GameContent;
using Terraria.GameContent.Personalities;
using Terraria.DataStructures;
using System.Collections.Generic;
using ReLogic.Content;
using Terraria.ModLoader.IO;

namespace ExampleMod.Content.NPCs
{
    // [AutoloadHead] and NPC.townNPC are extremely important and absolutely both necessary for any Town NPC to work at all.
    [AutoloadHead]
    public class ExamplePerson : ModNPC
    {
        public int NumberOfTimesTalkedTo = 0;

        public override void SetStaticDefaults()
        {
            // DisplayName automatically assigned from localization files, but the commented line below is the normal approach.
            // DisplayName.SetDefault("Example Person");
            Main.npcFrameCount[Type] = 25; // The amount of frames the NPC has

            NPCID.Sets.ExtraFramesCount[Type] = 9; // Generally for Town NPCs, but this is how the NPC does extra things such as sitting in a chair and talking to other NPCs.
            NPCID.Sets.AttackFrameCount[Type] = 4;
            NPCID.Sets.DangerDetectRange[Type] = 700; // The amount of pixels away from the center of the npc that it tries to attack enemies.
            NPCID.Sets.AttackType[Type] = 0;
            NPCID.Sets.AttackTime[Type] = 90; // The amount of time it takes for the NPC's attack animation to be over once it starts.
            NPCID.Sets.AttackAverageChance[Type] = 30;
            NPCID.Sets.HatOffsetY[Type] = 4; // For when a party is active, the party hat spawns at a Y offset.

            // Influences how the NPC looks in the Bestiary
            NPCID.Sets.NPCBestiaryDrawModifiers drawModifiers = new NPCID.Sets.NPCBestiaryDrawModifiers(0)
            {
                Velocity = 1f, // Draws the NPC in the bestiary as if its walking +1 tiles in the x direction
                Direction = -1 // -1 is left and 1 is right. NPCs are drawn facing the left by default but ExamplePerson will be drawn facing the right
                               // Rotation = MathHelper.ToRadians(180) // You can also change the rotation of an NPC. Rotation is measured in radians
                               // If you want to see an example of manually modifying these when the NPC is drawn, see PreDraw
            };

            NPCID.Sets.NPCBestiaryDrawOffset.Add(Type, drawModifiers);

            // Set Example Person's biome and neighbor preferences with the NPCHappiness hook. You can add happiness text and remarks with localization (See an example in ExampleMod/Localization/en-US.lang).
            // NOTE: The following code uses chaining - a style that works due to the fact that the SetXAffection methods return the same NPCHappiness instance they're called on.
            NPC.Happiness
            .SetBiomeAffection<HallowBiome>(AffectionLevel.Love) // Example Person prefers the forest.
            .SetBiomeAffection<ForestBiome>(AffectionLevel.Love)
            .SetBiomeAffection<DesertBiome>(AffectionLevel.Like)
            .SetBiomeAffection<SnowBiome>(AffectionLevel.Like)
            .SetBiomeAffection<UndergroundBiome>(AffectionLevel.Dislike) // Example Person likes the snow.
            .SetNPCAffection(NPCID.Truffle, AffectionLevel.Like) // Loves living near the dryad.
            .SetNPCAffection(NPCID.Guide, AffectionLevel.Like) // Likes living near the guide.
            .SetNPCAffection(NPCID.Wizard, AffectionLevel.Like) // Dislikes living near the merchant.
            .SetNPCAffection(NPCID.PartyGirl, AffectionLevel.Like) // Dislikes living near the merchant.
            .SetNPCAffection(NPCID.GoblinTinkerer, AffectionLevel.Dislike) // Dislikes living near the merchant.
            .SetNPCAffection(NPCID.TaxCollector, AffectionLevel.Hate) // Hates living near the demolitionist.
            ; // < Mind the semicolon!
        }

        public override void SetDefaults()
        {
            NPC.townNPC = true; // Sets NPC to be a Town NPC
            NPC.friendly = true; // NPC Will not attack player
            NPC.width = 18;
            NPC.height = 40;
            NPC.aiStyle = 7;
            NPC.damage = 10;
            NPC.defense = 15;
            NPC.lifeMax = 250;
            NPC.HitSound = SoundID.NPCHit1;
            NPC.DeathSound = SoundID.NPCDeath1;
            NPC.knockBackResist = 0.5f;

            AnimationType = NPCID.Guide;
        }

        public override void SetBestiary(BestiaryDatabase database, BestiaryEntry bestiaryEntry)
        {
            // We can use AddRange instead of calling Add multiple times in order to add multiple items at once
            bestiaryEntry.Info.AddRange(new IBestiaryInfoElement[] {
// Sets the preferred biomes of this town NPC listed in the bestiary.
// With Town NPCs, you usually set this to what biome it likes the most in regards to NPC happiness.
BestiaryDatabaseNPCsPopulator.CommonTags.SpawnConditions.Biomes.TheHallow,

// Sets your NPC's flavor text in the bestiary.
new FlavorTextBestiaryInfoElement("Did you want some lamp- I mean torches? Rope? Bombs? It's all your's, my friend, because this guy has it."),

// You can add multiple elements if you really wanted to
// You can also use localization keys (see Localization/en-US.lang)
new FlavorTextBestiaryInfoElement("Mods.NPCMorshu.Bestiary.RubyMerchant")
});
        }

        // The PreDraw hook is useful for drawing things before our sprite is drawn or running code before the sprite is drawn
        // Returning false will allow you to manually draw your NPC
        public override bool PreDraw(SpriteBatch spriteBatch, Vector2 screenPos, Color drawColor)
        {
            // This code slowly rotates the NPC in the bestiary
            // (simply checking NPC.IsABestiaryIconDummy and incrementing NPC.Rotation won't work here as it gets overridden by drawModifiers.Rotation each tick)
            if (NPCID.Sets.NPCBestiaryDrawOffset.TryGetValue(Type, out NPCID.Sets.NPCBestiaryDrawModifiers drawModifiers))
            {
                drawModifiers.Rotation += 0.001f;

                // Replace the existing NPCBestiaryDrawModifiers with our new one with an adjusted rotation
                NPCID.Sets.NPCBestiaryDrawOffset.Remove(Type);
                NPCID.Sets.NPCBestiaryDrawOffset.Add(Type, drawModifiers);
            }

            return true;
        }

        public override void HitEffect(int hitDirection, double damage)
        {
            int num = NPC.life > 0 ? 1 : 5;

            for (int k = 0; k < num; k++)
            {
                Dust.NewDust(NPC.position, NPC.width, NPC.height, (DustID.Blood));
            }
        }

        public override bool CanTownNPCSpawn(int numTownNPCs, int money)
        { // Requirements for the town NPC to spawn.
            for (int k = 0; k < 255; k++)
            {
                Player player = Main.player[k];
                if (!player.active)
                {
                    continue;
                }

                // Player has to have either an ExampleItem or an ExampleBlock in order for the NPC to spawn
                if (player.inventory.Any(item => item.type == (ItemID.Ruby) || item.type == (ItemID.LargeRuby)))
                {
                    return true;
                }
            }

            return false;
        }


        public override ITownNPCProfile TownNPCProfile()
        {
            return new ExamplePersonProfile();
        }

        public override List<string> SetNPCNameList()
        {
            return new List<string>() {
"Morshu"
};
        }

        public override void FindFrame(int frameHeight)
        {
            /*npc.frame.Width = 40;
            if (((int)Main.time / 10) % 2 == 0)
            {
            npc.frame.X = 40;
            }
            else
            {
            npc.frame.X = 0;
            }*/
        }

        public override string GetChat()
        {
            WeightedRandom<string> chat = new WeightedRandom<string>();

            int partyGirl = NPC.FindFirstNPC(NPCID.PartyGirl);
            if (partyGirl >= 0 && Main.rand.NextBool(4))
            {
                chat.Add(Language.GetTextValue("Mods.ExampleMod.Dialogue.ExamplePerson.PartyGirlDialogue", Main.npc[partyGirl].GivenName));
            }
            // These are things that the NPC has a chance of telling you when you talk to it.
            chat.Add(Language.GetTextValue("Mods.ExampleMod.Dialogue.ExamplePerson.StandardDialogue1"));
            chat.Add(Language.GetTextValue("Mods.ExampleMod.Dialogue.ExamplePerson.StandardDialogue2"));
            chat.Add(Language.GetTextValue("Mods.ExampleMod.Dialogue.ExamplePerson.StandardDialogue3"));
            chat.Add(Language.GetTextValue("Mods.ExampleMod.Dialogue.ExamplePerson.CommonDialogue"), 5.0);
            chat.Add(Language.GetTextValue("Mods.ExampleMod.Dialogue.ExamplePerson.RareDialogue"), 0.1);

            NumberOfTimesTalkedTo++;
            if (NumberOfTimesTalkedTo >= 10)
            {
                //This counter is linked to a single instance of the NPC, so if ExamplePerson is killed, the counter will reset.
                chat.Add(Language.GetTextValue("Mods.ExampleMod.Dialogue.ExamplePerson.TalkALot"));
            }

            return chat; // chat is implicitly cast to a string.
        }

        public override void SetChatButtons(ref string button, ref string button2)
        { // What the chat buttons are when you open up the chat UI
            button = Language.GetTextValue("LegacyInterface.28");

        }
        // Not completely finished, but below is what the NPC will sell

        public override void SetupShop(Chest shop, ref int nextSlot)
        {
            shop.item[nextSlot++].SetDefaults(ItemID.Torch);
            shop.item[nextSlot++].SetDefaults(ItemID.Rope);
            shop.item[nextSlot++].SetDefaults(ItemID.Bomb);
            shop.item[nextSlot++].SetDefaults(ItemID.RopeCoil);
            shop.item[nextSlot++].SetDefaults(ItemID.DirtBomb);
            shop.item[nextSlot++].SetDefaults(ItemID.Ruby);
            shop.item[nextSlot++].SetDefaults(ItemID.Topaz);
            shop.item[nextSlot++].SetDefaults(ItemID.Diamond);
            shop.item[nextSlot++].SetDefaults(ItemID.Amethyst);
            shop.item[nextSlot++].SetDefaults(ItemID.Emerald);
            shop.item[nextSlot++].SetDefaults(ItemID.Amber);
            shop.item[nextSlot++].SetDefaults(ItemID.Sapphire);
            shop.item[nextSlot++].SetDefaults(ItemID.LargeRuby);
        }
        //
        // if (Main.LocalPlayer.HasBuff(BuffID.Lifeforce)) {
        // shop.item[nextSlot++].SetDefaults(ItemType<ExampleHealingPotion>());
        // }
        //
        // // if (Main.LocalPlayer.GetModPlayer<ExamplePlayer>().ZoneExample && !GetInstance<ExampleConfigServer>().DisableExampleWings) {
        // // shop.item[nextSlot].SetDefaults(ItemType<ExampleWings>());
        // // nextSlot++;
        // // }
        //
        // if (Main.moonPhase < 2) {
        // shop.item[nextSlot++].SetDefaults(ItemType<ExampleSword>());
        // }
        // else if (Main.moonPhase < 4) {
        // // shop.item[nextSlot++].SetDefaults(ItemType<ExampleGun>());
        // shop.item[nextSlot].SetDefaults(ItemType<ExampleBullet>());
        // }
        // else if (Main.moonPhase < 6) {
        // // shop.item[nextSlot++].SetDefaults(ItemType<ExampleStaff>());
        // }
        //
        // // todo: Here is an example of how your npc can sell items from other mods.
        // // var modSummonersAssociation = ModLoader.TryGetMod("SummonersAssociation");
        // // if (ModLoader.TryGetMod("SummonersAssociation", out Mod modSummonersAssociation)) {
        // // shop.item[nextSlot].SetDefaults(modSummonersAssociation.ItemType("BloodTalisman"));
        // // nextSlot++;
        // // }
        //
        // // if (!Main.LocalPlayer.GetModPlayer<ExamplePlayer>().examplePersonGiftReceived && GetInstance<ExampleConfigServer>().ExamplePersonFreeGiftList != null) {
        // // foreach (var item in GetInstance<ExampleConfigServer>().ExamplePersonFreeGiftList) {
        // // if (Item.IsUnloaded) continue;
        // // shop.item[nextSlot].SetDefaults(Item.Type);
        // // shop.item[nextSlot].shopCustomPrice = 0;
        // // shop.item[nextSlot].GetGlobalItem<ExampleInstancedGlobalItem>().examplePersonFreeGift = true;
        // // nextSlot++;
        // // //TODO: Have tModLoader handle index issues.
        // // }
        // // }
        // }

        public override void ModifyNPCLoot(NPCLoot npcLoot)
        {
            npcLoot.Add(ItemDropRule.Common(ItemID.BombFish));
        }

        // Make this Town NPC teleport to the King and/or Queen statue when triggered.
        public override bool CanGoToStatue(bool toKingStatue) => true;
        // Create a square of pixels around the NPC on teleport.
        public void StatueTeleport()
        {
            for (int i = 0; i < 30; i++)
            {
                Vector2 position = Main.rand.NextVector2Square(-20, 21);
                if (Math.Abs(position.X) > Math.Abs(position.Y))
                {
                    position.X = Math.Sign(position.X) * 20;
                }
                else
                {
                    position.Y = Math.Sign(position.Y) * 20;
                }

                Dust.NewDustPerfect(NPC.Center + position, (DustID.ManaRegeneration), Vector2.Zero).noGravity = true;
            }
        }

        public override void TownNPCAttackStrength(ref int damage, ref float knockback)
        {
            damage = 20;
            knockback = 6f;
        }

        public override void TownNPCAttackCooldown(ref int cooldown, ref int randExtraCooldown)
        {
            cooldown = 30;
            randExtraCooldown = 30;
        }

        // todo: implement
        // public override void TownNPCAttackProj(ref int projType, ref int attackDelay) {
        // projType = ProjectileType<SparklingBall>();
        // attackDelay = 1;
        // }

        public override void TownNPCAttackProjSpeed(ref float multiplier, ref float gravityCorrection, ref float randomOffset)
        {
            multiplier = 12f;
            randomOffset = 2f;
        }

        public override void LoadData(TagCompound tag)
        {
            NumberOfTimesTalkedTo = tag.GetInt("numberOfTimesTalkedTo");
        }

        public override void SaveData(TagCompound tag)
        {
            tag["numberOfTimesTalkedTo"] = NumberOfTimesTalkedTo;
        }
        public class ExamplePersonProfile : ITownNPCProfile
        {
            public int RollVariation() => 0;
            public string GetNameForVariant(NPC npc) => npc.getNewNPCName();

            public Asset<Texture2D> GetTextureNPCShouldUse(NPC npc)
            {
                if (npc.IsABestiaryIconDummy && !npc.ForcePartyHatOn)
                    return ModContent.Request<Texture2D>("NPCMorshu/Content/NPCs/RubyMerchant");

                if (npc.altTexture == 1)
                    return ModContent.Request<Texture2D>("NPCMorshu/Content/NPCs/RubyMerchant_Party");

                return ModContent.Request<Texture2D>("NPCMorshu/Content/NPCs/RubyMerchant");
            }

            public int GetHeadTextureIndex(NPC npc) => ModContent.GetModHeadSlot("NPCMorshu/Content/NPCs/RubyMerchant_Head");
        }
    }
}
Try to copy the code more carefully
wait now i only have 1 more error and its the second one:
1660170325084.png
 
C#:
using Microsoft.Xna.Framework;
using System;
using System.Linq;
using Terraria;
using Terraria.Audio;
using Terraria.ID;
using Terraria.Localization;
using Terraria.ModLoader;
using Terraria.Utilities;
using Terraria.GameContent.Bestiary;
using Terraria.GameContent.ItemDropRules;
using Microsoft.Xna.Framework.Graphics;
using Terraria.GameContent;
using Terraria.GameContent.Personalities;
using Terraria.DataStructures;
using System.Collections.Generic;
using ReLogic.Content;
using Terraria.ModLoader.IO;

namespace ExampleMod.Content.NPCs
{
    // [AutoloadHead] and NPC.townNPC are extremely important and absolutely both necessary for any Town NPC to work at all.
    [AutoloadHead]
    public class ExamplePerson : ModNPC
    {
        public int NumberOfTimesTalkedTo = 0;

        public override void SetStaticDefaults()
        {
            // DisplayName automatically assigned from localization files, but the commented line below is the normal approach.
            // DisplayName.SetDefault("Example Person");
            Main.npcFrameCount[Type] = 25; // The amount of frames the NPC has

            NPCID.Sets.ExtraFramesCount[Type] = 9; // Generally for Town NPCs, but this is how the NPC does extra things such as sitting in a chair and talking to other NPCs.
            NPCID.Sets.AttackFrameCount[Type] = 4;
            NPCID.Sets.DangerDetectRange[Type] = 700; // The amount of pixels away from the center of the npc that it tries to attack enemies.
            NPCID.Sets.AttackType[Type] = 0;
            NPCID.Sets.AttackTime[Type] = 90; // The amount of time it takes for the NPC's attack animation to be over once it starts.
            NPCID.Sets.AttackAverageChance[Type] = 30;
            NPCID.Sets.HatOffsetY[Type] = 4; // For when a party is active, the party hat spawns at a Y offset.

            // Influences how the NPC looks in the Bestiary
            NPCID.Sets.NPCBestiaryDrawModifiers drawModifiers = new NPCID.Sets.NPCBestiaryDrawModifiers(0)
            {
                Velocity = 1f, // Draws the NPC in the bestiary as if its walking +1 tiles in the x direction
                Direction = -1 // -1 is left and 1 is right. NPCs are drawn facing the left by default but ExamplePerson will be drawn facing the right
                               // Rotation = MathHelper.ToRadians(180) // You can also change the rotation of an NPC. Rotation is measured in radians
                               // If you want to see an example of manually modifying these when the NPC is drawn, see PreDraw
            };

            NPCID.Sets.NPCBestiaryDrawOffset.Add(Type, drawModifiers);

            // Set Example Person's biome and neighbor preferences with the NPCHappiness hook. You can add happiness text and remarks with localization (See an example in ExampleMod/Localization/en-US.lang).
            // NOTE: The following code uses chaining - a style that works due to the fact that the SetXAffection methods return the same NPCHappiness instance they're called on.
            NPC.Happiness
            .SetBiomeAffection<HallowBiome>(AffectionLevel.Love) // Example Person prefers the forest.
            .SetBiomeAffection<ForestBiome>(AffectionLevel.Love)
            .SetBiomeAffection<DesertBiome>(AffectionLevel.Like)
            .SetBiomeAffection<SnowBiome>(AffectionLevel.Like)
            .SetBiomeAffection<UndergroundBiome>(AffectionLevel.Dislike) // Example Person likes the snow.
            .SetNPCAffection(NPCID.Truffle, AffectionLevel.Like) // Loves living near the dryad.
            .SetNPCAffection(NPCID.Guide, AffectionLevel.Like) // Likes living near the guide.
            .SetNPCAffection(NPCID.Wizard, AffectionLevel.Like) // Dislikes living near the merchant.
            .SetNPCAffection(NPCID.PartyGirl, AffectionLevel.Like) // Dislikes living near the merchant.
            .SetNPCAffection(NPCID.GoblinTinkerer, AffectionLevel.Dislike) // Dislikes living near the merchant.
            .SetNPCAffection(NPCID.TaxCollector, AffectionLevel.Hate) // Hates living near the demolitionist.
            ; // < Mind the semicolon!
        }

        public override void SetDefaults()
        {
            NPC.townNPC = true; // Sets NPC to be a Town NPC
            NPC.friendly = true; // NPC Will not attack player
            NPC.width = 18;
            NPC.height = 40;
            NPC.aiStyle = 7;
            NPC.damage = 10;
            NPC.defense = 15;
            NPC.lifeMax = 250;
            NPC.HitSound = SoundID.NPCHit1;
            NPC.DeathSound = SoundID.NPCDeath1;
            NPC.knockBackResist = 0.5f;

            AnimationType = NPCID.Guide;
        }

        public override void SetBestiary(BestiaryDatabase database, BestiaryEntry bestiaryEntry)
        {
            // We can use AddRange instead of calling Add multiple times in order to add multiple items at once
            bestiaryEntry.Info.AddRange(new IBestiaryInfoElement[] {
// Sets the preferred biomes of this town NPC listed in the bestiary.
// With Town NPCs, you usually set this to what biome it likes the most in regards to NPC happiness.
BestiaryDatabaseNPCsPopulator.CommonTags.SpawnConditions.Biomes.TheHallow,

// Sets your NPC's flavor text in the bestiary.
new FlavorTextBestiaryInfoElement("Did you want some lamp- I mean torches? Rope? Bombs? It's all your's, my friend, because this guy has it."),

// You can add multiple elements if you really wanted to
// You can also use localization keys (see Localization/en-US.lang)
new FlavorTextBestiaryInfoElement("Mods.NPCMorshu.Bestiary.RubyMerchant")
});
        }

        // The PreDraw hook is useful for drawing things before our sprite is drawn or running code before the sprite is drawn
        // Returning false will allow you to manually draw your NPC
        public override bool PreDraw(SpriteBatch spriteBatch, Vector2 screenPos, Color drawColor)
        {
            // This code slowly rotates the NPC in the bestiary
            // (simply checking NPC.IsABestiaryIconDummy and incrementing NPC.Rotation won't work here as it gets overridden by drawModifiers.Rotation each tick)
            if (NPCID.Sets.NPCBestiaryDrawOffset.TryGetValue(Type, out NPCID.Sets.NPCBestiaryDrawModifiers drawModifiers))
            {
                drawModifiers.Rotation += 0.001f;

                // Replace the existing NPCBestiaryDrawModifiers with our new one with an adjusted rotation
                NPCID.Sets.NPCBestiaryDrawOffset.Remove(Type);
                NPCID.Sets.NPCBestiaryDrawOffset.Add(Type, drawModifiers);
            }

            return true;
        }

        public override void HitEffect(int hitDirection, double damage)
        {
            int num = NPC.life > 0 ? 1 : 5;

            for (int k = 0; k < num; k++)
            {
                Dust.NewDust(NPC.position, NPC.width, NPC.height, (DustID.Blood));
            }
        }

        public override bool CanTownNPCSpawn(int numTownNPCs, int money)
        { // Requirements for the town NPC to spawn.
            for (int k = 0; k < 255; k++)
            {
                Player player = Main.player[k];
                if (!player.active)
                {
                    continue;
                }

                // Player has to have either an ExampleItem or an ExampleBlock in order for the NPC to spawn
                if (player.inventory.Any(item => item.type == (ItemID.Ruby) || item.type == (ItemID.LargeRuby)))
                {
                    return true;
                }
            }

            return false;
        }


        public override ITownNPCProfile TownNPCProfile()
        {
            return new ExamplePersonProfile();
        }

        public override List<string> SetNPCNameList()
        {
            return new List<string>() {
"Morshu"
};
        }

        public override void FindFrame(int frameHeight)
        {
            /*npc.frame.Width = 40;
            if (((int)Main.time / 10) % 2 == 0)
            {
            npc.frame.X = 40;
            }
            else
            {
            npc.frame.X = 0;
            }*/
        }

        public override string GetChat()
        {
            WeightedRandom<string> chat = new WeightedRandom<string>();

            int partyGirl = NPC.FindFirstNPC(NPCID.PartyGirl);
            if (partyGirl >= 0 && Main.rand.NextBool(4))
            {
                chat.Add(Language.GetTextValue("Mods.ExampleMod.Dialogue.ExamplePerson.PartyGirlDialogue", Main.npc[partyGirl].GivenName));
            }
            // These are things that the NPC has a chance of telling you when you talk to it.
            chat.Add(Language.GetTextValue("Mods.ExampleMod.Dialogue.ExamplePerson.StandardDialogue1"));
            chat.Add(Language.GetTextValue("Mods.ExampleMod.Dialogue.ExamplePerson.StandardDialogue2"));
            chat.Add(Language.GetTextValue("Mods.ExampleMod.Dialogue.ExamplePerson.StandardDialogue3"));
            chat.Add(Language.GetTextValue("Mods.ExampleMod.Dialogue.ExamplePerson.CommonDialogue"), 5.0);
            chat.Add(Language.GetTextValue("Mods.ExampleMod.Dialogue.ExamplePerson.RareDialogue"), 0.1);

            NumberOfTimesTalkedTo++;
            if (NumberOfTimesTalkedTo >= 10)
            {
                //This counter is linked to a single instance of the NPC, so if ExamplePerson is killed, the counter will reset.
                chat.Add(Language.GetTextValue("Mods.ExampleMod.Dialogue.ExamplePerson.TalkALot"));
            }

            return chat; // chat is implicitly cast to a string.
        }

        public override void SetChatButtons(ref string button, ref string button2)
        { // What the chat buttons are when you open up the chat UI
            button = Language.GetTextValue("LegacyInterface.28");

        }
        // Not completely finished, but below is what the NPC will sell

        public override void SetupShop(Chest shop, ref int nextSlot)
        {
            shop.item[nextSlot++].SetDefaults(ItemID.Torch);
            shop.item[nextSlot++].SetDefaults(ItemID.Rope);
            shop.item[nextSlot++].SetDefaults(ItemID.Bomb);
            shop.item[nextSlot++].SetDefaults(ItemID.RopeCoil);
            shop.item[nextSlot++].SetDefaults(ItemID.DirtBomb);
            shop.item[nextSlot++].SetDefaults(ItemID.Ruby);
            shop.item[nextSlot++].SetDefaults(ItemID.Topaz);
            shop.item[nextSlot++].SetDefaults(ItemID.Diamond);
            shop.item[nextSlot++].SetDefaults(ItemID.Amethyst);
            shop.item[nextSlot++].SetDefaults(ItemID.Emerald);
            shop.item[nextSlot++].SetDefaults(ItemID.Amber);
            shop.item[nextSlot++].SetDefaults(ItemID.Sapphire);
            shop.item[nextSlot++].SetDefaults(ItemID.LargeRuby);
        }
        //
        // if (Main.LocalPlayer.HasBuff(BuffID.Lifeforce)) {
        // shop.item[nextSlot++].SetDefaults(ItemType<ExampleHealingPotion>());
        // }
        //
        // // if (Main.LocalPlayer.GetModPlayer<ExamplePlayer>().ZoneExample && !GetInstance<ExampleConfigServer>().DisableExampleWings) {
        // // shop.item[nextSlot].SetDefaults(ItemType<ExampleWings>());
        // // nextSlot++;
        // // }
        //
        // if (Main.moonPhase < 2) {
        // shop.item[nextSlot++].SetDefaults(ItemType<ExampleSword>());
        // }
        // else if (Main.moonPhase < 4) {
        // // shop.item[nextSlot++].SetDefaults(ItemType<ExampleGun>());
        // shop.item[nextSlot].SetDefaults(ItemType<ExampleBullet>());
        // }
        // else if (Main.moonPhase < 6) {
        // // shop.item[nextSlot++].SetDefaults(ItemType<ExampleStaff>());
        // }
        //
        // // todo: Here is an example of how your npc can sell items from other mods.
        // // var modSummonersAssociation = ModLoader.TryGetMod("SummonersAssociation");
        // // if (ModLoader.TryGetMod("SummonersAssociation", out Mod modSummonersAssociation)) {
        // // shop.item[nextSlot].SetDefaults(modSummonersAssociation.ItemType("BloodTalisman"));
        // // nextSlot++;
        // // }
        //
        // // if (!Main.LocalPlayer.GetModPlayer<ExamplePlayer>().examplePersonGiftReceived && GetInstance<ExampleConfigServer>().ExamplePersonFreeGiftList != null) {
        // // foreach (var item in GetInstance<ExampleConfigServer>().ExamplePersonFreeGiftList) {
        // // if (Item.IsUnloaded) continue;
        // // shop.item[nextSlot].SetDefaults(Item.Type);
        // // shop.item[nextSlot].shopCustomPrice = 0;
        // // shop.item[nextSlot].GetGlobalItem<ExampleInstancedGlobalItem>().examplePersonFreeGift = true;
        // // nextSlot++;
        // // //TODO: Have tModLoader handle index issues.
        // // }
        // // }
        // }

        public override void ModifyNPCLoot(NPCLoot npcLoot)
        {
            npcLoot.Add(ItemDropRule.Common(ItemID.BombFish));
        }

        // Make this Town NPC teleport to the King and/or Queen statue when triggered.
        public override bool CanGoToStatue(bool toKingStatue) => true;
        // Create a square of pixels around the NPC on teleport.
        public void StatueTeleport()
        {
            for (int i = 0; i < 30; i++)
            {
                Vector2 position = Main.rand.NextVector2Square(-20, 21);
                if (Math.Abs(position.X) > Math.Abs(position.Y))
                {
                    position.X = Math.Sign(position.X) * 20;
                }
                else
                {
                    position.Y = Math.Sign(position.Y) * 20;
                }

                Dust.NewDustPerfect(NPC.Center + position, (DustID.ManaRegeneration), Vector2.Zero).noGravity = true;
            }
        }

        public override void TownNPCAttackStrength(ref int damage, ref float knockback)
        {
            damage = 20;
            knockback = 6f;
        }

        public override void TownNPCAttackCooldown(ref int cooldown, ref int randExtraCooldown)
        {
            cooldown = 30;
            randExtraCooldown = 30;
        }

        // todo: implement
        // public override void TownNPCAttackProj(ref int projType, ref int attackDelay) {
        // projType = ProjectileType<SparklingBall>();
        // attackDelay = 1;
        // }

        public override void TownNPCAttackProjSpeed(ref float multiplier, ref float gravityCorrection, ref float randomOffset)
        {
            multiplier = 12f;
            randomOffset = 2f;
        }

        public override void LoadData(TagCompound tag)
        {
            NumberOfTimesTalkedTo = tag.GetInt("numberOfTimesTalkedTo");
        }

        public override void SaveData(TagCompound tag)
        {
            tag["numberOfTimesTalkedTo"] = NumberOfTimesTalkedTo;
        }
        public class ExamplePersonProfile : ITownNPCProfile
        {
            public int RollVariation() => 0;
            public string GetNameForVariant(NPC npc) => npc.getNewNPCName();

            public Asset<Texture2D> GetTextureNPCShouldUse(NPC npc)
            {
                if (npc.IsABestiaryIconDummy && !npc.ForcePartyHatOn)
                    return ModContent.Request<Texture2D>("NPCMorshu/Content/NPCs/RubyMerchant");

                if (npc.altTexture == 1)
                    return ModContent.Request<Texture2D>("NPCMorshu/Content/NPCs/RubyMerchant_Party");

                return ModContent.Request<Texture2D>("NPCMorshu/Content/NPCs/RubyMerchant");
            }

            public int GetHeadTextureIndex(NPC npc) => ModContent.GetModHeadSlot("NPCMorshu/Content/NPCs/RubyMerchant_Head");
        }
    }
}
Try to copy the code more carefully
Never mind. This is stressful, I'll fix it later.
 
C#:
using Microsoft.Xna.Framework;
using System;
using System.Linq;
using Terraria;
using Terraria.Audio;
using Terraria.ID;
using Terraria.Localization;
using Terraria.ModLoader;
using Terraria.Utilities;
using Terraria.GameContent.Bestiary;
using Terraria.GameContent.ItemDropRules;
using Microsoft.Xna.Framework.Graphics;
using Terraria.GameContent;
using Terraria.GameContent.Personalities;
using Terraria.DataStructures;
using System.Collections.Generic;
using ReLogic.Content;
using Terraria.ModLoader.IO;

namespace ExampleMod.Content.NPCs
{
    // [AutoloadHead] and NPC.townNPC are extremely important and absolutely both necessary for any Town NPC to work at all.
    [AutoloadHead]
    public class ExamplePerson : ModNPC
    {
        public int NumberOfTimesTalkedTo = 0;

        public override void SetStaticDefaults()
        {
            // DisplayName automatically assigned from localization files, but the commented line below is the normal approach.
            // DisplayName.SetDefault("Example Person");
            Main.npcFrameCount[Type] = 25; // The amount of frames the NPC has

            NPCID.Sets.ExtraFramesCount[Type] = 9; // Generally for Town NPCs, but this is how the NPC does extra things such as sitting in a chair and talking to other NPCs.
            NPCID.Sets.AttackFrameCount[Type] = 4;
            NPCID.Sets.DangerDetectRange[Type] = 700; // The amount of pixels away from the center of the npc that it tries to attack enemies.
            NPCID.Sets.AttackType[Type] = 0;
            NPCID.Sets.AttackTime[Type] = 90; // The amount of time it takes for the NPC's attack animation to be over once it starts.
            NPCID.Sets.AttackAverageChance[Type] = 30;
            NPCID.Sets.HatOffsetY[Type] = 4; // For when a party is active, the party hat spawns at a Y offset.

            // Influences how the NPC looks in the Bestiary
            NPCID.Sets.NPCBestiaryDrawModifiers drawModifiers = new NPCID.Sets.NPCBestiaryDrawModifiers(0)
            {
                Velocity = 1f, // Draws the NPC in the bestiary as if its walking +1 tiles in the x direction
                Direction = -1 // -1 is left and 1 is right. NPCs are drawn facing the left by default but ExamplePerson will be drawn facing the right
                               // Rotation = MathHelper.ToRadians(180) // You can also change the rotation of an NPC. Rotation is measured in radians
                               // If you want to see an example of manually modifying these when the NPC is drawn, see PreDraw
            };

            NPCID.Sets.NPCBestiaryDrawOffset.Add(Type, drawModifiers);

            // Set Example Person's biome and neighbor preferences with the NPCHappiness hook. You can add happiness text and remarks with localization (See an example in ExampleMod/Localization/en-US.lang).
            // NOTE: The following code uses chaining - a style that works due to the fact that the SetXAffection methods return the same NPCHappiness instance they're called on.
            NPC.Happiness
            .SetBiomeAffection<HallowBiome>(AffectionLevel.Love) // Example Person prefers the forest.
            .SetBiomeAffection<ForestBiome>(AffectionLevel.Love)
            .SetBiomeAffection<DesertBiome>(AffectionLevel.Like)
            .SetBiomeAffection<SnowBiome>(AffectionLevel.Like)
            .SetBiomeAffection<UndergroundBiome>(AffectionLevel.Dislike) // Example Person likes the snow.
            .SetNPCAffection(NPCID.Truffle, AffectionLevel.Like) // Loves living near the dryad.
            .SetNPCAffection(NPCID.Guide, AffectionLevel.Like) // Likes living near the guide.
            .SetNPCAffection(NPCID.Wizard, AffectionLevel.Like) // Dislikes living near the merchant.
            .SetNPCAffection(NPCID.PartyGirl, AffectionLevel.Like) // Dislikes living near the merchant.
            .SetNPCAffection(NPCID.GoblinTinkerer, AffectionLevel.Dislike) // Dislikes living near the merchant.
            .SetNPCAffection(NPCID.TaxCollector, AffectionLevel.Hate) // Hates living near the demolitionist.
            ; // < Mind the semicolon!
        }

        public override void SetDefaults()
        {
            NPC.townNPC = true; // Sets NPC to be a Town NPC
            NPC.friendly = true; // NPC Will not attack player
            NPC.width = 18;
            NPC.height = 40;
            NPC.aiStyle = 7;
            NPC.damage = 10;
            NPC.defense = 15;
            NPC.lifeMax = 250;
            NPC.HitSound = SoundID.NPCHit1;
            NPC.DeathSound = SoundID.NPCDeath1;
            NPC.knockBackResist = 0.5f;

            AnimationType = NPCID.Guide;
        }

        public override void SetBestiary(BestiaryDatabase database, BestiaryEntry bestiaryEntry)
        {
            // We can use AddRange instead of calling Add multiple times in order to add multiple items at once
            bestiaryEntry.Info.AddRange(new IBestiaryInfoElement[] {
// Sets the preferred biomes of this town NPC listed in the bestiary.
// With Town NPCs, you usually set this to what biome it likes the most in regards to NPC happiness.
BestiaryDatabaseNPCsPopulator.CommonTags.SpawnConditions.Biomes.TheHallow,

// Sets your NPC's flavor text in the bestiary.
new FlavorTextBestiaryInfoElement("Did you want some lamp- I mean torches? Rope? Bombs? It's all your's, my friend, because this guy has it."),

// You can add multiple elements if you really wanted to
// You can also use localization keys (see Localization/en-US.lang)
new FlavorTextBestiaryInfoElement("Mods.NPCMorshu.Bestiary.RubyMerchant")
});
        }

        // The PreDraw hook is useful for drawing things before our sprite is drawn or running code before the sprite is drawn
        // Returning false will allow you to manually draw your NPC
        public override bool PreDraw(SpriteBatch spriteBatch, Vector2 screenPos, Color drawColor)
        {
            // This code slowly rotates the NPC in the bestiary
            // (simply checking NPC.IsABestiaryIconDummy and incrementing NPC.Rotation won't work here as it gets overridden by drawModifiers.Rotation each tick)
            if (NPCID.Sets.NPCBestiaryDrawOffset.TryGetValue(Type, out NPCID.Sets.NPCBestiaryDrawModifiers drawModifiers))
            {
                drawModifiers.Rotation += 0.001f;

                // Replace the existing NPCBestiaryDrawModifiers with our new one with an adjusted rotation
                NPCID.Sets.NPCBestiaryDrawOffset.Remove(Type);
                NPCID.Sets.NPCBestiaryDrawOffset.Add(Type, drawModifiers);
            }

            return true;
        }

        public override void HitEffect(int hitDirection, double damage)
        {
            int num = NPC.life > 0 ? 1 : 5;

            for (int k = 0; k < num; k++)
            {
                Dust.NewDust(NPC.position, NPC.width, NPC.height, (DustID.Blood));
            }
        }

        public override bool CanTownNPCSpawn(int numTownNPCs, int money)
        { // Requirements for the town NPC to spawn.
            for (int k = 0; k < 255; k++)
            {
                Player player = Main.player[k];
                if (!player.active)
                {
                    continue;
                }

                // Player has to have either an ExampleItem or an ExampleBlock in order for the NPC to spawn
                if (player.inventory.Any(item => item.type == (ItemID.Ruby) || item.type == (ItemID.LargeRuby)))
                {
                    return true;
                }
            }

            return false;
        }


        public override ITownNPCProfile TownNPCProfile()
        {
            return new ExamplePersonProfile();
        }

        public override List<string> SetNPCNameList()
        {
            return new List<string>() {
"Morshu"
};
        }

        public override void FindFrame(int frameHeight)
        {
            /*npc.frame.Width = 40;
            if (((int)Main.time / 10) % 2 == 0)
            {
            npc.frame.X = 40;
            }
            else
            {
            npc.frame.X = 0;
            }*/
        }

        public override string GetChat()
        {
            WeightedRandom<string> chat = new WeightedRandom<string>();

            int partyGirl = NPC.FindFirstNPC(NPCID.PartyGirl);
            if (partyGirl >= 0 && Main.rand.NextBool(4))
            {
                chat.Add(Language.GetTextValue("Mods.ExampleMod.Dialogue.ExamplePerson.PartyGirlDialogue", Main.npc[partyGirl].GivenName));
            }
            // These are things that the NPC has a chance of telling you when you talk to it.
            chat.Add(Language.GetTextValue("Mods.ExampleMod.Dialogue.ExamplePerson.StandardDialogue1"));
            chat.Add(Language.GetTextValue("Mods.ExampleMod.Dialogue.ExamplePerson.StandardDialogue2"));
            chat.Add(Language.GetTextValue("Mods.ExampleMod.Dialogue.ExamplePerson.StandardDialogue3"));
            chat.Add(Language.GetTextValue("Mods.ExampleMod.Dialogue.ExamplePerson.CommonDialogue"), 5.0);
            chat.Add(Language.GetTextValue("Mods.ExampleMod.Dialogue.ExamplePerson.RareDialogue"), 0.1);

            NumberOfTimesTalkedTo++;
            if (NumberOfTimesTalkedTo >= 10)
            {
                //This counter is linked to a single instance of the NPC, so if ExamplePerson is killed, the counter will reset.
                chat.Add(Language.GetTextValue("Mods.ExampleMod.Dialogue.ExamplePerson.TalkALot"));
            }

            return chat; // chat is implicitly cast to a string.
        }

        public override void SetChatButtons(ref string button, ref string button2)
        { // What the chat buttons are when you open up the chat UI
            button = Language.GetTextValue("LegacyInterface.28");

        }
        // Not completely finished, but below is what the NPC will sell

        public override void SetupShop(Chest shop, ref int nextSlot)
        {
            shop.item[nextSlot++].SetDefaults(ItemID.Torch);
            shop.item[nextSlot++].SetDefaults(ItemID.Rope);
            shop.item[nextSlot++].SetDefaults(ItemID.Bomb);
            shop.item[nextSlot++].SetDefaults(ItemID.RopeCoil);
            shop.item[nextSlot++].SetDefaults(ItemID.DirtBomb);
            shop.item[nextSlot++].SetDefaults(ItemID.Ruby);
            shop.item[nextSlot++].SetDefaults(ItemID.Topaz);
            shop.item[nextSlot++].SetDefaults(ItemID.Diamond);
            shop.item[nextSlot++].SetDefaults(ItemID.Amethyst);
            shop.item[nextSlot++].SetDefaults(ItemID.Emerald);
            shop.item[nextSlot++].SetDefaults(ItemID.Amber);
            shop.item[nextSlot++].SetDefaults(ItemID.Sapphire);
            shop.item[nextSlot++].SetDefaults(ItemID.LargeRuby);
        }
        //
        // if (Main.LocalPlayer.HasBuff(BuffID.Lifeforce)) {
        // shop.item[nextSlot++].SetDefaults(ItemType<ExampleHealingPotion>());
        // }
        //
        // // if (Main.LocalPlayer.GetModPlayer<ExamplePlayer>().ZoneExample && !GetInstance<ExampleConfigServer>().DisableExampleWings) {
        // // shop.item[nextSlot].SetDefaults(ItemType<ExampleWings>());
        // // nextSlot++;
        // // }
        //
        // if (Main.moonPhase < 2) {
        // shop.item[nextSlot++].SetDefaults(ItemType<ExampleSword>());
        // }
        // else if (Main.moonPhase < 4) {
        // // shop.item[nextSlot++].SetDefaults(ItemType<ExampleGun>());
        // shop.item[nextSlot].SetDefaults(ItemType<ExampleBullet>());
        // }
        // else if (Main.moonPhase < 6) {
        // // shop.item[nextSlot++].SetDefaults(ItemType<ExampleStaff>());
        // }
        //
        // // todo: Here is an example of how your npc can sell items from other mods.
        // // var modSummonersAssociation = ModLoader.TryGetMod("SummonersAssociation");
        // // if (ModLoader.TryGetMod("SummonersAssociation", out Mod modSummonersAssociation)) {
        // // shop.item[nextSlot].SetDefaults(modSummonersAssociation.ItemType("BloodTalisman"));
        // // nextSlot++;
        // // }
        //
        // // if (!Main.LocalPlayer.GetModPlayer<ExamplePlayer>().examplePersonGiftReceived && GetInstance<ExampleConfigServer>().ExamplePersonFreeGiftList != null) {
        // // foreach (var item in GetInstance<ExampleConfigServer>().ExamplePersonFreeGiftList) {
        // // if (Item.IsUnloaded) continue;
        // // shop.item[nextSlot].SetDefaults(Item.Type);
        // // shop.item[nextSlot].shopCustomPrice = 0;
        // // shop.item[nextSlot].GetGlobalItem<ExampleInstancedGlobalItem>().examplePersonFreeGift = true;
        // // nextSlot++;
        // // //TODO: Have tModLoader handle index issues.
        // // }
        // // }
        // }

        public override void ModifyNPCLoot(NPCLoot npcLoot)
        {
            npcLoot.Add(ItemDropRule.Common(ItemID.BombFish));
        }

        // Make this Town NPC teleport to the King and/or Queen statue when triggered.
        public override bool CanGoToStatue(bool toKingStatue) => true;
        // Create a square of pixels around the NPC on teleport.
        public void StatueTeleport()
        {
            for (int i = 0; i < 30; i++)
            {
                Vector2 position = Main.rand.NextVector2Square(-20, 21);
                if (Math.Abs(position.X) > Math.Abs(position.Y))
                {
                    position.X = Math.Sign(position.X) * 20;
                }
                else
                {
                    position.Y = Math.Sign(position.Y) * 20;
                }

                Dust.NewDustPerfect(NPC.Center + position, (DustID.ManaRegeneration), Vector2.Zero).noGravity = true;
            }
        }

        public override void TownNPCAttackStrength(ref int damage, ref float knockback)
        {
            damage = 20;
            knockback = 6f;
        }

        public override void TownNPCAttackCooldown(ref int cooldown, ref int randExtraCooldown)
        {
            cooldown = 30;
            randExtraCooldown = 30;
        }

        // todo: implement
        // public override void TownNPCAttackProj(ref int projType, ref int attackDelay) {
        // projType = ProjectileType<SparklingBall>();
        // attackDelay = 1;
        // }

        public override void TownNPCAttackProjSpeed(ref float multiplier, ref float gravityCorrection, ref float randomOffset)
        {
            multiplier = 12f;
            randomOffset = 2f;
        }

        public override void LoadData(TagCompound tag)
        {
            NumberOfTimesTalkedTo = tag.GetInt("numberOfTimesTalkedTo");
        }

        public override void SaveData(TagCompound tag)
        {
            tag["numberOfTimesTalkedTo"] = NumberOfTimesTalkedTo;
        }
        public class ExamplePersonProfile : ITownNPCProfile
        {
            public int RollVariation() => 0;
            public string GetNameForVariant(NPC npc) => npc.getNewNPCName();

            public Asset<Texture2D> GetTextureNPCShouldUse(NPC npc)
            {
                if (npc.IsABestiaryIconDummy && !npc.ForcePartyHatOn)
                    return ModContent.Request<Texture2D>("NPCMorshu/Content/NPCs/RubyMerchant");

                if (npc.altTexture == 1)
                    return ModContent.Request<Texture2D>("NPCMorshu/Content/NPCs/RubyMerchant_Party");

                return ModContent.Request<Texture2D>("NPCMorshu/Content/NPCs/RubyMerchant");
            }

            public int GetHeadTextureIndex(NPC npc) => ModContent.GetModHeadSlot("NPCMorshu/Content/NPCs/RubyMerchant_Head");
        }
    }
}
Try to copy the code more carefully
Sucess!
1660175699416.png
 
Back
Top Bottom