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

Hey, is there a way to make your bosses dash at your player? I can't find any up-to-date ways to make my boss dash at me. Can anyone help?

Here is the code, if anyone wanted to re-make my situation. Here, my boss only shoots projectiles, and doesn't charge. I know I haven't added the charge code yet, but that's because I don't know how.
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Terraria;
using Terraria.ModLoader;
using Terraria.ID;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace BetterExploringMod.NPCs.Boss
{
    [AutoloadBossHead]
    public class TutorialBoss : ModNPC
    {
        private Player player;
        private float speed;

        public override void SetStaticDefaults()
        {
            DisplayName.SetDefault("Icicle Guardian");
            Main.npcFrameCount[npc.type] = 3;
        }

        public override void SetDefaults()
        {
            npc.aiStyle = -1; // Will not have any AI from any existing AI styles.
            npc.lifeMax = 2500; // The Max HP the boss has on Normal
            npc.damage = 15; // The base damage value the boss has on Normal
            npc.defense = 3; // The base defense on Normal
            npc.knockBackResist = 0f; // No knockback
            npc.width = 100;
            npc.height = 100;
            npc.value = 10000;
            npc.npcSlots = 1f; // The higher the number, the more NPC slots this NPC takes.
            npc.boss = true; // Is a boss
            npc.lavaImmune = true; // Not hurt by lava
            npc.noGravity = true; // Not affected by gravity
            npc.noTileCollide = true; // Will not collide with the tiles.
            npc.HitSound = SoundID.NPCHit4;
            npc.DeathSound = SoundID.NPCDeath1;
            music = mod.GetSoundSlot(SoundType.Music, "Sounds/Music/FrozenEyeMusic");
            bossBag = mod.ItemType("TutorialBossBag"); // Needed for the NPC to drop loot bag.
        }

        public override void ScaleExpertStats(int numPlayers, float bossLifeScale)
        {
            npc.lifeMax = (int)(npc.lifeMax * 0.625f * bossLifeScale);
            npc.damage = (int)(npc.damage * 0.6f);
            npc.defense = (int)(npc.defense + numPlayers);
        }

        public override void AI()
        {
            if(Main.expertMode)
            {
                Target(); // Sets the Player Target

                DespawnHandler(); // Handles if the NPC should despawn.

                Move(new Vector2(-(Main.rand.Next(299)), -300f)); // Calls the Move Method
                                                                //Attacking
                npc.ai[1] -= 1f; // Subtracts 1 from the ai.
                if (npc.ai[1] == 0f)
                {
                    Shoot();
                }
                if (npc.ai[1] == -15f)
                {
                    Shoot();
                }
                if (npc.ai[1] == -30f)
                {
                    Shoot();
                }
                if (npc.ai[1] == -45f)
                {
                    Shoot();
                }
                if (npc.ai[1] == -60f)
                {
                    Shoot();
                    npc.ai[1] = 180f;
                }
            }
            else
            {
                Target(); // Sets the Player Target

                DespawnHandler(); // Handles if the NPC should despawn.

                Move(new Vector2((Main.rand.Next(299)), -300f)); // Calls the Move Method
                                                                //Attacking
                npc.ai[1] -= 1f; // Subtracts 1 from the ai.
                if (npc.ai[1] == 0f)
                {
                    Shoot();
                }
                if (npc.ai[1] == -15f)
                {
                    Shoot();
                }
                if (npc.ai[1] == -30f)
                {
                    Shoot();
                    npc.ai[1] = 300f;
                }
            }
        }
        private void Target()
        {
            player = Main.player[npc.target]; // This will get the player target.
        }

        private void Move(Vector2 offset)
        {
            speed = 5f; // Sets the max speed of the npc.
            Vector2 moveTo = player.Center + offset; // Gets the point that the npc will be moving to.
            Vector2 move = moveTo - npc.Center;
            float magnitude = Magnitude(move);
            if(magnitude > speed)
            {
                move *= speed / magnitude;
            }
            float turnResistance = 60f; // The larget the number the slower the npc will turn.
            move = (npc.velocity * turnResistance + move) / (turnResistance + 1f);
            magnitude = Magnitude(move);
            if(magnitude > speed)
            {
                move *= speed / magnitude;
            }
            npc.velocity = move;
        }
        private void DespawnHandler()
        {
            if(!player.active || player.dead)
            {
                npc.TargetClosest(false);
                player = Main.player[npc.target];
                if(!player.active || player.dead)
                {
                    npc.velocity = new Vector2(0f, -10f);
                    if(npc.timeLeft > 10)
                    {
                        npc.timeLeft = 10;
                    }
                    return;
                }
            }
        }

        private void Shoot()
        {
            int type = mod.ProjectileType("PearlwoodsBane");
            Vector2 velocity = player.Center - npc.Center; // Get the distance between target and npc.
            float magnitude = Magnitude(velocity);
            if(magnitude > 0) {
                velocity *= 5f / magnitude;
            } else
            {
                velocity = new Vector2(0f, 5f);
            }
            Projectile.NewProjectile(npc.Center, velocity, type, npc.damage, 2f);
        }

        private float Magnitude(Vector2 mag)
        {
            return (float)Math.Sqrt(mag.X * mag.X + mag.Y * mag.Y);
        }

        public override void FindFrame(int frameHeight)
        {
            npc.frameCounter += 1;
            npc.frameCounter %= 20;
            int frame = (int)(npc.frameCounter / 2.0);
            if (frame >= Main.npcFrameCount[npc.type]) frame = 0;
            npc.frame.Y = frame * frameHeight;

            RotateNPCToTarget();
        }

        private void RotateNPCToTarget()
        {
            if (player == null) return;
            Vector2 direction = npc.Center - player.Center;
            float rotation = (float)Math.Atan2(direction.Y, direction.X);
            npc.rotation = rotation + ((float)Math.PI * 0.5f);
        }
        public override void NPCLoot()
        {
            if (Main.expertMode)
            {
                npc.DropBossBags();
            } else
            {
                if (Main.rand.Next(3) == 0) // For items that you want to have a chance to drop
                {
                    Item.NewItem((int)npc.position.X, (int)npc.position.Y, npc.width, npc.height, ItemID.SuspiciousLookingEye);
                }
                Item.NewItem((int)npc.position.X, (int)npc.position.Y, npc.width, npc.height, mod.ItemType("Starpowder"), (Main.rand.Next(3))); // For Items that you want to always drop
            }
        }

        public override bool? DrawHealthBar(byte hbPosition, ref float scale, ref Vector2 position)
        {
            scale = 1.5f;
            return null;
        }
      
    }
}
I recommend looking at the source code for the EoC but I think we aren't allowed to talk about it in forums so that's all I can say.
[doublepost=1563151031,1563150971][/doublepost]
I can't spot anything particularly wrong, but the code is long so I somewhat ignored most of it only focusing on the targeting part.

