public override void ModifyHitByAnything(NPC npc, Player player, ref int damage, ref float knockback, ref bool crit) { base.ModifyHitByAnything(npc, player, ref damage, ref knockback, ref crit); if (Main.rand.NextBool(10) && npc.HasPlayerTarget && player.whoAmI == npc.target && player.active && !player.dead && !player.ghost) { bool doTheTeleport = true; Vector2 teleportTarget = player.Center; float offset = 100f * -player.direction; teleportTarget.X += offset; teleportTarget.Y -= 50f; if (!Collision.CanHit(teleportTarget, 1, 1, player.position, player.width, player.height)) { teleportTarget.X -= offset * 2f; if (!Collision.CanHit(teleportTarget, 1, 1, player.position, player.width, player.height)) { doTheTeleport = false; } } if (doTheTeleport) { FargoSoulsUtil.GrossVanillaDodgeDust(npc); damage = 0; npc.Center = teleportTarget; npc.netUpdate = true; FargoSoulsUtil.GrossVanillaDodgeDust(npc); } } }
public override void HitEffect(int hitDirection, double damage) { if (NPC.life <= 0) { for (int i = 3; i <= 10; i++) { Vector2 pos = NPC.position + new Vector2(Main.rand.NextFloat(NPC.width), Main.rand.NextFloat(NPC.height)); if (!Main.dedServ) { Gore.NewGore(NPC.GetSource_FromThis(), pos, NPC.velocity, ModContent.Find <ModGore>(Mod.Name, $"TimberGore{i}").Type, NPC.scale); } } if (spawnPhase2) { FargoSoulsUtil.NewNPCEasy(NPC.GetSource_FromAI(), NPC.Center, ModContent.NPCType <TimberChampionHead>(), NPC.whoAmI, target: NPC.target); } FargoSoulsUtil.GrossVanillaDodgeDust(NPC); for (int i = 0; i < 6; i++) { ExplodeDust(NPC.position + new Vector2(Main.rand.Next(NPC.width), Main.rand.Next(NPC.height))); } } }
public override void AI() { if (!spawned) { spawned = true; NPC.TargetClosest(false); if (Main.netMode != NetmodeID.MultiplayerClient) { head = FargoSoulsUtil.NPCExists(FargoSoulsUtil.NewNPCEasy(NPC.GetSource_FromThis(), NPC.Center, ModContent.NPCType <TrojanSquirrelHead>(), NPC.whoAmI, target: NPC.target)); arms = FargoSoulsUtil.NPCExists(FargoSoulsUtil.NewNPCEasy(NPC.GetSource_FromThis(), NPC.Center, ModContent.NPCType <TrojanSquirrelArms>(), NPC.whoAmI, target: NPC.target)); } //drop summon if (FargoSoulsWorld.EternityMode && !FargoSoulsWorld.downedBoss[(int)FargoSoulsWorld.Downed.TrojanSquirrel] && Main.netMode != NetmodeID.MultiplayerClient) { Item.NewItem(NPC.GetSource_Loot(), Main.player[NPC.target].Hitbox, ModContent.ItemType <SquirrelCoatofArms>()); } //start by jumping NPC.ai[0] = 1f; NPC.ai[3] = 1f; for (int i = 0; i < 80; i++) { int d = Dust.NewDust(NPC.position, NPC.width, NPC.height, DustID.Smoke, NPC.velocity.X, NPC.velocity.Y, 50, default(Color), 4f); Main.dust[d].velocity.Y -= 1.5f; Main.dust[d].velocity *= 1.5f; Main.dust[d].noGravity = true; } FargoSoulsUtil.GrossVanillaDodgeDust(NPC); SoundEngine.PlaySound(SoundID.Roar, Main.player[NPC.target].Center); } Player player = Main.player[NPC.target]; NPC.direction = NPC.spriteDirection = NPC.Center.X < player.Center.X ? 1 : -1; bool despawn = false; switch ((int)NPC.ai[0]) { case 0: //mourning wood movement { Vector2 target = player.Bottom - Vector2.UnitY; if (NPC.localAI[0] > 0) //doing running attack { NPC.localAI[0] -= 1f; float distance = NPC.Center.X - target.X; bool passedTarget = Math.Sign(distance) == NPC.localAI[1]; if (passedTarget && Math.Abs(distance) > 160) { NPC.localAI[0] = 0f; } target = new Vector2(NPC.Center.X + 256f * NPC.localAI[1], target.Y); if (NPC.localAI[0] == 0f) { NPC.TargetClosest(false); } if (FargoSoulsWorld.EternityMode && head == null && NPC.localAI[0] % 3 == 0 && Main.netMode != NetmodeID.MultiplayerClient) { int p = Projectile.NewProjectile(NPC.GetSource_FromThis(), NPC.Top.X, NPC.Top.Y, Main.rand.NextFloat(-5, 5), Main.rand.NextFloat(-5), Main.rand.Next(326, 329), FargoSoulsUtil.ScaledProjectileDamage(NPC.damage), 0f, Main.myPlayer); if (p != Main.maxProjectiles) { Main.projectile[p].timeLeft = 90; } } } else if (!NPC.HasValidTarget || NPC.Distance(player.Center) > (FargoSoulsWorld.EternityMode ? 1600 : 2400)) { target = NPC.Center + new Vector2(256f * Math.Sign(NPC.Center.X - player.Center.X), -128); NPC.TargetClosest(false); despawn = true; } if (Math.Abs(NPC.velocity.Y) < 0.05f && NPC.localAI[3] >= 2) { if (NPC.localAI[3] == 2) { NPC.localAI[3] = 0f; } else { NPC.localAI[3] -= 1; NPC.ai[0] = 1f; NPC.ai[3] = 1f; } SoundEngine.PlaySound(SoundID.Item14, NPC.Center); ExplodeAttack(); } bool goFast = despawn || NPC.localAI[0] > 0; Movement(target, goFast); if (arms != null && (NPC.localAI[3] == -1 || NPC.localAI[3] == 1)) //from arms { NPC.direction = NPC.spriteDirection = (int)NPC.localAI[3]; } bool canDoAttacks = FargoSoulsWorld.EternityMode && !goFast; if (canDoAttacks) //decide next action { float increment = 1f; if (head == null) { increment += 0.5f; } if (arms == null) { increment += 0.5f; } if (FargoSoulsWorld.MasochistModeReal) { increment += 1f; } if (NPC.dontTakeDamage) { increment /= 2; } if (target.Y > NPC.Top.Y) { NPC.ai[1] += increment; } else { NPC.ai[2] += increment; } if (Math.Abs(NPC.velocity.Y) < 0.05f) { //its structured like this to ensure body picks the right attack for the situation after being delayed by head/arms bool canProceed = !(head != null && head.ai[0] != 0) && !(arms != null && arms.ai[0] != 0); int threshold = 300; if (NPC.ai[1] > threshold) { if (canProceed) { NPC.ai[0] = 1f; NPC.ai[1] = 0f; //NPC.ai[2] = 0f; NPC.ai[3] = 0f; NPC.localAI[0] = 0f; NPC.netUpdate = true; } else { NPC.ai[1] -= 10f; } } if (NPC.ai[2] > threshold) { if (canProceed) { NPC.ai[0] = 1f; //NPC.ai[1] = 0f; NPC.ai[2] = 0f; NPC.ai[3] = 1f; NPC.localAI[0] = 0f; NPC.netUpdate = true; } else { NPC.ai[2] -= 10f; } } } } } break; case 1: //telegraph something { NPC.velocity.X *= 0.9f; TileCollision(player.Bottom.Y - 1 > NPC.Bottom.Y, Math.Abs(player.Center.X - NPC.Center.X) < NPC.width / 2 && NPC.Bottom.Y < player.Bottom.Y - 1); int threshold = 120; if (FargoSoulsWorld.EternityMode) { if (head == null) { threshold -= 20; } if (arms == null) { threshold -= 20; } if (head == null && arms == null) { threshold -= 30; } if (NPC.localAI[3] >= 2) { threshold -= 20; } } if (FargoSoulsWorld.MasochistModeReal) { threshold -= 20; } if (++NPC.localAI[0] > threshold) { NPC.localAI[0] = 0f; NPC.netUpdate = true; if (NPC.ai[3] == 0f) { NPC.ai[0] = 0f; NPC.localAI[0] = 300f; NPC.localAI[1] = Math.Sign(player.Center.X - NPC.Center.X); NPC.localAI[2] = player.Center.X; } else { NPC.ai[0] = 2f; } } } break; case 2: //jump { const float gravity = 0.4f; float time = FargoSoulsWorld.EternityMode && arms == null ? 60f : 90f; if (NPC.localAI[0]++ == 0) { Vector2 distance = player.Top - NPC.Bottom; if (FargoSoulsWorld.EternityMode && arms == null) { distance.X += NPC.width * Math.Sign(player.Center.X - NPC.Center.X); if (NPC.localAI[3] < 2) { NPC.localAI[3] = 2; //flag to stomp again on landing if (head == null) { NPC.localAI[3] += 2; //flag to do more stomps } } ExplodeAttack(); } distance.X = distance.X / time; distance.Y = distance.Y / time - 0.5f * gravity * time; NPC.velocity = distance; NPC.netUpdate = true; SoundEngine.PlaySound(SoundID.Item14, NPC.Center); } else { NPC.velocity.Y += gravity; } if (NPC.localAI[0] > time) { NPC.TargetClosest(false); NPC.velocity.X = Utils.Clamp(NPC.velocity.X, -20, 20); NPC.velocity.Y = Utils.Clamp(NPC.velocity.Y, -10, 10); NPC.ai[0] = 0f; NPC.localAI[0] = 0f; NPC.netUpdate = true; } } break; default: NPC.ai[0] = 0; goto case 0; } if (despawn) { if (NPC.timeLeft > 60) { NPC.timeLeft = 60; } } else { if (NPC.timeLeft < 600) { NPC.timeLeft = 600; } } if (head == null) { Vector2 pos = NPC.Top; pos.X += 2f * 16f * NPC.direction; pos.Y -= 8f; int width = 4 * 16; int height = 2 * 16; pos.X -= width / 2f; pos.Y -= height / 2f; for (int i = 0; i < 3; i++) { int d = Dust.NewDust(pos, width, height, DustID.Smoke, NPC.velocity.X, NPC.velocity.Y, 50, default(Color), 2.5f); Main.dust[d].velocity.Y -= 1.5f; Main.dust[d].velocity *= 1.5f; Main.dust[d].noGravity = true; } if (Main.rand.NextBool(3)) { int d = Dust.NewDust(pos, width, height, DustID.Torch, NPC.velocity.X * 0.4f, NPC.velocity.Y * 0.4f, 100, default(Color), 2.5f); Main.dust[d].noGravity = true; Main.dust[d].velocity.Y -= 3f; Main.dust[d].velocity *= 1.5f; } } else { lifeMaxHead = head.lifeMax; head = FargoSoulsUtil.NPCExists(head.whoAmI, ModContent.NPCType <TrojanSquirrelHead>()); } if (arms == null) { Vector2 pos = NPC.Center; pos.X -= 16f * NPC.direction; pos.Y -= 3f * 16f; int width = 2 * 16; int height = 2 * 16; pos.X -= width / 2f; pos.Y -= height / 2f; for (int i = 0; i < 2; i++) { int d = Dust.NewDust(pos, width, height, DustID.Smoke, NPC.velocity.X, NPC.velocity.Y, 50, default(Color), 1.5f); Main.dust[d].noGravity = true; } if (Main.rand.NextBool()) { int d2 = Dust.NewDust(pos, width, height, DustID.Torch, NPC.velocity.X * 0.4f, NPC.velocity.Y * 0.4f, 100, default(Color), 3f); Main.dust[d2].noGravity = true; } } else { lifeMaxArms = arms.lifeMax; arms = FargoSoulsUtil.NPCExists(arms.whoAmI, ModContent.NPCType <TrojanSquirrelArms>()); } if (NPC.life < NPC.lifeMax / 2 && Main.rand.NextBool(3)) { int d = Dust.NewDust(NPC.position, NPC.width, NPC.height, DustID.Smoke, NPC.velocity.X, NPC.velocity.Y, 50, default(Color), 4f); Main.dust[d].velocity.Y -= 1.5f; Main.dust[d].velocity *= 1.5f; Main.dust[d].noGravity = true; } if (FargoSoulsWorld.EternityMode) { bool wasImmune = NPC.dontTakeDamage; NPC.dontTakeDamage = NPC.life < NPC.lifeMax / 2 && (head != null || arms != null); if (wasImmune != NPC.dontTakeDamage) { for (int i = 0; i < 6; i++) { ExplodeDust(NPC.position + new Vector2(Main.rand.Next(NPC.width), Main.rand.Next(NPC.height))); } } } else { NPC.dontTakeDamage = false; } }