private void MakeCrystalVulnerable()
        {
            if (AttackTimer == 1)
            {
                startPos = npc.Center;

                while (crystalLocations.Count < 4)
                {
                    BuildCrystalLocations();
                }

                if (Main.netMode != NetmodeID.MultiplayerClient)
                {
                    List <Vector2> possibleLocations = new List <Vector2>(crystalLocations);
                    possibleLocations.ForEach(n => n += new Vector2(0, -48));
                    possibleLocations = Helper.RandomizeList(possibleLocations, Main.rand);
                    for (int k = 0; k < crystals.Count; k++)
                    {
                        NPC crystalNpc            = crystals[k];
                        VitricBossCrystal crystal = crystalNpc.modNPC as VitricBossCrystal;

                        crystal.StartPos = crystalNpc.Center;
                        Vector2 target = possibleLocations[k];
                        crystal.TargetPos    = target;
                        crystalNpc.ai[1]     = 0; //reset the crystal's timers
                        crystalNpc.ai[2]     = 1; //set them into this attack's mode
                        crystalNpc.netUpdate = true;
                    }
                }
            }

            if (AttackTimer < 60)
            {
                npc.Center = Vector2.SmoothStep(startPos, homePos, AttackTimer / 60f);
            }

            if (AttackTimer == 180 && Main.netMode != NetmodeID.MultiplayerClient)
            {
                var crystal = crystals.FirstOrDefault(n => n.ai[0] == 2);

                if (crystal != null)
                {
                    crystal.ai[0] = 0;
                }
            }

            if (AttackTimer > 180 && AttackTimer % 25 == 0 && Main.netMode != NetmodeID.MultiplayerClient)
            {
                Projectile.NewProjectile(homePos + new Vector2(Main.rand.Next(-700, 700), -460), new Vector2(0, 18), ProjectileType <TelegraphedGlassSpike>(), 15, 0);
            }

            if (AttackTimer >= 720)
            {
                ResetAttack();
            }
        }
        private void CrystalSmash()
        {
            while (crystalLocations.Count < 4)
            {
                BuildCrystalLocations();
            }

            //boss during the attack
            if (AttackTimer == 1)
            {
                endPos = npc.Center; //set the ending point to the center of the arena so we can come back later
            }
            //actual movement
            if (AttackTimer < 270)
            {
                npc.position.Y += (float)Math.Sin(AttackTimer / 90 * 6.28f) * 2.5f;
                float vel = ((AttackTimer % 68) / 17 - (float)Math.Pow(AttackTimer % 68, 2) / 1156) * 7;
                npc.position.X += (AttackTimer < 68 || AttackTimer > 68 * 3) ? vel : -vel;
            }

            if (AttackTimer == 270)//where we start our return trip
            {
                startPos      = npc.Center;
                npc.velocity *= 0;
            }

            if (AttackTimer > 270)
            {
                npc.Center = Vector2.SmoothStep(startPos, endPos, (AttackTimer - 270) / 90); //smoothstep back to the center
            }
            int lockSpeed = 60 - BrokenCount * (Main.expertMode ? 7 : 4);

            //Crystals during the attack
            for (int k = 0; k < 4; k++)
            {
                NPC crystal = crystals[k];
                VitricBossCrystal crystalModNPC = crystal.modNPC as VitricBossCrystal;
                if (AttackTimer == lockSpeed + k * lockSpeed && Main.netMode != NetmodeID.MultiplayerClient) //set motion points correctly
                {
                    RandomizeTarget();                                                                       //pick a random target to smash a crystal down

                    Player player = Main.player[npc.target];
                    crystal.ai[2]             = 0;                                                                            //set the crystal into normal mode
                    crystalModNPC.StartPos    = crystal.Center;
                    crystalModNPC.TargetPos   = new Vector2(player.Center.X + player.velocity.X * 50, player.Center.Y - 250); //endpoint is above the player
                    crystalModNPC.TargetPos.X = MathHelper.Clamp(crystalModNPC.TargetPos.X, homePos.X - 800, homePos.X + 800);
                    crystal.netUpdate         = true;
                }

                if (AttackTimer >= lockSpeed + k * lockSpeed && AttackTimer <= lockSpeed + (k + 1) * lockSpeed) //move the crystal there
                {
                    crystal.Center = Vector2.SmoothStep(crystalModNPC.StartPos, crystalModNPC.TargetPos, (AttackTimer - (lockSpeed + k * lockSpeed)) / lockSpeed);
                }

                if (AttackTimer == lockSpeed + (k + 1) * lockSpeed) //set the crystal into falling mode after moving
                {
                    Player player = Main.player[npc.target];
                    crystal.ai[2]           = 3;
                    crystal.ai[1]           = 0;
                    crystalModNPC.TargetPos = player.Center;
                }
            }

            //ending the attack
            if (AttackTimer > 120 + lockSpeed * 4)
            {
                ResetAttack();
            }
        }
        private void CrystalSmashSpaced()
        {
            for (int k = 0; k < 4; k++)
            {
                NPC crystal = crystals[k];
                VitricBossCrystal crystalModNPC = crystal.modNPC as VitricBossCrystal;

                if (AttackTimer == 60)                                                     //set motion points correctly
                {
                    crystal.ai[2]           = 0;                                           //set the crystal into normal mode
                    crystalModNPC.StartPos  = crystal.Center;
                    crystalModNPC.TargetPos = homePos + new Vector2(-500 + k * 333, -400); //endpoint is above the player
                }

                if (AttackTimer >= 60 && AttackTimer <= 120) //move the crystal there
                {
                    crystal.Center = Vector2.SmoothStep(crystalModNPC.StartPos, crystalModNPC.TargetPos, (AttackTimer - 60) / 60f);
                }

                if (AttackTimer == 120) //set the crystal into falling mode after moving
                {
                    crystal.ai[2]             = 3;
                    crystal.ai[1]             = 0;
                    crystalModNPC.TargetPos.Y = homePos.Y + 800; //fall through platforms
                }

                if (AttackTimer > 180)
                {
                    Player player   = Main.player[npc.target];
                    int    fireRate = 60;
                    float  variance = 0;

                    if (crystal.ai[0] == 3)
                    {
                        fireRate = 35;
                        variance = 0.5f;
                    }

                    if (Main.expertMode)
                    {
                        fireRate -= 10;
                    }

                    if (AttackTimer % fireRate == 0 && Main.netMode != NetmodeID.MultiplayerClient)
                    {
                        Projectile.NewProjectile(crystal.Center + new Vector2(0, -32), Vector2.Normalize(crystal.Center - player.Center).RotatedByRandom(variance) * -10, ProjectileType <NPCs.Vitric.SnakeSpit>(), 26, 0, Main.myPlayer);
                    }

                    if (AttackTimer % 10 == 0)
                    {
                        Dust.NewDustPerfect(crystal.Center, DustType <LavaSpew>());
                    }
                }
            }

            //ending the attack
            if (AttackTimer > 360)
            {
                ResetAttack();
            }
        }
        private void FireCage()
        {
            if (AttackTimer % 110 == 0 && AttackTimer != 0 && AttackTimer < 800) //the sand cones the boss fires
            {
                if (Main.netMode != NetmodeID.MultiplayerClient)
                {
                    float rot = (npc.Center - Main.player[npc.target].Center).ToRotation() + Main.rand.NextFloat(-0.5f, 0.5f);

                    int index = Projectile.NewProjectile(npc.Center + new Vector2(0, 30), Vector2.Zero, ProjectileType <FireCone>(), 25, 0, Main.myPlayer, 0, rot); //fire cone

                    (Main.projectile[index].modProjectile as FireCone).extraShots = BrokenCount >= 1;

                    lockedRotation = rot + 3.14f;

                    RandomizeTarget();
                }
            }

            if (AttackTimer % 110 == 25)
            {
                Helper.PlayPitched("VitricBoss/ceiroslidopensmall", 0.5f, Main.rand.NextFloat(0.1f, 1), npc.Center);
            }

            if (AttackTimer > 110 && AttackTimer % 110 > 10 && AttackTimer % 110 <= 90)
            {
                SetFrameY(2);

                int x = (int)(Math.Sin((AttackTimer % 110 - 10) / 80f * 3.14f) * 8);
                SetFrameX(x);
            }
            else
            {
                SetFrameY(0);
            }

            if (AttackTimer >= 110)
            {
                rotationLocked = true;
            }

            for (int k = 0; k < 4; k++) //each crystal
            {
                NPC crystal = crystals[k];
                VitricBossCrystal crystalModNPC = crystal.modNPC as VitricBossCrystal;
                if (AttackTimer == 1) //set the crystal's home position to where they are
                {
                    crystalModNPC.StartPos = crystal.Center;
                    favoriteCrystal        = bossRand.Next(4); //randomize which crystal will have the opening
                }

                if (AttackTimer > 1 && AttackTimer <= 60) //suck the crystals in
                {
                    crystal.Center = npc.Center + (Vector2.SmoothStep(crystalModNPC.StartPos, npc.Center, AttackTimer / 60) - npc.Center).RotatedBy(AttackTimer / 60f * 3.14f);
                }

                if (AttackTimer == 61)  //Set the crystal's new endpoints. !! actual endpoints are offset by pi !!
                {
                    crystalModNPC.StartPos  = crystal.Center;
                    crystalModNPC.TargetPos = npc.Center + new Vector2(0, -800).RotatedBy(1.57f * k);
                    crystal.ai[2]           = 2; //set them into this mode to get the rotational effect
                }

                if (AttackTimer >= 120 && AttackTimer < 360) //spiral outwards slowly
                {
                    crystal.Center = npc.Center + (Vector2.SmoothStep(crystalModNPC.StartPos, crystalModNPC.TargetPos, (AttackTimer - 120) / 240) - npc.Center).RotatedBy((AttackTimer - 120) / 240 * 3.14f);
                }

                if (AttackTimer == 360)
                {
                    Helper.PlayPitched("VitricBoss/RingIdle", 0.075f, -0.2f, npc.Center);
                }

                if (AttackTimer >= 360 && AttackTimer < 840) //come back in
                {
                    float addedRotation = BrokenCount * (Main.expertMode ? 2.3f : 1.8f);
                    crystal.Center = npc.Center + (Vector2.SmoothStep(crystalModNPC.TargetPos, crystalModNPC.StartPos, (AttackTimer - 360) / 480) - npc.Center).RotatedBy(-(AttackTimer - 360) / 480 * (4.72f + addedRotation));

                    //the chosen "favorite" or master crystal is the one where our opening should be
                    if (k != favoriteCrystal)
                    {
                        crystalModNPC.shouldDrawArc = true;

                        float alpha = 0;

                        if (AttackTimer < 420)
                        {
                            alpha = (AttackTimer - 360) / 60f;
                        }
                        else if (AttackTimer > 760)
                        {
                            alpha = 1 - (AttackTimer - 760) / 80f;
                        }
                        else
                        {
                            alpha = 1;
                        }

                        for (int i = 0; i < 4 - (int)(AttackTimer - 360) / 100; i++)
                        {
                            var rot = Main.rand.NextFloat(1.57f);
                            Dust.NewDustPerfect(npc.Center + (crystal.Center - npc.Center).RotatedBy(rot), DustType <Dusts.Glow>(),
                                                -Vector2.UnitX.RotatedBy(crystal.rotation + rot + Main.rand.NextFloat(-0.45f, 0.45f)) * Main.rand.NextFloat(1, 4) * alpha, 0, new Color(255, 160, 100) * alpha, Main.rand.NextFloat(0.4f, 0.8f) * alpha);
                        }
                    }
                }

                if (AttackTimer >= 840 && AttackTimer < 880) //reset to ready position
                {
                    crystal.Center = Vector2.SmoothStep(npc.Center, npc.Center + new Vector2(0, -120).RotatedBy(1.57f * k), (AttackTimer - 840) / 40);
                }

                if (AttackTimer == 880) //end of the attack
                {
                    crystal.ai[2] = 0;  //reset our crystals
                    ResetAttack();      //all done!
                }
            }

            if (AttackTimer >= 360 && AttackTimer < 840) //the collision handler for this attack. out here so its not done 4 times
            {
                foreach (Player player in Main.player.Where(n => n.active))
                {
                    float dist        = Vector2.Distance(player.Center, npc.Center);        //distance the player is from the boss
                    float angleOff    = (player.Center - npc.Center).ToRotation() % 6.28f;  //where the player is versus the boss angularly. used to check if the player is in the opening
                    NPC   crystal     = crystals[favoriteCrystal];
                    float crystalDist = Vector2.Distance(crystal.Center, npc.Center);       //distance from the boss to the ring
                    float crystalOff  = (crystal.Center - npc.Center).ToRotation() % 6.28f; //crystal's rotation
                    float angleDiff   = Helper.CompareAngle(angleOff, crystalOff);

                    // if the player's distance from the boss is within 2 player widths of the ring and if the player isnt in the gab where they would be safe
                    if ((dist > (minCageBounceDist) && dist <= crystalDist + player.width && dist >= crystalDist - player.width) && !(angleDiff > 0 && angleDiff < 1.57f))
                    {
                        Vector2 maxSpeed = new Vector2(maxCageBounceSpeed);
                        player.Hurt(Terraria.DataStructures.PlayerDeathReason.ByNPC(npc.whoAmI), Main.expertMode ? 90 : 65, 0);                     //do big damag
                        player.velocity = Vector2.Clamp(player.velocity + Vector2.Normalize(player.Center - npc.Center) * -3, -maxSpeed, maxSpeed); //knock into boss
                        Main.PlaySound(SoundID.DD2_LightningAuraZap);                                                                               //bzzt!
                    }
                }
            }
        }