By "doesn't actually look at the player" do you mean the AI does not target them at all? Or do you mean the NPC's sprite does not face the player or rotate towards it depending on what kind of graphics you're working with.

In the first case, I would suggest to slap down a bunch of NewText printing your targetPosition's coordinates right after a value is assigned to it. So you can be really sure the targeting is working as it should, which would point the problem somewhere else (say, the AI movements for instance).
In the second case, you need to adjust the NPC's sprite to behave the way you want it to behave. I personally do it in the FindFrame hook, unless it has changed in recent ModLoader and I'm an old fart (which I am). Simple examples would include changing npc.rotation to face the targeted player, or flipping the sprite with npc.spriteDirection to face towards the target. This is also where you'd normally code the NPC's animation.
Well, how would I do that? I don't know which variables to put in to make it face the player.
 
how i do a Boss's second stage like the Eye Of Ctulhu,Brain Of Ctulhu,The Twins,Plantera,Golem and Duke Fishron?
 
how i do a Boss's second stage like the Eye Of Ctulhu,Brain Of Ctulhu,The Twins,Plantera,Golem and Duke Fishron?
To do this you could put in a line such as this;
if (npc.life > npc.lifeMax / 2)
{
//Code for first stage
}
if (npc.life <= npc.lifeMax / 2)
{
//Code for second stage
}
There may be a better way of doing this but if there is I don't know it.
Hope this helped.
 
