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) { EModeGlobalNPC.empressBoss = npc.whoAmI; if (FargoSoulsWorld.SwarmActive) { return(base.PreAI(npc)); } if (Main.LocalPlayer.active && !Main.LocalPlayer.dead && !Main.LocalPlayer.ghost) { Main.LocalPlayer.AddBuff(ModContent.BuffType <Purged>(), 2); } bool useP2Attacks = npc.ai[3] != 0 || FargoSoulsWorld.MasochistModeReal; switch ((int)npc.ai[0]) { //0 spawn case 1: //move over player if (npc.ai[1] == 0) { AttackTimer = 0; AttackCounter++; NetSync(npc); } break; case 2: //homing bolts, ends at ai1=130 if (useP2Attacks && npc.ai[1] > 80 && !FargoSoulsWorld.MasochistModeReal) { npc.ai[1] -= 0.5f; //p2, more delay before next attack } break; case 4: //pseudorandom swords following you, ends at ai1=100 { if (npc.ai[1] == 0) { AttackTimer = 0; NetSync(npc); TryRandom(npc); } const int specialAttackThreshold = 97; if (npc.ai[1] > specialAttackThreshold && useP2Attacks) //p2 only sword circle { SwordCircle(npc, specialAttackThreshold); } } break; case 5: //stupid long trail circle ring if (AttackTimer < 2) { if (npc.ai[1] > 1f) { npc.ai[1] -= 0.5f; //progress slower } if (npc.ai[1] == 30) //repeat attack { npc.ai[1] = 0f; AttackTimer++; } } //p2, do sword rings if (useP2Attacks && AttackTimer >= 2) { if (npc.ai[1] == 20) { startRotation = Main.rand.NextFloat(MathHelper.TwoPi); } if (npc.ai[1] >= (FargoSoulsWorld.MasochistModeReal ? 20 : 35) && npc.ai[1] <= 60) { npc.position -= npc.velocity; npc.velocity = Vector2.Zero; if (npc.ai[1] % 5 == 0) { for (float i = 0; i < 1; i += 1f / 24f) { Vector2 spinningpoint = Vector2.UnitY.RotatedBy(MathHelper.PiOver2 + MathHelper.TwoPi * i + startRotation); if (Main.netMode != NetmodeID.MultiplayerClient) { Projectile.NewProjectile(npc.GetSource_FromThis(), npc.Center + spinningpoint.RotatedBy(-MathHelper.PiOver2) * 30f, Vector2.Zero, ProjectileID.FairyQueenLance, FargoSoulsUtil.ScaledProjectileDamage(BaseProjDmg(npc), 1.3f), 0f, Main.myPlayer, spinningpoint.ToRotation(), i); } } } } } break; case 6: //sun rays if (!FargoSoulsWorld.MasochistModeReal) { if (npc.ai[1] == 0 && AttackTimer == 0 && Main.projectile.Count(p => p.active && p.type == ProjectileID.HallowBossRainbowStreak) > 20) { npc.ai[1] -= 30; npc.netUpdate = true; } if (npc.ai[1] == 1) { NetSync(npc); } npc.position -= npc.velocity / (npc.ai[3] == 0 ? 2 : 4); //move slower } break; case 7: //sword walls, ends at ai1=260 { int start = FargoSoulsWorld.MasochistModeReal ? -15 : -45; if (npc.ai[1] == 0) { TryRandom(npc); npc.netUpdate = true; NetSync(npc); //sync it in advance to prepare for actual attacks } const int specialAttackThreshold = 255; if (npc.ai[1] == specialAttackThreshold) { AttackTimer = start; P2SwordsAttackCounter++; startRotation = Main.rand.NextFloat(MathHelper.TwoPi); } if (npc.ai[1] > specialAttackThreshold) { if (DoParallelSwordWalls) { ParallelSwordWalls(npc, specialAttackThreshold); } else //excel spreadsheet { ExcelSpreadsheet(npc, specialAttackThreshold); } } } break; case 8: //dash from right to left case 9: //dash from left to right Dash(npc, useP2Attacks); break; case 10: //p2 transition if (npc.dontTakeDamage && npc.ai[1] > 120) { Vector2 target = Main.player[npc.target].Center - 160f * Vector2.UnitY; npc.Center = Vector2.Lerp(npc.Center, target, 0.1f); if (npc.life < npc.lifeMax / 2) { npc.HealEffect(npc.lifeMax / 2 - npc.life); npc.life = npc.lifeMax / 2; } } break; case 11: //p2 direct sword trail if ((FargoSoulsWorld.MasochistModeReal || npc.ai[1] > 40) && npc.ai[1] % 3 == 0 && npc.HasValidTarget) //add perpendicular swords { Vector2 offset = Main.player[npc.target].velocity; if (offset == Vector2.Zero || offset.Length() < 1) { offset = offset.SafeNormalize(-Vector2.UnitY); } offset = 90f * offset.RotatedBy(MathHelper.PiOver2); Vector2 spawnPos = Main.player[npc.target].Center + offset; Vector2 vel = Main.player[npc.target].DirectionFrom(spawnPos); if (Main.netMode != NetmodeID.MultiplayerClient) { Projectile.NewProjectile(npc.GetSource_FromThis(), spawnPos, Vector2.Zero, ProjectileID.FairyQueenLance, FargoSoulsUtil.ScaledProjectileDamage(BaseProjDmg(npc), 1.3f), 0f, Main.myPlayer, vel.ToRotation(), npc.ai[1] / 100f); } } break; case 12: //8-way homing bolts { const int max = 24; const int delay = 75; if (npc.ai[1] < 4) { Vector2 target = Main.player[npc.target].Center - 160f * Vector2.UnitY; npc.Center = Vector2.Lerp(npc.Center, target, 0.1f); if (npc.Distance(target) > 160) { npc.ai[1] -= 1f; } } if (npc.ai[1] == delay) { startRotation = npc.HasValidTarget ? npc.DirectionTo(Main.player[npc.target].Center).ToRotation() : MathHelper.PiOver2; } if (npc.ai[1] >= delay && npc.ai[1] < delay + max) { if (Main.netMode != NetmodeID.MultiplayerClient) { float ai1 = (npc.ai[1] - delay) / max; if (FargoSoulsWorld.MasochistModeReal) { float math = MathHelper.TwoPi / max * (npc.ai[1] - delay); Vector2 boltVel = -Vector2.UnitY.RotatedBy(-math); Projectile.NewProjectile(npc.GetSource_FromThis(), npc.Center, 20f * boltVel, ProjectileID.HallowBossRainbowStreak, FargoSoulsUtil.ScaledProjectileDamage(BaseProjDmg(npc), 1.3f), 0f, Main.myPlayer, npc.target, ai1); } float spread = MathHelper.ToRadians(24); float swordRotation = startRotation + MathHelper.Lerp(-spread, spread, ai1); Vector2 appearVel = swordRotation.ToRotationVector2(); Projectile.NewProjectile(npc.GetSource_FromThis(), npc.Center + appearVel * 160f + appearVel * 10f * 60f, -appearVel * 10f, ProjectileID.FairyQueenLance, FargoSoulsUtil.ScaledProjectileDamage(BaseProjDmg(npc), 1.3f), 0f, Main.myPlayer, swordRotation, ai1); } } if (npc.ai[1] > delay + max && !FargoSoulsWorld.MasochistModeReal) { npc.ai[1] -= 0.65f; //more delay before next attack } } break; default: break; } EModeUtils.DropSummon(npc, "PrismaticPrimrose", NPC.downedEmpressOfLight, ref DroppedSummon, Main.hardMode); return(true); }
public override bool PreAI(NPC npc) { bool result = base.PreAI(npc); EModeGlobalNPC.skeleBoss = npc.whoAmI; if (FargoSoulsWorld.SwarmActive) { return(result); } if (!SpawnedArms && npc.life < npc.lifeMax * .25) { SpawnedArms = true; FargoSoulsUtil.NewNPCEasy(npc.GetSource_FromAI(), npc.Center, NPCID.SkeletronHand, npc.whoAmI, 1f, npc.whoAmI, 0f, 0f, npc.target); FargoSoulsUtil.NewNPCEasy(npc.GetSource_FromAI(), npc.Center, NPCID.SkeletronHand, npc.whoAmI, -1f, npc.whoAmI, 0f, 0f, npc.target); string text = Language.GetTextValue($"Mods.{mod.Name}.Message.SkeletronRegrow"); FargoSoulsUtil.PrintLocalization($"{npc.FullName} {text}", new Color(175, 75, 255)); } if (npc.ai[1] == 0f) { if (npc.ai[2] == 800 - 90) //telegraph spin { if (Main.netMode != NetmodeID.MultiplayerClient) { Projectile.NewProjectile(npc.GetSource_FromThis(), npc.Center, Vector2.Zero, ModContent.ProjectileType <TargetingReticle>(), 0, 0f, Main.myPlayer, npc.whoAmI, npc.type); } } if (npc.ai[2] < 800 - 5) { ReticleTarget = npc.target; } } if (npc.ai[1] == 1f || npc.ai[1] == 2f) //spinning or DG mode { //force targeted player back to the one i telegraphed with reticle (otherwise, may target another player when spin starts) if (ReticleTarget > -1 && ReticleTarget < Main.maxPlayers) { npc.target = ReticleTarget; ReticleTarget = -1; npc.netUpdate = true; NetSync(npc); if (!npc.HasValidTarget) { npc.TargetClosest(false); } if (npc.ai[1] == 1) //do cross guardian attack { if (!FargoSoulsWorld.MasochistModeReal) { for (int i = 0; i < Main.maxProjectiles; i++) //also clear leftover babies { if (Main.projectile[i].active && Main.projectile[i].hostile && Main.projectile[i].type == ModContent.ProjectileType <SkeletronGuardian2>()) { Main.projectile[i].Kill(); } } } if ((npc.life >= npc.lifeMax * .75 || FargoSoulsWorld.MasochistModeReal) && Main.netMode != NetmodeID.MultiplayerClient) { for (int i = 0; i < 4; i++) { for (int j = -2; j <= 2; j++) { Vector2 spawnPos = new Vector2(1200, 80 * j); Vector2 vel = -8 * Vector2.UnitX; spawnPos = Main.player[npc.target].Center + spawnPos.RotatedBy(Math.PI / 2 * (i + 0.5)); vel = vel.RotatedBy(Math.PI / 2 * (i + 0.5)); int p = Projectile.NewProjectile(npc.GetSource_FromThis(), spawnPos, vel, ModContent.ProjectileType <Projectiles.Champions.ShadowGuardian>(), FargoSoulsUtil.ScaledProjectileDamage(npc.damage), 0f, Main.myPlayer); if (p != Main.maxProjectiles) { Main.projectile[p].timeLeft = 1200 / 8 + 1; } } } } } } float ratio = (float)npc.life / npc.lifeMax; float cooldown = 20f; if (!FargoSoulsWorld.MasochistModeReal) { cooldown += 100f * ratio; } if (++npc.localAI[2] >= cooldown) //spray bones { npc.localAI[2] = 0f; if (cooldown > 0 && npc.HasPlayerTarget && Main.netMode != NetmodeID.MultiplayerClient) { Vector2 speed = Vector2.Normalize(Main.player[npc.target].Center - npc.Center) * 6f; for (int i = 0; i < 8; i++) { Vector2 vel = speed.RotatedBy(Math.PI * 2 / 8 * i); vel += npc.velocity * (1f - ratio); vel.Y -= Math.Abs(vel.X) * 0.2f; Projectile.NewProjectile(npc.GetSource_FromThis(), npc.Center, vel, ModContent.ProjectileType <SkeletronBone>(), npc.defDamage / 9 * 2, 0f, Main.myPlayer); } } } if (BabyGuardianTimer > 180) { BabyGuardianTimer = 180; } if (npc.life < npc.lifeMax * .75 && npc.ai[1] == 1f && --BabyGuardianTimer < 0) { BabyGuardianTimer = 180; SoundEngine.PlaySound(SoundID.ForceRoarPitched, npc.Center); if (Main.netMode != NetmodeID.MultiplayerClient) //spray of baby guardian missiles { const int max = 30; float modifier = 1f - (float)npc.life / npc.lifeMax; modifier *= 4f / 3f; //scaling maxes at 25% life if (modifier > 1f || FargoSoulsWorld.MasochistModeReal) //cap it, or force it to cap in emode { modifier = 1f; } int actualNumberToSpawn = (int)(max * modifier); for (int i = 0; i < actualNumberToSpawn; i++) { float speed = Main.rand.NextFloat(3f, 9f); Vector2 velocity = speed * npc.DirectionFrom(Main.player[npc.target].Center).RotatedBy(Math.PI * (Main.rand.NextDouble() - 0.5)); float ai1 = speed / (60f + Main.rand.NextFloat(actualNumberToSpawn * 2)); Projectile.NewProjectile(npc.GetSource_FromThis(), npc.Center, velocity, ModContent.ProjectileType <SkeletronGuardian>(), FargoSoulsUtil.ScaledProjectileDamage(npc.damage, 0.8f), 0f, Main.myPlayer, 0f, ai1); } } } } else { if (npc.ai[2] == 0) { //compensate for not changing targets when beginning spin npc.TargetClosest(false); //prevent skeletron from firing his stupid tick 1 no telegraph skull right after finishing spin if (!FargoSoulsWorld.MasochistModeReal) { npc.ai[2] = 1; } } if (npc.life < npc.lifeMax * .75) //phase 2 { if (npc.ai[2] <= 60 && npc.ai[2] % 10 == 0) //vomit skeletons { int[] skeletons = { NPCID.BoneThrowingSkeleton, NPCID.BoneThrowingSkeleton2, NPCID.BoneThrowingSkeleton3, NPCID.BoneThrowingSkeleton4 }; if (Main.npc.Count(n => n.active && skeletons.Contains(n.type)) < 12) { float gravity = 0.4f; //shoot down const float time = 60f; Vector2 distance = Main.player[npc.target].Top - npc.Center + Main.rand.NextVector2Circular(80, 80); distance.X = distance.X / time; distance.Y = distance.Y / time - 0.5f * gravity * time; FargoSoulsUtil.NewNPCEasy( npc.GetSource_FromAI(), npc.Center, Main.rand.Next(skeletons), velocity: distance); SoundEngine.PlaySound(SoundID.NPCDeath13, npc.Center); } } if (--BabyGuardianTimer < 0) { BabyGuardianTimer = FargoSoulsWorld.MasochistModeReal ? 180 : 240; SoundEngine.PlaySound(SoundID.ForceRoarPitched, npc.Center); for (int j = -1; j <= 1; j++) //to both sides { if (j == 0) { continue; } const int gap = 40; const int max = 14; float modifier = 1f - (float)npc.life / npc.lifeMax; modifier *= 4f / 3f; //scaling maxes at 25% life if (modifier > 1f || FargoSoulsWorld.MasochistModeReal) //cap it, or force it to cap in emode { modifier = 1f; } int actualNumberToSpawn = (int)(max * modifier); Vector2 baseVel = npc.DirectionTo(Main.player[npc.target].Center).RotatedBy(MathHelper.ToRadians(gap) * j); for (int k = 0; k < actualNumberToSpawn; k++) //a fan of skulls { if (Main.netMode != NetmodeID.MultiplayerClient) { float velModifier = 1f + 9f * k / max; Projectile.NewProjectile(npc.GetSource_FromThis(), npc.Center, velModifier * baseVel.RotatedBy(MathHelper.ToRadians(10) * j * k), ModContent.ProjectileType <SkeletronGuardian2>(), FargoSoulsUtil.ScaledProjectileDamage(npc.damage, 0.8f), 0f, Main.myPlayer); } } } if (Main.netMode != NetmodeID.MultiplayerClient) //one more shot straight behind skeletron { float velModifier = 10f; Projectile.NewProjectile(npc.GetSource_FromThis(), npc.Center, velModifier * npc.DirectionFrom(Main.player[npc.target].Center), ModContent.ProjectileType <SkeletronGuardian2>(), FargoSoulsUtil.ScaledProjectileDamage(npc.damage, 0.8f), 0f, Main.myPlayer); } } } } if (npc.ai[1] == 2f) { npc.defense = 9999; npc.damage = npc.defDamage * 15; if (!Main.dayTime && !FargoSoulsWorld.MasochistModeReal) { if (++DGSpeedRampup < 120) { npc.position -= npc.velocity * (120 - DGSpeedRampup) / 120; } } } EModeUtils.DropSummon(npc, "SuspiciousSkull", NPC.downedBoss3, ref DroppedSummon); return(result); }
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(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, npc.damage / 4, 0f, Main.myPlayer); } } if (npc.HasValidTarget) { Main.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(spawn, speed, ModContent.ProjectileType <SlimeBallHostile>(), npc.damage / 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.Center, distance + Main.rand.NextVector2Square(-1f, 1f), ModContent.ProjectileType <SlimeSpike>(), npc.damage / 4, 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(spawnPos, (IsBerserk ? 6f : 0f) * Vector2.UnitY, ModContent.ProjectileType <SlimeSpike2>(), npc.damage / 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) * NetMessage.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; * Main.PlaySound(SoundID.Roar, npc.Center, 0); * } * * 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.Center, distance + Main.rand.NextVector2Square(-1f, 1f) * 2f, * ModContent.ProjectileType<SlimeSpike>(), npc.damage / 4, 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) { Main.PlaySound(SoundID.Roar, npc.Center, 0); } 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, ModContent.ItemType <SlimyCrown>(), NPC.downedSlimeKing, ref DroppedSummon); return(true); }
public override bool PreAI(NPC npc) { bool result = base.PreAI(npc); EModeGlobalNPC.moonBoss = npc.whoAmI; if (FargoSoulsWorld.SwarmActive) { return(result); } if (!SpawnedRituals) { SpawnedRituals = true; VulnerabilityState = 0; if (Main.netMode != NetmodeID.MultiplayerClient) { Projectile.NewProjectile(npc.GetSource_FromThis(), npc.Center, Vector2.Zero, ModContent.ProjectileType <LunarRitual>(), 25, 0f, Main.myPlayer, 0f, npc.whoAmI); Projectile.NewProjectile(npc.GetSource_FromThis(), 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(npc.GetSource_FromThis(), 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); 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++) { if (Main.netMode != NetmodeID.MultiplayerClient) { Projectile.NewProjectile(npc.GetSource_FromThis(), 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)); if (Main.netMode != NetmodeID.MultiplayerClient) { Projectile.NewProjectile(npc.GetSource_FromThis(), 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++) { if (Main.netMode != NetmodeID.MultiplayerClient) { int p = Projectile.NewProjectile(npc.GetSource_FromThis(), 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); FargoSoulsUtil.NewNPCEasy(npc.GetSource_FromAI(), bodyPart.Center, NPCID.AncientLight, 0, 0f, (Main.rand.NextFloat() - 0.5f) * 0.3f * 6.28318548202515f / 60f, vel.X, vel.Y, velocity: vel); } } } 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); if (Main.netMode != NetmodeID.MultiplayerClient) { int p = Projectile.NewProjectile(npc.GetSource_FromThis(), npc.Center, vel, type, damage, 0f, Main.myPlayer, rotationModifier, speed); if (p != Main.maxProjectiles) { Main.projectile[p].timeLeft = 1800 - VulnerabilityTimer; } p = Projectile.NewProjectile(npc.GetSource_FromThis(), npc.Center, vel, type, damage, 0f, Main.myPlayer, -rotationModifier, speed); if (p != Main.maxProjectiles) { Main.projectile[p].timeLeft = 1800 - VulnerabilityTimer; } } } SoundEngine.PlaySound(SoundID.Item84, npc.Center); } break; } } } else //only when vulnerable { if (!EnteredPhase2) { EnteredPhase2 = true; AttackTimer = 0; SoundEngine.PlaySound(SoundID.Roar, Main.LocalPlayer.Center); 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(npc.GetSource_FromThis(), 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.GetSource_FromThis(), 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(npc.GetSource_FromThis(), 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(npc.GetSource_FromThis(), 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(npc.GetSource_FromThis(), 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(npc.GetSource_FromThis(), 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.GetSource_FromThis(), 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.GetSource_FromThis(), 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.GetSource_FromThis(), 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) //next vuln phase { VulnerabilityState = ++VulnerabilityState % 5; VulnerabilityTimer = 0; AttackTimer = 0; AttackMemory = 0; npc.netUpdate = true; NetSync(npc); if (FargoSoulsWorld.MasochistModeReal) { switch (VulnerabilityState) { case 0: //melee for (int i = 0; i < 3; i++) { NPC bodyPart = Main.npc[(int)npc.localAI[i]]; if (bodyPart.active && bodyPart.type == NPCID.MoonLordHead) { for (int j = -3; j <= 3; j++) { FargoSoulsUtil.NewNPCEasy(npc.GetSource_FromAI(), bodyPart.Center, NPCID.SolarGoop, target: npc.target, velocity: -10f * Vector2.UnitY.RotatedBy(MathHelper.ToRadians(20 * j))); } } } break; case 1: //ranged if (Main.netMode != NetmodeID.MultiplayerClient) { Projectile.NewProjectile( npc.GetSource_FromThis(), npc.Center, Vector2.Zero, ModContent.ProjectileType <MoonLordVortexOld>(), 40, 0f, Main.myPlayer, 0, npc.whoAmI); } break; case 2: //magic if (Main.netMode != NetmodeID.MultiplayerClient) { for (int i = -1; i <= 1; i++) { int p = Projectile.NewProjectile( npc.GetSource_FromThis(), npc.Center, Vector2.Zero, ModContent.ProjectileType <GlowLine>(), 0, 0f, Main.myPlayer, 17f, npc.whoAmI); if (p != Main.maxProjectiles) { Main.projectile[p].localAI[0] = 950f * i; if (Main.netMode == NetmodeID.Server) { NetMessage.SendData(MessageID.SyncProjectile, number: p); } } } } break; case 3: //summon for (int i = 0; i < 3; i++) { NPC bodyPart = Main.npc[(int)npc.localAI[i]]; if (bodyPart.active) { for (int j = -2; j <= 2; j++) { Vector2 vel = 9f * bodyPart.DirectionTo(Main.player[npc.target].Center).RotatedBy(MathHelper.Pi / 5 * j); FargoSoulsUtil.NewNPCEasy(npc.GetSource_FromAI(), bodyPart.Center, NPCID.AncientLight, 0, 0f, (Main.rand.NextFloat() - 0.5f) * 0.3f * 6.28318548202515f / 60f, vel.X, vel.Y, npc.target, vel); } } } break; default: if (Main.netMode != NetmodeID.MultiplayerClient) { const int max = 8; 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); Projectile.NewProjectile(npc.GetSource_FromThis(), npc.Center, vel, type, damage, 0f, Main.myPlayer, rotationModifier, speed); Projectile.NewProjectile(npc.GetSource_FromThis(), npc.Center, vel, type, damage, 0f, Main.myPlayer, -rotationModifier, speed); } SoundEngine.PlaySound(SoundID.Item84, npc.Center); } break; } } } } //because 1.4 is f*****g stupid and time freeze prevents custom skies from working I HATE 1.4 if (Main.GameModeInfo.IsJourneyMode && CreativePowerManager.Instance.GetPower <CreativePowers.FreezeTime>().Enabled) { CreativePowerManager.Instance.GetPower <CreativePowers.FreezeTime>().SetPowerInfo(false); } if (!Main.dedServ && VulnerabilityTimer % 30 == 0 && NPC.FindFirstNPC(npc.type) == npc.whoAmI) { if (!SkyManager.Instance["FargowiltasSouls:MoonLordSky"].IsActive()) { SkyManager.Instance.Activate("FargowiltasSouls:MoonLordSky"); } void HandleScene(string name) { if (!Filters.Scene[$"FargowiltasSouls:{name}"].IsActive()) { Filters.Scene.Activate($"FargowiltasSouls:{name}"); } } switch (VulnerabilityState) { case 0: HandleScene("Solar"); break; case 1: HandleScene("Vortex"); break; case 2: HandleScene("Nebula"); break; case 3: HandleScene("Stardust"); if (VulnerabilityTimer < 120) //so that player isn't punished for using weapons during prior phase { Main.LocalPlayer.GetModPlayer <EModePlayer>().MasomodeMinionNerfTimer = 0; } break; default: break; } } EModeUtils.DropSummon(npc, "CelestialSigil2", NPC.downedMoonlord, ref DroppedSummon, NPC.downedAncientCultist); return(result); }
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.betsyBoss = npc.whoAmI; if (FargoSoulsWorld.SwarmActive) { return(true); } if (FargoSoulsWorld.MasochistModeReal) { for (int i = 0; i < 3; i++) { Rectangle rectangle = new Rectangle((int)Main.screenPosition.X + Main.screenWidth / 3, (int)Main.screenPosition.Y + Main.screenHeight / 3, Main.screenWidth / 3, Main.screenHeight / 3); CombatText.NewText(rectangle, new Color(100 + Main.rand.Next(150), 100 + Main.rand.Next(150), 100 + Main.rand.Next(150)), Main.rand.Next(new List <string> { "CRINGE", "NOT POGGERS", "MONKAS", "SHOW WINGS", "AERIAL BANE POG", "REAL BOSS WHEN?", "#NOTMYMASOMODE", "OOA BAD ANYWAY", "COPE MALD SEETHE", "GET REAL", "GET FAKE", "POGGERS", "ResidentSleeper", "If you can read this say 22", "GuraSit", "play calamity", "play thorium", "hardcore 1hp challenge when?", "now do it with a copper shortsword", "Zenith Yoyo?", "guys how do i beat moon lord", "GUYS I GOT TERRAPRISMA", "how do i install this update", "Hi YouTube!", "<Message was deleted by staff>", $"<User {Main.rand.Next(10)}{Main.rand.Next(10)}{Main.rand.Next(10)}{Main.rand.Next(10)}{Main.rand.Next(10)} was banned>", $"<User {Main.rand.Next(10)}{Main.rand.Next(10)}{Main.rand.Next(10)}{Main.rand.Next(10)}{Main.rand.Next(10)} was muted>", }), Main.rand.NextBool(), Main.rand.NextBool()); } if (Main.rand.NextBool(30) && npc.HasPlayerTarget) { switch (Main.rand.Next(12)) { case 0: if (!Main.dedServ) { SoundEngine.PlaySound(new SoundStyle("FargowiltasSouls/Sounds/Thunder"), Main.player[npc.target].Center); } break; case 1: SoundEngine.PlaySound(SoundID.ScaryScream, Main.player[npc.target].Center); //arte scream break; case 2: SoundEngine.PlaySound(SoundID.Roar, Main.player[npc.target].Center); break; case 3: SoundEngine.PlaySound(SoundID.ForceRoarPitched, Main.player[npc.target].Center); //eoc roar break; case 4: if (!Main.dedServ) { SoundEngine.PlaySound(new SoundStyle("FargowiltasSouls/Sounds/Monster94"), Main.player[npc.target].Center); } break; case 5: if (!Main.dedServ) { SoundEngine.PlaySound(new SoundStyle("FargowiltasSouls/Sounds/Monster5") { Volume = 1.5f }, Main.player[npc.target].Center); } break; case 6: if (!Main.dedServ) { SoundEngine.PlaySound(new SoundStyle("FargowiltasSouls/Sounds/Thunder") { Volume = 1.5f, Pitch = 1.5f }, Main.player[npc.target].Center); } break; case 7: if (!Main.dedServ) { SoundEngine.PlaySound(new SoundStyle("FargowiltasSouls/Sounds/Zombie_104"), Main.player[npc.target].Center); } break; case 8: if (!Main.dedServ) { SoundEngine.PlaySound(new SoundStyle("FargowiltasSouls/Sounds/Monster70"), Main.player[npc.target].Center); } break; case 9: if (!Main.dedServ) { SoundEngine.PlaySound(new SoundStyle("FargowiltasSouls/Sounds/Railgun"), Main.player[npc.target].Center); } break; case 10: if (!Main.dedServ) { SoundEngine.PlaySound(new SoundStyle("FargowiltasSouls/Sounds/Navi"), Main.player[npc.target].Center); } break; case 11: if (!Main.dedServ) { SoundEngine.PlaySound(new SoundStyle("FargowiltasSouls/Sounds/ZaWarudo") { Volume = 1.5f }, Main.player[npc.target].Center); } break; default: SoundEngine.PlaySound(SoundID.NPCDeath10, Main.player[npc.target].Center); break; } } } if (!InPhase2 && npc.life < npc.lifeMax / 2) { InPhase2 = true; SoundEngine.PlaySound(SoundID.Roar, npc.Center); } if (npc.ai[0] == 6f) //when approaching for roar { if (npc.ai[1] == 0f) { npc.position += npc.velocity; } else if (npc.ai[1] == 1f) { DoFuryRingAttack = true; } } if (DoFuryRingAttack) { npc.velocity = Vector2.Zero; if (FuryRingTimer == 0) { if (Main.netMode != NetmodeID.MultiplayerClient) { Projectile.NewProjectile(npc.GetSource_FromThis(), npc.Center, Vector2.Zero, ModContent.ProjectileType <GlowRingHollow>(), FargoSoulsUtil.ScaledProjectileDamage(npc.damage, 4f / 3), 0f, Main.myPlayer, 4); } if (FargoSoulsWorld.MasochistModeReal) { if (NPC.CountNPCS(NPCID.DD2DarkMageT3) < 3) { FargoSoulsUtil.NewNPCEasy(npc.GetSource_FromAI(), npc.Center, NPCID.DD2DarkMageT3, target: npc.target); } } } FuryRingTimer++; if (FuryRingTimer % 2 == 0) { if (Main.netMode != NetmodeID.MultiplayerClient) { float rotation = FuryRingShotRotationCounter; if (FargoSoulsWorld.MasochistModeReal && FuryRingTimer >= 30 && FuryRingTimer <= 60) { rotation += 1; //staggers each wave instead of lining them up behind each other } Projectile.NewProjectile(npc.GetSource_FromThis(), npc.Center, -Vector2.UnitY.RotatedBy(2 * Math.PI / 30 * rotation), ModContent.ProjectileType <BetsyFury>(), FargoSoulsUtil.ScaledProjectileDamage(npc.damage, 4f / 3), 0f, Main.myPlayer, npc.target); Projectile.NewProjectile(npc.GetSource_FromThis(), npc.Center, -Vector2.UnitY.RotatedBy(2 * Math.PI / 30 * -rotation), ModContent.ProjectileType <BetsyFury>(), FargoSoulsUtil.ScaledProjectileDamage(npc.damage, 4f / 3), 0f, Main.myPlayer, npc.target); } FuryRingShotRotationCounter++; } if (FuryRingTimer > (InPhase2 ? 90 : 30) + 2) { DoFuryRingAttack = false; InFuryRingAttackCooldown = true; FuryRingTimer = 0; FuryRingShotRotationCounter = 0; } EModeGlobalNPC.Aura(npc, 1200, BuffID.WitheredWeapon, true, 226); EModeGlobalNPC.Aura(npc, 1200, BuffID.WitheredArmor, true, 226); } if (InFuryRingAttackCooldown) { EModeGlobalNPC.Aura(npc, 1200, BuffID.WitheredWeapon, true, 226); EModeGlobalNPC.Aura(npc, 1200, BuffID.WitheredArmor, true, 226); if (++FuryRingShotRotationCounter > 90) { InFuryRingAttackCooldown = false; FuryRingTimer = 0; FuryRingShotRotationCounter = 0; } npc.position -= npc.velocity * 0.5f; if (FuryRingTimer % 2 == 0) { return(false); } } if (!DD2Event.Ongoing && npc.HasPlayerTarget && (!Main.player[npc.target].active || Main.player[npc.target].dead || npc.Distance(Main.player[npc.target].Center) > 3000)) { int p = Player.FindClosest(npc.Center, 0, 0); //extra despawn code for when summoned outside event if (p < 0 || !Main.player[p].active || Main.player[p].dead || npc.Distance(Main.player[p].Center) > 3000) { npc.active = false; } } EModeUtils.DropSummon(npc, "BetsyEgg", FargoSoulsWorld.downedBetsy, ref DroppedSummon, NPC.downedGolemBoss); return(true); }
public override void AI(NPC npc) { IsVenomEnraged = false; if (FargoSoulsWorld.SwarmActive) { return; } 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); int n = NPC.NewNPC((int)spawnPos.X, (int)spawnPos.Y, ModContent.NPCType <CrystalLeaf>(), 0, npc.whoAmI, innerRingDistance, 0, rotation * i); if (Main.netMode == NetmodeID.Server && n != Main.maxNPCs) { NetMessage.SendData(MessageID.SyncNPC, -1, -1, null, n); } } } } else if (RingTossTimer == 120) { if (FargoSoulsWorld.MasochistModeReal) { RingTossTimer = 0; } npc.netUpdate = true; NetSync(npc); if (Main.netMode != NetmodeID.MultiplayerClient) { float speed = 8f; int p = Projectile.NewProjectile(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 { Main.PlaySound(SoundID.Grass, n.Center); Projectile.NewProjectile(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 (npc.HasValidTarget && Main.netMode != NetmodeID.MultiplayerClient) { Projectile.NewProjectile(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(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; } if (FargoSoulsWorld.MasochistModeReal) { NPCs.EModeGlobalNPC.Aura(npc, 600, ModContent.BuffType <IvyVenom>(), true, 188); npc.defense += 21; } 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); int n = NPC.NewNPC((int)spawnPos.X, (int)spawnPos.Y, ModContent.NPCType <CrystalLeaf>(), 0, npc.whoAmI, distance, 0, rotation * i); if (Main.netMode == NetmodeID.Server && n != Main.maxNPCs) { NetMessage.SendData(MessageID.SyncNPC, -1, -1, null, n); } } } 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); int n = NPC.NewNPC((int)spawnPos.X, (int)spawnPos.Y, ModContent.NPCType <CrystalLeaf>(), 0, npc.whoAmI, innerRingDistance, 0, innerRotation * i); if (Main.netMode == NetmodeID.Server && n != Main.maxNPCs) { NetMessage.SendData(MessageID.SyncNPC, -1, -1, null, n); } } } 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.Center, Vector2.Zero, ModContent.ProjectileType <DicerPlantera>(), npc.defDamage / 4, 0f, Main.myPlayer); for (int i = 0; i < 3; i++) { Projectile.NewProjectile(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); Main.PlaySound(SoundID.Roar, npc.Center, 0); 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 { Main.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.Center, Main.rand.NextVector2CircularEdge(24, 24), ModContent.ProjectileType <PlanteraTentacle>(), npc.damage / 4, 0f, Main.myPlayer, npc.whoAmI, attackAngle); Projectile.NewProjectile(npc.Center, Main.rand.NextVector2CircularEdge(24, 24), ModContent.ProjectileType <PlanteraTentacle>(), npc.damage / 4, 0f, Main.myPlayer, npc.whoAmI, attackAngle + MathHelper.Pi); } if (i == 0) { break; } } } if (TentacleTimer < -360) { 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); } } EModeUtils.DropSummon(npc, ModContent.ItemType <PlanterasFruit>(), NPC.downedPlantBoss, ref DroppedSummon, NPC.downedMechBoss1 && NPC.downedMechBoss2 && NPC.downedMechBoss3); }
public override bool PreAI(NPC npc) { bool result = base.PreAI(npc); EModeGlobalNPC.cultBoss = npc.whoAmI; if (FargoSoulsWorld.SwarmActive) { return(result); } 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; SoundEngine.PlaySound(SoundID.Roar, npc.Center); if (Main.netMode != NetmodeID.MultiplayerClient) { npc.netUpdate = true; NetSync(npc); } } //necessary because calameme int damage = Math.Max(75, FargoSoulsUtil.ScaledProjectileDamage(npc.damage)); damage /= 4; 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(npc.GetSource_FromThis(), 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(npc.GetSource_FromThis(), 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(npc.GetSource_FromThis(), 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.GetSource_FromThis(), 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) { FargoSoulsUtil.NewNPCEasy(npc.GetSource_FromAI(), Main.npc[i].Center, NPCID.SolarFlare, target: npc.target); } } } } 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(npc.GetSource_FromThis(), 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)) * 24f; Projectile.NewProjectile(npc.GetSource_FromThis(), 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(npc.GetSource_FromThis(), 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(npc.GetSource_FromThis(), 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(npc.GetSource_FromThis(), 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, "CultistSummon", NPC.downedAncientCultist, ref DroppedSummon, NPC.downedGolemBoss); return(result); }
public override void AI(NPC npc) { NPC.golemBoss = npc.whoAmI; if (FargoSoulsWorld.SwarmActive) { return; } /*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; * } * }*/ if (Main.LocalPlayer.active && Main.LocalPlayer.Distance(npc.Center) < 2000) { Main.LocalPlayer.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) { DoStompBehaviour = false; IsInTemple = Main.tile[(int)npc.Center.X / 16, (int)npc.Center.Y / 16] != null && Main.tile[(int)npc.Center.X / 16, (int)npc.Center.Y / 16].wall == WallID.LihzahrdBrickUnsafe; if (Main.netMode != NetmodeID.MultiplayerClient) //landing attacks { 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; Projectile.NewProjectile(tilePosX * 16 + 8, tilePosY * 16 + 8, 0f, 0f, ModContent.ProjectileType <GolemGeyser2>(), npc.damage / 4, 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; Projectile.NewProjectile(tilePosX * 16 + 8, tilePosY * 16 + 8, 0f, 0f, ModContent.ProjectileType <GolemGeyser>(), npc.damage / 4, 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) { 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; if (Main.tile[tilePosX, tilePosY] == null) { Main.tile[tilePosX, tilePosY] = new Tile(); } //first move up through solid tiles while (Main.tile[tilePosX, tilePosY].nactive() && Main.tileSolid[Main.tile[tilePosX, tilePosY].type]) { tilePosY--; if (Main.tile[tilePosX, tilePosY] == null) { Main.tile[tilePosX, tilePosY] = new Tile(); } } //then move up through air until next ceiling reached while (!(Main.tile[tilePosX, tilePosY].nactive() && Main.tileSolid[Main.tile[tilePosX, tilePosY].type])) { tilePosY--; if (Main.tile[tilePosX, tilePosY] == null) { Main.tile[tilePosX, tilePosY] = new Tile(); } } Vector2 spawn = new Vector2(tilePosX * 16 + 8, tilePosY * 16 + 8); Projectile.NewProjectile(spawn, Vector2.Zero, ModContent.ProjectileType <GolemBoulder>(), npc.damage / 4, 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; if (Main.tile[tilePosX, tilePosY] == null) { Main.tile[tilePosX, tilePosY] = new Tile(); } while (!(Main.tile[tilePosX, tilePosY].nactive() && Main.tileSolid[(int)Main.tile[tilePosX, tilePosY].type])) { tilePosY++; if (Main.tile[tilePosX, tilePosY] == null) { Main.tile[tilePosX, tilePosY] = new Tile(); } } if (npc.HasPlayerTarget && Main.player[npc.target].position.Y > tilePosY * 16) { Projectile.NewProjectile(tilePosX * 16 + 8, tilePosY * 16 + 8, 6.3f, 6.3f, ProjectileID.FlamesTrap, npc.damage / 4, 0f, Main.myPlayer); Projectile.NewProjectile(tilePosX * 16 + 8, tilePosY * 16 + 8, -6.3f, 6.3f, ProjectileID.FlamesTrap, npc.damage / 4, 0f, Main.myPlayer); } Projectile.NewProjectile(tilePosX * 16 + 8, tilePosY * 16 + 8, 0f, -8f, ProjectileID.GeyserTrap, npc.damage / 4, 0f, Main.myPlayer); Projectile.NewProjectile(tilePosX * 16 + 8, tilePosY * 16 + 8 - 640, 0f, -8f, ProjectileID.GeyserTrap, npc.damage / 4, 0f, Main.myPlayer); Projectile.NewProjectile(tilePosX * 16 + 8, tilePosY * 16 + 8 - 640, 0f, 8f, ProjectileID.GeyserTrap, npc.damage / 4, 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; if (Main.tile[tilePosX, tilePosY] == null) { Main.tile[tilePosX, tilePosY] = new Tile(); } for (int j = 0; j < 30; j++) { if (Main.tile[tilePosX, tilePosY].nactive() && Main.tileSolid[Main.tile[tilePosX, tilePosY].type]) { break; } tilePosY--; if (Main.tile[tilePosX, tilePosY] == null) { Main.tile[tilePosX, tilePosY] = new Tile(); } } Vector2 spawn = new Vector2(tilePosX * 16 + 8, tilePosY * 16 + 8); Projectile.NewProjectile(spawn, Vector2.Zero, ModContent.ProjectileType <GolemBoulder>(), npc.damage / 4, 0f, Main.myPlayer); } } } //golem's anti-air fireball spray (whenever he lands while player is below) /*if (npc.HasPlayerTarget && Main.player[npc.target].position.Y > npc.position.Y + npc.height) * { * float gravity = 0.2f; //shoot down * 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 = masobool3 ? 1 : 3; * for (int i = -max; i <= max; i++) * { * Projectile.NewProjectile(npc.Center.X, npc.Center.Y, distance.X + i * 1.5f, distance.Y, * ModContent.ProjectileType<GolemFireball>(), npc.damage / 5, 0f, Main.myPlayer, gravity, 0f); * } * }*/ } } } else if (npc.velocity.Y > 0) { DoStompBehaviour = true; } if (++SpikyBallTimer >= 900) //spray spiky balls { if (Main.tile[(int)npc.Center.X / 16, (int)npc.Center.Y / 16] != null && //in temple Main.tile[(int)npc.Center.X / 16, (int)npc.Center.Y / 16].wall == 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.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>(), npc.damage / 4, 0f, Main.myPlayer); } } } else //outside temple { SpikyBallTimer = 600; //do it more often for (int i = 0; i < 16; i++) { Projectile.NewProjectile(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>(), npc.damage / 4, 0f, Main.myPlayer); } } } /*Counter2++; * if (Counter2 > 240) //golem's anti-air fireball spray (when player is above) * { * Counter2 = 0; * if (npc.HasPlayerTarget && Main.player[npc.target].position.Y < npc.position.Y * && Main.netMode != NetmodeID.MultiplayerClient) //shoutouts to arterius * { * bool inTemple = Main.tile[(int)npc.Center.X / 16, (int)npc.Center.Y / 16] != null && //in temple * Main.tile[(int)npc.Center.X / 16, (int)npc.Center.Y / 16].wall == WallID.LihzahrdBrickUnsafe; * * float gravity = -0.2f; //normally floats up * //if (Main.player[npc.target].position.Y > npc.position.Y + npc.height) 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 ? 1 : 3; * for (int i = -max; i <= max; i++) * { * Projectile.NewProjectile(npc.Center.X, npc.Center.Y, distance.X + i, distance.Y, * ModContent.ProjectileType<GolemFireball>(), npc.damage / 5, 0f, Main.myPlayer, gravity, 0f); * } * } * }*/ EModeUtils.DropSummon(npc, ModContent.ItemType <LihzahrdPowerCell2>(), NPC.downedGolemBoss, ref DroppedSummon, NPC.downedPlantBoss); }
public override void AI(NPC npc) { EModeGlobalNPC.primeBoss = npc.whoAmI; if (FargoSoulsWorld.SwarmActive) { return; } if (npc.ai[1] == 3) //despawn faster { if (npc.timeLeft > 60) { npc.timeLeft = 60; } } if (npc.ai[1] == 0f) { HaveShotGuardians = false; if (npc.ai[2] == 600 - 90) //telegraph spin { if (Main.netMode != NetmodeID.MultiplayerClient) { Projectile.NewProjectile(npc.Center, Vector2.Zero, ModContent.ProjectileType <TargetingReticle>(), 0, 0f, Main.myPlayer, npc.whoAmI, npc.type); } } if (npc.ai[2] < 600 - 5) { MemorizedTarget = npc.target; } } if (npc.ai[1] == 1f) { if (MemorizedTarget > -1 && MemorizedTarget < Main.maxPlayers) { npc.target = MemorizedTarget; npc.netUpdate = true; MemorizedTarget = -1; if (!npc.HasValidTarget) { npc.TargetClosest(false); } } } if (npc.ai[0] != 2f || FargoSoulsWorld.MasochistModeReal) { if (!HaveShotGuardians && npc.ai[1] == 1f && npc.ai[2] > 2f) //spinning, do wave of guardians { HaveShotGuardians = true; if (Main.netMode != NetmodeID.MultiplayerClient) { for (int i = 0; i < 4; i++) { for (int j = -2; j <= 2; j++) { Vector2 spawnPos = new Vector2(1200, 80 * j); Vector2 vel = -10 * Vector2.UnitX; spawnPos = Main.player[npc.target].Center + spawnPos.RotatedBy(Math.PI / 2 * i); vel = vel.RotatedBy(Math.PI / 2 * i); int p = Projectile.NewProjectile(spawnPos, vel, ModContent.ProjectileType <PrimeGuardian>(), npc.damage / 4, 0f, Main.myPlayer); if (p != Main.maxProjectiles) { Main.projectile[p].timeLeft = 1200 / 10 + 1; } } } } } if (++ProjectileAttackTimer >= 360) { ProjectileAttackTimer = 0; if (npc.HasPlayerTarget) //skeleton commando rockets LUL { Vector2 speed = Main.player[npc.target].Center - npc.Center; speed.X += Main.rand.Next(-20, 21); speed.Y += Main.rand.Next(-20, 21); speed.Normalize(); int damage = npc.damage / 4; if (Main.netMode != NetmodeID.MultiplayerClient) { Projectile.NewProjectile(npc.Center, 3f * speed, ProjectileID.RocketSkeleton, damage, 0f, Main.myPlayer); Projectile.NewProjectile(npc.Center, 3f * speed.RotatedBy(MathHelper.ToRadians(5f)), ProjectileID.RocketSkeleton, damage, 0f, Main.myPlayer); Projectile.NewProjectile(npc.Center, 3f * speed.RotatedBy(MathHelper.ToRadians(-5f)), ProjectileID.RocketSkeleton, damage, 0f, Main.myPlayer); } Main.PlaySound(SoundID.Item11, npc.Center); } } } if (npc.ai[0] != 2f) //in phase 1 { if (npc.life < npc.lifeMax * .75) //enter phase 2 { npc.ai[0] = 2f; npc.ai[1] = 0f; //revert to nonspin mode npc.ai[2] = 600f - 90f - 2f; //but only for telegraph and then go back into spin npc.ai[3] = 0f; npc.netUpdate = true; if (Main.netMode != NetmodeID.MultiplayerClient) { if (!NPC.AnyNPCs(NPCID.PrimeLaser)) //revive all dead limbs { int n = NPC.NewNPC((int)npc.Center.X, (int)npc.Center.Y, NPCID.PrimeLaser, npc.whoAmI, 1f, npc.whoAmI, 0f, 150f, npc.target); if (n != Main.maxNPCs && Main.netMode == NetmodeID.Server) { NetMessage.SendData(MessageID.SyncNPC, -1, -1, null, n); } } if (!NPC.AnyNPCs(NPCID.PrimeSaw)) { int n = NPC.NewNPC((int)npc.Center.X, (int)npc.Center.Y, NPCID.PrimeSaw, npc.whoAmI, 1f, npc.whoAmI, 0f, 0f, npc.target); if (n != Main.maxNPCs && Main.netMode == NetmodeID.Server) { NetMessage.SendData(MessageID.SyncNPC, -1, -1, null, n); } } if (!NPC.AnyNPCs(NPCID.PrimeCannon)) { int n = NPC.NewNPC((int)npc.Center.X, (int)npc.Center.Y, NPCID.PrimeCannon, npc.whoAmI, -1f, npc.whoAmI, 0f, 150f, npc.target); if (n != Main.maxNPCs && Main.netMode == NetmodeID.Server) { NetMessage.SendData(MessageID.SyncNPC, -1, -1, null, n); } } if (!NPC.AnyNPCs(NPCID.PrimeVice)) { int n = NPC.NewNPC((int)npc.Center.X, (int)npc.Center.Y, NPCID.PrimeVice, npc.whoAmI, -1f, npc.whoAmI, 0f, 0f, npc.target); if (n != Main.maxNPCs && Main.netMode == NetmodeID.Server) { NetMessage.SendData(MessageID.SyncNPC, -1, -1, null, n); } } } Main.PlaySound(SoundID.Roar, (int)npc.position.X, (int)npc.position.Y, 0); return; } } else //in phase 2 { npc.dontTakeDamage = false; if (npc.ai[1] == 1f && npc.ai[2] > 2f) //spinning { if (npc.HasValidTarget) { npc.position += npc.DirectionTo(Main.player[npc.target].Center) * 5; } if (++ProjectileAttackTimer > 90) //projectile attack { ProjectileAttackTimer = -30; int damage = npc.defDamage / 3; if (Main.netMode != NetmodeID.MultiplayerClient) { Main.PlaySound(SoundID.Item, (int)npc.position.X, (int)npc.position.Y, 105, 2f, -0.3f); float modifier = (float)npc.life / npc.lifeMax; if (FargoSoulsWorld.MasochistModeReal) { modifier /= 2; } int starMax = (int)(7f - 6f * modifier); const int max = 8; for (int i = 0; i < max; i++) { Vector2 speed = 12f * npc.DirectionTo(Main.player[npc.target].Center).RotatedBy(2 * Math.PI / max * i); for (int j = -starMax; j <= starMax; j++) { int p = Projectile.NewProjectile(npc.Center, speed.RotatedBy(MathHelper.ToRadians(2f) * j), ModContent.ProjectileType <DarkStar>(), damage, 0f, Main.myPlayer); Main.projectile[p].soundDelay = -1; //dont play sounds if (p != Main.maxProjectiles) { Main.projectile[p].timeLeft = 480; } } } } } } else if (npc.ai[1] == 2f) //dg phase { while (npc.buffType[0] != 0) { npc.buffImmune[npc.buffType[0]] = true; npc.DelBuff(0); } if (!Main.dayTime) { npc.position -= npc.velocity * 0.1f; if (!FargoSoulsWorld.MasochistModeReal && ++DungeonGuardianStartup < 120) { npc.position -= npc.velocity * (120 - DungeonGuardianStartup) / 120 * 0.9f; } } } else //not spinning { ProjectileAttackTimer = 0; //buffer this for spin npc.position += npc.velocity / 4f; } if (!FullySpawnedLimbs && npc.ai[3] >= 0f) //spawn 4 more limbs { npc.ai[3]++; if (npc.ai[3] == 60f) //first set of limb management { int[] limbs = { NPCID.PrimeCannon, NPCID.PrimeLaser, NPCID.PrimeSaw, NPCID.PrimeVice }; foreach (NPC l in Main.npc.Where(l => l.active && l.ai[1] == npc.whoAmI && limbs.Contains(l.type))) { l.GetEModeNPCMod <PrimeLimb>().IsSwipeLimb = true; l.ai[2] = 0; int heal = (l.lifeMax - l.life) / 2; l.life += heal; if (heal > 0) { l.HealEffect(heal); } l.dontTakeDamage = false; l.netUpdate = true; NetSync(l); } if (Main.netMode != NetmodeID.MultiplayerClient) //now spawn the other four { int n = NPC.NewNPC((int)npc.Center.X, (int)npc.Center.Y, NPCID.PrimeLaser, npc.whoAmI, -1f, npc.whoAmI, 0f, 150f, npc.target); if (n != Main.maxNPCs && Main.netMode == NetmodeID.Server) { NetMessage.SendData(MessageID.SyncNPC, -1, -1, null, n); } n = NPC.NewNPC((int)npc.Center.X, (int)npc.Center.Y, NPCID.PrimeSaw, npc.whoAmI, -1f, npc.whoAmI, 0f, 0f, npc.target); if (n != Main.maxNPCs && Main.netMode == NetmodeID.Server) { NetMessage.SendData(MessageID.SyncNPC, -1, -1, null, n); } n = NPC.NewNPC((int)npc.Center.X, (int)npc.Center.Y, NPCID.PrimeCannon, npc.whoAmI, 1f, npc.whoAmI, 0f, 150f, npc.target); if (n != Main.maxNPCs && Main.netMode == NetmodeID.Server) { NetMessage.SendData(MessageID.SyncNPC, -1, -1, null, n); } n = NPC.NewNPC((int)npc.Center.X, (int)npc.Center.Y, NPCID.PrimeVice, npc.whoAmI, 1f, npc.whoAmI, 0f, 0f, npc.target); if (n != Main.maxNPCs && Main.netMode == NetmodeID.Server) { NetMessage.SendData(MessageID.SyncNPC, -1, -1, null, n); } } } else if (npc.ai[3] >= 180f) { FullySpawnedLimbs = true; npc.ai[3] = -1f; npc.netUpdate = true; Main.PlaySound(SoundID.Roar, (int)npc.position.X, (int)npc.position.Y, 0); if (Main.netMode != NetmodeID.MultiplayerClient) { int rangedArm = Main.rand.NextBool() ? NPCID.PrimeCannon : NPCID.PrimeLaser; int meleeArm = Main.rand.NextBool() ? NPCID.PrimeSaw : NPCID.PrimeVice; int[] limbs = { NPCID.PrimeCannon, NPCID.PrimeLaser, NPCID.PrimeSaw, NPCID.PrimeVice }; foreach (NPC l in Main.npc.Where(l => l.active && l.ai[1] == npc.whoAmI && limbs.Contains(l.type) && !l.GetEModeNPCMod <PrimeLimb>().IsSwipeLimb)) { l.GetEModeNPCMod <PrimeLimb>().RangedAttackMode = npc.type == rangedArm || npc.type == meleeArm; int heal = l.lifeMax; l.life = Math.Min(l.life + l.lifeMax / 2, l.lifeMax); heal -= l.life; if (heal > 0) { l.HealEffect(heal); } l.dontTakeDamage = false; l.netUpdate = true; NetSync(l); } } } } } EModeUtils.DropSummon(npc, ModContent.ItemType <MechSkull>(), NPC.downedMechBoss3, ref DroppedSummon, Main.hardMode); }
public override bool PreAI(NPC npc) { base.AI(npc); EModeGlobalNPC.beeBoss = npc.whoAmI; if (FargoSoulsWorld.SwarmActive) { return(true); } 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 = NPC.NewNPC((int)vector72.X, (int)vector72.Y, ModContent.NPCType <RoyalSubject>(), 0, 0f, 0f, 0f, 0f, 255); if (n != Main.maxNPCs) { Main.npc[n].velocity.X = Main.rand.Next(-200, 201) * 0.002f; Main.npc[n].velocity.Y = Main.rand.Next(-200, 201) * 0.002f; Main.npc[n].localAI[0] = 60f; if (Main.netMode == NetmodeID.Server) { NetMessage.SendData(MessageID.SyncNPC, -1, -1, null, n); } } FargoSoulsUtil.PrintText("Royal Subject has awoken!", 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 = NPC.NewNPC((int)vector72.X, (int)vector72.Y, ModContent.NPCType <RoyalSubject>(), 0, 0f, 0f, 0f, 0f, 255); if (n != Main.maxNPCs) { Main.npc[n].velocity.X = Main.rand.Next(-200, 201) * 0.1f; Main.npc[n].velocity.Y = Main.rand.Next(-200, 201) * 0.1f; Main.npc[n].localAI[0] = 60f; if (Main.netMode == NetmodeID.Server) { NetMessage.SendData(MessageID.SyncNPC, -1, -1, null, n); } } FargoSoulsUtil.PrintText("Royal Subject has awoken!", 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; Main.PlaySound(SoundID.Roar, npc.Center, 0); 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 } 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 (!InPhase2) { 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.Center, ProjectileID.Stinger, 6, 11, 1); } } } } else { 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.Center, distance, ModContent.ProjectileType <Beehive>(), npc.damage / 4, 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.Center, Vector2.Zero, ModContent.ProjectileType <GlowRing>(), 0, 0f, Main.myPlayer, npc.whoAmI, npc.type); } if (npc.HasValidTarget) { Main.PlaySound(SoundID.ForceRoar, Main.player[npc.target].Center, -1); //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.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>(), npc.damage / (FargoSoulsWorld.MasochistModeReal ? 3 : 4), 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 && npc.ai[2] < 0) //when about to do dashes triggered by royal subjects/bee swarm, telegraph and stall { if (npc.ai[2] == -44) //telegraph { Main.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; } } npc.velocity *= 0.95f; npc.ai[2]++; return(false); } EModeUtils.DropSummon(npc, ModContent.ItemType <Abeemination2>(), NPC.downedQueenBee, ref DroppedSummon); return(true); }
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); }
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); }
public override bool PreAI(NPC npc) { EModeGlobalNPC.eyeBoss = npc.whoAmI; if (FargoSoulsWorld.SwarmActive) { return(true); } void SpawnServants() { if (FargoSoulsWorld.MasochistModeReal && 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((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) { int p = Projectile.NewProjectile(npc.Center, Vector2.Zero, ModContent.ProjectileType <BloodScythe>(), npc.damage / 4, 1f, Main.myPlayer); if (p != Main.maxProjectiles) { Main.projectile[p].timeLeft = 75; } } else { Projectile.NewProjectile(npc.Center, Vector2.Normalize(npc.velocity), ModContent.ProjectileType <BloodScythe>(), npc.damage / 4, 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; } if (Main.netMode != NetmodeID.MultiplayerClient) { FargoSoulsUtil.XWay(8, npc.Center, ModContent.ProjectileType <BloodScythe>(), 1.5f, npc.damage / 4, 0); } } 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 -= 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) { Main.PlaySound(SoundID.ForceRoar, Main.player[npc.target].Center, -1); //eoc roar 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 (Main.netMode != NetmodeID.MultiplayerClient) { FargoSoulsUtil.XWay(8, npc.Center, ModContent.ProjectileType <BloodScythe>(), 1f, npc.damage / 4, 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; float 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.nactive()) { floatUp = Main.tileSolid[tile.type]; } } 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 += 4; if (npc.alpha > 255) { npc.alpha = 255; } 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; Main.PlaySound(SoundID.Roar, npc.HasValidTarget ? Main.player[npc.target].Center : npc.Center, 0); if (Main.netMode != NetmodeID.MultiplayerClient) { Projectile.NewProjectile(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]; * Main.PlaySound(SoundID.Item9, (int)player.position.X, (int)player.position.Y, 104, 1f, 0f); * 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(spawnPos, speed, ModContent.ProjectileType<BloodScythe>(), npc.damage / 4, 1f, Main.myPlayer); * spawnPos.X += 72 * direction; * speed.Y += 0.15f; * } * } * } * }*/ } else { npc.alpha = 0; npc.dontTakeDamage = false; } // Drop summon EModeUtils.DropSummon(npc, ModContent.ItemType <SuspiciousEye>(), NPC.downedBoss1, ref DroppedSummon); return(true); }
public override bool PreAI(NPC npc) { EModeGlobalNPC.queenSlimeBoss = npc.whoAmI; if (FargoSoulsWorld.SwarmActive) { return(true); } void TrySpawnMinions(ref bool check, double threshold) { if (!check && npc.life < npc.lifeMax * threshold) { check = true; FargoSoulsUtil.PrintLocalization($"Mods.{mod.Name}.Message.GelatinSubjects", new Color(175, 75, 255)); for (int i = 0; i < 6; i++) { FargoSoulsUtil.NewNPCEasy(npc.GetSource_FromAI(), npc.Center, ModContent.NPCType <GelatinSubject>(), npc.whoAmI, target: npc.target, velocity: Main.rand.NextFloat(8f) * npc.DirectionFrom(Main.player[npc.target].Center).RotatedByRandom(MathHelper.PiOver2)); } 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); } } } TrySpawnMinions(ref SpawnedMinions1, 0.75); TrySpawnMinions(ref SpawnedMinions2, 0.25); GelatinSubjectDR = NPC.AnyNPCs(ModContent.NPCType <GelatinSubject>()); npc.HitSound = GelatinSubjectDR ? SoundID.Item27 : SoundID.NPCHit1; //ai0 //0 = default //3 = chase? //4 = stomp //5 = shooty gels if (npc.ai[0] == 5) //when shooting, p1 and p2 { if (NPC.AnyNPCs(ModContent.NPCType <GelatinSubject>())) { npc.ai[1] -= 0.5f; } if (npc.ai[1] == 45 && --SpikeCounter < 0) //every few shots { SpikeCounter = 4; NetSync(npc); SoundEngine.PlaySound(SoundID.Roar, npc.Center); if (Main.netMode != NetmodeID.MultiplayerClient) { Vector2 focus = Main.player[npc.target].Center; for (int i = 0; i < 50; i++) { Tile tile = Framing.GetTileSafely(focus); if (tile.HasUnactuatedTile && (Main.tileSolid[tile.TileType] || Main.tileSolidTop[tile.TileType])) { break; } focus.Y += 16f; } focus.Y -= Player.defaultHeight / 2f; for (int i = -5; i <= 5; i++) { Vector2 targetPos = focus; targetPos.X += 330 * i; float minionTravelTime = StompTravelTime + Main.rand.Next(30); float minionGravity = 0.4f; Vector2 vel = targetPos - npc.Center; vel.X = vel.X / minionTravelTime; vel.Y = vel.Y / minionTravelTime - 0.5f * minionGravity * minionTravelTime; FargoSoulsUtil.NewNPCEasy(npc.GetSource_FromAI(), npc.Center, ModContent.NPCType <GelatinSlime>(), npc.whoAmI, minionTravelTime, minionGravity, vel.X, vel.Y, target: npc.target); } } } } if (npc.life > npc.lifeMax / 2) //phase 1 { if (StompTimer > 0 || (npc.ai[0] == 0 && npc.velocity.Y == 0)) { if (StompTimer < 0) { StompTimer++; } else { npc.ai[0] = 4; //activates trail visual } if (!Stompy(npc)) { return(false); } } } else //phase 2 { npc.defense = npc.defDefense / 2; if (RainTimer < 0) { RainTimer++; } if (RainTimer <= 0 && StompTimer < 0) //dont run timer during rain attack { StompTimer++; } if (npc.ai[0] == 0) //basic flying ai { if (RainTimer == 0) { if (npc.velocity.Y < 0) { npc.position.Y += npc.velocity.Y; } npc.ai[1] -= 1; //dont progress to next ai if (npc.HasValidTarget && Math.Abs(npc.Center.Y - (Main.player[npc.target].Center.Y - 250)) < 32) { RainTimer = 1; //begin attack NetSync(npc); npc.netUpdate = true; SoundEngine.PlaySound(SoundID.Roar, 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, -16); } } } else if (RainTimer > 0) //actually doing rain { npc.velocity.X *= 0.9f; npc.ai[1] -= 1f; //dont progress ai RainTimer++; const int delay = 45; const int timeBeforeStreamsMove = 45; const int maxAttackTime = 480; int attackTimer = RainTimer - delay - timeBeforeStreamsMove; if (attackTimer < 0) { attackTimer = 0; } if (RainTimer == delay) { RainDirection = Math.Sign(Main.player[npc.target].Center.X - npc.Center.X); } if (RainTimer > delay && RainTimer < delay + maxAttackTime && RainTimer % 5 == 0) { const float maxWavy = 200; Vector2 focusPoint = new Vector2(npc.Center.X, Math.Min(npc.Center.Y, Main.player[npc.target].Center.Y)); focusPoint.X += maxWavy * RainDirection * (float)Math.Sin(Math.PI * 2f / maxAttackTime * attackTimer * 1.5f); focusPoint.Y -= 500; for (int i = -4; i <= 4; i++) { Vector2 spawnPos = focusPoint + Main.rand.NextVector2Circular(32, 32); spawnPos.X += 330 * i; if (Main.netMode != NetmodeID.MultiplayerClient) { Projectile.NewProjectile(npc.GetSource_FromThis(), spawnPos, 8f * Vector2.UnitY, ProjectileID.QueenSlimeMinionBlueSpike, FargoSoulsUtil.ScaledProjectileDamage(npc.damage), 0f, Main.myPlayer); } } } bool endAttack = RainTimer > delay + maxAttackTime + 90; if (npc.Distance(Main.player[npc.target].Center) > 1200) { endAttack = true; StompTimer = 0; StompCounter = -3; //enraged super stomps } if (!npc.HasValidTarget) { npc.TargetClosest(false); if (!npc.HasValidTarget) { endAttack = true; } } if (endAttack) { RainTimer = -1000; npc.netUpdate = true; NetSync(npc); if (StompTimer == 0) //transition directly to stompy if ready { npc.ai[0] = 4f; npc.ai[1] = 0f; } } } else { npc.ai[1] += 1; //proceed to next ais faster } } else if (npc.ai[0] == 4) //stompy { if (!Stompy(npc)) { return(false); } } else if (npc.ai[0] == 5) //when shooting { //be careful to stay above player if (npc.HasValidTarget && npc.Bottom.Y > Main.player[npc.target].Top.Y - 80 && npc.velocity.Y > -8f) { npc.velocity.Y -= 0.8f; } } } //FargoSoulsUtil.PrintAI(npc); EModeUtils.DropSummon(npc, "JellyCrystal", NPC.downedQueenSlime, ref DroppedSummon, Main.hardMode); return(true); }
public override void AI(NPC npc) { base.AI(npc); EModeGlobalNPC.skeleBoss = npc.whoAmI; if (FargoSoulsWorld.SwarmActive) { return; } if (npc.ai[1] == 0f) { if (npc.ai[2] == 800 - 90) //telegraph spin { if (Main.netMode != NetmodeID.MultiplayerClient) { Projectile.NewProjectile(npc.Center, Vector2.Zero, ModContent.ProjectileType <TargetingReticle>(), 0, 0f, Main.myPlayer, npc.whoAmI, npc.type); } } if (npc.ai[2] < 800 - 5) { ReticleTarget = npc.target; } } if (npc.ai[1] == 1f || npc.ai[1] == 2f) //spinning or DG mode { //force targeted player back to the one i telegraphed with reticle (otherwise, may target another player when spin starts) if (ReticleTarget > -1 && ReticleTarget < Main.maxPlayers) { npc.target = ReticleTarget; ReticleTarget = -1; npc.netUpdate = true; NetSync(npc); if (!npc.HasValidTarget) { npc.TargetClosest(false); } if (npc.ai[1] == 1) //do cross guardian attack { if (!FargoSoulsWorld.MasochistModeReal) { for (int i = 0; i < Main.maxProjectiles; i++) //also clear leftover babies { if (Main.projectile[i].active && Main.projectile[i].hostile && Main.projectile[i].type == ModContent.ProjectileType <SkeletronGuardian2>()) { Main.projectile[i].Kill(); } } } if (Main.netMode != NetmodeID.MultiplayerClient) { for (int i = 0; i < 4; i++) { for (int j = -2; j <= 2; j++) { Vector2 spawnPos = new Vector2(1200, 80 * j); Vector2 vel = -8 * Vector2.UnitX; spawnPos = Main.player[npc.target].Center + spawnPos.RotatedBy(Math.PI / 2 * (i + 0.5)); vel = vel.RotatedBy(Math.PI / 2 * (i + 0.5)); int p = Projectile.NewProjectile(spawnPos, vel, ModContent.ProjectileType <Projectiles.Champions.ShadowGuardian>(), npc.damage / 4, 0f, Main.myPlayer); if (p != Main.maxProjectiles) { Main.projectile[p].timeLeft = 1200 / 8 + 1; } } } } } } npc.localAI[2]++; float ratio = (float)npc.life / npc.lifeMax; float threshold = 20f + 100f * ratio; if (npc.localAI[2] >= threshold) //spray bones { npc.localAI[2] = 0f; if (threshold > 0 && npc.HasPlayerTarget && Main.netMode != NetmodeID.MultiplayerClient) { Vector2 speed = Vector2.Normalize(Main.player[npc.target].Center - npc.Center) * 6f; for (int i = 0; i < 8; i++) { Vector2 vel = speed.RotatedBy(Math.PI * 2 / 8 * i); vel += npc.velocity * (1f - ratio); vel.Y -= Math.Abs(vel.X) * 0.2f; Projectile.NewProjectile(npc.Center, vel, ModContent.ProjectileType <SkeletronBone>(), npc.defDamage / 9 * 2, 0f, Main.myPlayer); } } } if (BabyGuardianTimer > 180) { BabyGuardianTimer = 180; } if (npc.life < npc.lifeMax * .75 && npc.ai[1] == 1f && --BabyGuardianTimer < 0) { BabyGuardianTimer = 180; Main.PlaySound(SoundID.ForceRoar, npc.Center, -1); if (Main.netMode != NetmodeID.MultiplayerClient) //spray of baby guardian missiles { const int max = 30; float modifier = 1f - (float)npc.life / npc.lifeMax; modifier *= 4f / 3f; //scaling maxes at 25% life if (modifier > 1f) { modifier = 1f; } int actualNumberToSpawn = (int)(max * modifier); for (int i = 0; i < actualNumberToSpawn; i++) { float speed = Main.rand.NextFloat(3f, 9f); Vector2 velocity = speed * npc.DirectionFrom(Main.player[npc.target].Center).RotatedBy(Math.PI * (Main.rand.NextDouble() - 0.5)); float ai1 = speed / (60f + Main.rand.NextFloat(actualNumberToSpawn * 2)); Projectile.NewProjectile(npc.Center, velocity, ModContent.ProjectileType <SkeletronGuardian>(), npc.damage / 5, 0f, Main.myPlayer, 0f, ai1); } } } } else { //prevent skeletron from firing his stupid tick 1 no telegraph skull right after finishing spin if (npc.ai[2] == 0 && !FargoSoulsWorld.MasochistModeReal) { npc.ai[2] = 1; } if (npc.life < npc.lifeMax * .75 && --BabyGuardianTimer < 0) { BabyGuardianTimer = FargoSoulsWorld.MasochistModeReal ? 180 : 240; Main.PlaySound(SoundID.ForceRoar, npc.Center, -1); if (Main.netMode != NetmodeID.MultiplayerClient) //area denial circle spray of baby guardians { for (int j = -1; j <= 1; j++) //to both sides { if (j == 0) { continue; } const int gap = 40; const int max = 14; float modifier = 1f - (float)npc.life / npc.lifeMax; modifier *= 4f / 3f; //scaling maxes at 25% life if (modifier > 1f || FargoSoulsWorld.MasochistModeReal) { modifier = 1f; } int actualNumberToSpawn = (int)(max * modifier); Vector2 baseVel = npc.DirectionTo(Main.player[npc.target].Center).RotatedBy(MathHelper.ToRadians(gap) * j); for (int k = 0; k < actualNumberToSpawn; k++) //a fan of skulls { if (Main.netMode != NetmodeID.MultiplayerClient) { float velModifier = 1f + 9f * k / max; Projectile.NewProjectile(npc.Center, velModifier * baseVel.RotatedBy(MathHelper.ToRadians(10) * j * k), ModContent.ProjectileType <SkeletronGuardian2>(), npc.damage / 5, 0f, Main.myPlayer); } } } if (Main.netMode != NetmodeID.MultiplayerClient) //one more shot straight behind skeletron { float velModifier = 10f; Projectile.NewProjectile(npc.Center, velModifier * npc.DirectionFrom(Main.player[npc.target].Center), ModContent.ProjectileType <SkeletronGuardian2>(), npc.damage / 5, 0f, Main.myPlayer); } } } } if (npc.ai[1] == 2f) { npc.defense = 9999; npc.damage = npc.defDamage * 15; if (!Main.dayTime && !FargoSoulsWorld.MasochistModeReal) { if (++DGSpeedRampup < 120) { npc.position -= npc.velocity * (120 - DGSpeedRampup) / 120; } } } EModeUtils.DropSummon(npc, ModContent.ItemType <SuspiciousSkull>(), NPC.downedBoss3, ref DroppedSummon); //FargoSoulsUtil.PrintAI(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); }