tAPI [Tutorial] Custom Bosses - NPC AI and Server Syncing

Did you know if it's possible to make ore generate if a boss die or trigger a new mode after hardmode (like the WoF)
Yes. First look at my example LootRule code. You will notice that some of the LootRules use a method called Code. Here you can basically make any code happen when a boss is defeated. So you can place code to change some tiles to ores, set a variable that stores whether the boss has been defeated to true, etc. In fact, my mod does these exact things; feel free to decompile it to look as an example.
 
i've never messed with LootRules before, i might use them to manage my new boss's drops better! thanks for the guide!
 
can you add a section on how to make a boss summoning item and mine don't work at all

apocalypsio.cs
Code:
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;

using TAPI;
using Terraria;

namespace Notch.Items
{
    public class ItemName : ModItem
    {
        public ItemName(ModBase mBase, Item item)
        {
       
        }
       
        public override bool? UseItem(Player p)
        {
            //int mX = (int) (Main.screenPosition.X + Main.mouseX);
            //int mY = (int) (Main.screenPosition.Y + Main.mouseY); 
            int npcID = NPC.NewNPC((int)p.Center.X - 300, (int)p.Center.Y - 300, NPCDef.byName["Notch:EyeOfApocalypse"].type, 0);
                if (Main.netMode == 2)
                    NetMessage.SendData(23, -1, -1, "", npcID, 0.0f, 0.0f, 0.0f, 0);
            Main.NewText("The apocalypse is bring to the world");
           
            return true;
        }
    }
}
 
can you add a section on how to make a boss summoning item and mine don't work at all

apocalypsio.cs
Code:
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;

using TAPI;
using Terraria;

namespace Notch.Items
{
    public class ItemName : ModItem
    {
        public ItemName(ModBase mBase, Item item)
        {
      
        }
      
        public override bool? UseItem(Player p)
        {
            //int mX = (int) (Main.screenPosition.X + Main.mouseX);
            //int mY = (int) (Main.screenPosition.Y + Main.mouseY);
            int npcID = NPC.NewNPC((int)p.Center.X - 300, (int)p.Center.Y - 300, NPCDef.byName["Notch:EyeOfApocalypse"].type, 0);
                if (Main.netMode == 2)
                    NetMessage.SendData(23, -1, -1, "", npcID, 0.0f, 0.0f, 0.0f, 0);
            Main.NewText("The apocalypse is bring to the world");
          
            return true;
        }
    }
}
I can't see anything wrong with that code at the moment; more information is needed. Try renaming the class name (ItemName) to the name of the item's json file.
 
I can't see anything wrong with that code at the moment; more information is needed. Try renaming the class name (ItemName) to the name of the item's json file.
It say

Building mod Notch

