Example #1
0
        public override bool PreAI(NPC npc)
        {
            bool result = base.PreAI(npc);

            NPC.golemBoss = npc.whoAmI;

            if (FargoSoulsWorld.SwarmActive)
            {
                return(result);
            }

            /*if (npc.ai[0] == 0f && npc.velocity.Y == 0f) //manipulating golem jump ai
             * {
             *  if (npc.ai[1] > 0f)
             *  {
             *      npc.ai[1] += 5f; //count up to initiate jump faster
             *  }
             *  else
             *  {
             *      float threshold = -2f - (float)Math.Round(18f * npc.life / npc.lifeMax);
             *
             *      if (npc.ai[1] < threshold) //jump activates at npc.ai[1] == -1
             *          npc.ai[1] = threshold;
             *  }
             * }*/

            foreach (Player p in Main.player)
            {
                if (p.active && p.Distance(npc.Center) < 2000)
                {
                    p.AddBuff(ModContent.BuffType <LowGround>(), 2);
                }
            }

            HealPerSecond = FargoSoulsWorld.MasochistModeReal ? 240 : 180;
            if (!IsInTemple) //temple enrage, more horiz move and fast jumps
            {
                HealPerSecond  *= 2;
                npc.position.X += npc.velocity.X / 2f;
                if (npc.velocity.Y < 0)
                {
                    npc.position.Y += npc.velocity.Y * 0.5f;
                    if (npc.velocity.Y > -2)
                    {
                        npc.velocity.Y = 20;
                    }
                }
            }

            if (npc.velocity.Y < 0) //jumping up
            {
                if (!HaveBoostedJumpHeight)
                {
                    HaveBoostedJumpHeight = true;
                    npc.velocity.Y       *= 1.25f;

                    if (!IsInTemple) //temple enrage
                    {
                        if (Main.player[npc.target].Center.Y < npc.Center.Y - 16 * 30)
                        {
                            npc.velocity.Y *= 1.5f;
                        }
                    }
                }
            }
            else
            {
                HaveBoostedJumpHeight = false;
            }

            if (DoStompBehaviour)
            {
                if (npc.velocity.Y == 0f) //landing attacks
                {
                    DoStompBehaviour = false;
                    IsInTemple       = Framing.GetTileSafely(npc.Center).WallType == WallID.LihzahrdBrickUnsafe;

                    if (IsInTemple) //in temple
                    {
                        StompAttackCounter++;
                        if (StompAttackCounter == 1) //plant geysers
                        {
                            if (FargoSoulsWorld.MasochistModeReal)
                            {
                                StompAttackCounter++;
                            }

                            Vector2 spawnPos = new Vector2(npc.position.X, npc.Center.Y); //floor geysers
                            spawnPos.X -= npc.width * 7;
                            for (int i = 0; i < 6; i++)
                            {
                                int tilePosX = (int)spawnPos.X / 16 + npc.width * i * 3 / 16;
                                int tilePosY = (int)spawnPos.Y / 16;// + 1;

                                if (Main.netMode != NetmodeID.MultiplayerClient)
                                {
                                    Projectile.NewProjectile(npc.GetSource_FromThis(), tilePosX * 16 + 8, tilePosY * 16 + 8, 0f, 0f, ModContent.ProjectileType <GolemGeyser2>(), FargoSoulsUtil.ScaledProjectileDamage(npc.damage), 0f, Main.myPlayer, npc.whoAmI);
                                }
                            }

                            spawnPos = npc.Center;
                            for (int i = -3; i <= 3; i++) //ceiling geysers
                            {
                                int tilePosX = (int)spawnPos.X / 16 + npc.width * i * 3 / 16;
                                int tilePosY = (int)spawnPos.Y / 16;// + 1;

                                if (Main.netMode != NetmodeID.MultiplayerClient)
                                {
                                    Projectile.NewProjectile(npc.GetSource_FromThis(), tilePosX * 16 + 8, tilePosY * 16 + 8, 0f, 0f, ModContent.ProjectileType <GolemGeyser>(), FargoSoulsUtil.ScaledProjectileDamage(npc.damage), 0f, Main.myPlayer, npc.whoAmI);
                                }
                            }
                        }
                        else if (StompAttackCounter == 2) //empty jump
                        {
                        }
                        else if (StompAttackCounter == 3) //rocks fall
                        {
                            if (FargoSoulsWorld.MasochistModeReal)
                            {
                                StompAttackCounter = 0;
                            }

                            if (npc.HasPlayerTarget)
                            {
                                if (!Main.dedServ)
                                {
                                    Main.LocalPlayer.GetModPlayer <FargoSoulsPlayer>().Screenshake = 20;
                                }

                                if (Main.netMode != NetmodeID.MultiplayerClient)
                                {
                                    Projectile.NewProjectile(npc.GetSource_FromThis(), npc.Center, Vector2.Zero, ProjectileID.DD2OgreSmash, 0, 0, Main.myPlayer);
                                }

                                for (int i = -2; i <= 2; i++)
                                {
                                    int tilePosX = (int)Main.player[npc.target].Center.X / 16;
                                    int tilePosY = (int)Main.player[npc.target].Center.Y / 16;// + 1;
                                    tilePosX += 4 * i;

                                    //first move up through solid tiles
                                    while (Main.tile[tilePosX, tilePosY].HasUnactuatedTile && Main.tileSolid[Main.tile[tilePosX, tilePosY].TileType])
                                    {
                                        tilePosY--;
                                    }
                                    //then move up through air until next ceiling reached
                                    while (!(Main.tile[tilePosX, tilePosY].HasUnactuatedTile && Main.tileSolid[Main.tile[tilePosX, tilePosY].TileType]))
                                    {
                                        tilePosY--;
                                    }

                                    Vector2 spawn = new Vector2(tilePosX * 16 + 8, tilePosY * 16 + 8);
                                    if (Main.netMode != NetmodeID.MultiplayerClient)
                                    {
                                        Projectile.NewProjectile(npc.GetSource_FromThis(), spawn, Vector2.Zero, ModContent.ProjectileType <GolemBoulder>(), FargoSoulsUtil.ScaledProjectileDamage(npc.damage), 0f, Main.myPlayer);
                                    }
                                }
                            }
                        }
                        else //empty jump
                        {
                            StompAttackCounter = 0;
                        }
                    }
                    else //outside temple
                    {
                        Vector2 spawnPos = new Vector2(npc.position.X, npc.Center.Y);
                        spawnPos.X -= npc.width * 7;
                        for (int i = 0; i < 6; i++)
                        {
                            int tilePosX = (int)spawnPos.X / 16 + npc.width * i * 3 / 16;
                            int tilePosY = (int)spawnPos.Y / 16;// + 1;

                            while (!(Main.tile[tilePosX, tilePosY].HasUnactuatedTile && Main.tileSolid[(int)Main.tile[tilePosX, tilePosY].TileType]))
                            {
                                tilePosY++;
                            }

                            if (Main.netMode != NetmodeID.MultiplayerClient)
                            {
                                if (npc.HasPlayerTarget && Main.player[npc.target].position.Y > tilePosY * 16)
                                {
                                    Projectile.NewProjectile(npc.GetSource_FromThis(), tilePosX * 16 + 8, tilePosY * 16 + 8, 6.3f, 6.3f,
                                                             ProjectileID.FlamesTrap, FargoSoulsUtil.ScaledProjectileDamage(npc.damage), 0f, Main.myPlayer);
                                    Projectile.NewProjectile(npc.GetSource_FromThis(), tilePosX * 16 + 8, tilePosY * 16 + 8, -6.3f, 6.3f,
                                                             ProjectileID.FlamesTrap, FargoSoulsUtil.ScaledProjectileDamage(npc.damage), 0f, Main.myPlayer);
                                }

                                Projectile.NewProjectile(npc.GetSource_FromThis(), tilePosX * 16 + 8, tilePosY * 16 + 8, 0f, -8f, ProjectileID.GeyserTrap, FargoSoulsUtil.ScaledProjectileDamage(npc.damage), 0f, Main.myPlayer);

                                Projectile.NewProjectile(npc.GetSource_FromThis(), tilePosX * 16 + 8, tilePosY * 16 + 8 - 640, 0f, -8f, ProjectileID.GeyserTrap, FargoSoulsUtil.ScaledProjectileDamage(npc.damage), 0f, Main.myPlayer);
                                Projectile.NewProjectile(npc.GetSource_FromThis(), tilePosX * 16 + 8, tilePosY * 16 + 8 - 640, 0f, 8f, ProjectileID.GeyserTrap, FargoSoulsUtil.ScaledProjectileDamage(npc.damage), 0f, Main.myPlayer);
                            }
                        }
                        if (npc.HasPlayerTarget)
                        {
                            for (int i = -3; i <= 3; i++)
                            {
                                int tilePosX = (int)Main.player[npc.target].Center.X / 16;
                                int tilePosY = (int)Main.player[npc.target].Center.Y / 16;// + 1;
                                tilePosX += 10 * i;

                                for (int j = 0; j < 30; j++)
                                {
                                    if (Main.tile[tilePosX, tilePosY].HasUnactuatedTile && Main.tileSolid[Main.tile[tilePosX, tilePosY].TileType])
                                    {
                                        break;
                                    }
                                    tilePosY--;
                                }

                                Vector2 spawn = new Vector2(tilePosX * 16 + 8, tilePosY * 16 + 8);
                                if (Main.netMode != NetmodeID.MultiplayerClient)
                                {
                                    Projectile.NewProjectile(npc.GetSource_FromThis(), spawn, Vector2.Zero, ModContent.ProjectileType <GolemBoulder>(), FargoSoulsUtil.ScaledProjectileDamage(npc.damage), 0f, Main.myPlayer);
                                }
                            }
                        }
                    }
                }
            }
            else if (npc.velocity.Y > 0)
            {
                DoStompBehaviour = true;
            }

            //spray spiky balls
            if (FargoSoulsWorld.MasochistModeReal && ++SpikyBallTimer >= 900)
            {
                if (Framing.GetTileSafely(npc.Center).WallType == WallID.LihzahrdBrickUnsafe)
                {
                    if (npc.velocity.Y > 0) //only when falling, implicitly assume at peak of a jump
                    {
                        SpikyBallTimer = FargoSoulsWorld.MasochistModeReal ? 600 : 0;
                        for (int i = 0; i < 8; i++)
                        {
                            Projectile.NewProjectile(npc.GetSource_FromThis(), npc.position.X + Main.rand.Next(npc.width), npc.position.Y + Main.rand.Next(npc.height),
                                                     Main.rand.NextFloat(-0.3f, 0.3f), Main.rand.NextFloat(-10, -6), ModContent.ProjectileType <GolemSpikyBall>(), FargoSoulsUtil.ScaledProjectileDamage(npc.damage), 0f, Main.myPlayer);
                        }
                    }
                }
                else //outside temple
                {
                    SpikyBallTimer = 600; //do it more often
                    for (int i = 0; i < 16; i++)
                    {
                        Projectile.NewProjectile(npc.GetSource_FromThis(), npc.position.X + Main.rand.Next(npc.width), npc.position.Y + Main.rand.Next(npc.height),
                                                 Main.rand.NextFloat(-1f, 1f), Main.rand.Next(-20, -9), ModContent.ProjectileType <GolemSpikyBall>(), FargoSoulsUtil.ScaledProjectileDamage(npc.damage), 0f, Main.myPlayer);
                    }
                }
            }

            //golem's anti-air fireball spray (when player is above)
            if (FargoSoulsWorld.MasochistModeReal && ++AntiAirTimer > 240 && npc.velocity.Y == 0)
            {
                AntiAirTimer = 0;
                if (npc.HasPlayerTarget && Main.player[npc.target].Center.Y < npc.Bottom.Y &&
                    Main.netMode != NetmodeID.MultiplayerClient)    //shoutouts to arterius
                {
                    bool inTemple = Framing.GetTileSafely(npc.Center).WallType == WallID.LihzahrdBrickUnsafe;

                    float gravity = -0.2f; //normally floats up
                    if (Main.player[npc.target].Center.Y > npc.Bottom.Y)
                    {
                        gravity *= -1f; //aim down if player below golem
                    }
                    const float time     = 60f;
                    Vector2     distance = Main.player[npc.target].Center - npc.Center;
                    distance  += Main.player[npc.target].velocity * 45f;
                    distance.X = distance.X / time;
                    distance.Y = distance.Y / time - 0.5f * gravity * time;

                    if (Math.Sign(distance.Y) != Math.Sign(gravity))
                    {
                        distance.Y = 0f; //cannot arc shots to hit someone on the same elevation
                    }
                    int max = inTemple ? 2 : 4;
                    for (int i = -max; i <= max; i++)
                    {
                        Projectile.NewProjectile(npc.GetSource_FromThis(), npc.Center.X, npc.Center.Y, distance.X + i, distance.Y,
                                                 ModContent.ProjectileType <GolemFireball>(), FargoSoulsUtil.ScaledProjectileDamage(npc.damage, 0.8f), 0f, Main.myPlayer, gravity, 0);
                    }
                }
            }

            EModeUtils.DropSummon(npc, "LihzahrdPowerCell2", NPC.downedGolemBoss, ref DroppedSummon, NPC.downedPlantBoss);

            return(result);
        }