Im making a mod but stuck on the boss, always getting the same error
c:\Users\user\Documents\My Games\Terraria\ModLoader\Mod Sources\ShaanGuns\NPCs\Jords\BossName.cs(40,30) : error CS0115: 'ShaanGuns.NPCs.Boss.Jords.AutoloadHead(ref string, ref string)': no suitable method found to override


Do you know how to fix it
You need a png file named (Boss name)_Head_Boss.png

Otherwise remove the "AutoLoadBossHead" at the top of the cs file.

(The head is the image that appears on the map)
yeah but the autoload its outdated the new one its "[AutoloadBossHead]"

example:

Code:
using Terraria;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Terraria.ModLoader;
using Terraria.ID;
using static Terraria.ModLoader.ModContent;

namespace YourModName
{ 
    [AutoloadBossHead]
    public class YourNameHereWithNoSpaces: ModNPC
    {
     public override void SetStaticDefaults() {

       DisplayName.SetDefault("Your Boss Name Here");

        }
        public override void SetDefaults()
        {
              //your code here
        }

hope its helps ;)
 
how do make skeletron boss? I want to make a skeleton man or pumpkin man boss but zombie or something. how?
 
visual studio can't recognise "using tAPI" for some reason (might be just me being stupid because i just started modding)
 
visual studio can't recognise "using tAPI" for some reason (might be just me being stupid because i just started modding)
This is a tAPI guide (the predecessor of tModLoader) so much of the file formatting is outdated, albeit everything beyond that is still applicable.

For a general modding guide I would suggest to look somewhere else. The tModLoader wiki on github could be a start. Otherwise, all you need really is replace
Code:
using tAPI;
with
Code:
using Terraria.ModLoader;

On a side note, I would suggest the people still finding this thread to direct coding questions to the tModLoader discord where your inquiries are much more likely to be seen.
 
This is a tAPI guide (the predecessor of tModLoader) so much of the file formatting is outdated, albeit everything beyond that is still applicable.

For a general modding guide I would suggest to look somewhere else. The tModLoader wiki on github could be a start. Otherwise, all you need really is replace
Code:
using tAPI;
with
Code:
using Terraria.ModLoader;

On a side note, I would suggest the people still finding this thread to direct coding questions to the tModLoader discord where your inquiries are much more likely to be seen.
thanks, i'll try if it works
 
So, my boss ai works fine, but the animation is very broken. When ai[1] is 0, the sprite is stacked on top of itself, so that there are three bosses on top of eachother. When ai[1] is 1 or 2 the boss completely dissapears. And when ai[1] is anything else, it dissapears again. What is happening, and how can i fix it? Heres my code:
C#:
using Terraria.ModLoader;
using Terraria;
using Terraria.ID;
using Microsoft.Xna.Framework;
using Terraria.ModLoader.Utilities;
using Terraria.GameContent.ItemDropRules;
using OneFourTestMod.Items;
using System;
using OneFourTestMod.Projectiles;
using Mono.Cecil;
using static Terraria.ModLoader.PlayerDrawLayer;

namespace OneFourTestMod.Enemies
{
    [AutoloadBossHead]
    public class SandGod : ModNPC
    {
        private int ai;
        private int attacktimer = 0;
        private bool fastspeed = false;

        private bool stunned;
        private int stunnedtimer;

        public override void SetStaticDefaults()
        {
            DisplayName.SetDefault("The God of Sand");
            Main.npcFrameCount[NPC.type] = Main.npcFrameCount[6];
        }