Validating Jsons ...
Compiling code ...
Apocalypsio.cs (7.32)
Type 'Microsoft.Xna.Framework.Vector2 is defined in an assembly that is not referenced. You must add a reference to assembly 'Microsoft.Xna.Framework, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = 842cf8be1de50553'.
npcID NPC.NewNPC int = ((int) p.Center.X - 300, (int) p.Center.Y - 300 NPCDef.byName ["Notch: EyeOfApocalypse"] type 0.)
^
Apocalypsio.cs (44.32)
'Microsoft.Xna.Framework.Vector2' does not contain a definition for 'X' and no extension method 'X' accepting a first argument of type 'Microsoft.Xna.Framework.Vector2' was found (a directive using an assembly reference or is it missing?)
npcID NPC.NewNPC int = ((int) p.Center.X - 300, (int) p.Center.Y - 300 NPCDef.byName ["Notch: EyeOfApocalypse"] type 0.)
^
Apocalypsio.cs (67,32)
'Microsoft.Xna.Framework.Vector2' does not contain a definition for 'Y' and no extension method 'Y' accepting a first argument of type 'Microsoft.Xna.Framework.Vector2' was found (a directive using an assembly reference or is it missing?)
npcID NPC.NewNPC int = ((int) p.Center.X - 300, (int) p.Center.Y - 300 NPCDef.byName ["Notch: EyeOfApocalypse"] type 0.)
^
Apocalypsio.cs (38.38)
'Microsoft.Xna.Framework.Vector2' does not contain a definition for 'X' and no extension method 'X' accepting a first argument of type 'Microsoft.Xna.Framework.Vector2' was found (a directive using an assembly reference or is it missing?)
Main.PlaySound (15, (int) p.Center.X, (int) p.Center.Y, 0);
^
Apocalypsio.cs (55.38)
'Microsoft.Xna.Framework.Vector2' does not contain a definition for 'Y' and no extension method 'Y' accepting a first argument of type 'Microsoft.Xna.Framework.Vector2' was found (a directive using an assembly reference or is it missing?)
Main.PlaySound (15, (int) p.Center.X, (int) p.Center.Y, 0);
^
Apocalypsio.cs (5.38)
Type 'Microsoft.Xna.Framework.Audio.SoundEffectInstance is defined in an assembly that is not referenced. You must add a reference to assembly 'Microsoft.Xna.Framework, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = 842cf8be1de50553'.
Main.PlaySound (15, (int) p.Center.X, (int) p.Center.Y, 0);
^
Apocalypsio.cs (5.38)
Type 'Microsoft.Xna.Framework.Audio.SoundEffect is defined in an assembly that is not referenced. You must add a reference to assembly 'Microsoft.Xna.Framework, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = 842cf8be1de50553'.
Main.PlaySound (15, (int) p.Center.X, (int) p.Center.Y, 0);
^
Apocalypsio.cs (5.39)
The type or namespace name 'Vector2' not found (a using directive or an assembly reference is it missing?)
Vector2 npcPos = p.position - new Vector2 (0.200);
^
Apocalypsio.cs (39,39)
The type or namespace name 'Vector2' not found (a using directive or an assembly reference is it missing?)
Vector2 npcPos = p.position - new Vector2 (0.200);
^
Failed to build Notch.
 
It say

Building mod Notch

Validating Jsons ...
Compiling code ...
Apocalypsio.cs (7.32)
Type 'Microsoft.Xna.Framework.Vector2 is defined in an assembly that is not referenced. You must add a reference to assembly 'Microsoft.Xna.Framework, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = 842cf8be1de50553'.
npcID NPC.NewNPC int = ((int) p.Center.X - 300, (int) p.Center.Y - 300 NPCDef.byName ["Notch: EyeOfApocalypse"] type 0.)
^
Apocalypsio.cs (44.32)
'Microsoft.Xna.Framework.Vector2' does not contain a definition for 'X' and no extension method 'X' accepting a first argument of type 'Microsoft.Xna.Framework.Vector2' was found (a directive using an assembly reference or is it missing?)
npcID NPC.NewNPC int = ((int) p.Center.X - 300, (int) p.Center.Y - 300 NPCDef.byName ["Notch: EyeOfApocalypse"] type 0.)
^
Apocalypsio.cs (67,32)
'Microsoft.Xna.Framework.Vector2' does not contain a definition for 'Y' and no extension method 'Y' accepting a first argument of type 'Microsoft.Xna.Framework.Vector2' was found (a directive using an assembly reference or is it missing?)
npcID NPC.NewNPC int = ((int) p.Center.X - 300, (int) p.Center.Y - 300 NPCDef.byName ["Notch: EyeOfApocalypse"] type 0.)
^
Apocalypsio.cs (38.38)
'Microsoft.Xna.Framework.Vector2' does not contain a definition for 'X' and no extension method 'X' accepting a first argument of type 'Microsoft.Xna.Framework.Vector2' was found (a directive using an assembly reference or is it missing?)
Main.PlaySound (15, (int) p.Center.X, (int) p.Center.Y, 0);
^
Apocalypsio.cs (55.38)
'Microsoft.Xna.Framework.Vector2' does not contain a definition for 'Y' and no extension method 'Y' accepting a first argument of type 'Microsoft.Xna.Framework.Vector2' was found (a directive using an assembly reference or is it missing?)
Main.PlaySound (15, (int) p.Center.X, (int) p.Center.Y, 0);
^
Apocalypsio.cs (5.38)
Type 'Microsoft.Xna.Framework.Audio.SoundEffectInstance is defined in an assembly that is not referenced. You must add a reference to assembly 'Microsoft.Xna.Framework, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = 842cf8be1de50553'.
Main.PlaySound (15, (int) p.Center.X, (int) p.Center.Y, 0);
^
Apocalypsio.cs (5.38)
Type 'Microsoft.Xna.Framework.Audio.SoundEffect is defined in an assembly that is not referenced. You must add a reference to assembly 'Microsoft.Xna.Framework, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = 842cf8be1de50553'.
Main.PlaySound (15, (int) p.Center.X, (int) p.Center.Y, 0);
^
Apocalypsio.cs (5.39)
The type or namespace name 'Vector2' not found (a using directive or an assembly reference is it missing?)
Vector2 npcPos = p.position - new Vector2 (0.200);
^
Apocalypsio.cs (39,39)
The type or namespace name 'Vector2' not found (a using directive or an assembly reference is it missing?)
Vector2 npcPos = p.position - new Vector2 (0.200);
^
Failed to build Notch.
That... looks like there was a problem with letting your compiler know about Microsoft.Xna.Framework. At this point I would ask people in the main tAPI thread for help.
 