Example #2
0
        public override bool PreAI(NPC npc)
        {
            bool result = base.PreAI(npc);

            EModeGlobalNPC.beeBoss = npc.whoAmI;

            if (FargoSoulsWorld.SwarmActive)
            {
                return(result);
            }


            if (!SpawnedRoyalSubjectWave1 && npc.life < npc.lifeMax / 3 * 2 && npc.HasPlayerTarget)
            {
                SpawnedRoyalSubjectWave1 = true;

                Vector2 vector72 = new Vector2(npc.position.X + npc.width / 2 + Main.rand.Next(20) * npc.direction, npc.position.Y + npc.height * 0.8f);

                int n = FargoSoulsUtil.NewNPCEasy(npc.GetSource_FromAI(), vector72, ModContent.NPCType <RoyalSubject>(),
                                                  velocity: new Vector2(Main.rand.Next(-200, 201) * 0.1f, Main.rand.Next(-200, 201) * 0.1f));
                if (n != Main.maxNPCs)
                {
                    Main.npc[n].localAI[0] = 60f;
                }

                string name      = Language.GetTextValue($"Mods.{mod.Name}.NPCName.RoyalSubject");
                string hasAwoken = Language.GetTextValue($"Mods.{mod.Name}.Message.HasAwoken");
                FargoSoulsUtil.PrintText($"{name} {hasAwoken}", new Color(175, 75, 255));

                npc.netUpdate = true;
                NetSync(npc);
            }

            if (!SpawnedRoyalSubjectWave2 && npc.life < npc.lifeMax / 3 && npc.HasPlayerTarget)
            {
                SpawnedRoyalSubjectWave2 = true;

                if (FargoSoulsWorld.MasochistModeReal)
                {
                    SpawnedRoyalSubjectWave1 = false; //do this again
                }
                Vector2 vector72 = new Vector2(npc.position.X + npc.width / 2 + Main.rand.Next(20) * npc.direction, npc.position.Y + npc.height * 0.8f);

                int n = FargoSoulsUtil.NewNPCEasy(npc.GetSource_FromAI(), vector72, ModContent.NPCType <RoyalSubject>(),
                                                  velocity: new Vector2(Main.rand.Next(-200, 201) * 0.1f, Main.rand.Next(-200, 201) * 0.1f));
                if (n != Main.maxNPCs)
                {
                    Main.npc[n].localAI[0] = 60f;
                }

                string name      = Language.GetTextValue($"Mods.{mod.Name}.NPCName.RoyalSubject");
                string hasAwoken = Language.GetTextValue($"Mods.{mod.Name}.Message.HasAwoken");
                FargoSoulsUtil.PrintText($"{name} {hasAwoken}", new Color(175, 75, 255));

                NPC.SpawnOnPlayer(npc.target, ModContent.NPCType <RoyalSubject>()); //so that both dont stack for being spawned from qb

                npc.netUpdate = true;
                NetSync(npc);
            }


            if (!InPhase2 && npc.life < npc.lifeMax / 2) //enable new attack and roar below 50%
            {
                InPhase2 = true;
                SoundEngine.PlaySound(SoundID.Roar, npc.Center);

                if (FargoSoulsWorld.MasochistModeReal)
                {
                    SpawnedRoyalSubjectWave1 = false; //do this again
                }
                npc.netUpdate = true;
                NetSync(npc);
            }

            if (NPC.AnyNPCs(ModContent.NPCType <RoyalSubject>()))
            {
                npc.HitSound = SoundID.NPCHit4;
                npc.color    = new Color(127, 127, 127);

                int dustId = Dust.NewDust(npc.position, npc.width, npc.height, 1, 0f, 0f, 100, default(Color), 2f);
                Main.dust[dustId].noGravity = true;
                int dustId3 = Dust.NewDust(npc.position, npc.width, npc.height, 1, 0f, 0f, 100, default(Color), 2f);
                Main.dust[dustId3].noGravity = true;

                npc.ai[0] = 3; //always shoot stingers mode

                if (npc.ai[1] > 1)
                {
                    npc.ai[1] -= 0.5f; //slower stingers
                }
            }
            else
            {
                npc.HitSound = SoundID.NPCHit1;
                npc.color    = default;

                if (InPhase2 && HiveThrowTimer % 2 == 0)
                {
                    HiveThrowTimer++; //throw hives faster when no royal subjects alive
                }
            }

            if (FargoSoulsWorld.MasochistModeReal)
            {
                HiveThrowTimer++;

                if (ForgorDeathrayTimer > 0 && --ForgorDeathrayTimer % 10 == 0 && npc.HasValidTarget && Main.netMode != NetmodeID.MultiplayerClient)
                {
                    Projectile.NewProjectile(npc.GetSource_FromThis(),
                                             Main.player[npc.target].Center - 2000 * Vector2.UnitY, Vector2.UnitY,
                                             ModContent.ProjectileType <WillDeathraySmall>(),
                                             (int)(npc.damage * .75), 0f, Main.myPlayer,
                                             Main.player[npc.target].Center.X, npc.whoAmI);
                }
            }

            if (!InPhase2 || FargoSoulsWorld.MasochistModeReal)
            {
                if (npc.ai[0] == 3f || npc.ai[0] == 1f) //only when in stationary modes
                {
                    if (++StingerRingTimer > 90 * 3)
                    {
                        StingerRingTimer = 0;
                    }

                    if (StingerRingTimer % 90 == 0)
                    {
                        if (Main.netMode != NetmodeID.MultiplayerClient)
                        {
                            FargoSoulsUtil.XWay(StingerRingTimer == 90 * 3 ? 16 : 8, npc.GetSource_FromThis(), npc.Center, ProjectileID.QueenBeeStinger, 6, 11, 1);
                        }
                    }
                }
            }

            if (InPhase2)
            {
                if (++HiveThrowTimer > 570 && BeeSwarmTimer <= 600 && (npc.ai[0] == 3f || npc.ai[0] == 1f)) //lobs hives below 50%, not dashing
                {
                    HiveThrowTimer = 0;

                    npc.netUpdate = true;
                    NetSync(npc);

                    const float gravity  = 0.25f;
                    float       time     = 75f;
                    Vector2     distance = Main.player[npc.target].Center - Vector2.UnitY * 16 - npc.Center + Main.player[npc.target].velocity * 30f;
                    distance.X = distance.X / time;
                    distance.Y = distance.Y / time - 0.5f * gravity * time;
                    if (Main.netMode != NetmodeID.MultiplayerClient)
                    {
                        Projectile.NewProjectile(npc.GetSource_FromThis(), npc.Center, distance, ModContent.ProjectileType <Beehive>(),
                                                 FargoSoulsUtil.ScaledProjectileDamage(npc.damage), 0f, Main.myPlayer, time - 5);
                    }
                }

                if (npc.ai[0] == 0 && npc.ai[1] == 1f) //if qb tries to start doing dashes of her own volition
                {
                    npc.ai[0]     = 3f;
                    npc.ai[1]     = 0f; //don't
                    npc.netUpdate = true;
                }
            }

            //only while stationary mode
            if (npc.ai[0] == 3f || npc.ai[0] == 1f)
            {
                if (InPhase2 && ++BeeSwarmTimer > 600)
                {
                    if (BeeSwarmTimer < 720) //slow down
                    {
                        if (BeeSwarmTimer == 601)
                        {
                            npc.netUpdate = true;
                            NetSync(npc);

                            if (Main.netMode != NetmodeID.MultiplayerClient)
                            {
                                Projectile.NewProjectile(npc.GetSource_FromThis(), npc.Center, Vector2.Zero, ModContent.ProjectileType <GlowRing>(), 0, 0f, Main.myPlayer, npc.whoAmI, npc.type);
                            }

                            if (npc.HasValidTarget)
                            {
                                SoundEngine.PlaySound(SoundID.ForceRoarPitched, Main.player[npc.target].Center); //eoc roar
                            }
                            if (FargoSoulsWorld.MasochistModeReal)
                            {
                                BeeSwarmTimer += 30;
                            }
                        }

                        if (Collision.CanHitLine(npc.Center, 0, 0, Main.player[npc.target].Center, 0, 0))
                        {
                            npc.velocity *= 0.975f;
                        }
                        else if (BeeSwarmTimer > 630)
                        {
                            BeeSwarmTimer--; //stall this section until has line of sight
                            return(true);
                        }
                    }
                    else if (BeeSwarmTimer < 840) //spray bees
                    {
                        npc.velocity = Vector2.Zero;

                        if (BeeSwarmTimer % 2 == 0 && Main.netMode != NetmodeID.MultiplayerClient)
                        {
                            const float rotation = 0.025f;
                            for (int i = -1; i <= 1; i += 2)
                            {
                                Projectile.NewProjectile(npc.GetSource_FromThis(), npc.Center + new Vector2(3 * npc.direction, 15), i * Main.rand.NextFloat(9f, 18f) * Vector2.UnitX.RotatedBy(MathHelper.ToRadians(Main.rand.NextFloat(-45, 45))),
                                                         ModContent.ProjectileType <Bee>(), FargoSoulsUtil.ScaledProjectileDamage(npc.damage, FargoSoulsWorld.MasochistModeReal ? 4f / 3 : 1), 0f, Main.myPlayer, npc.target, Main.rand.NextBool() ? -rotation : rotation);
                            }
                        }
                    }
                    else if (BeeSwarmTimer > 870) //return to normal AI
                    {
                        BeeSwarmTimer   = 0;
                        HiveThrowTimer -= 60;

                        npc.netUpdate = true;
                        NetSync(npc);

                        npc.ai[0] = 0f;
                        npc.ai[1] = 4f; //trigger dashes, but skip the first one
                        npc.ai[2] = -44f;
                        npc.ai[3] = 0f;
                    }

                    if (npc.netUpdate)
                    {
                        npc.netUpdate = false;

                        if (Main.netMode == NetmodeID.Server)
                        {
                            NetMessage.SendData(MessageID.SyncNPC, -1, -1, null, npc.whoAmI);
                        }
                    }
                    return(false);
                }
            }

            if (npc.ai[0] == 0 && npc.ai[1] == 4) //when about to do dashes triggered by royal subjects/bee swarm, telegraph and stall
            {
                if (npc.ai[2] < 0)
                {
                    if (npc.ai[2] == -44) //telegraph
                    {
                        SoundEngine.PlaySound(SoundID.Item21, npc.Center);

                        for (int i = 0; i < 44; i++)
                        {
                            int d = Dust.NewDust(npc.position, npc.width, npc.height, Main.rand.NextBool() ? 152 : 153, npc.velocity.X * 0.2f, npc.velocity.Y * 0.2f);
                            Main.dust[d].scale     = Main.rand.NextFloat(1f, 3f);
                            Main.dust[d].velocity *= Main.rand.NextFloat(4.4f);
                            Main.dust[d].noGravity = Main.rand.NextBool();
                            if (Main.dust[d].noGravity)
                            {
                                Main.dust[d].scale    *= 2.2f;
                                Main.dust[d].velocity *= 4.4f;
                            }
                        }

                        if (FargoSoulsWorld.MasochistModeReal)
                        {
                            npc.ai[2] = 0;
                        }

                        ForgorDeathrayTimer = 95;
                    }

                    npc.velocity *= 0.95f;
                    npc.ai[2]++;

                    return(false);
                }
            }

            if (!npc.HasValidTarget || (npc.HasPlayerTarget && npc.Distance(Main.player[npc.target].Center) > 3000))
            {
                if (npc.timeLeft > 30)
                {
                    npc.timeLeft = 30;
                }
            }

            EModeUtils.DropSummon(npc, "Abeemination2", NPC.downedQueenBee, ref DroppedSummon);

            return(result);
        }
