using System; using System.IO; using Decimation.Content.Buffs.Debuffs; using Decimation.Content.Items.Boss.Arachnus; using Decimation.Content.Items.Misc.Souls; using Decimation.Content.Items.Weapons.Arachnus; using Decimation.Content.Projectiles; using Decimation.Content.Tiles.ShrineoftheMoltenOne; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Terraria; using Terraria.ID; using Terraria.ModLoader; namespace Decimation.Content.NPCs.Arachnus { [AutoloadBossHead] internal class Arachnus : ModNPC { public enum ArachnusMessageType { RoarSound, FlamesSound } private int _counter; private int _counterMax = 1320; private float _speed = 2; public override void SetStaticDefaults() { DisplayName.SetDefault("Arachnus"); Main.npcFrameCount[npc.type] = 4; } public override void SetDefaults() { npc.aiStyle = -1; npc.lifeMax = 80000; npc.damage = 100; npc.defense = 25; npc.knockBackResist = 0f; npc.width = 200; npc.height = 200; npc.value = 50000; npc.npcSlots = 1f; npc.boss = true; npc.lavaImmune = true; npc.noGravity = true; npc.noTileCollide = false; // When not enraged npc.HitSound = SoundID.NPCHit6; npc.DeathSound = SoundID.NPCDeath10; music = mod.GetSoundSlot(SoundType.Music, "Sounds/Music/Drums_of_hell"); bossBag = ModContent.ItemType(); npc.lavaImmune = true; npc.buffImmune[BuffID.OnFire] = true; npc.buffImmune[BuffID.Burning] = true; } public override void ScaleExpertStats(int numPlayers, float bossLifeScale) { npc.lifeMax = (int) (npc.lifeMax * 0.625f * bossLifeScale); npc.damage = (int) (npc.damage * 0.6f); npc.defense = npc.defense + numPlayers * 2; } private bool CheckDispawn() { bool playersActive = false; bool playersDead = true; foreach (Player player in Main.player) { if (player.active) playersActive = true; if (!player.dead) playersDead = false; } return playersDead || !playersActive; } private void Move() { // Rotate to player Vector2 moveTo = Main.player[npc.target].Center - npc.Center; float angle = (float) Math.Atan2(moveTo.Y, moveTo.X); npc.rotation = (float) (angle + Math.PI * 0.5f); // Move Vector2 move = moveTo; float magnitude = (float) Math.Sqrt(move.X * move.X + move.Y * move.Y); if (magnitude > _speed) move *= _speed / magnitude; float turnResistance = 50f; move = (npc.velocity * turnResistance + move) / (turnResistance + 1f); magnitude = (float) Math.Sqrt(move.X * move.X + move.Y * move.Y); if (magnitude > _speed) move *= _speed / magnitude; npc.velocity = npc.ai[1] != 99 ? move : new Vector2(0, 0); } private bool CheckForShrine() { bool tooFarFromShrine = true; if (_counter % 60 == 0) { int validBlockCount = 0; for (int i = (int) (-50 + npc.Center.X / 16f); i <= (int) (50 + npc.Center.X / 16f); i++) for (int j = (int) (-50 + npc.Center.Y / 16f); j <= (int) (50 + npc.Center.Y / 16f); j++) if (i >= 0 && i <= Main.maxTilesX && j >= 0 && j <= Main.maxTilesY) if (Main.tile[i, j].type == ModContent.TileType() || Main.tile[i, j].type == ModContent.TileType() || Main.tile[i, j].type == ModContent.TileType() || Main.tile[i, j].type == ModContent.TileType() || Main.tile[i, j].type == ModContent.TileType() || Main.tile[i, j].type == ModContent.TileType()) validBlockCount++; if (validBlockCount < 15) tooFarFromShrine = true; else tooFarFromShrine = false; } else { return npc.ai[2] == 1; } return tooFarFromShrine; } private void CheckEnraged() { npc.ai[2] = !Main.player[npc.target].ZoneUnderworldHeight || !Collision.CanHit(npc.Center, 0, 0, Main.player[npc.target].Center, 0, 0) || CheckForShrine() ? 1 : 0; } public override void AI() { if (CheckDispawn()) { npc.velocity = new Vector2(0, 10f); npc.noTileCollide = true; if (npc.timeLeft > 10) npc.timeLeft = 10; } npc.TargetClosest(); CheckEnraged(); // Normal ai if (npc.ai[0] == 0) { float mouthX = (float) (npc.height / 2 * Math.Cos(npc.rotation - Math.PI * 0.5f)) + npc.Center.X; float mouthY = (float) (npc.height / 2 * Math.Sin(npc.rotation - Math.PI * 0.5f)) + npc.Center.Y; //Counter if (npc.life <= npc.lifeMax / 2) _counterMax = 1500; if (_counter >= _counterMax && Main.netMode != 1) { _counter = 0; npc.netUpdate = true; } // Fireballs if (_counter <= 600) { npc.ai[1] = 0; } else if (_counter > 600 && _counter < 800) { npc.ai[1] = 98; } // Blast of Heat else if (_counter >= 800 && _counter <= 1100) { npc.ai[1] = 1; } // Increase speed else if (_counter > 1320 && _counter <= 1500 || Main.expertMode && _counter > 600 && _counter < 800 && npc.life <= npc.lifeMax / 4) { if (_counter == 1321) { if (Main.netMode == NetmodeID.SinglePlayer) Main.PlaySound(SoundID.Roar, (int) npc.position.X, (int) npc.position.Y, 0); if (Main.netMode == NetmodeID.Server) GetPacket(ArachnusMessageType.RoarSound).Send(); } npc.ai[1] = 2; } else { npc.ai[1] = 99; } if (_counter % 40 == 0 && npc.ai[1] == 0 && Main.netMode != 1) { float speedX = (float) (6 * Math.Cos(npc.rotation - Math.PI * 0.5f)) * 2; float speedY = (float) (6 * Math.Sin(npc.rotation - Math.PI * 0.5f)) * 2; Projectile.NewProjectile(new Vector2(mouthX, mouthY), new Vector2(speedX, speedY), ModContent.ProjectileType(), 30, 0f); } else if (_counter % 5 == 0 && npc.ai[1] == 1) { if (Main.netMode != 1) { float speedX = (float) (7 * Math.Cos(npc.rotation - Math.PI * 0.5f)); float speedY = (float) (7 * Math.Sin(npc.rotation - Math.PI * 0.5f)); Projectile.NewProjectile(new Vector2(mouthX, mouthY), new Vector2(speedX, speedY), npc.ai[2] == 1 ? ModContent.ProjectileType() : ModContent.ProjectileType(), 30, 0f); } Main.PlaySound(SoundID.Item34, npc.position); if (Main.netMode == 2) GetPacket(ArachnusMessageType.FlamesSound).Send(); } else if (npc.ai[1] == 2) { _speed = 20f; if (Main.expertMode) { _speed = (npc.lifeMax - npc.life) / 500; if (npc.ai[2] == 1) _speed += 20; } else if (npc.ai[2] == 1) { _speed = 40f; } } if (npc.ai[1] != 2) _speed = 2f; // Enraged if (npc.ai[2] == 1) { npc.noTileCollide = true; Dust.NewDust(npc.position, npc.width, npc.height, DustID.Shadowflame); if (npc.ai[1] != 2) { _speed = 6f; npc.defense = 300; } } _counter++; } Move(); } public override void SendExtraAI(BinaryWriter writer) { writer.Write(_counter); writer.Write(_counterMax); writer.Write(_speed); } public override void ReceiveExtraAI(BinaryReader reader) { _counter = reader.ReadInt32(); _counterMax = reader.ReadInt32(); _speed = reader.ReadSingle(); } private ModPacket GetPacket(ArachnusMessageType type) { ModPacket packet = mod.GetPacket(); packet.Write((byte) DecimationModMessageType.Arachnus); packet.Write(npc.whoAmI); packet.Write((byte) type); return packet; } public void HandlePacket(BinaryReader reader) { ArachnusMessageType type = (ArachnusMessageType) reader.ReadByte(); switch (type) { case ArachnusMessageType.RoarSound: Main.PlaySound(SoundID.Roar, (int) npc.position.X, (int) npc.position.Y, 0); break; case ArachnusMessageType.FlamesSound: Main.PlaySound(SoundID.Item34, npc.position); break; } } public override void OnHitPlayer(Player target, int damage, bool crit) { if (npc.ai[1] == 2 && Main.expertMode) target.AddBuff(ModContent.BuffType(), 900); base.OnHitPlayer(target, damage, crit); } public override void FindFrame(int frameHeight) { npc.frameCounter += 3f; if (npc.frameCounter >= 40) npc.frameCounter = 0; npc.frame.Y = (int) npc.frameCounter / 10 * frameHeight; } public override void NPCLoot() { Item.NewItem(npc.Center, ModContent.ItemType(), Main.rand.Next(15, 31)); if (!Main.expertMode) { int rand = Main.rand.Next(3); if (rand == 0) Item.NewItem(npc.Center, ModContent.ItemType()); else if (rand == 1) Item.NewItem(npc.Center, ModContent.ItemType()); else if (rand == 2) Item.NewItem(npc.Center, ModContent.ItemType()); } else { npc.DropBossBags(); } } public override void BossLoot(ref string name, ref int potionType) { name = "Arachnus"; // Maybe better potionType = ItemID.SuperHealingPotion; DecimationWorld.downedArachnus = true; } public override bool? DrawHealthBar(byte hbPosition, ref float scale, ref Vector2 position) { scale = 1.5f; return null; } public override bool PreDraw(SpriteBatch spriteBatch, Color drawColor) { Vector2 frameSize = new Vector2(298, 318); Texture2D texture = mod.GetTexture("Content/NPCs/Arachnus/Arachnus"); spriteBatch.Draw ( texture, new Vector2 ( npc.position.X - Main.screenPosition.X + frameSize.X * 0.34f, npc.position.Y - Main.screenPosition.Y + frameSize.Y * 0.31f ), npc.frame, drawColor, npc.rotation, frameSize * 0.5f, npc.scale, SpriteEffects.None, 0f ); return false; } } }