I found a fix but the boss cannot be summoned

edit:I can summon him but the loot rule don't apply

Code:
using System;
using Microsoft.Xna.Framework;
using Terraria;
using TAPI;

namespace Notch
{
    public class EyeOfApocalypse : ModNPC
    {
        public override void OnSpawn() //optional
        {

        }

        public override void AI() //this is where you program your AI
        {

        }

        public override void HitEffect(int hitDirection, double damage, bool isDead) //This is for whenever your boss gets hit by an attack. Create dust or gore.
        {

        }
        public override void SetupLootRules(NPC unused) //this is what makes special things happen when your boss dies, like loot or text
        {
            bool flag = true;
            LootRule.settingUp = true;
            LootRule[] rules = new LootRule[5];
            rules[0] = new LootRule(null).Item("Greater Healing Potion").Stack(5, 30);
            rules[1] = new LootRule(null).Times((NPC npc) => 5 + Main.rand.Next(5)).Item("Heart");
            rules[2] = new LootRule(null).Item("Notch:Soulofdestruction").Stack(20, 40);
            rules[3] = new LootRule(null).Code(delegate(NPC npc)
            {
                LootRule.DownedBoss(ref Notch.downedEyeOfApocalypse);
            });
            rules[4] = new LootRule(null).Code(delegate(NPC npc)
            {
                LootRule.DownedBossMessage(npc.displayName + " " + Lang.misc[17], 50, 150, 200);
            });
            LootRule.AddFor("Notch:EyeOfApocalypse", rules);
            LootRule.settingUp = flag;
        }
    }
}
 
Last edited:
I found a fix but the boss cannot be summoned

edit:I can summon him but the loot rule don't apply

Code:
using System;
using Microsoft.Xna.Framework;
using Terraria;
using TAPI;

namespace Notch
{
    public class EyeOfApocalypse : ModNPC
    {
        public override void OnSpawn() //optional
        {

        }

        public override void AI() //this is where you program your AI
        {

        }

        public override void HitEffect(int hitDirection, double damage, bool isDead) //This is for whenever your boss gets hit by an attack. Create dust or gore.
        {

        }
        public override void SetupLootRules(NPC unused) //this is what makes special things happen when your boss dies, like loot or text
        {
            bool flag = true;
            LootRule.settingUp = true;
            LootRule[] rules = new LootRule[5];
            rules[0] = new LootRule(null).Item("Greater Healing Potion").Stack(5, 30);
            rules[1] = new LootRule(null).Times((NPC npc) => 5 + Main.rand.Next(5)).Item("Heart");
            rules[2] = new LootRule(null).Item("Notch:Soulofdestruction").Stack(20, 40);
            rules[3] = new LootRule(null).Code(delegate(NPC npc)
            {
                LootRule.DownedBoss(ref Notch.downedEyeOfApocalypse);
            });
            rules[4] = new LootRule(null).Code(delegate(NPC npc)
            {
                LootRule.DownedBossMessage(npc.displayName + " " + Lang.misc[17], 50, 150, 200);
            });
            LootRule.AddFor("Notch:EyeOfApocalypse", rules);
            LootRule.settingUp = flag;
        }
    }
}
So you're saying that when you defeat the boss, the items aren't dropping and the defeat message isn't showing?
 
Could you please check your movement code? I'm cracking my head here and I strongly believe npc.velocity = move can't possibly be right for so many reasons. Please
 