Example #3
0
        public override void AI(NPC npc)
        {
            base.AI(npc);

            EModeGlobalNPC.wallBoss = npc.whoAmI;

            if (FargoSoulsWorld.SwarmActive)
            {
                return;
            }

            if (npc.ai[3] == 0f) //when spawned in, make one eye invul
            {
                for (int i = 0; i < Main.maxNPCs; i++)
                {
                    if (Main.npc[i].active && Main.npc[i].type == NPCID.WallofFleshEye && Main.npc[i].realLife == npc.whoAmI)
                    {
                        Main.npc[i].ai[2]     = -1f;
                        Main.npc[i].netUpdate = true;

                        npc.ai[3]     = 1f;
                        npc.netUpdate = true;
                        break;
                    }
                }
            }

            if (InPhase2) //phase 2
            {
                if (++WorldEvilAttackCycleTimer > 600)
                {
                    WorldEvilAttackCycleTimer = 0;
                    UseCorruptAttack          = !UseCorruptAttack;

                    npc.netUpdate = true;
                    NetSync(npc);
                }
                else if (WorldEvilAttackCycleTimer > 600 - 120)           //telegraph for special attacks
                {
                    int     type          = !UseCorruptAttack ? 75 : 170; //corruption dust, then crimson dust
                    int     speed         = !UseCorruptAttack ? 10 : 8;
                    float   scale         = !UseCorruptAttack ? 6f : 4f;
                    float   speedModifier = !UseCorruptAttack ? 12f : 5f;
                    Vector2 direction     = npc.DirectionTo(Main.player[npc.target].Center);
                    Vector2 vel           = speed * direction;
                    int     d             = Dust.NewDust(npc.Center + 32f * direction, 0, 0, type, vel.X, vel.Y, 100, Color.White, scale);
                    Main.dust[d].velocity *= speedModifier;
                    Main.dust[d].noGravity = true;
                }
                else if (WorldEvilAttackCycleTimer < 240) //special attacks
                {
                    if (UseCorruptAttack)                 //cursed inferno attack
                    {
                        if (WorldEvilAttackCycleTimer == 10 && Main.netMode != NetmodeID.MultiplayerClient)
                        {
                            Projectile.NewProjectile(npc.Center, Vector2.UnitY, ModContent.ProjectileType <CursedDeathrayWOFS>(), 0, 0f, Main.myPlayer, npc.direction, npc.whoAmI);
                        }

                        if (WorldEvilAttackCycleTimer % 4 == 0)
                        {
                            float   xDistance = (2500f - 1800f * WorldEvilAttackCycleTimer / 240f) * Math.Sign(npc.velocity.X);
                            Vector2 spawnPos  = new Vector2(npc.Center.X + xDistance, npc.Center.Y);

                            Main.PlaySound(SoundID.Item34, spawnPos);

                            const int offsetY = 800;
                            const int speed   = 14;
                            if (Main.netMode != NetmodeID.MultiplayerClient)
                            {
                                Projectile.NewProjectile(spawnPos + Vector2.UnitY * offsetY, Vector2.UnitY * -speed, ModContent.ProjectileType <CursedFlamethrower>(), npc.damage / 4, 0f, Main.myPlayer);
                                Projectile.NewProjectile(spawnPos + Vector2.UnitY * offsetY / 2, Vector2.UnitY * speed, ModContent.ProjectileType <CursedFlamethrower>(), npc.damage / 4, 0f, Main.myPlayer);
                                Projectile.NewProjectile(spawnPos + Vector2.UnitY * -offsetY / 2, Vector2.UnitY * -speed, ModContent.ProjectileType <CursedFlamethrower>(), npc.damage / 4, 0f, Main.myPlayer);
                                Projectile.NewProjectile(spawnPos + Vector2.UnitY * -offsetY, Vector2.UnitY * speed, ModContent.ProjectileType <CursedFlamethrower>(), npc.damage / 4, 0f, Main.myPlayer);
                            }
                        }
                    }
                    else //ichor attack
                    {
                        if (WorldEvilAttackCycleTimer % 8 == 0)
                        {
                            if (Main.netMode != NetmodeID.MultiplayerClient)
                            {
                                for (int i = 0; i < 8; i++)
                                {
                                    Vector2 target = npc.Center;
                                    target.X += Math.Sign(npc.velocity.X) * 1000f * WorldEvilAttackCycleTimer / 240f; //gradually targets further and further
                                    target.X += Main.rand.NextFloat(-100, 100);
                                    target.Y += Main.rand.NextFloat(-450, 450);

                                    const float gravity  = 0.5f;
                                    float       time     = 60f;
                                    Vector2     distance = target - npc.Center;
                                    distance.X = distance.X / time;
                                    distance.Y = distance.Y / time - 0.5f * gravity * time;

                                    Projectile.NewProjectile(npc.Center + Vector2.UnitX * Math.Sign(npc.velocity.X) * 32f, distance,
                                                             ModContent.ProjectileType <GoldenShowerWOF>(), npc.damage / 4, 0f, Main.myPlayer, time);
                                }
                            }
                        }
                    }
                }
            }
            else if (npc.life < npc.lifeMax * (FargoSoulsWorld.MasochistModeReal ? 0.9 : .75)) //enter phase 2
            {
                InPhase2      = true;
                npc.netUpdate = true;
                NetSync(npc);

                if (!Main.dedServ)
                {
                    Main.PlaySound(mod.GetLegacySoundSlot(SoundType.Custom, "Sounds/Monster94"),
                                   npc.HasValidTarget && Main.player[npc.target].ZoneUnderworldHeight ? Main.player[npc.target].Center : npc.Center);

                    if (Main.LocalPlayer.active)
                    {
                        Main.LocalPlayer.GetModPlayer <FargoPlayer>().Screenshake = 90;
                    }
                }
            }

            if (npc.ai[3] == 2) //phase 3
            {
                if (InDesperationPhase)
                {
                    //ChainBarrageTimer -= 0.5f; //increment faster

                    if (WorldEvilAttackCycleTimer % 2 == 1) //always make sure its even in here
                    {
                        WorldEvilAttackCycleTimer--;
                    }
                }

                int floor   = 240 - (InDesperationPhase ? 120 : 0);
                int ceiling = 600 - 180 - (InDesperationPhase ? 120 : 0);

                if (WorldEvilAttackCycleTimer >= floor && WorldEvilAttackCycleTimer <= ceiling)
                {
                    if (--ChainBarrageTimer < 0)
                    {
                        ChainBarrageTimer = 80;
                        if (npc.HasValidTarget && Main.player[npc.target].ZoneUnderworldHeight)
                        {
                            if (Main.netMode != NetmodeID.MultiplayerClient) //spawn reticles for chain barrages
                            {
                                Vector2 spawnPos = Main.player[npc.target].Center;

                                float offset = 1000f * (ceiling - WorldEvilAttackCycleTimer) / (ceiling - floor); //progress further as attack continues
                                spawnPos.X += Math.Sign(npc.velocity.X) * offset;
                                spawnPos.Y += Main.rand.NextFloat(-100, 100);

                                if (spawnPos.Y / 16 < Main.maxTilesY - 200) //clamp so it stays in hell
                                {
                                    spawnPos.Y = (Main.maxTilesY - 200) * 16;
                                }
                                if (spawnPos.Y / 16 >= Main.maxTilesY)
                                {
                                    spawnPos.Y = Main.maxTilesY * 16 - 16;
                                }
                                Projectile.NewProjectile(spawnPos, Vector2.Zero, ModContent.ProjectileType <WOFReticle>(), npc.damage / 6, 0f, Main.myPlayer);
                            }
                        }
                    }
                }
                else
                {
                    ChainBarrageTimer = 0;
                }
            }
            else if (npc.ai[3] == 1 && npc.life < npc.lifeMax * (FargoSoulsWorld.MasochistModeReal ? .8 : .5)) //enter phase 3
            {
                npc.ai[3]     = 2;
                npc.netUpdate = true;
                NetSync(npc);

                if (!Main.dedServ)
                {
                    Main.PlaySound(mod.GetLegacySoundSlot(SoundType.Custom, "Sounds/Monster94"),
                                   npc.HasValidTarget && Main.player[npc.target].ZoneUnderworldHeight ? Main.player[npc.target].Center : npc.Center);

                    if (Main.LocalPlayer.active)
                    {
                        Main.LocalPlayer.GetModPlayer <FargoPlayer>().Screenshake = 90;
                    }
                }
            }

            if (npc.life < npc.lifeMax / (FargoSoulsWorld.MasochistModeReal ? 4 : 10)) //final phase
            {
                WorldEvilAttackCycleTimer++;

                if (!InDesperationPhase)
                {
                    InDesperationPhase = true;

                    //temporarily stop eyes from attacking during the transition to avoid accidental insta-lasers
                    for (int i = 0; i < Main.maxNPCs; i++)
                    {
                        if (Main.npc[i].active && Main.npc[i].type == NPCID.WallofFleshEye && Main.npc[i].realLife == npc.whoAmI)
                        {
                            Main.npc[i].GetEModeNPCMod <WallofFleshEye>().PreventAttacks = 60;
                        }
                    }

                    npc.netUpdate = true;
                    NetSync(npc);

                    if (!Main.dedServ)
                    {
                        Main.PlaySound(mod.GetLegacySoundSlot(SoundType.Custom, "Sounds/Monster5").WithVolume(1.5f),
                                       npc.HasValidTarget && Main.player[npc.target].ZoneUnderworldHeight ? Main.player[npc.target].Center : npc.Center);

                        if (Main.LocalPlayer.active)
                        {
                            Main.LocalPlayer.GetModPlayer <FargoPlayer>().Screenshake = 180;
                        }
                    }
                }
            }

            float maxSpeed = FargoSoulsWorld.MasochistModeReal ? 4.5f : 3.5f; //don't let wof move faster than this normally

            if (npc.HasPlayerTarget && (Main.player[npc.target].dead || Vector2.Distance(npc.Center, Main.player[npc.target].Center) > 3000))
            {
                npc.TargetClosest(true);
                if (Main.player[npc.target].dead || Vector2.Distance(npc.Center, Main.player[npc.target].Center) > 3000)
                {
                    npc.position.X += 60 * Math.Sign(npc.velocity.X); //move faster to despawn
                }
                else if (Math.Abs(npc.velocity.X) > maxSpeed)
                {
                    npc.position.X -= (Math.Abs(npc.velocity.X) - maxSpeed) * Math.Sign(npc.velocity.X);
                }
            }
            else if (Math.Abs(npc.velocity.X) > maxSpeed)
            {
                npc.position.X -= (Math.Abs(npc.velocity.X) - maxSpeed) * Math.Sign(npc.velocity.X);
            }

            if (Main.LocalPlayer.active & !Main.LocalPlayer.dead && !Main.LocalPlayer.ghost && Main.LocalPlayer.ZoneUnderworldHeight)
            {
                float velX = npc.velocity.X;
                if (velX > maxSpeed)
                {
                    velX = maxSpeed;
                }
                else if (velX < -maxSpeed)
                {
                    velX = -maxSpeed;
                }

                for (int i = 0; i < 10; i++) //dust
                {
                    Vector2 dustPos = new Vector2(2000 * npc.direction, 0f).RotatedBy(Math.PI / 3 * (-0.5 + Main.rand.NextDouble()));
                    int     d       = Dust.NewDust(npc.Center + dustPos, 0, 0, DustID.Fire);
                    Main.dust[d].scale     += 1f;
                    Main.dust[d].velocity.X = velX;
                    Main.dust[d].velocity.Y = npc.velocity.Y;
                    Main.dust[d].noGravity  = true;
                    Main.dust[d].noLight    = true;
                }

                if (++npc.localAI[1] > 15f)
                {
                    npc.localAI[1] = 0f; //tongue the player if they're 2000-2800 units away
                    if (Math.Abs(2400 - npc.Distance(Main.LocalPlayer.Center)) < 400)
                    {
                        if (!Main.LocalPlayer.tongued)
                        {
                            Main.PlaySound(SoundID.ForceRoar, Main.LocalPlayer.Center, -1); //eoc roar
                        }
                        Main.LocalPlayer.AddBuff(BuffID.TheTongue, 10);
                    }
                }
            }

            EModeUtils.DropSummon(npc, ModContent.ItemType <FleshyDoll>(), Main.hardMode, ref DroppedSummon);
        }
Example #4
0
        public override void AI(NPC npc)
        {
            base.AI(npc);

            EModeGlobalNPC.cultBoss = npc.whoAmI;

            if (FargoSoulsWorld.SwarmActive)
            {
                return;
            }

            if (npc.ai[3] == -1f)
            {
                if (Fargowiltas.Instance.MasomodeEXLoaded && npc.ai[1] >= 120f && npc.ai[1] < 419f) //skip summoning ritual LMAO
                {
                    npc.ai[1]     = 419f;
                    npc.netUpdate = true;
                }

                if (npc.ai[0] == 5)
                {
                    if (npc.ai[1] == 1f)
                    {
                        RitualRotation = Main.rand.Next(360);
                        npc.netUpdate  = true;
                        NetSync(npc);
                    }

                    if (npc.ai[1] > 30f && npc.ai[1] < 330f)
                    {
                        RitualRotation += 2f - Math.Min(1f, 2f * npc.life / npc.lifeMax); //always at least 1, begins scaling below 50% life
                        npc.Center      = Main.player[npc.target].Center + 180f * Vector2.UnitX.RotatedBy(MathHelper.ToRadians(RitualRotation));
                    }

                    /*if (npc.ai[1] > 275f && npc.ai[1] < 330f) //dust that reveals the real cultist at last second
                     * {
                     *  float modifier = 0;
                     *  int repeats = (int)npc.ai[1] - 275;
                     *  for (int i = 0; i < repeats; i++)
                     *      modifier = MathHelper.Lerp(modifier, 1f, 0.08f);
                     *  float distance = npc.height * 2 * modifier;
                     *  float rotation = MathHelper.TwoPi * modifier;
                     *  for (int i = 0; i < 4; i++)
                     *  {
                     *      int d = Dust.NewDust(npc.Center + distance * Vector2.UnitX.RotatedBy(rotation + MathHelper.TwoPi / 4 * i), 0, 0, 88, newColor: Color.White);
                     *      Main.dust[d].noGravity = true;
                     *      Main.dust[d].velocity *= npc.ai[1] > 315 ? 18f : 0.5f;
                     *      Main.dust[d].scale = 0.5f + 2.5f * modifier;
                     *  }
                     * }*/
                }
            }
            else
            {
                //if (npc.ai[3] == 0) npc.damage = 0;

                //about to begin moving for ritual: 0 39 0 12
                //begin transit for ritual: 1 34 0 12
                //pause just before ritual: 0 0 0 13
                //ritual: 5 0 0 -1

                if (!EnteredPhase2 && npc.life < npc.lifeMax / 2) //p2 transition, force a ritual immediately
                {
                    EnteredPhase2 = true;
                    npc.ai[0]     = 5;
                    npc.ai[1]     = 0;
                    npc.ai[2]     = 0;
                    npc.ai[3]     = -1;
                    Main.PlaySound(SoundID.Roar, npc.Center, 0);

                    if (Main.netMode != NetmodeID.MultiplayerClient)
                    {
                        npc.netUpdate = true;
                        NetSync(npc);
                    }
                }

                int damage = Math.Max(npc.damage, 75); //necessary because calameme
                switch ((int)npc.ai[0])
                {
                case -1:
                    if (npc.ai[1] == 419f)     //always start fight with a ritual
                    {
                        npc.ai[0]     = 0f;
                        npc.ai[1]     = 0f;
                        npc.ai[3]     = 11f;
                        npc.netUpdate = true;
                    }
                    break;

                case 2:     //ice mist, frost wave support
                    if (EnteredPhase2)
                    {
                        if (npc.ai[1] < 60 && npc.ai[1] % 4 == 3)
                        {
                            int spacing = 14 - (int)(npc.ai[1] - 3) / 4; //start far and get closer
                            for (int j = -1; j <= 1; j += 2)             //from above and below
                            {
                                for (int i = -1; i <= 1; i += 2)         //waves beside you
                                {
                                    if (i == 0)
                                    {
                                        continue;
                                    }
                                    Vector2 spawnPos = Main.player[npc.target].Center;
                                    spawnPos.X += Math.Sign(i) * 150 * 2 + i * 120 * spacing;
                                    spawnPos.Y -= (700 + Math.Abs(i) * 50) * j;
                                    float speed = 8 + spacing * 0.8f;
                                    if (Main.netMode != NetmodeID.MultiplayerClient)
                                    {
                                        Projectile.NewProjectile(spawnPos, Vector2.UnitY * speed * j, ProjectileID.FrostWave, damage / 3, 0f, Main.myPlayer);
                                    }
                                }
                            }
                        }
                    }
                    else
                    {
                        if (npc.ai[1] == (FargoSoulsWorld.MasochistModeReal ? 5f : 60f) && Main.netMode != NetmodeID.MultiplayerClient)     //single wave
                        {
                            for (int i = 0; i < Main.maxNPCs; i++)
                            {
                                if (Main.npc[i].active && Main.npc[i].type == NPCID.CultistBossClone)
                                {
                                    Vector2 distance = Main.player[npc.target].Center - Main.npc[i].Center;
                                    distance.Normalize();
                                    distance *= Main.rand.NextFloat(8f, 9f);
                                    distance  = distance.RotatedByRandom(Math.PI / 24);
                                    Projectile.NewProjectile(Main.npc[i].Center, distance,
                                                             ProjectileID.FrostWave, damage / 3, 0f, Main.myPlayer);
                                }
                            }
                        }
                    }
                    break;

                case 3:     //fireballs
                    if (Main.netMode != NetmodeID.MultiplayerClient)
                    {
                        if (EnteredPhase2)     //fireball ring
                        {
                            if (npc.ai[1] == 3f)
                            {
                                int max = NPC.CountNPCS(NPCID.CultistBossClone) * 2 + 6;

                                Vector2     baseOffset  = npc.DirectionTo(Main.player[npc.target].Center);
                                const float spawnOffset = 1200f;
                                const float speed       = 7f;
                                const float ai0         = spawnOffset / speed;
                                for (int i = 0; i < max; i++)
                                {
                                    Projectile.NewProjectile(Main.player[npc.target].Center + spawnOffset * baseOffset.RotatedBy(2 * Math.PI / max * i),
                                                             -speed * baseOffset.RotatedBy(2 * Math.PI / max * i), ModContent.ProjectileType <CultistFireball>(),
                                                             damage / 3, 0f, Main.myPlayer, ai0);
                                }

                                Projectile.NewProjectile(npc.Center, Vector2.Zero, ModContent.ProjectileType <GlowRing>(), 0, 0f, Main.myPlayer, npc.whoAmI, npc.type);
                            }
                        }

                        if (npc.ai[1] % 20 == 6)     //homing flare support
                        {
                            for (int i = 0; i < Main.maxNPCs; i++)
                            {
                                if (Main.npc[i].active && Main.npc[i].type == NPCID.CultistBossClone)
                                {
                                    int n = NPC.NewNPC((int)Main.npc[i].Center.X, (int)Main.npc[i].Center.Y, NPCID.SolarFlare, Target: npc.target);
                                    if (n != Main.maxNPCs && Main.netMode == NetmodeID.Server)
                                    {
                                        NetMessage.SendData(MessageID.SyncNPC, number: n);
                                    }
                                }
                            }
                        }
                    }
                    break;

                case 4:     //lightning
                    if (npc.ai[1] == 19f && npc.HasPlayerTarget && Main.netMode != NetmodeID.MultiplayerClient)
                    {
                        int cultistCount = 1;
                        for (int i = 0; i < Main.maxNPCs; i++)
                        {
                            if (Main.npc[i].active && Main.npc[i].type == NPCID.CultistBossClone)
                            {
                                if (EnteredPhase2)     //vortex lightning
                                {
                                    Projectile.NewProjectile(Main.npc[i].Center, Main.rand.NextVector2Square(-15, 15), ModContent.ProjectileType <CultistVortex>(),
                                                             damage / 15 * 6, 0, Main.myPlayer, 0f, cultistCount);
                                    cultistCount++;
                                }
                                else     //aimed lightning
                                {
                                    if (FargoSoulsWorld.MasochistModeReal)
                                    {
                                        Vector2 dir    = Main.player[npc.target].Center - Main.npc[i].Center;
                                        float   ai1New = Main.rand.Next(100);
                                        Vector2 vel    = Vector2.Normalize(dir.RotatedByRandom(Math.PI / 4)) * 6f;
                                        Projectile.NewProjectile(Main.npc[i].Center, vel, ModContent.ProjectileType <HostileLightning>(),
                                                                 damage / 15 * 6, 0, Main.myPlayer, dir.ToRotation(), ai1New);
                                    }
                                    else
                                    {
                                        Vector2 vel = Main.npc[i].DirectionTo(Main.player[npc.target].Center).RotatedByRandom(MathHelper.ToRadians(5));
                                        vel *= Main.rand.NextFloat(4f, 6f);
                                        Projectile.NewProjectile(Main.npc[i].Center, vel, ModContent.ProjectileType <LightningVortexHostile>(), damage / 15 * 6, 0, Main.myPlayer);
                                    }
                                }
                            }
                        }
                    }
                    break;

                case 7:
                    if (npc.ai[1] == 3f && Main.netMode != NetmodeID.MultiplayerClient)     //ancient light, jellyfish support
                    {
                        for (int i = 0; i < Main.maxProjectiles; i++)
                        {
                            if (Main.projectile[i].active && Main.projectile[i].type == ModContent.ProjectileType <CultistRitual>())
                            {
                                Projectile.NewProjectile(new Vector2(Main.projectile[i].Center.X, Main.player[npc.target].Center.Y - 700),
                                                         Vector2.Zero, ModContent.ProjectileType <StardustRain>(), damage / 3, 0f, Main.myPlayer);
                            }
                        }
                    }
                    break;

                case 8:
                    if (npc.ai[1] == 3f)     //ancient doom, nebula sphere support
                    {
                        int t = npc.HasPlayerTarget ? npc.target : npc.FindClosestPlayer();
                        if (t != -1 && Main.player[t].active)
                        {
                            for (int i = 0; i < Main.maxNPCs; i++)
                            {
                                if (Main.npc[i].active && Main.npc[i].type == NPCID.CultistBossClone)
                                {
                                    Projectile.NewProjectile(Main.npc[i].Center, Vector2.Zero, ProjectileID.NebulaSphere, damage / 15 * 6, 0f, Main.myPlayer);
                                }
                            }
                        }
                    }
                    break;

                default:
                    break;
                }
            }

            npc.defense = npc.defDefense; //prevent vanilla p2 from lowering defense!
            Lighting.AddLight(npc.Center, 1f, 1f, 1f);

            EModeUtils.DropSummon(npc, ModContent.ItemType <CultistSummon>(), NPC.downedAncientCultist, ref DroppedSummon, NPC.downedGolemBoss);
        }
