public override bool PreAI(NPC npc) { EModeGlobalNPC.brainBoss = npc.whoAmI; if (FargoSoulsWorld.SwarmActive) { return(base.PreAI(npc)); } if (!npc.HasValidTarget || npc.Distance(Main.player[npc.target].Center) > 3000) { npc.velocity.Y += 0.75f; if (npc.timeLeft > 120) { npc.timeLeft = 120; } } if (npc.alpha > 0 && (npc.ai[0] == 2 || npc.ai[0] == -3) && npc.HasValidTarget) //stay at a minimum distance { const float safeRange = 360; /*Vector2 stayAwayFromHere = Main.player[npc.target].Center + Main.player[npc.target].velocity * 30f; * if (npc.Distance(stayAwayFromHere) < safeRange) * npc.Center = stayAwayFromHere + npc.DirectionFrom(stayAwayFromHere) * safeRange;*/ Vector2 stayAwayFromHere = Main.player[npc.target].Center; if (npc.Distance(stayAwayFromHere) < safeRange) { npc.Center = stayAwayFromHere + npc.DirectionFrom(stayAwayFromHere) * safeRange; } } if (EnteredPhase2) { if (npc.buffType[0] != 0) //constant debuff cleanse { npc.buffImmune[npc.buffType[0]] = true; npc.DelBuff(0); } void TelegraphConfusion(Vector2 spawn) { Projectile.NewProjectile(npc.GetSource_FromThis(), spawn, Vector2.Zero, ModContent.ProjectileType <GlowRingHollow>(), 0, 0f, Main.myPlayer, 8, 180); Projectile.NewProjectile(npc.GetSource_FromThis(), spawn, Vector2.Zero, ModContent.ProjectileType <GlowRingHollow>(), 0, 0f, Main.myPlayer, 8, 200); Projectile.NewProjectile(npc.GetSource_FromThis(), spawn, Vector2.Zero, ModContent.ProjectileType <GlowRingHollow>(), 0, 0f, Main.myPlayer, 8, 220); }; void LaserSpread(Vector2 spawn) { if (npc.HasValidTarget && Main.netMode != NetmodeID.MultiplayerClient) //laser spreads from each illusion { int max = FargoSoulsWorld.MasochistModeReal ? 7 : 3; int degree = FargoSoulsWorld.MasochistModeReal ? 2 : 3; int laserDamage = FargoSoulsUtil.ScaledProjectileDamage(npc.damage, 4f / 3); Projectile.NewProjectile(npc.GetSource_FromThis(), spawn, new Vector2(0, -4), ModContent.ProjectileType <BrainofConfusion>(), 0, 0, Main.myPlayer); for (int i = -max; i <= max; i++) { Projectile.NewProjectile(npc.GetSource_FromThis(), spawn, 0.2f * Main.player[npc.target].DirectionFrom(spawn).RotatedBy(MathHelper.ToRadians(degree) * i), ModContent.ProjectileType <DestroyerLaser>(), laserDamage, 0f, Main.myPlayer); } } }; int confusionThreshold = FargoSoulsWorld.MasochistModeReal ? 240 : 300; if (--ConfusionTimer < 0) { ConfusionTimer = confusionThreshold; if (Main.player[npc.target].HasBuff(BuffID.Confused)) { SoundEngine.PlaySound(SoundID.ForceRoarPitched, npc.Center); TelegraphConfusion(npc.Center); IllusionTimer = 120 + 90; if (Main.netMode != NetmodeID.MultiplayerClient) { int type = ModContent.ProjectileType <BrainIllusionProj>(); //make illusions attack int alpha = (int)(255f * npc.life / npc.lifeMax); void SpawnClone(Vector2 center) { int n = NPC.NewNPC(npc.GetSource_FromAI(), (int)center.X, (int)center.Y, ModContent.NPCType <BrainIllusionAttack>(), npc.whoAmI, npc.whoAmI, alpha); if (n != Main.maxNPCs) { NetMessage.SendData(MessageID.SyncNPC, -1, -1, null, n); } } foreach (Projectile p in Main.projectile.Where(p => p.active && p.type == type && p.ai[0] == npc.whoAmI && p.ai[1] == 0f)) { if (p.Distance(Main.player[npc.target].Center) < 1000) { //p.ai[1] = 1f; //p.netUpdate = true; SpawnClone(p.Center); } p.Kill(); } Vector2 offset = npc.Center - Main.player[npc.target].Center; Vector2 spawnPos = Main.player[npc.target].Center; SpawnClone(new Vector2(spawnPos.X + offset.X, spawnPos.Y + offset.Y)); SpawnClone(new Vector2(spawnPos.X + offset.X, spawnPos.Y - offset.Y)); SpawnClone(new Vector2(spawnPos.X - offset.X, spawnPos.Y + offset.Y)); SpawnClone(new Vector2(spawnPos.X - offset.X, spawnPos.Y - offset.Y)); } } else { SoundEngine.PlaySound(SoundID.Roar, npc.Center); Vector2 offset = npc.Center - Main.player[npc.target].Center; Vector2 spawnPos = Main.player[npc.target].Center; TelegraphConfusion(new Vector2(spawnPos.X + offset.X, spawnPos.Y + offset.Y)); TelegraphConfusion(new Vector2(spawnPos.X + offset.X, spawnPos.Y - offset.Y)); TelegraphConfusion(new Vector2(spawnPos.X - offset.X, spawnPos.Y + offset.Y)); TelegraphConfusion(new Vector2(spawnPos.X - offset.X, spawnPos.Y - offset.Y)); } npc.netUpdate = true; NetSync(npc); } else if (ConfusionTimer == confusionThreshold - 60) { //npc.netUpdate = true; //disabled because might be causing mp issues??? //NetSync(npc); if (!Main.player[npc.target].HasBuff(BuffID.Confused)) { Vector2 offset = npc.Center - Main.player[npc.target].Center; Vector2 spawnPos = Main.player[npc.target].Center; LaserSpread(new Vector2(spawnPos.X + offset.X, spawnPos.Y + offset.Y)); LaserSpread(new Vector2(spawnPos.X + offset.X, spawnPos.Y - offset.Y)); LaserSpread(new Vector2(spawnPos.X - offset.X, spawnPos.Y + offset.Y)); LaserSpread(new Vector2(spawnPos.X - offset.X, spawnPos.Y - offset.Y)); } if (npc.Distance(Main.LocalPlayer.Center) < 3000 && !Main.LocalPlayer.HasBuff(BuffID.Confused)) //inflict confusion { FargoSoulsUtil.AddDebuffFixedDuration(Main.LocalPlayer, BuffID.Confused, confusionThreshold + 5); } } if (--IllusionTimer < 0) //spawn illusions { IllusionTimer = Main.rand.Next(5, 11); if (npc.life > npc.lifeMax / 2) { IllusionTimer += 5; } if (npc.life < npc.lifeMax / 10) { IllusionTimer -= 2; } if (FargoSoulsWorld.MasochistModeReal) { IllusionTimer -= 2; } if (Main.netMode != NetmodeID.MultiplayerClient) { Vector2 spawn = Main.player[npc.target].Center + Main.rand.NextVector2CircularEdge(1200f, 1200f); Vector2 speed = Main.player[npc.target].Center + Main.player[npc.target].velocity * 45f + Main.rand.NextVector2Circular(-600f, 600f) - spawn; speed = Vector2.Normalize(speed) * Main.rand.NextFloat(12f, 48f); Projectile.NewProjectile(npc.GetSource_FromThis(), spawn, speed, ModContent.ProjectileType <BrainIllusionProj>(), FargoSoulsUtil.ScaledProjectileDamage(npc.damage, 4f / 3), 0f, Main.myPlayer, npc.whoAmI); } } if (IllusionTimer > 60) { if (npc.ai[0] == -1f && npc.localAI[1] < 80) //force a tp { npc.localAI[1] = 80f; } if (npc.ai[0] == -3f && npc.ai[3] > 200) //stay invis { npc.dontTakeDamage = true; npc.ai[0] = -3f; npc.ai[3] = 255; npc.alpha = 255; return(false); } } } else if (!npc.dontTakeDamage) { EnteredPhase2 = true; if (Main.netMode != NetmodeID.MultiplayerClient) //spawn illusions { bool recolor = SoulConfig.Instance.BossRecolors && FargoSoulsWorld.EternityMode; int type = recolor ? ModContent.NPCType <BrainIllusion2>() : ModContent.NPCType <BrainIllusion>(); FargoSoulsUtil.NewNPCEasy(npc.GetSource_FromAI(), npc.Center, type, npc.whoAmI, npc.whoAmI, -1, 1); FargoSoulsUtil.NewNPCEasy(npc.GetSource_FromAI(), npc.Center, type, npc.whoAmI, npc.whoAmI, 1, -1); FargoSoulsUtil.NewNPCEasy(npc.GetSource_FromAI(), npc.Center, type, npc.whoAmI, npc.whoAmI, 1, 1); FargoSoulsUtil.NewNPCEasy(npc.GetSource_FromAI(), npc.Center, ModContent.NPCType <BrainClone>(), npc.whoAmI); for (int i = 0; i < Main.maxProjectiles; i++) //clear old golden showers { if (Main.projectile[i].active && Main.projectile[i].type == ModContent.ProjectileType <GoldenShowerHoming>()) { Main.projectile[i].Kill(); } } } } EModeUtils.DropSummon(npc, "GoreySpine", NPC.downedBoss2, ref DroppedSummon); npc.defense = 0; npc.defDefense = 0; return(base.PreAI(npc)); }
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); }