Could you please check your movement code? I'm cracking my head here and I strongly believe npc.velocity = move can't possibly be right for so many reasons. Please
Oh, woops, it looks like I accidentally gave that variable the wrong type (float instead of Vector2). I'll fix that right away; sorry for any inconvenience I might have caused anyone! Thanks for pointing out the error.
 
I had to tweak the movement some to get something that works somehow, but overall, and including the movement sesction, this tutorial has been great. Sucessfuly implemented my first boss in my mod! Thank you.
 
Great stuff. Now I need to figure out how to get this modified (the MNet) to get my summoning items working.

Yeah.. didn't know you needed MNet for that >_______>
 
So I have this bag NPC that stays still, and it has a letter on it. So every time I go to the right of it, since the sprite of the NPC flips, the letter does as well. Any way to make it so that the sprite of the NPC stays the same no matter what? (I know of npc.spriteDirection but no idea how to use it, if that is even the way to do it.)

(also very nice tutorial :) It will help me with making bosses for my mod ^_^ )
 
So I have this bag NPC that stays still, and it has a letter on it. So every time I go to the right of it, since the sprite of the NPC flips, the letter does as well. Any way to make it so that the sprite of the NPC stays the same no matter what? (I know of npc.spriteDirection but no idea how to use it, if that is even the way to do it.)

(also very nice tutorial :) It will help me with making bosses for my mod ^_^ )
My guess is that you didn't set an aiStyle for it? If you didn't set an aiStyle, that means it has an aiStyle of 0, which slows it down and makes it always face you. You'll need to give it any negative aiStyle for a true custom AI.
 
My guess is that you didn't set an aiStyle for it? If you didn't set an aiStyle, that means it has an aiStyle of 0, which slows it down and makes it always face you. You'll need to give it any negative aiStyle for a true custom AI.
*facepalms* that fixed it, thanks so much! I had forgotten to try negatives for that, I haven't tried modding since tconfig a couple years ago now I think so I forgot that for some things you do negative numbers. Thanks again!
 
So, I have to ask because I'm an idiot with tAPI

create a MNet, think that was all I needed to actually get my monster-spawns-monster coding working. Nope.

Any help would be appreciated.
My MNet:
Code:
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;

using TAPI;
using Terraria;
using BaseMod;

namespace OmnirsNosPak
{
    public class MNet : ModNet//Bluemagic's code -- http://forums.terraria.org/index.php?members/bluemagic123.16350/
    {

        public static void SendNetMessage(int msg, params object[] param) { SendNetMessageRC(-1, msg, param); }

        public static void SendNetMessageRC(int remoteClient, int msg, params object[] param)
        {
            if (Main.netMode == 0) { return; }
            NetMessage.SendModData(MBase.self, msg, remoteClient, -1, param);
        }

        public static void SendNPCData(int npc, int ignore = -1) //This sends the data for an NPC without having to use netUpdate.
        {
            NetMessage.SendData(23, -1, ignore, "", npc, 0f, 0f, 0f, 0f);
        }

        public static void SendNPCLocalData(int npc, int ignore = -1) //This sends the npc's localAI array.
        {
            float[] localAI = Main.npc[npc].localAI;
            NetMessage.SendModData(Mods.GetMod("OmnirsNosPak"), 1, -1, ignore, npc, localAI[0], localAI[1], localAI[2], localAI[3]); //This is NetMessage.SendModData(Mod mod, int messageID, int remoteClient, int ignoreClient, object data, object moreData, object evenMoreData, object asMuchDataAsYouWant)
        }

        public static void SendNPCAllData(int npc, int ignore = -1) //This sends the npc's data first, and then send's its localAI.
        {
            SendNPCData(npc, ignore);
            SendNPCLocalData(npc, ignore);
        }

        public override void NetReceive(BinBuffer bb, int messageID, MessageBuffer buffer) //This is what happens when we receive custom data.
        {
            switch (messageID)
            {
                case 1: //Here we copy the data into the NPC's localAI, so that everything is synchronized.
                    int npc = bb.ReadInt();
                    float[] localAI = Main.npc[npc].localAI;
                    localAI[0] = bb.ReadFloat();
                    localAI[1] = bb.ReadFloat();
                    localAI[2] = bb.ReadFloat();
                    localAI[3] = bb.ReadFloat();
                    if (Main.netMode == 2)
                    {
                        SendNPCLocalData(npc, buffer.whoAmI);
                    }
                    break;
                default:
                    break;
            }
        }
    }
}