Example #5
0
        public override void AI(NPC npc)
        {
            EModeGlobalNPC.moonBoss = npc.whoAmI;

            if (FargoSoulsWorld.SwarmActive)
            {
                return;
            }

            if (!SpawnedRituals)
            {
                SpawnedRituals     = true;
                VulnerabilityState = 0;
                if (Main.netMode != NetmodeID.MultiplayerClient)
                {
                    Projectile.NewProjectile(npc.Center, Vector2.Zero, ModContent.ProjectileType <LunarRitual>(), 25, 0f, Main.myPlayer, 0f, npc.whoAmI);
                    Projectile.NewProjectile(npc.Center, Vector2.Zero, ModContent.ProjectileType <FragmentRitual>(), 0, 0f, Main.myPlayer, 0f, npc.whoAmI);
                }
            }

            if (Main.LocalPlayer.active && !Main.LocalPlayer.dead && !Main.LocalPlayer.ghost && VulnerabilityState >= 0 && VulnerabilityState <= 3)
            {
                Main.LocalPlayer.AddBuff(ModContent.BuffType <NullificationCurse>(), 2);
            }

            npc.position -= npc.velocity * 2f / 3f; //SLOW DOWN

            if (npc.dontTakeDamage)
            {
                if (AttackTimer == 370 && Main.netMode != NetmodeID.MultiplayerClient)
                {
                    for (int i = 0; i < 3; i++)
                    {
                        NPC bodyPart = Main.npc[(int)npc.localAI[i]];
                        if (bodyPart.active)
                        {
                            Projectile.NewProjectile(bodyPart.Center, Vector2.Zero, ModContent.ProjectileType <GlowRing>(), 0, 0f, Main.myPlayer, bodyPart.whoAmI, bodyPart.type);
                        }
                    }
                }

                if (AttackTimer > 400)
                {
                    AttackTimer   = 0;
                    npc.netUpdate = true;
                    NetSync(npc);

                    if (Main.netMode != NetmodeID.MultiplayerClient)
                    {
                        switch (VulnerabilityState)
                        {
                        case 0:     //melee
                            for (int i = 0; i < 3; i++)
                            {
                                NPC bodyPart = Main.npc[(int)npc.localAI[i]];

                                if (bodyPart.active)
                                {
                                    int damage = 30;
                                    for (int j = -2; j <= 2; j++)
                                    {
                                        Projectile.NewProjectile(bodyPart.Center,
                                                                 6f * bodyPart.DirectionFrom(Main.player[npc.target].Center).RotatedBy(Math.PI / 2 / 4 * j),
                                                                 ModContent.ProjectileType <MoonLordFireball>(), damage, 0f, Main.myPlayer, 20, 20 + 60);
                                    }
                                }
                            }
                            break;

                        case 1:     //ranged
                            for (int j = 0; j < 6; j++)
                            {
                                Vector2 spawn = Main.player[npc.target].Center + 500 * npc.DirectionFrom(Main.player[npc.target].Center).RotatedBy(MathHelper.TwoPi / 6 * (j + 0.5f));
                                Projectile.NewProjectile(spawn, Vector2.Zero, ModContent.ProjectileType <LightningVortexHostile>(), 30, 0f, Main.myPlayer, 1, Main.player[npc.target].DirectionFrom(spawn).ToRotation());
                            }
                            break;

                        case 2:     //magic
                            for (int i = 0; i < 3; i++)
                            {
                                NPC bodyPart = Main.npc[(int)npc.localAI[i]];

                                if (bodyPart.active &&
                                    ((i == 2 && bodyPart.type == NPCID.MoonLordHead) ||
                                     bodyPart.type == NPCID.MoonLordHand))
                                {
                                    int       damage = 35;
                                    const int max    = 6;
                                    for (int j = 0; j < max; j++)
                                    {
                                        int p = Projectile.NewProjectile(bodyPart.Center,
                                                                         2.5f * bodyPart.DirectionFrom(Main.player[npc.target].Center).RotatedBy(Math.PI * 2 / max * (j + 0.5)),
                                                                         ModContent.ProjectileType <MoonLordNebulaBlaze>(), damage, 0f, Main.myPlayer);
                                        if (p != Main.maxProjectiles)
                                        {
                                            Main.projectile[p].timeLeft = 1200;
                                        }
                                    }
                                }
                            }
                            break;

                        case 3:     //summoner
                            for (int i = 0; i < 3; i++)
                            {
                                NPC bodyPart = Main.npc[(int)npc.localAI[i]];

                                if (bodyPart.active &&
                                    ((i == 2 && bodyPart.type == NPCID.MoonLordHead) ||
                                     bodyPart.type == NPCID.MoonLordHand))
                                {
                                    Vector2 speed = Main.player[npc.target].Center - bodyPart.Center;
                                    speed.Normalize();
                                    speed *= 5f;
                                    for (int j = -1; j <= 1; j++)
                                    {
                                        Vector2 vel = speed.RotatedBy(MathHelper.ToRadians(15) * j);
                                        int     n   = NPC.NewNPC((int)bodyPart.Center.X, (int)bodyPart.Center.Y, NPCID.AncientLight, 0, 0f, (Main.rand.NextFloat() - 0.5f) * 0.3f * 6.28318548202515f / 60f, vel.X, vel.Y);
                                        if (n != Main.maxNPCs)
                                        {
                                            Main.npc[n].velocity  = vel;
                                            Main.npc[n].netUpdate = true;
                                            if (Main.netMode == NetmodeID.Server)
                                            {
                                                NetMessage.SendData(MessageID.SyncNPC, -1, -1, null, n);
                                            }
                                        }
                                    }
                                }
                            }
                            break;

                        default:     //phantasmal eye rings
                            if (Main.netMode != NetmodeID.MultiplayerClient)
                            {
                                const int   max              = 4;
                                const int   speed            = 8;
                                const float rotationModifier = 0.5f;
                                int         damage           = 40;
                                float       rotation         = 2f * (float)Math.PI / max;
                                Vector2     vel              = Vector2.UnitY * speed;
                                int         type             = ModContent.ProjectileType <Projectiles.MutantBoss.MutantSphereRing>();
                                for (int i = 0; i < max; i++)
                                {
                                    vel = vel.RotatedBy(rotation);
                                    int p = Projectile.NewProjectile(npc.Center, vel, type, damage, 0f, Main.myPlayer, rotationModifier, speed);
                                    if (p != Main.maxProjectiles)
                                    {
                                        Main.projectile[p].timeLeft = 1800 - VulnerabilityTimer;
                                    }
                                    p = Projectile.NewProjectile(npc.Center, vel, type, damage, 0f, Main.myPlayer, -rotationModifier, speed);
                                    if (p != Main.maxProjectiles)
                                    {
                                        Main.projectile[p].timeLeft = 1800 - VulnerabilityTimer;
                                    }
                                }
                                Main.PlaySound(SoundID.Item84, npc.Center);
                            }
                            break;
                        }
                    }
                }
            }
            else //only when vulnerable
            {
                if (!EnteredPhase2)
                {
                    EnteredPhase2 = true;
                    AttackTimer   = 0;
                    Main.PlaySound(SoundID.Roar, Main.LocalPlayer.Center, 0);
                    npc.netUpdate = true;
                    NetSync(npc);
                }

                Player player = Main.player[npc.target];
                switch (VulnerabilityState)
                {
                case 0:     //melee
                {
                    if (AttackTimer > 30)
                    {
                        AttackTimer -= 300;
                        AttackMemory = AttackMemory == 0 ? 1 : 0;

                        float handToAttackWith = npc.localAI[AttackMemory];
                        if (Main.netMode != NetmodeID.MultiplayerClient)
                        {
                            Projectile.NewProjectile(Main.npc[(int)handToAttackWith].Center, Vector2.Zero, ModContent.ProjectileType <MoonLordSun>(), 60, 0f, Main.myPlayer, npc.whoAmI, handToAttackWith);
                        }
                    }
                }
                break;

                case 1:                    //vortex
                {
                    if (AttackMemory == 0) //spawn the vortex
                    {
                        AttackMemory = 1;
                        for (int i = -1; i <= 1; i += 2)
                        {
                            if (Main.netMode != NetmodeID.MultiplayerClient)
                            {
                                Projectile.NewProjectile(npc.Center, Vector2.Zero, ModContent.ProjectileType <MoonLordVortex>(), 40, 0f, Main.myPlayer, i, npc.whoAmI);
                            }
                        }
                    }
                }
                break;

                case 2:     //nebula
                {
                    if (AttackTimer > 30)
                    {
                        AttackTimer -= 360;

                        for (int i = 0; i < 3; i++)
                        {
                            NPC bodyPart = Main.npc[(int)npc.localAI[i]];
                            int damage   = 35;
                            for (int j = -2; j <= 2; j++)
                            {
                                if (Main.netMode != NetmodeID.MultiplayerClient)
                                {
                                    Projectile.NewProjectile(bodyPart.Center,
                                                             2.5f * bodyPart.DirectionFrom(Main.player[npc.target].Center).RotatedBy(Math.PI / 2 / 2 * (j + Main.rand.NextFloat(-0.25f, 0.25f))),
                                                             ModContent.ProjectileType <MoonLordNebulaBlaze2>(), damage, 0f, Main.myPlayer, npc.whoAmI);
                                }
                            }
                        }
                    }
                }
                break;

                case 3:     //stardust
                {
                    if (AttackTimer > 360)
                    {
                        AttackTimer -= 360;
                        AttackMemory = 0;
                    }

                    float baseRotation = MathHelper.ToRadians(50);
                    if (++AttackMemory == 10)
                    {
                        if (Main.netMode != NetmodeID.MultiplayerClient)
                        {
                            Projectile.NewProjectile(Main.npc[(int)npc.localAI[0]].Center, Main.npc[(int)npc.localAI[0]].DirectionTo(player.Center), ModContent.ProjectileType <PhantasmalDeathrayMLSmall>(),
                                                     60, 0f, Main.myPlayer, baseRotation * Main.rand.NextFloat(0.9f, 1.1f), npc.localAI[0]);
                        }
                    }
                    else if (AttackMemory == 20)
                    {
                        if (Main.netMode != NetmodeID.MultiplayerClient)
                        {
                            Projectile.NewProjectile(Main.npc[(int)npc.localAI[1]].Center, Main.npc[(int)npc.localAI[2]].DirectionTo(player.Center), ModContent.ProjectileType <PhantasmalDeathrayMLSmall>(),
                                                     60, 0f, Main.myPlayer, -baseRotation * Main.rand.NextFloat(0.9f, 1.1f), npc.localAI[1]);
                        }
                    }
                    else if (AttackMemory == 30)
                    {
                        if (Main.netMode != NetmodeID.MultiplayerClient)
                        {
                            Projectile.NewProjectile(Main.npc[(int)npc.localAI[2]].Center, Main.npc[(int)npc.localAI[1]].DirectionTo(player.Center), ModContent.ProjectileType <PhantasmalDeathrayMLSmall>(),
                                                     60, 0f, Main.myPlayer, baseRotation * Main.rand.NextFloat(0.9f, 1.1f), npc.localAI[2]);
                        }
                    }
                    else if (AttackMemory == 40)
                    {
                        if (Main.netMode != NetmodeID.MultiplayerClient)
                        {
                            Projectile.NewProjectile(npc.Center, npc.DirectionTo(player.Center), ModContent.ProjectileType <PhantasmalDeathrayMLSmall>(),
                                                     60, 0f, Main.myPlayer, -baseRotation * Main.rand.NextFloat(0.9f, 1.1f), npc.whoAmI);
                        }
                    }
                }
                break;

                default:                   //any
                {
                    if (AttackMemory == 0) //spawn the moons
                    {
                        AttackMemory = 1;

                        foreach (Projectile p in Main.projectile.Where(p => p.active && p.hostile))
                        {
                            if (p.type == ModContent.ProjectileType <LunarRitual>() && p.ai[1] == npc.whoAmI)        //find my arena
                            {
                                if (Main.netMode != NetmodeID.MultiplayerClient)
                                {
                                    for (int i = 0; i < 4; i++)
                                    {
                                        Projectile.NewProjectile(npc.Center, p.DirectionTo(Main.player[npc.target].Center).RotatedBy(MathHelper.TwoPi / 4 * i), ModContent.ProjectileType <MoonLordMoon>(),
                                                                 60, 0f, Main.myPlayer, p.identity, 1450);
                                    }
                                    for (int i = 0; i < 4; i++)
                                    {
                                        Projectile.NewProjectile(npc.Center, p.DirectionTo(Main.player[npc.target].Center).RotatedBy(MathHelper.TwoPi / 4 * (i + 0.5f)), ModContent.ProjectileType <MoonLordMoon>(),
                                                                 60, 0f, Main.myPlayer, p.identity, -950);
                                    }
                                }
                                break;
                            }
                        }
                    }
                }
                break;
                }
            }

            if (npc.ai[0] == 2f) //moon lord is dead
            {
                VulnerabilityState = 4;
                VulnerabilityTimer = 0;
                AttackTimer        = 0;
            }
            else //moon lord isn't dead
            {
                int increment = (int)Math.Max(1, (1f - (float)npc.life / npc.lifeMax) * 4);
                if (FargoSoulsWorld.MasochistModeReal)
                {
                    increment++;
                }

                VulnerabilityTimer += increment;
                AttackTimer        += increment;

                if (VulnerabilityTimer > 1800)
                {
                    VulnerabilityState = ++VulnerabilityState % 5;

                    VulnerabilityTimer = 0;
                    AttackTimer        = 0;
                    AttackMemory       = 0;

                    npc.netUpdate = true;
                    NetSync(npc);
                }
            }

            switch (VulnerabilityState)
            {
            case 0: Main.monolithType = 3; break;

            case 1: Main.monolithType = 0; break;

            case 2: Main.monolithType = 1; break;

            case 3:
                Main.monolithType = 2;
                if (VulnerabilityTimer < 120)     //so that player isn't punished for using weapons during prior phase
                {
                    Main.LocalPlayer.GetModPlayer <FargoPlayer>().MasomodeMinionNerfTimer = 0;
                }
                break;

            default: break;
            }

            EModeUtils.DropSummon(npc, ModContent.ItemType <CelestialSigil2>(), NPC.downedMoonlord, ref DroppedSummon, NPC.downedAncientCultist);
        }
        public override bool PreAI(NPC npc)
        {
            EModeGlobalNPC.slimeBoss = npc.whoAmI;
            npc.color = Main.DiscoColor * 0.3f; // Rainbow colour

            if (FargoSoulsWorld.SwarmActive)
            {
                return(true);
            }

            if (FargoSoulsWorld.MasochistModeReal)
            {
                npc.position.X += npc.velocity.X * 0.2f;
            }

            // Attack that happens when landing
            if (LandingAttackReady)
            {
                if (npc.velocity.Y == 0f)
                {
                    LandingAttackReady = false;
                    if (Main.netMode != NetmodeID.MultiplayerClient)
                    {
                        if (FargoSoulsWorld.MasochistModeReal)
                        {
                            for (int i = 0; i < 30; i++) //spike spray
                            {
                                Projectile.NewProjectile(npc.GetSource_FromThis(), new Vector2(npc.Center.X + Main.rand.Next(-5, 5), npc.Center.Y - 15),
                                                         new Vector2(Main.rand.NextFloat(-6, 6), Main.rand.NextFloat(-8, -5)),
                                                         ProjectileID.SpikedSlimeSpike, FargoSoulsUtil.ScaledProjectileDamage(npc.damage), 0f, Main.myPlayer);
                            }
                        }

                        if (npc.HasValidTarget)
                        {
                            SoundEngine.PlaySound(SoundID.Item21, Main.player[npc.target].Center);
                            if (Main.netMode != NetmodeID.MultiplayerClient)
                            {
                                for (int i = 0; i < 6; i++)
                                {
                                    Vector2 spawn = Main.player[npc.target].Center;
                                    spawn.X += Main.rand.Next(-150, 151);
                                    spawn.Y -= Main.rand.Next(600, 901);
                                    Vector2 speed = Main.player[npc.target].Center - spawn;
                                    speed.Normalize();
                                    speed *= IsBerserk ? 10f : 5f;
                                    speed  = speed.RotatedByRandom(MathHelper.ToRadians(4));
                                    Projectile.NewProjectile(npc.GetSource_FromThis(), spawn, speed, ModContent.ProjectileType <SlimeBallHostile>(), FargoSoulsUtil.ScaledProjectileDamage(npc.damage, 4f / 6), 0f, Main.myPlayer);
                                }
                            }
                        }
                    }
                }
            }
            else if (npc.velocity.Y > 0)
            {
                // If they're in the air, flag that the landing attack should be used next time they land
                LandingAttackReady = true;
            }

            if (npc.velocity.Y < 0)    // Jumping up
            {
                if (!CurrentlyJumping) // Once per jump...
                {
                    CurrentlyJumping = true;

                    bool shootSpikes = false;

                    if (FargoSoulsWorld.MasochistModeReal)
                    {
                        shootSpikes = true;
                    }

                    // If player is well above me, jump higher and spray spikes
                    if (npc.HasValidTarget && Main.player[npc.target].Center.Y < npc.position.Y + npc.height - 240)
                    {
                        npc.velocity.Y *= 2f;
                        shootSpikes     = true;
                    }

                    if (shootSpikes && Main.netMode != NetmodeID.MultiplayerClient)
                    {
                        const float gravity  = 0.15f;
                        float       time     = 90f;
                        Vector2     distance = Main.player[npc.target].Center - npc.Center + Main.player[npc.target].velocity * 30f;
                        distance.X = distance.X / time;
                        distance.Y = distance.Y / time - 0.5f * gravity * time;
                        for (int i = 0; i < 15; i++)
                        {
                            Projectile.NewProjectile(npc.GetSource_FromThis(), npc.Center, distance + Main.rand.NextVector2Square(-1f, 1f),
                                                     ModContent.ProjectileType <SlimeSpike>(), FargoSoulsUtil.ScaledProjectileDamage(npc.damage), 0f, Main.myPlayer);
                        }
                    }
                }
            }
            else
            {
                CurrentlyJumping = false;
            }

            if ((IsBerserk || npc.life < npc.lifeMax * .5f) && npc.HasValidTarget)
            {
                if (--SpikeRainCounter < 0) // Spike rain
                {
                    SpikeRainCounter = 240;

                    if (Main.netMode != NetmodeID.MultiplayerClient)
                    {
                        for (int i = -12; i <= 12; i++)
                        {
                            Vector2 spawnPos = Main.player[npc.target].Center;
                            spawnPos.X += 110 * i;
                            spawnPos.Y -= 500;
                            Projectile.NewProjectile(npc.GetSource_FromThis(), spawnPos, (IsBerserk ? 6f : 0f) * Vector2.UnitY,
                                                     ModContent.ProjectileType <SlimeSpike2>(), FargoSoulsUtil.ScaledProjectileDamage(npc.damage, 4f / 6), 0f, Main.myPlayer);
                        }
                    }
                }
            }

            /*if (!masoBool[0]) //is not berserk
             * {
             *  SharkCount = 0;
             *
             *  if (npc.HasPlayerTarget)
             *  {
             *      Player player = Main.player[npc.target];
             *      if (player.active && !player.dead && player.Center.Y < npc.position.Y && npc.Distance(player.Center) < 1000f)
             *      {
             *          Counter[1]++; //timer runs if player is above me and nearby
             *          if (Counter[1] >= 600 && Main.netMode != NetmodeID.MultiplayerClient) //go berserk
             *          {
             *              masoBool[0] = true;
             *              npc.netUpdate = true;
             *              NetUpdateMaso(npc.whoAmI);
             *              if (Main.netMode == NetmodeID.Server)
             *                  ChatHelper.BroadcastChatMessage(NetworkText.FromLiteral("King Slime has enraged!"), new Color(175, 75, 255));
             *              else
             *                  Main.NewText("King Slime has enraged!", 175, 75, 255);
             *          }
             *      }
             *      else
             *      {
             *          Counter[1] = 0;
             *      }
             *  }
             * }
             * else //is berserk
             * {
             *  SharkCount = 1;
             *
             *  if (!masoBool[2])
             *  {
             *      masoBool[2] = true;
             *      SoundEngine.PlaySound(SoundID.Roar, npc.Center);
             *  }
             *
             *  if (Counter[0] > 45) //faster slime spike rain
             *      Counter[0] = 45;
             *
             *  if (++Counter[2] > 30) //aimed spikes
             *  {
             *      Counter[2] = 0;
             *      const float gravity = 0.15f;
             *      float time = 45f;
             *      Vector2 distance = Main.player[npc.target].Center - npc.Center + Main.player[npc.target].velocity * 30f;
             *      distance.X = distance.X / time;
             *      distance.Y = distance.Y / time - 0.5f * gravity * time;
             *      for (int i = 0; i < 15; i++)
             *      {
             *          Projectile.NewProjectile(npc.GetSource_FromThis(), npc.Center, distance + Main.rand.NextVector2Square(-1f, 1f) * 2f,
             *              ModContent.ProjectileType<SlimeSpike>(), FargoSoulsUtil.ScaledProjectileDamage(npc.damage), 0f, Main.myPlayer);
             *      }
             *  }
             *
             *  if (npc.HasValidTarget && Main.netMode != NetmodeID.MultiplayerClient && Main.player[npc.target].position.Y > npc.position.Y) //player went back down
             *  {
             *      masoBool[0] = false;
             *      masoBool[2] = false;
             *      NetUpdateMaso(npc.whoAmI);
             *  }
             * }*/

            if (npc.life < npc.lifeMax / 2)
            {
                if (npc.ai[1] == 5) //when teleporting
                {
                    if (npc.ai[0] == 1 && !DidP2SpecialTeleport)
                    {
                        SoundEngine.PlaySound(SoundID.Roar, npc.Center);
                    }

                    if (npc.HasPlayerTarget) //live update tp position
                    {
                        if (DidP2SpecialTeleport)
                        {
                            if (npc.ai[0] == 1) //only update y pos once
                            {
                                npc.localAI[2] = Main.player[npc.target].Center.Y;
                            }
                        }
                        else
                        {
                            Vector2 desiredTeleport = Main.player[npc.target].Center;
                            desiredTeleport.X += 800 * System.Math.Sign(Main.player[npc.target].Center.X - npc.Center.X); //tp ahead of player

                            if (Collision.CanHitLine(desiredTeleport, 0, 0, Main.player[npc.target].position, Main.player[npc.target].width, Main.player[npc.target].height))
                            {
                                npc.localAI[1] = desiredTeleport.X;
                                npc.localAI[2] = desiredTeleport.Y;
                            }
                        }
                    }
                }
                else if (npc.ai[1] == 6) //actually did the teleport and now regrowing
                {
                    DidP2SpecialTeleport = true;
                }
                else
                {
                    if (!DidP2SpecialTeleport)
                    {
                        npc.ai[2] += 60;
                    }

                    npc.ai[2] += 1f / 3f; //always increment the teleport timer
                }
            }

            // Drop summon
            EModeUtils.DropSummon(npc, "SlimyCrown", NPC.downedSlimeKing, ref DroppedSummon);

            return(base.PreAI(npc));
        }