        public override void SetDefaults()
        {
            NPC.width = 128;
            NPC.height = 128;
            NPC.damage = 100;
            NPC.defense = 25;
            NPC.lifeMax = 2500;
            NPC.value = 5000f;
            NPC.knockBackResist = 0;
            NPC.lavaImmune = true;
            NPC.noTileCollide = true;
            NPC.noGravity = true;
            NPC.aiStyle = -1; //120 is empress of light
            NPC.HitSound = SoundID.NPCHit1;
            NPC.DeathSound = SoundID.NPCDeath1;
            NPC.friendly = false;
            NPC.dontTakeDamageFromHostiles = true;
            NPC.boss = true;
            Music = MusicID.Boss2;
        }

        public override void ScaleExpertStats(int numPlayers, float bossLifeScale)
        {
            NPC.lifeMax = (int)(NPC.lifeMax * bossLifeScale);
            NPC.damage = (int)(NPC.damage * 1.3f);
        }

        public override void ModifyNPCLoot(NPCLoot npcLoot)
        {
            npcLoot.Add(ItemDropRule.Common(ItemID.SandBlock, 1, 200, 400));
            npcLoot.Add(ItemDropRule.Common(ItemID.Sandstone, 2, 200, 400));
            npcLoot.Add(ItemDropRule.Common(ItemID.HardenedSand, 2, 200, 400));
            npcLoot.Add(ItemDropRule.Common(ItemID.Ruby, 1, 1, 100));
            
            if (Main.rand.Next(1,2) == 1)
            {
                npcLoot.Add(ItemDropRule.Common(ModContent.ItemType<TestSword>(), 3));
            } else
            {
                npcLoot.Add(ItemDropRule.Common(ModContent.ItemType<TestGun>(), 3));
            }
        }

        
        public override void AI()
        {
            // Gets the player and Target vector
            NPC.TargetClosest(true);
            Player player = Main.player[NPC.target];
            Vector2 target = NPC.HasPlayerTarget ? player.Center : Main.npc[NPC.target].Center;

            // Ensures the npc is not rotated
            NPC.rotation = 0.0f;
            NPC.netAlways = true;
            NPC.TargetClosest(true);

            // Ensures npc life is not greater than its max life
            if (NPC.life >= NPC.lifeMax)
            {
                NPC.life = NPC.lifeMax;
            }

            // Despawning
            if (NPC.target < 0 || NPC.target == 255 || player.dead || !player.active)
            {
                NPC.TargetClosest(false);
                NPC.direction = 1;
                NPC.velocity.Y = NPC.velocity.Y - 0.1f;
                if (NPC.timeLeft > 20)
                {
                    NPC.timeLeft = 20;
                    return;
                }
            }

            // Stunned
            if (stunned)
            {
                NPC.velocity.X = 0.0f;
                NPC.velocity.Y = 0.0f;
                stunnedtimer++;
                if (stunnedtimer >= 100)
                {
                    stunned = false;
                    stunnedtimer = 0;
                }
            }

            // Increment ai
            ai++;

            // Movement
            NPC.ai[0] = (float)ai * 1f;
            int distance = (int)Vector2.Distance(target, NPC.Center);
            if ((double)NPC.ai[0] < 300)
            {
                NPC.ai[1] = 0;
                MoveTowards(NPC, target, (float)(distance > 300 ? 13f : 7f), 30f);
                NPC.netUpdate = true;
            } else if ((double)NPC.ai[0] >= 300 && (double)NPC.ai[0] < 450.0)
            {
                stunned = true;
                NPC.ai[1] = 1;
                NPC.defense = 50;
                NPC.damage = 25;
                MoveTowards(NPC, target, (float)(distance > 300 ? 13f : 7f), 30f);
                NPC.netUpdate = true;
            } else if ((double)NPC.ai[0] >= 450.0)
            {
                NPC.ai[1] = 2;
                stunned = false;
                NPC.damage = (int)(NPC.damage * 0.5f * 1.3f);
                NPC.defense = 25;
                if (!fastspeed)
                {
                    fastspeed = true;
                } else
                {
                    if ((double)NPC.ai[0] % 50 == 0)
                    {
                        float speed = 12f;
                        Vector2 vector = new Vector2(NPC.position.X + (float)NPC.width * 0.5f, NPC.position.Y + (float)NPC.height * 0.5f);
                        float x = player.position.X + (float)(player.width / 2) - vector.X;
                        float y = player.position.Y + (float)(player.height / 2) - vector.Y;
                        float distance2 = (float)Math.Sqrt(x * x + y * y);
                        float factor = speed / distance2;
                        NPC.velocity.X = x * factor * 1.5f;
                        NPC.velocity.Y = y * factor * 1.5f;
                    }
                }
                NPC.netUpdate = true;
            }

            // Attack
            if ((double)NPC.ai[0] % (Main.expertMode ? 100 : 150) == 0 && !stunned && !fastspeed)
            {
                attacktimer++;
                if (attacktimer <= 2)
                {
                    NPC.ai[1] = 3;
                    NPC.velocity.X = 0f;
                    NPC.velocity.Y = 0f;
                    Vector2 shootPos = NPC.Center;
                    float accuracy = 5f * (NPC.life / NPC.lifeMax);
                    Vector2 shootVel = target - shootPos + new Vector2(Main.rand.NextFloat(-accuracy, accuracy), Main.rand.NextFloat(-accuracy, accuracy));
                    shootVel.Normalize();
                    shootVel *= 14.5f;
                    for (int i = 0; i < (Main.expertMode ? 10 : 6); i++)
                    {
                        Projectile.NewProjectile(NPC.GetBossSpawnSource(player.whoAmI), new Vector2(shootPos.X + (float)(-100 * NPC.direction) + (float)Main.rand.Next(-40, 41), shootPos.Y - (float)Main.rand.Next(-50, 40)), shootVel, ModContent.ProjectileType<SandGodProjectile>(), NPC.damage / 3, 5f);
                    }
                } else
                {
                    attacktimer = 0;
                }
            }

            if ((double)NPC.ai[0] >= 650.0)
            {
                ai = 0;
                fastspeed = false;
            }
        }