My Creature:

Code:
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

using TAPI;
using Terraria;
using BaseMod;

namespace OmnirsNosPak.NPCs
{
    public class OmnirsEarthCrystal : GNPC
    {

        float customAi1;
        float customspawn1;

        bool flag15 = false;

        public override bool CanSpawn(int x, int y, int type, Player player)
        {

            bool oSky = (y < (Main.maxTilesY * 0.1f));
            bool oSurface = (y >= (Main.maxTilesY * 0.1f) && y < (Main.maxTilesY * 0.2f));
            bool oUnderSurface = (y >= (Main.maxTilesY * 0.2f) && y < (Main.maxTilesY * 0.3f));
            bool oUnderground = (y >= (Main.maxTilesY * 0.3f) && y < (Main.maxTilesY * 0.4f));
            bool oCavern = (y >= (Main.maxTilesY * 0.4f) && y < (Main.maxTilesY * 0.6f));
            bool oMagmaCavern = (y >= (Main.maxTilesY * 0.6f) && y < (Main.maxTilesY * 0.8f));
            bool oUnderworld = (y >= (Main.maxTilesY * 0.8f));
            bool oBorders = (y < (Main.maxTilesY * 0.03f) || x < (Main.maxTilesX * 0.03f) || y > (Main.maxTilesY * 0.97f) || x > (Main.maxTilesX * 0.97f));
            if (oBorders || NPC.AnyNPCs(NPCDef.byName["OmnirsNosPak:OmnirsTheEarthFiendLich"].type) || NPC.AnyNPCs(NPCDef.byName["OmnirsNosPak:OmnirsEarthCrystal"].type))
            {
                return false;
            }
            if (!Main.hardMode && (player.zone["Corruption"] || player.zone["Crimson"]) && Main.rand.Next(500) == 1) return true;
            if (Main.hardMode && (player.zone["Corruption"] || player.zone["Crimson"]) && Main.rand.Next(50) == 1) return true;
            return false;
        }
        //Spawns on the Hardmode Surface, between 7/10th and 8.5/10th (Width).

        public override string SetName()
        {
            return "Earth Crystal";
        }

        public override void AI()
        {
            npc.dontTakeDamage = true;
            if (customspawn1 > 0)
            {
                Main.NewText("Step2", 175, 75, 255);
                if (Main.netMode != 1)
                {
                    Main.NewText("Step3", 175, 75, 255);
                    int npcID = NPC.NewNPC((int)npc.Center.X, (int)npc.Center.Y, "OmnirsNosPak:OmnirsTheEarthFiendLich", 0);
                    Main.npc[npcID].Center = npc.Center;
                    Main.npc[npcID].netUpdate = true;
                    npc.life = 0;
                }
            }
            #region Ogre/custom frames
            int num = 1;
            if (!Main.dedServ)
            {
                num = 40;
            }
            npc.frameCounter++;
            if (npc.frameCounter > 6.0)
            {
                npc.frame.Y = npc.frame.Y + num;
                npc.frameCounter = 0.0;
            }
            if (npc.frame.Y / num >= Main.npcFrameCount[npc.type])
            {
                npc.frame.Y = 0;
            }
            for (int num131 = 0; num131 < 255; num131++)
            {
                if (Main.player[num131].active && Main.player[num131].talkNPC == this.npc.whoAmI)
                {
                    flag15 = true;
                    if (this.npc.ai[0] != 0f)
                    {
                        this.npc.netUpdate = true;
                    }
                    this.npc.ai[0] = 0f;
                    this.npc.ai[1] = 300f;
                    this.npc.ai[2] = 100f;
                    if (Main.player[num131].position.X + (float)(Main.player[num131].width / 2) < this.npc.position.X + (float)(this.npc.width / 2))
                    {
                        this.npc.direction = -1;
                    }
                    else
                    {
                        this.npc.direction = 1;
                    }
                }
            }

            #endregion
            npc.timeLeft = 1800;
            if (npc.timeLeft > 1800 && flag15 == false)
            {
                npc.timeLeft = 1800;
                return;
            }
            return;
        }

        public override void SetChatButtons(ref string[] buttons)
        {
            buttons[0] = "I'm ready";
        }