Example #7
0
        public override bool PreAI(NPC npc)
        {
            bool result = base.PreAI(npc);

            IsVenomEnraged = false;

            if (FargoSoulsWorld.SwarmActive)
            {
                return(result);
            }

            if (!npc.HasValidTarget)
            {
                npc.velocity.Y++;
            }

            const float innerRingDistance = 130f;
            const int   delayForRingToss  = 360 + 120;

            if (--RingTossTimer < 0)
            {
                RingTossTimer = delayForRingToss;
                if (Main.netMode != NetmodeID.MultiplayerClient && !Main.npc.Any(n => n.active && n.type == ModContent.NPCType <CrystalLeaf>() && n.ai[0] == npc.whoAmI && n.ai[1] == innerRingDistance))
                {
                    const int max      = 5;
                    float     rotation = 2f * (float)Math.PI / max;
                    for (int i = 0; i < max; i++)
                    {
                        Vector2 spawnPos = npc.Center + new Vector2(innerRingDistance, 0f).RotatedBy(rotation * i);
                        FargoSoulsUtil.NewNPCEasy(npc.GetSource_FromAI(), spawnPos, ModContent.NPCType <CrystalLeaf>(), 0, npc.whoAmI, innerRingDistance, 0, rotation * i);
                    }
                }
            }
            else if (RingTossTimer == 120)
            {
                if (FargoSoulsWorld.MasochistModeReal)
                {
                    RingTossTimer = 0; //instantly spawn next set of crystals
                }
                npc.netUpdate = true;
                NetSync(npc);

                if (Main.netMode != NetmodeID.MultiplayerClient)
                {
                    float speed = 8f;
                    int   p     = Projectile.NewProjectile(npc.GetSource_FromThis(), npc.Center, speed * npc.DirectionTo(Main.player[npc.target].Center), ModContent.ProjectileType <MutantMark2>(), npc.defDamage / 4, 0f, Main.myPlayer);
                    if (p != Main.maxProjectiles)
                    {
                        Main.projectile[p].timeLeft -= 300;

                        foreach (NPC n in Main.npc.Where(n => n.active && n.type == ModContent.NPCType <CrystalLeaf>() && n.ai[0] == npc.whoAmI && n.ai[1] == innerRingDistance)) //my crystal leaves
                        {
                            SoundEngine.PlaySound(SoundID.Grass, n.Center);
                            Projectile.NewProjectile(npc.GetSource_FromThis(), n.Center, Vector2.Zero, ModContent.ProjectileType <PlanteraCrystalLeafRing>(), npc.defDamage / 4, 0f, Main.myPlayer, Main.projectile[p].identity, n.ai[3]);

                            n.life = 0;
                            n.HitEffect();
                            n.checkDead();
                            n.active = false;
                            if (Main.netMode == NetmodeID.Server)
                            {
                                NetMessage.SendData(MessageID.SyncNPC, -1, -1, null, n.whoAmI);
                            }
                        }
                    }
                }
            }

            if (npc.life > npc.lifeMax / 2)
            {
                if (--DicerTimer < 0)
                {
                    DicerTimer = 150 * 4 + 25;
                    if (FargoSoulsWorld.MasochistModeReal && npc.HasValidTarget && Main.netMode != NetmodeID.MultiplayerClient)
                    {
                        Projectile.NewProjectile(npc.GetSource_FromThis(), Main.player[npc.target].Center, Vector2.Zero, ModContent.ProjectileType <DicerPlantera>(), npc.defDamage / 4, 0f, Main.myPlayer, 0, 0);
                        for (int i = 0; i < 3; i++)
                        {
                            Projectile.NewProjectile(npc.GetSource_FromThis(), Main.player[npc.target].Center, 30f * npc.DirectionTo(Main.player[npc.target].Center).RotatedBy(2 * (float)Math.PI / 3 * i),
                                                     ModContent.ProjectileType <DicerPlantera>(), npc.defDamage / 4, 0f, Main.myPlayer, 1, 1);
                        }
                    }
                }
            }
            else
            {
                if (!InPhase2)
                {
                    InPhase2   = true;
                    DicerTimer = 0;
                }

                void SpawnOuterLeafRing()
                {
                    const int   max      = 12;
                    const float distance = 250;
                    float       rotation = 2f * (float)Math.PI / max;

                    for (int i = 0; i < max; i++)
                    {
                        Vector2 spawnPos = npc.Center + new Vector2(distance, 0f).RotatedBy(rotation * i);
                        FargoSoulsUtil.NewNPCEasy(npc.GetSource_FromAI(), spawnPos, ModContent.NPCType <CrystalLeaf>(), 0, npc.whoAmI, distance, 0, rotation * i);
                    }
                }

                if (!EnteredPhase2)
                {
                    EnteredPhase2 = true;

                    if (Main.netMode != NetmodeID.MultiplayerClient)
                    {
                        if (!Main.npc.Any(n => n.active && n.type == ModContent.NPCType <CrystalLeaf>() && n.ai[0] == npc.whoAmI && n.ai[1] == innerRingDistance))
                        {
                            const int innerMax      = 5;
                            float     innerRotation = 2f * (float)Math.PI / innerMax;
                            for (int i = 0; i < innerMax; i++)
                            {
                                Vector2 spawnPos = npc.Center + new Vector2(innerRingDistance, 0f).RotatedBy(innerRotation * i);
                                FargoSoulsUtil.NewNPCEasy(npc.GetSource_FromAI(), spawnPos, ModContent.NPCType <CrystalLeaf>(), 0, npc.whoAmI, innerRingDistance, 0, innerRotation * i);
                            }
                        }

                        SpawnOuterLeafRing();

                        for (int i = 0; i < Main.maxProjectiles; i++)
                        {
                            if (Main.projectile[i].active && Main.projectile[i].hostile &&
                                (Main.projectile[i].type == ProjectileID.ThornBall ||
                                 Main.projectile[i].type == ModContent.ProjectileType <DicerPlantera>() ||
                                 Main.projectile[i].type == ModContent.ProjectileType <PlanteraCrystalLeafRing>() ||
                                 Main.projectile[i].type == ModContent.ProjectileType <CrystalLeafShot>()))
                            {
                                Main.projectile[i].Kill();
                            }
                        }
                    }
                }

                //explode time * explode repetitions + spread delay * propagations
                const int delayForDicers = 150 * 4 + 25 * 8;

                if (--DicerTimer < -120)
                {
                    DicerTimer = delayForDicers + delayForRingToss + 240;
                    //Counter3 = delayForDicers + 120; //extra compensation for the toss offset

                    npc.netUpdate = true;
                    NetSync(npc);

                    if (Main.netMode != NetmodeID.MultiplayerClient)
                    {
                        Projectile.NewProjectile(npc.GetSource_FromThis(), npc.Center, Vector2.Zero, ModContent.ProjectileType <DicerPlantera>(), npc.defDamage / 4, 0f, Main.myPlayer);
                        for (int i = 0; i < 3; i++)
                        {
                            Projectile.NewProjectile(npc.GetSource_FromThis(), npc.Center, 25f * npc.DirectionTo(Main.player[npc.target].Center).RotatedBy(2 * (float)Math.PI / 3 * i),
                                                     ModContent.ProjectileType <DicerPlantera>(), npc.defDamage / 4, 0f, Main.myPlayer, 1, 8);
                        }
                    }
                }

                if (DicerTimer > delayForDicers || DicerTimer < 0)
                {
                    if (RingTossTimer > 120) //to still respawn the leaf ring if it's missing but disable throwing it
                    {
                        RingTossTimer = 120;
                    }
                }
                else if (DicerTimer < delayForDicers)
                {
                    RingTossTimer -= 1;

                    if (RingTossTimer % 2 == 0) //make sure plantera can get the timing for its check
                    {
                        RingTossTimer--;
                    }
                }
                else if (DicerTimer == delayForDicers)
                {
                    RingTossTimer = 121; //activate it immediately as the mines fade
                }

                IsVenomEnraged = npc.HasPlayerTarget && Main.player[npc.target].venom;

                if (--TentacleTimer <= 0)
                {
                    float slowdown = Math.Min(0.9f, -TentacleTimer / 60f);
                    if (FargoSoulsWorld.MasochistModeReal && slowdown > 0.75f)
                    {
                        slowdown = 0.75f;
                    }
                    npc.position -= npc.velocity * slowdown;

                    if (TentacleTimer == 0)
                    {
                        TentacleAttackAngleOffset = Main.rand.NextFloat(MathHelper.TwoPi);

                        SoundEngine.PlaySound(SoundID.Roar, npc.Center);

                        npc.netUpdate = true;
                        NetSync(npc);

                        foreach (NPC n in Main.npc.Where(n => n.active && n.type == ModContent.NPCType <CrystalLeaf>() && n.ai[0] == npc.whoAmI && n.ai[1] > innerRingDistance)) //my crystal leaves
                        {
                            SoundEngine.PlaySound(SoundID.Grass, n.Center);

                            n.life = 0;
                            n.HitEffect();
                            n.checkDead();
                            n.active = false;
                            if (Main.netMode == NetmodeID.Server)
                            {
                                NetMessage.SendData(MessageID.SyncNPC, -1, -1, null, n.whoAmI);
                            }
                        }
                    }

                    const int maxTime           = 30;
                    const int interval          = 3;
                    float     maxDegreeCoverage = 45f; //on either side of the middle, the full coverage of one side is x2 this
                    if (TentacleTimer >= -maxTime && TentacleTimer % interval == 0)
                    {
                        int tentacleSpawnOffset = Math.Abs(TentacleTimer) / interval;
                        for (int i = -tentacleSpawnOffset; i <= tentacleSpawnOffset; i += tentacleSpawnOffset * 2)
                        {
                            float attackAngle = MathHelper.WrapAngle(
                                TentacleAttackAngleOffset
                                + MathHelper.ToRadians(maxDegreeCoverage / (maxTime / interval)) * (i + Main.rand.NextFloat(-0.5f, 0.5f))
                                );

                            if (Main.netMode != NetmodeID.MultiplayerClient)
                            {
                                Projectile.NewProjectile(npc.GetSource_FromThis(), npc.Center, Main.rand.NextVector2CircularEdge(24, 24),
                                                         ModContent.ProjectileType <PlanteraTentacle>(), FargoSoulsUtil.ScaledProjectileDamage(npc.damage), 0f, Main.myPlayer, npc.whoAmI, attackAngle);
                                Projectile.NewProjectile(npc.GetSource_FromThis(), npc.Center, Main.rand.NextVector2CircularEdge(24, 24),
                                                         ModContent.ProjectileType <PlanteraTentacle>(), FargoSoulsUtil.ScaledProjectileDamage(npc.damage), 0f, Main.myPlayer, npc.whoAmI, attackAngle + MathHelper.Pi);
                            }

                            if (i == 0)
                            {
                                break;
                            }
                        }
                    }

                    if (TentacleTimer < -390)
                    {
                        TentacleTimer = 600 + Main.rand.Next(120);

                        if (!FargoSoulsWorld.MasochistModeReal)
                        {
                            npc.velocity = Vector2.Zero;
                        }

                        npc.netUpdate = true;
                        NetSync(npc);

                        SpawnOuterLeafRing();
                    }
                }
                else
                {
                    npc.position -= npc.velocity * (IsVenomEnraged ? 0.1f : 0.2f);
                }

                if (FargoSoulsWorld.MasochistModeReal && --TentacleTimerMaso < 0)
                {
                    TentacleTimerMaso = 420;
                    if (Main.netMode != NetmodeID.MultiplayerClient)
                    {
                        float angle = npc.DirectionTo(Main.player[npc.target].Center).ToRotation();
                        for (int i = -1; i <= 1; i++)
                        {
                            float offset = MathHelper.ToRadians(6) * i;
                            Projectile.NewProjectile(npc.GetSource_FromThis(), npc.Center, Main.rand.NextVector2CircularEdge(24, 24),
                                                     ModContent.ProjectileType <PlanteraTentacle>(), FargoSoulsUtil.ScaledProjectileDamage(npc.damage), 0f, Main.myPlayer, npc.whoAmI, angle + offset);
                            Projectile.NewProjectile(npc.GetSource_FromThis(), npc.Center, Main.rand.NextVector2CircularEdge(24, 24),
                                                     ModContent.ProjectileType <PlanteraTentacle>(), FargoSoulsUtil.ScaledProjectileDamage(npc.damage), 0f, Main.myPlayer, npc.whoAmI, -angle + offset);
                        }
                    }
                }
            }

            EModeUtils.DropSummon(npc, "PlanterasFruit", NPC.downedPlantBoss, ref DroppedSummon, NPC.downedMechBoss1 && NPC.downedMechBoss2 && NPC.downedMechBoss3);

            return(result);
        }
        public override bool PreAI(NPC npc)
        {
            bool result = base.PreAI(npc);

            EModeGlobalNPC.deerBoss = npc.whoAmI;

            if (FargoSoulsWorld.SwarmActive)
            {
                return(result);
            }

            const int MaxBerserkTime = 600;

            BerserkSpeedupTimer -= 1;

            if (npc.localAI[3] > 0 || EnteredPhase3)
            {
                npc.localAI[2]++; //cry about it
            }
            const int TeleportThreshold = 780;

            if (npc.ai[0] != 0)
            {
                npc.alpha -= 10;
                if (npc.alpha < 0)
                {
                    npc.alpha = 0;
                }

                if (EnteredPhase3)
                {
                    npc.localAI[2]++;
                }
            }

            TeleportTimer++;
            if (EnteredPhase3)
            {
                TeleportTimer++;
            }

            if (Main.LocalPlayer.active && !Main.LocalPlayer.ghost && !Main.LocalPlayer.dead && npc.Distance(Main.LocalPlayer.Center) < 1200)
            {
                Main.LocalPlayer.AddBuff(ModContent.BuffType <LowGround>(), 2);
            }

            switch ((int)npc.ai[0])
            {
            case 0:     //walking at player
                if (TeleportTimer < TeleportThreshold)
                {
                    if (EnteredPhase3)
                    {
                        npc.position.X += npc.velocity.X;
                    }

                    if (npc.velocity.Y == 0)
                    {
                        if (EnteredPhase2)
                        {
                            npc.position.X += npc.velocity.X;
                        }
                        if (BerserkSpeedupTimer > 0)
                        {
                            npc.position.X += npc.velocity.X * 4f * BerserkSpeedupTimer / MaxBerserkTime;
                        }
                    }
                }

                if (EnteredPhase2)
                {
                    if (!EnteredPhase3 && npc.life < npc.lifeMax * .33)
                    {
                        npc.ai[0]     = 3;
                        npc.ai[1]     = 0;
                        npc.netUpdate = true;
                        break;
                    }

                    if (TeleportTimer > TeleportThreshold)
                    {
                        npc.velocity.X    *= 0.9f;
                        npc.dontTakeDamage = true;
                        npc.localAI[1]     = 0; //reset walls attack counter

                        if (EnteredPhase2 && Main.LocalPlayer.active && !Main.LocalPlayer.ghost && !Main.LocalPlayer.dead)
                        {
                            FargoSoulsUtil.AddDebuffFixedDuration(Main.LocalPlayer, BuffID.Darkness, 2);
                            FargoSoulsUtil.AddDebuffFixedDuration(Main.LocalPlayer, BuffID.Blackout, 2);
                        }

                        if (npc.alpha == 0)
                        {
                            SoundEngine.PlaySound(SoundID.Roar, npc.Center);

                            if (Main.netMode != NetmodeID.MultiplayerClient)
                            {
                                const int max = 12;
                                for (int i = 0; i < 12; i++)
                                {
                                    Vector2 spawnPos = Main.player[npc.target].Center + 16 * Main.rand.NextFloat(6, 36) * Vector2.UnitX.RotatedBy(MathHelper.TwoPi / max * (i + Main.rand.NextFloat()));
                                    Projectile.NewProjectile(npc.GetSource_FromThis(), spawnPos, Vector2.Zero, ModContent.ProjectileType <DeerclopsHand>(), 0, 0f, Main.myPlayer, npc.target);
                                }
                            }
                        }

                        npc.alpha += 5;
                        if (npc.alpha > 255)
                        {
                            npc.alpha = 255;

                            npc.localAI[3] = 30;

                            if (npc.HasPlayerTarget)     //teleport
                            {
                                float distance = 16 * 14 * Math.Sign(npc.Center.X - Main.player[npc.target].Center.X);
                                distance *= -1f;                             //alternate back and forth

                                if (TeleportTimer == TeleportThreshold + 10) //introduce randomness
                                {
                                    if (Main.rand.NextBool())
                                    {
                                        distance *= -1f;
                                    }

                                    if (Main.netMode == NetmodeID.Server)
                                    {
                                        NetMessage.SendData(MessageID.SyncNPC, number: npc.whoAmI);
                                    }

                                    DoLaserAttack = !DoLaserAttack;     //guarantee he alternates wall attacks at some point in the fight
                                    NetSync(npc);
                                }

                                npc.Bottom = Main.player[npc.target].Bottom + distance * Vector2.UnitX;

                                npc.direction  = Math.Sign(Main.player[npc.target].Center.X - npc.Center.X);
                                npc.velocity.X = 3.4f * npc.direction;
                                npc.velocity.Y = 0;

                                int addedThreshold = 180;
                                if (EnteredPhase3)
                                {
                                    addedThreshold -= 30;
                                }
                                if (FargoSoulsWorld.MasochistModeReal)
                                {
                                    addedThreshold -= 30;
                                }

                                if (TeleportTimer > TeleportThreshold + addedThreshold)
                                {
                                    TeleportTimer  = 0;
                                    npc.velocity.X = 0;
                                    npc.ai[0]      = 4;
                                    npc.ai[1]      = 0;
                                    NetSync(npc);
                                    if (Main.netMode == NetmodeID.Server)
                                    {
                                        NetMessage.SendData(MessageID.SyncNPC, number: npc.whoAmI);
                                    }
                                }
                            }
                        }
                        else
                        {
                            TeleportTimer = TeleportThreshold;

                            if (npc.localAI[3] > 0)
                            {
                                npc.localAI[3] -= 3;     //remove visual effect
                            }
                        }

                        return(false);
                    }
                }
                else if (npc.life < npc.lifeMax * .66)
                {
                    npc.ai[0]     = 3;
                    npc.ai[1]     = 0;
                    npc.netUpdate = true;
                }
                break;

            case 1:     //ice wave, npc.localai[1] counts them, attacks at ai1=30, last spike 52, ends at ai1=80
                if (npc.ai[1] < 30)
                {
                    if (FargoSoulsWorld.MasochistModeReal)
                    {
                        npc.ai[1]        += 0.5f;
                        npc.frameCounter += 0.5;
                    }
                }
                break;

            case 2:     //debris attack
                break;

            case 3:     //roar at 30, ends at ai1=60
                if (!FargoSoulsWorld.MasochistModeReal && npc.ai[1] < 30)
                {
                    npc.ai[1]        -= 0.5f;
                    npc.frameCounter -= 0.5;
                }

                if (EnteredPhase2)
                {
                    npc.localAI[1] = 0;     //ensure this is always the same
                    npc.localAI[3] = 30;    //go invul

                    if (npc.ai[1] > 30)
                    {
                        Main.dayTime = false;
                        Main.time    = 16200;  //midnight, to help teleport visual
                    }
                }
                else if (npc.life < npc.lifeMax * .66)
                {
                    EnteredPhase2 = true;
                    NetSync(npc);
                }

                if (EnteredPhase3)
                {
                    if (!Main.dedServ)
                    {
                        Main.LocalPlayer.GetModPlayer <FargoSoulsPlayer>().Screenshake = 2;
                    }

                    if (npc.ai[1] > 30)         //roaring
                    {
                        if (npc.HasValidTarget) //fly over player
                        {
                            npc.position = Vector2.Lerp(npc.position, Main.player[npc.target].Center - 450 * Vector2.UnitY, 0.2f);
                        }
                    }
                }
                else if (npc.life < npc.lifeMax * .33)
                {
                    EnteredPhase3 = true;
                    NetSync(npc);
                }

                if (EnteredPhase3 || FargoSoulsWorld.MasochistModeReal)
                {
                    BerserkSpeedupTimer = MaxBerserkTime;
                }
                break;

            case 4:                 //both sides ice wave, attacks at ai1=50, last spike 70, ends at ai1=90
            {
                int cooldown = 100; //stops deerclops from teleporting while old ice walls are still there
                if (EnteredPhase3)
                {
                    cooldown *= 2;
                }
                if (TeleportTimer > TeleportThreshold - cooldown)
                {
                    TeleportTimer = TeleportThreshold - cooldown;
                }

                if (EnteredPhase2 && npc.ai[1] == 0)
                {
                    if (npc.alpha == 0)         //i.e. dont randomize when coming out of tp
                    {
                        DoLaserAttack = Main.rand.NextBool();
                    }
                    NetSync(npc);

                    if (DoLaserAttack && Main.netMode != NetmodeID.MultiplayerClient)
                    {
                        Projectile.NewProjectile(npc.GetSource_FromThis(), npc.Center, Vector2.Zero, ModContent.ProjectileType <GlowRing>(), 0, 0f, Main.myPlayer, npc.whoAmI, npc.type);
                    }
                }

                Vector2 eye = npc.Center + new Vector2(64 * npc.direction, -24f) * npc.scale;

                if (FargoSoulsWorld.MasochistModeReal)
                {
                    const int desiredStartup = 30;         //effectively changes startup from 50 to this value
                    const int threshold      = 50 - desiredStartup / 2;
                    if (npc.ai[1] < threshold)
                    {
                        npc.ai[1]++;
                    }
                }

                if (DoLaserAttack && npc.ai[1] >= 70)
                {
                    if (EnteredPhase3)
                    {
                        const float baseIncrement = 0.33f;
                        float       increment     = baseIncrement;
                        //if (FargoSoulsWorld.MasochistModeReal) increment *= 2;

                        if (npc.ai[1] == 70)         //shoot laser
                        {
                            float time = (90 - 70) / baseIncrement - 5;
                            time *= 5;         //account for the ray having extra updates
                            float rotation = MathHelper.Pi * (FargoSoulsWorld.MasochistModeReal ? 1f : 0.8f) / time * -npc.direction;

                            if (Main.netMode != NetmodeID.MultiplayerClient)
                            {
                                Projectile.NewProjectile(npc.GetSource_FromThis(), eye, Vector2.UnitY, ModContent.ProjectileType <DeerclopsDeathray>(), FargoSoulsUtil.ScaledProjectileDamage(npc.damage, 2f), 0f, Main.myPlayer, rotation, time);
                            }
                        }

                        npc.ai[1] += increment;         //more endlag than normal

                        if (npc.ai[1] < 90)
                        {
                            return(false);        //stop deerclops from turning around
                        }
                    }
                    else
                    {
                        npc.ai[1] += 0.33f;         //more endlag than normal

                        if (npc.ai[1] >= 89)
                        {
                            npc.ai[0]        = 2;  //force debris attack instead
                            npc.ai[1]        = 0;
                            npc.frameCounter = 0;
                            npc.netUpdate    = true;
                            break;
                        }
                    }

                    if (npc.ai[1] < 90)
                    {
                        return(false);        //stop deerclops from turning around
                    }
                }
            }
            break;

            case 6:     //trying to return home
                npc.TargetClosest();

                if (npc.ai[1] > 120 && (!npc.HasValidTarget || npc.Distance(Main.player[npc.target].Center) > 1600))
                {
                    if (Main.netMode != NetmodeID.MultiplayerClient)     //force despawn
                    {
                        npc.ai[0]      = 8f;
                        npc.ai[1]      = 0.0f;
                        npc.localAI[1] = 0.0f;
                        npc.netUpdate  = true;
                    }
                }
                break;

            default:
                break;
            }

            if (EnteredPhase3 && !(npc.ai[0] == 0 && npc.alpha > 0))
            {
                npc.localAI[3] += 3;
                if (npc.localAI[3] > 30)
                {
                    npc.localAI[3] = 30;
                }
            }

            //FargoSoulsUtil.PrintAI(npc);

            EModeUtils.DropSummon(npc, "DeerThing2", NPC.downedDeerclops, ref DroppedSummon);

            return(result);
        }