        private void MoveTowards(NPC npc, Vector2 playertarget, float speed, float turnresistance)
        {
            var move = playertarget - npc.Center;
            float length = move.Length();
            if (length > speed)
            {
                move *= speed / length;
            }
            move = (npc.velocity * turnresistance + move) / (turnresistance + 1f);
            length = move.Length();
            if (length > speed)
            {
                move *= speed / length;
            }
            npc.velocity = move;
        }

        public override void FindFrame(int frameHeight)
        {
            if (NPC.ai[1] == 0)
            {
                NPC.frame.Y = 0;
            } else if (NPC.ai[1] == 1)
            {
                NPC.frame.Y = frameHeight;
            } else  if (NPC.ai[1] == 2)
            {
                NPC.frame.Y = frameHeight * 2;
            } else if (NPC.ai[1] == 3)
            {
                NPC.frame.Y = frameHeight * 3;
            } else
            {
                NPC.frame.Y = frameHeight * 4;
            }
        }
    }
}
 
So, my boss ai works fine, but the animation is very broken. When ai[1] is 0, the sprite is stacked on top of itself, so that there are three bosses on top of eachother. When ai[1] is 1 or 2 the boss completely dissapears. And when ai[1] is anything else, it dissapears again. What is happening, and how can i fix it? Heres my code:
C#:
using Terraria.ModLoader;
using Terraria;
using Terraria.ID;
using Microsoft.Xna.Framework;
using Terraria.ModLoader.Utilities;
using Terraria.GameContent.ItemDropRules;
using OneFourTestMod.Items;
using System;
using OneFourTestMod.Projectiles;
using Mono.Cecil;
using static Terraria.ModLoader.PlayerDrawLayer;

namespace OneFourTestMod.Enemies
{
    [AutoloadBossHead]
    public class SandGod : ModNPC
    {
        private int ai;
        private int attacktimer = 0;
        private bool fastspeed = false;