        public override void OnChatButtonClicked(string[] buttons, int buttonIndex, ref bool openShop)
        {
            if (buttonIndex == 0)
            {
                if (customspawn1 <= 0 && !NPC.AnyNPCs(NPCDef.byName["OmnirsNosPak:OmnirsTheEarthFiendLich"].type))
                {
                    customspawn1 += 1f;
                    Main.NewText("Step1", 175, 75, 255);
                }
            }
        }



        public override string SetChat()
        {
            return "This is the Earth Crystal, guarded by Lich. Are you prepared to fight this fiend for it?";
        }

        public override bool? CanHitFriendNPC(NPC npc) { return false; }
    }
}
 
As far as I know, to sync an NPC summoned through another NPC you simply need to call the vanilla NetMessage:
Code:
NetMessage.SendData(23, -1, -1, "", ID, 0f, 0f, 0f, 0);
Just call it right after the new NPC is created in the code and change ID to the ID of the spawned NPC.
 
So, I have to ask because I'm an idiot with tAPI

create a MNet, think that was all I needed to actually get my monster-spawns-monster coding working. Nope.

Any help would be appreciated.
My MNet:
Code:
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;

using TAPI;
using Terraria;
using BaseMod;

namespace OmnirsNosPak
{
    public class MNet : ModNet//Bluemagic's code -- http://forums.terraria.org/index.php?members/bluemagic123.16350/
    {

        public static void SendNetMessage(int msg, params object[] param) { SendNetMessageRC(-1, msg, param); }

        public static void SendNetMessageRC(int remoteClient, int msg, params object[] param)
        {
            if (Main.netMode == 0) { return; }
            NetMessage.SendModData(MBase.self, msg, remoteClient, -1, param);
        }

        public static void SendNPCData(int npc, int ignore = -1) //This sends the data for an NPC without having to use netUpdate.
        {
            NetMessage.SendData(23, -1, ignore, "", npc, 0f, 0f, 0f, 0f);
        }

        public static void SendNPCLocalData(int npc, int ignore = -1) //This sends the npc's localAI array.
        {
            float[] localAI = Main.npc[npc].localAI;
            NetMessage.SendModData(Mods.GetMod("OmnirsNosPak"), 1, -1, ignore, npc, localAI[0], localAI[1], localAI[2], localAI[3]); //This is NetMessage.SendModData(Mod mod, int messageID, int remoteClient, int ignoreClient, object data, object moreData, object evenMoreData, object asMuchDataAsYouWant)
        }

        public static void SendNPCAllData(int npc, int ignore = -1) //This sends the npc's data first, and then send's its localAI.
        {
            SendNPCData(npc, ignore);
            SendNPCLocalData(npc, ignore);
        }

        public override void NetReceive(BinBuffer bb, int messageID, MessageBuffer buffer) //This is what happens when we receive custom data.
        {
            switch (messageID)
            {
                case 1: //Here we copy the data into the NPC's localAI, so that everything is synchronized.
                    int npc = bb.ReadInt();
                    float[] localAI = Main.npc[npc].localAI;
                    localAI[0] = bb.ReadFloat();
                    localAI[1] = bb.ReadFloat();
                    localAI[2] = bb.ReadFloat();
                    localAI[3] = bb.ReadFloat();
                    if (Main.netMode == 2)
                    {
                        SendNPCLocalData(npc, buffer.whoAmI);
                    }
                    break;
                default:
                    break;
            }
        }
    }
}

My Creature:

Code:
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

using TAPI;
using Terraria;
using BaseMod;

namespace OmnirsNosPak.NPCs
{
    public class OmnirsEarthCrystal : GNPC
    {

        float customAi1;
        float customspawn1;

        bool flag15 = false;