Example #9
0
        public override bool PreAI(NPC npc)
        {
            EModeGlobalNPC.eyeBoss = npc.whoAmI;

            if (FargoSoulsWorld.SwarmActive)
            {
                return(true);
            }

            void SpawnServants()
            {
                if (npc.life <= npc.lifeMax * 0.65 && NPC.CountNPCS(NPCID.ServantofCthulhu) < 9 && Main.netMode != NetmodeID.MultiplayerClient)
                {
                    Vector2 vel = new Vector2(3, 3);
                    for (int i = 0; i < 4; i++)
                    {
                        int n = NPC.NewNPC(npc.GetSource_FromAI(), (int)npc.Center.X, (int)npc.Center.Y, NPCID.ServantofCthulhu);
                        if (n != Main.maxNPCs)
                        {
                            Main.npc[n].velocity = vel.RotatedBy(Math.PI / 2 * i);
                            if (Main.netMode == NetmodeID.Server)
                            {
                                NetMessage.SendData(MessageID.SyncNPC, -1, -1, null, n);
                            }
                        }
                    }
                }
            }

            npc.dontTakeDamage = npc.alpha > 50;
            if (npc.dontTakeDamage)
            {
                Lighting.AddLight(npc.Center, 0.75f, 1.35f, 1.5f);
            }

            if (ScytheSpawnTimer > 0)
            {
                if (ScytheSpawnTimer % (IsInFinalPhase ? 2 : 6) == 0 && Main.netMode != NetmodeID.MultiplayerClient)
                {
                    if (IsInFinalPhase && !FargoSoulsWorld.MasochistModeReal)
                    {
                        int p = Projectile.NewProjectile(npc.GetSource_FromThis(), npc.Center, Vector2.Zero, ModContent.ProjectileType <BloodScythe>(), FargoSoulsUtil.ScaledProjectileDamage(npc.damage), 1f, Main.myPlayer);
                        if (p != Main.maxProjectiles)
                        {
                            Main.projectile[p].timeLeft = 75;
                        }
                    }
                    else
                    {
                        Projectile.NewProjectile(npc.GetSource_FromThis(), npc.Center, Vector2.Normalize(npc.velocity), ModContent.ProjectileType <BloodScythe>(), FargoSoulsUtil.ScaledProjectileDamage(npc.damage), 1f, Main.myPlayer);
                    }
                }
                ScytheSpawnTimer--;
            }

            if (npc.ai[0] == 0f && npc.ai[1] == 2f && npc.ai[2] == 0f)
            {
                ScytheSpawnTimer = 30;
            }

            if (npc.ai[1] == 3f && !IsInFinalPhase) //during dashes in phase 2
            {
                if (FargoSoulsWorld.MasochistModeReal)
                {
                    ScytheSpawnTimer = 30;
                    SpawnServants();
                }

                if (!ScytheRingIsOnCD)
                {
                    ScytheRingIsOnCD = true;
                    if (Main.netMode != NetmodeID.MultiplayerClient)
                    {
                        FargoSoulsUtil.XWay(8, npc.GetSource_FromThis(), npc.Center, ModContent.ProjectileType <BloodScythe>(), 1.5f, FargoSoulsUtil.ScaledProjectileDamage(npc.damage), 0);
                    }
                }
            }
            else
            {
                ScytheRingIsOnCD = false; //hacky fix for scythe spam during p2 transition
            }

            if (npc.life < npc.lifeMax / 2)
            {
                if (IsInFinalPhase) //final phase
                {
                    const float speedModifier = 0.3f;

                    if (npc.HasValidTarget && !Main.dayTime)
                    {
                        if (npc.timeLeft < 300)
                        {
                            npc.timeLeft = 300;
                        }
                    }
                    else //despawn and retarget
                    {
                        npc.TargetClosest(false);
                        npc.velocity.X *= 0.98f;
                        npc.velocity.Y -= npc.velocity.Y > 0 ? 1f : 0.25f;

                        if (npc.timeLeft > 30)
                        {
                            npc.timeLeft = 30;
                        }

                        AITimer          = 90;
                        FinalPhaseDashCD = 0;
                        FinalPhaseBerserkDashesComplete = true;
                        FinalPhaseDashHorizSpeedSet     = false;
                        FinalPhaseAttackCounter         = 0;

                        npc.alpha = 0;

                        const float PI = (float)Math.PI;
                        if (npc.rotation > PI)
                        {
                            npc.rotation -= 2 * PI;
                        }
                        if (npc.rotation < -PI)
                        {
                            npc.rotation += 2 * PI;
                        }

                        float targetRotation = npc.DirectionTo(Main.player[npc.target].Center).ToRotation() - PI / 2;
                        if (targetRotation > PI)
                        {
                            targetRotation -= 2 * PI;
                        }
                        if (targetRotation < -PI)
                        {
                            targetRotation += 2 * PI;
                        }
                        npc.rotation = MathHelper.Lerp(npc.rotation, targetRotation, 0.07f);
                    }

                    if (++AITimer == 1) //teleport to random position
                    {
                        if (Main.netMode != NetmodeID.MultiplayerClient)
                        {
                            npc.Center      = Main.player[npc.target].Center;
                            npc.position.X += Main.rand.NextBool() ? -600 : 600;
                            npc.position.Y += Main.rand.NextBool() ? -400 : 400;
                            npc.TargetClosest(false);
                            npc.netUpdate = true;
                            NetSync(npc);
                        }
                    }
                    else if (AITimer < 90) //fade in, moving into position
                    {
                        npc.alpha -= FargoSoulsWorld.MasochistModeReal ? 5 : 4;
                        if (npc.alpha < 0)
                        {
                            npc.alpha = 0;
                            if (FargoSoulsWorld.MasochistModeReal && AITimer < 90)
                            {
                                AITimer = 90;
                            }
                        }

                        const float PI = (float)Math.PI;
                        if (npc.rotation > PI)
                        {
                            npc.rotation -= 2 * PI;
                        }
                        if (npc.rotation < -PI)
                        {
                            npc.rotation += 2 * PI;
                        }

                        float targetRotation = npc.DirectionTo(Main.player[npc.target].Center).ToRotation() - PI / 2;
                        if (targetRotation > PI)
                        {
                            targetRotation -= 2 * PI;
                        }
                        if (targetRotation < -PI)
                        {
                            targetRotation += 2 * PI;
                        }
                        npc.rotation = MathHelper.Lerp(npc.rotation, targetRotation, 0.07f);

                        for (int i = 0; i < 3; i++)
                        {
                            int d = Dust.NewDust(npc.position, npc.width, npc.height, 229, 0f, 0f, 0, default(Color), 1.5f);
                            Main.dust[d].noGravity = true;
                            Main.dust[d].noLight   = true;
                            Main.dust[d].velocity *= 4f;
                        }

                        Vector2 target = Main.player[npc.target].Center;
                        target.X += npc.Center.X < target.X ? -600 : 600;
                        target.Y += npc.Center.Y < target.Y ? -400 : 400;

                        if (npc.Center.X < target.X)
                        {
                            npc.velocity.X += speedModifier;
                            if (npc.velocity.X < 0)
                            {
                                npc.velocity.X += speedModifier * 2;
                            }
                        }
                        else
                        {
                            npc.velocity.X -= speedModifier;
                            if (npc.velocity.X > 0)
                            {
                                npc.velocity.X -= speedModifier * 2;
                            }
                        }
                        if (npc.Center.Y < target.Y)
                        {
                            npc.velocity.Y += speedModifier;
                            if (npc.velocity.Y < 0)
                            {
                                npc.velocity.Y += speedModifier * 2;
                            }
                        }
                        else
                        {
                            npc.velocity.Y -= speedModifier;
                            if (npc.velocity.Y > 0)
                            {
                                npc.velocity.Y -= speedModifier * 2;
                            }
                        }
                        if (Math.Abs(npc.velocity.X) > 24)
                        {
                            npc.velocity.X = 24 * Math.Sign(npc.velocity.X);
                        }
                        if (Math.Abs(npc.velocity.Y) > 24)
                        {
                            npc.velocity.Y = 24 * Math.Sign(npc.velocity.Y);
                        }
                    }
                    else if (!FinalPhaseBerserkDashesComplete) //berserk dashing phase
                    {
                        AITimer = 90;

                        const float xSpeed = 18f;
                        const float ySpeed = 40f;

                        if (++FinalPhaseDashCD == 1)
                        {
                            SoundEngine.PlaySound(SoundID.ForceRoarPitched, Main.player[npc.target].Center);

                            if (!FinalPhaseDashHorizSpeedSet) //only set this on the first dash of each set
                            {
                                FinalPhaseDashHorizSpeedSet = true;
                                npc.velocity.X = npc.Center.X < Main.player[npc.target].Center.X ? xSpeed : -xSpeed;
                            }

                            npc.velocity.Y = npc.Center.Y < Main.player[npc.target].Center.Y ? ySpeed : -ySpeed; //alternate this every dash

                            ScytheSpawnTimer = 30;
                            if (FargoSoulsWorld.MasochistModeReal)
                            {
                                SpawnServants();
                            }
                            if (Main.netMode != NetmodeID.MultiplayerClient)
                            {
                                FargoSoulsUtil.XWay(8, npc.GetSource_FromThis(), npc.Center, ModContent.ProjectileType <BloodScythe>(), 1f, FargoSoulsUtil.ScaledProjectileDamage(npc.damage), 0);
                            }

                            npc.netUpdate = true;
                        }
                        else if (FinalPhaseDashCD > 20)
                        {
                            FinalPhaseDashCD = 0;
                        }

                        if (++FinalPhaseDashStageDuration > 600 * 3 / xSpeed + 5) //proceed
                        {
                            ScytheSpawnTimer                = 0;
                            FinalPhaseDashStageDuration     = 0;
                            FinalPhaseBerserkDashesComplete = true;
                            if (!FargoSoulsWorld.MasochistModeReal)
                            {
                                FinalPhaseAttackCounter++;
                            }
                            npc.velocity *= 0.75f;
                            npc.netUpdate = true;
                        }

                        const float PI = (float)Math.PI;
                        npc.rotation = npc.velocity.ToRotation() - PI / 2;
                        if (npc.rotation > PI)
                        {
                            npc.rotation -= 2 * PI;
                        }
                        if (npc.rotation < -PI)
                        {
                            npc.rotation += 2 * PI;
                        }
                    }
                    else
                    {
                        bool mustRest = FinalPhaseAttackCounter >= 5;

                        const int restingTime = 240;

                        int threshold = 180;
                        if (mustRest)
                        {
                            threshold += restingTime;
                        }

                        if (mustRest && AITimer < restingTime + 90)
                        {
                            if (AITimer == 91)
                            {
                                npc.velocity = npc.DirectionTo(Main.player[npc.target].Center) * npc.velocity.Length() * 0.75f;
                            }

                            npc.velocity.X *= 0.98f;
                            if (Math.Abs(npc.Center.X - Main.player[npc.target].Center.X) < 300)
                            {
                                npc.velocity.X *= 0.9f;
                            }

                            bool floatUp = Collision.SolidCollision(npc.position, npc.width, npc.height);
                            if (!floatUp && npc.Bottom.X > 0 && npc.Bottom.X < Main.maxTilesX * 16 && npc.Bottom.Y > 0 && npc.Bottom.Y < Main.maxTilesY * 16)
                            {
                                Tile tile = Framing.GetTileSafely(npc.Bottom);
                                if (tile != null && tile.HasUnactuatedTile)
                                {
                                    floatUp = Main.tileSolid[tile.TileType];
                                }
                            }

                            if (floatUp)
                            {
                                npc.velocity.X *= 0.95f;

                                npc.velocity.Y -= speedModifier;
                                if (npc.velocity.Y > 0)
                                {
                                    npc.velocity.Y = 0;
                                }
                                if (Math.Abs(npc.velocity.Y) > 24)
                                {
                                    npc.velocity.Y = 24 * Math.Sign(npc.velocity.Y);
                                }
                            }
                            else
                            {
                                npc.velocity.Y += speedModifier;
                                if (npc.velocity.Y < 0)
                                {
                                    npc.velocity.Y += speedModifier * 2;
                                }
                                if (npc.velocity.Y > 15)
                                {
                                    npc.velocity.Y = 15;
                                }
                            }
                        }
                        else
                        {
                            npc.alpha += FargoSoulsWorld.MasochistModeReal ? 16 : 4;
                            if (npc.alpha > 255)
                            {
                                npc.alpha = 255;
                                if (FargoSoulsWorld.MasochistModeReal && AITimer < threshold)
                                {
                                    AITimer = threshold;
                                }
                            }

                            if (mustRest)
                            {
                                npc.velocity.Y -= speedModifier * 0.5f;
                                if (npc.velocity.Y > 0)
                                {
                                    npc.velocity.Y = 0;
                                }
                                if (Math.Abs(npc.velocity.Y) > 24)
                                {
                                    npc.velocity.Y = 24 * Math.Sign(npc.velocity.Y);
                                }
                            }
                            else
                            {
                                npc.velocity *= 0.98f;
                            }
                        }

                        const float PI             = (float)Math.PI;
                        float       targetRotation = MathHelper.WrapAngle(npc.DirectionTo(Main.player[npc.target].Center).ToRotation() - PI / 2);
                        npc.rotation = MathHelper.WrapAngle(MathHelper.Lerp(npc.rotation, targetRotation, 0.07f));

                        if (npc.alpha > 0)
                        {
                            for (int i = 0; i < 3; i++)
                            {
                                int d = Dust.NewDust(npc.position, npc.width, npc.height, 229, 0f, 0f, 0, default(Color), 1.5f);
                                Main.dust[d].noGravity = true;
                                Main.dust[d].noLight   = true;
                                Main.dust[d].velocity *= 4f;
                            }
                        }

                        if (AITimer > threshold) //reset
                        {
                            AITimer          = 0;
                            FinalPhaseDashCD = 0;
                            FinalPhaseBerserkDashesComplete = false;
                            FinalPhaseDashHorizSpeedSet     = false;
                            if (mustRest)
                            {
                                FinalPhaseAttackCounter = 0;
                            }
                            npc.velocity  = Vector2.Zero;
                            npc.netUpdate = true;
                        }
                    }

                    if (npc.netUpdate)
                    {
                        if (Main.netMode == NetmodeID.Server)
                        {
                            NetMessage.SendData(MessageID.SyncNPC, -1, -1, null, npc.whoAmI);
                            NetSync(npc);
                        }
                        npc.netUpdate = false;
                    }
                    return(false);
                }
                else if (!IsInFinalPhase && npc.life <= npc.lifeMax * 0.1) //go into final phase
                {
                    npc.velocity *= 0.98f;
                    npc.alpha    += 4;
                    for (int i = 0; i < 3; i++)
                    {
                        int d = Dust.NewDust(npc.position, npc.width, npc.height, 229, 0f, 0f, 0, default(Color), 1.5f);
                        Main.dust[d].noGravity = true;
                        Main.dust[d].noLight   = true;
                        Main.dust[d].velocity *= 4f;
                    }
                    if (npc.alpha > 255)
                    {
                        npc.alpha      = 255;
                        IsInFinalPhase = true;

                        SoundEngine.PlaySound(SoundID.Roar, npc.HasValidTarget ? Main.player[npc.target].Center : npc.Center);

                        if (Main.netMode != NetmodeID.MultiplayerClient)
                        {
                            Projectile.NewProjectile(npc.GetSource_FromThis(), npc.Center, Vector2.Zero, ModContent.ProjectileType <GlowRing>(), 0, 0f, Main.myPlayer, npc.whoAmI, npc.type);
                        }
                    }
                    return(false);
                }
                else if (npc.ai[0] == 3 && (npc.ai[1] == 0 || npc.ai[1] == 5))
                {
                    if (npc.ai[2] < 2)
                    {
                        npc.ai[2]--;
                        npc.alpha += 4;
                        for (int i = 0; i < 3; i++)
                        {
                            int d = Dust.NewDust(npc.position, npc.width, npc.height, 229, 0f, 0f, 0, default(Color), 1.5f);
                            Main.dust[d].noGravity = true;
                            Main.dust[d].noLight   = true;
                            Main.dust[d].velocity *= 4f;
                        }
                        if (npc.alpha > 255)
                        {
                            npc.alpha = 255;
                            if (Main.netMode != NetmodeID.MultiplayerClient && npc.HasPlayerTarget)
                            {
                                npc.ai[2] = 60;
                                npc.ai[1] = 5f;

                                Vector2 distance = Main.player[npc.target].Center - npc.Center;
                                if (Math.Abs(distance.X) > 1200)
                                {
                                    distance.X = 1200 * Math.Sign(distance.X);
                                }
                                else if (Math.Abs(distance.X) < 600)
                                {
                                    distance.X = 600 * Math.Sign(distance.X);
                                }
                                if (distance.Y > 0) //always ensure eoc teleports above player
                                {
                                    distance.Y *= -1;
                                }
                                if (Math.Abs(distance.Y) > 450)
                                {
                                    distance.Y = 450 * Math.Sign(distance.Y);
                                }
                                if (Math.Abs(distance.Y) < 150)
                                {
                                    distance.Y = 150 * Math.Sign(distance.Y);
                                }
                                npc.Center = Main.player[npc.target].Center + distance;

                                npc.netUpdate = true;
                            }
                        }
                    }
                    else
                    {
                        npc.alpha -= 4;
                        if (npc.alpha < 0)
                        {
                            npc.alpha = 0;
                        }
                        else
                        {
                            npc.ai[2]--;
                            npc.position -= npc.velocity / 2;
                            for (int i = 0; i < 3; i++)
                            {
                                int d = Dust.NewDust(npc.position, npc.width, npc.height, 229, 0f, 0f, 0, default(Color), 1.5f);
                                Main.dust[d].noGravity = true;
                                Main.dust[d].noLight   = true;
                                Main.dust[d].velocity *= 4f;
                            }
                        }
                    }
                }

                /*if (++Timer > 600)
                 * {
                 *  Timer = 0;
                 *  if (npc.HasValidTarget)
                 *  {
                 *      Player player = Main.player[npc.target];
                 *      SoundEngine.PlaySound(SoundID.Item9104, player.Center);
                 *      if (Main.netMode != NetmodeID.MultiplayerClient)
                 *      {
                 *          Vector2 spawnPos = player.Center;
                 *          int direction;
                 *          if (player.velocity.X == 0f)
                 *              direction = player.direction;
                 *          else
                 *              direction = Math.Sign(player.velocity.X);
                 *          spawnPos.X += 600 * direction;
                 *          spawnPos.Y -= 600;
                 *          Vector2 speed = Vector2.UnitY;
                 *          for (int i = 0; i < 30; i++)
                 *          {
                 *              Projectile.NewProjectile(npc.GetSource_FromThis(), spawnPos, speed, ModContent.ProjectileType<BloodScythe>(), FargoSoulsUtil.ScaledProjectileDamage(npc.damage), 1f, Main.myPlayer);
                 *              spawnPos.X += 72 * direction;
                 *              speed.Y += 0.15f;
                 *          }
                 *      }
                 *  }
                 * }*/
            }
            else
            {
                npc.alpha          = 0;
                npc.dontTakeDamage = false;
            }

            // Drop summon
            EModeUtils.DropSummon(npc, "SuspiciousEye", NPC.downedBoss1, ref DroppedSummon);

            return(true);
        }