        private bool stunned;
        private int stunnedtimer;

        public override void SetStaticDefaults()
        {
            DisplayName.SetDefault("The God of Sand");
            Main.npcFrameCount[NPC.type] = Main.npcFrameCount[6];
        }

        public override void SetDefaults()
        {
            NPC.width = 128;
            NPC.height = 128;
            NPC.damage = 100;
            NPC.defense = 25;
            NPC.lifeMax = 2500;
            NPC.value = 5000f;
            NPC.knockBackResist = 0;
            NPC.lavaImmune = true;
            NPC.noTileCollide = true;
            NPC.noGravity = true;
            NPC.aiStyle = -1; //120 is empress of light
            NPC.HitSound = SoundID.NPCHit1;
            NPC.DeathSound = SoundID.NPCDeath1;
            NPC.friendly = false;
            NPC.dontTakeDamageFromHostiles = true;
            NPC.boss = true;
            Music = MusicID.Boss2;
        }

        public override void ScaleExpertStats(int numPlayers, float bossLifeScale)
        {
            NPC.lifeMax = (int)(NPC.lifeMax * bossLifeScale);
            NPC.damage = (int)(NPC.damage * 1.3f);
        }

        public override void ModifyNPCLoot(NPCLoot npcLoot)
        {
            npcLoot.Add(ItemDropRule.Common(ItemID.SandBlock, 1, 200, 400));
            npcLoot.Add(ItemDropRule.Common(ItemID.Sandstone, 2, 200, 400));
            npcLoot.Add(ItemDropRule.Common(ItemID.HardenedSand, 2, 200, 400));
            npcLoot.Add(ItemDropRule.Common(ItemID.Ruby, 1, 1, 100));
         
            if (Main.rand.Next(1,2) == 1)
            {
                npcLoot.Add(ItemDropRule.Common(ModContent.ItemType<TestSword>(), 3));
            } else
            {
                npcLoot.Add(ItemDropRule.Common(ModContent.ItemType<TestGun>(), 3));
            }
        }

     
        public override void AI()
        {
            // Gets the player and Target vector
            NPC.TargetClosest(true);
            Player player = Main.player[NPC.target];
            Vector2 target = NPC.HasPlayerTarget ? player.Center : Main.npc[NPC.target].Center;

            // Ensures the npc is not rotated
            NPC.rotation = 0.0f;
            NPC.netAlways = true;
            NPC.TargetClosest(true);

            // Ensures npc life is not greater than its max life
            if (NPC.life >= NPC.lifeMax)
            {
                NPC.life = NPC.lifeMax;
            }

            // Despawning
            if (NPC.target < 0 || NPC.target == 255 || player.dead || !player.active)
            {
                NPC.TargetClosest(false);
                NPC.direction = 1;
                NPC.velocity.Y = NPC.velocity.Y - 0.1f;
                if (NPC.timeLeft > 20)
                {
                    NPC.timeLeft = 20;
                    return;
                }
            }

            // Stunned
            if (stunned)
            {
                NPC.velocity.X = 0.0f;
                NPC.velocity.Y = 0.0f;
                stunnedtimer++;
                if (stunnedtimer >= 100)
                {
                    stunned = false;
                    stunnedtimer = 0;
                }
            }

            // Increment ai
            ai++;

            // Movement
            NPC.ai[0] = (float)ai * 1f;
            int distance = (int)Vector2.Distance(target, NPC.Center);
            if ((double)NPC.ai[0] < 300)
            {
                NPC.ai[1] = 0;
                MoveTowards(NPC, target, (float)(distance > 300 ? 13f : 7f), 30f);
                NPC.netUpdate = true;
            } else if ((double)NPC.ai[0] >= 300 && (double)NPC.ai[0] < 450.0)
            {
                stunned = true;
                NPC.ai[1] = 1;
                NPC.defense = 50;
                NPC.damage = 25;
                MoveTowards(NPC, target, (float)(distance > 300 ? 13f : 7f), 30f);
                NPC.netUpdate = true;
            } else if ((double)NPC.ai[0] >= 450.0)
            {
                NPC.ai[1] = 2;
                stunned = false;
                NPC.damage = (int)(NPC.damage * 0.5f * 1.3f);
                NPC.defense = 25;
                if (!fastspeed)
                {
                    fastspeed = true;
                } else
                {
                    if ((double)NPC.ai[0] % 50 == 0)
                    {
                        float speed = 12f;
                        Vector2 vector = new Vector2(NPC.position.X + (float)NPC.width * 0.5f, NPC.position.Y + (float)NPC.height * 0.5f);
                        float x = player.position.X + (float)(player.width / 2) - vector.X;
                        float y = player.position.Y + (float)(player.height / 2) - vector.Y;
                        float distance2 = (float)Math.Sqrt(x * x + y * y);
                        float factor = speed / distance2;
                        NPC.velocity.X = x * factor * 1.5f;
                        NPC.velocity.Y = y * factor * 1.5f;
                    }
                }
                NPC.netUpdate = true;
            }

            // Attack
            if ((double)NPC.ai[0] % (Main.expertMode ? 100 : 150) == 0 && !stunned && !fastspeed)
            {
                attacktimer++;
                if (attacktimer <= 2)
                {
                    NPC.ai[1] = 3;
                    NPC.velocity.X = 0f;
                    NPC.velocity.Y = 0f;
                    Vector2 shootPos = NPC.Center;
                    float accuracy = 5f * (NPC.life / NPC.lifeMax);
                    Vector2 shootVel = target - shootPos + new Vector2(Main.rand.NextFloat(-accuracy, accuracy), Main.rand.NextFloat(-accuracy, accuracy));
                    shootVel.Normalize();
                    shootVel *= 14.5f;
                    for (int i = 0; i < (Main.expertMode ? 10 : 6); i++)
                    {
                        Projectile.NewProjectile(NPC.GetBossSpawnSource(player.whoAmI), new Vector2(shootPos.X + (float)(-100 * NPC.direction) + (float)Main.rand.Next(-40, 41), shootPos.Y - (float)Main.rand.Next(-50, 40)), shootVel, ModContent.ProjectileType<SandGodProjectile>(), NPC.damage / 3, 5f);
                    }
                } else
                {
                    attacktimer = 0;
                }
            }

            if ((double)NPC.ai[0] >= 650.0)
            {
                ai = 0;
                fastspeed = false;
            }
        }

        private void MoveTowards(NPC npc, Vector2 playertarget, float speed, float turnresistance)
        {
            var move = playertarget - npc.Center;
            float length = move.Length();
            if (length > speed)
            {
                move *= speed / length;
            }
            move = (npc.velocity * turnresistance + move) / (turnresistance + 1f);
            length = move.Length();
            if (length > speed)
            {
                move *= speed / length;
            }
            npc.velocity = move;
        }

        public override void FindFrame(int frameHeight)
        {
            if (NPC.ai[1] == 0)
            {
                NPC.frame.Y = 0;
            } else if (NPC.ai[1] == 1)
            {
                NPC.frame.Y = frameHeight;
            } else  if (NPC.ai[1] == 2)
            {
                NPC.frame.Y = frameHeight * 2;
            } else if (NPC.ai[1] == 3)
            {
                NPC.frame.Y = frameHeight * 3;
            } else
            {
                NPC.frame.Y = frameHeight * 4;
            }
        }
    }
}
FindFrame is setting your sprite to the first to the fifth of your sprite sheet animation depending on the value of ai[1], but you're setting the frame count at the start of the script to be the same as eaters of souls (which is 2 sprites iirc). What does your actual sprite sheet look like?
 
Back
Top Bottom