        public override bool CanSpawn(int x, int y, int type, Player player)
        {

            bool oSky = (y < (Main.maxTilesY * 0.1f));
            bool oSurface = (y >= (Main.maxTilesY * 0.1f) && y < (Main.maxTilesY * 0.2f));
            bool oUnderSurface = (y >= (Main.maxTilesY * 0.2f) && y < (Main.maxTilesY * 0.3f));
            bool oUnderground = (y >= (Main.maxTilesY * 0.3f) && y < (Main.maxTilesY * 0.4f));
            bool oCavern = (y >= (Main.maxTilesY * 0.4f) && y < (Main.maxTilesY * 0.6f));
            bool oMagmaCavern = (y >= (Main.maxTilesY * 0.6f) && y < (Main.maxTilesY * 0.8f));
            bool oUnderworld = (y >= (Main.maxTilesY * 0.8f));
            bool oBorders = (y < (Main.maxTilesY * 0.03f) || x < (Main.maxTilesX * 0.03f) || y > (Main.maxTilesY * 0.97f) || x > (Main.maxTilesX * 0.97f));
            if (oBorders || NPC.AnyNPCs(NPCDef.byName["OmnirsNosPak:OmnirsTheEarthFiendLich"].type) || NPC.AnyNPCs(NPCDef.byName["OmnirsNosPak:OmnirsEarthCrystal"].type))
            {
                return false;
            }
            if (!Main.hardMode && (player.zone["Corruption"] || player.zone["Crimson"]) && Main.rand.Next(500) == 1) return true;
            if (Main.hardMode && (player.zone["Corruption"] || player.zone["Crimson"]) && Main.rand.Next(50) == 1) return true;
            return false;
        }
        //Spawns on the Hardmode Surface, between 7/10th and 8.5/10th (Width).

        public override string SetName()
        {
            return "Earth Crystal";
        }

        public override void AI()
        {
            npc.dontTakeDamage = true;
            if (customspawn1 > 0)
            {
                Main.NewText("Step2", 175, 75, 255);
                if (Main.netMode != 1)
                {
                    Main.NewText("Step3", 175, 75, 255);
                    int npcID = NPC.NewNPC((int)npc.Center.X, (int)npc.Center.Y, "OmnirsNosPak:OmnirsTheEarthFiendLich", 0);
                    Main.npc[npcID].Center = npc.Center;
                    Main.npc[npcID].netUpdate = true;
                    npc.life = 0;
                }
            }
            #region Ogre/custom frames
            int num = 1;
            if (!Main.dedServ)
            {
                num = 40;
            }
            npc.frameCounter++;
            if (npc.frameCounter > 6.0)
            {
                npc.frame.Y = npc.frame.Y + num;
                npc.frameCounter = 0.0;
            }
            if (npc.frame.Y / num >= Main.npcFrameCount[npc.type])
            {
                npc.frame.Y = 0;
            }
            for (int num131 = 0; num131 < 255; num131++)
            {
                if (Main.player[num131].active && Main.player[num131].talkNPC == this.npc.whoAmI)
                {
                    flag15 = true;
                    if (this.npc.ai[0] != 0f)
                    {
                        this.npc.netUpdate = true;
                    }
                    this.npc.ai[0] = 0f;
                    this.npc.ai[1] = 300f;
                    this.npc.ai[2] = 100f;
                    if (Main.player[num131].position.X + (float)(Main.player[num131].width / 2) < this.npc.position.X + (float)(this.npc.width / 2))
                    {
                        this.npc.direction = -1;
                    }
                    else
                    {
                        this.npc.direction = 1;
                    }
                }
            }

            #endregion
            npc.timeLeft = 1800;
            if (npc.timeLeft > 1800 && flag15 == false)
            {
                npc.timeLeft = 1800;
                return;
            }
            return;
        }

        public override void SetChatButtons(ref string[] buttons)
        {
            buttons[0] = "I'm ready";
        }

        public override void OnChatButtonClicked(string[] buttons, int buttonIndex, ref bool openShop)
        {
            if (buttonIndex == 0)
            {
                if (customspawn1 <= 0 && !NPC.AnyNPCs(NPCDef.byName["OmnirsNosPak:OmnirsTheEarthFiendLich"].type))
                {
                    customspawn1 += 1f;
                    Main.NewText("Step1", 175, 75, 255);
                }
            }
        }



        public override string SetChat()
        {
            return "This is the Earth Crystal, guarded by Lich. Are you prepared to fight this fiend for it?";
        }

        public override bool? CanHitFriendNPC(NPC npc) { return false; }
    }
}
Unless you're changing the NPC's localAI or custom fields right after it spawns, the only thing you should need to do to sync it is to set netUpdate to true. You only really need ModNet for whenever you change localAI and want to sync it, or change a custom field and want to sync that. (Also, ModNet is different from other classes in that in order to send data, you need to manually call its methods).
 
Back
Top Bottom