using System.IO; using System.Linq; using Decimation.Content.Buffs.Debuffs; using Decimation.Content.Items.Boss.DuneWyrm; using Decimation.Content.Items.Misc.Souls; using Decimation.Content.Items.Vanity.DuneWyrm; using Decimation.Content.NPCs.DuneWyrm.AncientTombCrawler; using Decimation.Content.Projectiles; using Decimation.Lib.NPCs; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Terraria; using Terraria.ID; using Terraria.ModLoader; namespace Decimation.Content.NPCs.DuneWyrm { [AutoloadBossHead] internal class DuneWyrmHead : DuneWyrm { private int _previousTile = -1; private bool _spawnedAncientTombCrawler; public override void SetDefaults() { npc.lifeMax = 11000; npc.damage = 65; npc.defense = 15; npc.width = 116; npc.height = 116; Main.npcFrameCount[npc.type] = 1; npc.npcSlots = 1f; npc.aiStyle = -1; npc.boss = true; bossBag = ModContent.ItemType(); DuneWyrmBody.bodyPartsCount = 0; } public override void Init() { base.Init(); head = true; } public override void OnHitNPC(NPC target, int damage, float knockback, bool crit) { if (Main.rand.NextBool(5) || !Main.expertMode && Main.rand.NextBool(2)) target.AddBuff(ModContent.BuffType(), Main.expertMode ? 600 : 300); } public override void OnHitPlayer(Player target, int damage, bool crit) { if (Main.rand.NextBool(5) || !Main.expertMode && Main.rand.NextBool(2)) target.AddBuff(ModContent.BuffType(), Main.expertMode ? 600 : 300); } public override void NPCLoot() { if (!Main.expertMode) { Item.NewItem(npc.Center, ModContent.ItemType(), Main.rand.Next(15, 26)); if (Main.rand.NextBool(20)) Item.NewItem(npc.Center, ModContent.ItemType()); } else { npc.DropBossBags(); } } public override void BossLoot(ref string name, ref int potionType) { name = "The Great Dune Wyrm"; DecimationWorld.downedDuneWyrm = true; potionType = ItemID.HealingPotion; base.BossLoot(ref name, ref potionType); } public override void SendExtraAI(BinaryWriter writer) { writer.Write(_previousTile); writer.Write(_spawnedAncientTombCrawler); } public override void ReceiveExtraAI(BinaryReader reader) { _previousTile = reader.ReadInt32(); _spawnedAncientTombCrawler = reader.ReadBoolean(); } public override void CustomBehavior() { if (npc.life < npc.lifeMax / 2f) ComputeSpeed(); if (Main.expertMode) SummonSandnado(); if (Main.tile[(int) npc.Center.X / 16, (int) npc.Center.Y / 16].type != 0 && _previousTile == 0) ShootAmmonite(); if (npc.life <= npc.lifeMax * 0.15f && !_spawnedAncientTombCrawler && !NPC.AnyNPCs(ModContent.NPCType())) { if (Main.netMode != 1) NPC.SpawnOnPlayer(npc.target, ModContent.NPCType()); _spawnedAncientTombCrawler = true; } _previousTile = Main.tile[(int) npc.Center.X / 16, (int) npc.Center.Y / 16].type; } public override bool ShouldRun() { bool playersActive = Main.player.Any(p => p.active); bool playersDead = Main.player.Any(p => p.dead); return !Main.player[npc.target].ZoneDesert || !playersActive || playersDead; } private void ComputeSpeed() { const float ratio = 0.4545454f; float deltaLife = npc.lifeMax / 2f - npc.life; float addedSpeed = deltaLife * ratio / 1000f; speed = BaseSpeed + addedSpeed; } private void SummonSandnado() { int tile = Main.tile[(int) npc.Center.X / 16, (int) npc.Center.Y / 16].type; if (tile == 0 && _previousTile != 0 && Main.netMode != 1) Projectile.NewProjectile(npc.Center, new Vector2(0, 0), ProjectileID.SandnadoHostile, 15, 10f); } private void ShootAmmonite() { Main.PlaySound(SoundID.Item14, npc.Center); // Smoke for (int i = 0; i < 50; i++) { int dustIndex = Dust.NewDust(new Vector2(npc.position.X, npc.position.Y), npc.width, npc.height, 31, 0f, 0f, 100, default, 2f); Main.dust[dustIndex].velocity *= 1.4f; } float x = npc.position.X + npc.width / 2f - 24f; float y = npc.position.Y + npc.height / 2f - 24f; for (int g = 0; g < 2; g++) { int goreIndex = Gore.NewGore( new Vector2(x, y), default, Main.rand.Next(61, 64)); Main.gore[goreIndex].scale = 1.5f; Main.gore[goreIndex].velocity.X += 1.5f; Main.gore[goreIndex].velocity.Y += 1.5f; goreIndex = Gore.NewGore( new Vector2(x, y), default, Main.rand.Next(61, 64)); Main.gore[goreIndex].scale = 1.5f; Main.gore[goreIndex].velocity.X -= 1.5f; Main.gore[goreIndex].velocity.Y += 1.5f; goreIndex = Gore.NewGore( new Vector2(x, y), default, Main.rand.Next(61, 64)); Main.gore[goreIndex].scale = 1.5f; Main.gore[goreIndex].velocity.X += 1.5f; Main.gore[goreIndex].velocity.Y -= 1.5f; goreIndex = Gore.NewGore( new Vector2(x, y), default, Main.rand.Next(61, 64)); Main.gore[goreIndex].scale = 1.5f; Main.gore[goreIndex].velocity.X -= 1.5f; Main.gore[goreIndex].velocity.Y -= 1.5f; } // Ammonite int ammoniteNbr = Main.rand.Next(5, 9); if (Main.netMode != 1) for (int i = 0; i < ammoniteNbr; i++) Projectile.NewProjectile(npc.Center, new Vector2(Main.rand.Next(-8, 9), Main.rand.Next(8, 15)), ModContent.ProjectileType(), 15, 5f); } public override bool? DrawHealthBar(byte hbPosition, ref float scale, ref Vector2 position) { scale = 1.9f; //this make the NPC Health Bar bigger return null; } public override bool PreDraw(SpriteBatch spriteBatch, Color drawColor) { Draw("Content/NPCs/DuneWyrm/DuneWyrmHead", spriteBatch, drawColor); return false; } } internal class DuneWyrmBody : DuneWyrm { public static int bodyPartsCount; private int _bodyIndex; public override void SetDefaults() { npc.width = 66; npc.height = 66; npc.damage = 45; npc.defense = 5; npc.lifeMax = 1; npc.dontCountMe = true; _bodyIndex = bodyPartsCount++; } public override bool PreDraw(SpriteBatch spriteBatch, Color drawColor) { Vector2 frameSize = new Vector2(npc.width, npc.height); Texture2D texture = mod.GetTexture("Content/NPCs/DuneWyrm/DuneWyrmBody"); Rectangle sourceRectangle = npc.frame; if (_bodyIndex % 4 == 0) { texture = mod.GetTexture("Content/NPCs/DuneWyrm/DuneWyrmBody2"); sourceRectangle.Width = 88; sourceRectangle.Height = 66; frameSize.X += 11; frameSize.Y -= 10; } Vector2 position = new Vector2( npc.position.X - Main.screenPosition.X + frameSize.X / 2f, npc.position.Y - Main.screenPosition.Y + frameSize.Y / 2f ); spriteBatch.Draw ( texture, position, sourceRectangle, drawColor, npc.rotation, frameSize * 0.5f, npc.scale, SpriteEffects.None, 0f ); return false; } } internal class DuneWyrmTail : DuneWyrm { public override void SetDefaults() { npc.width = 54; npc.height = 54; npc.damage = 45; npc.defense = 14; npc.lifeMax = 1; npc.dontCountMe = true; } public override void Init() { base.Init(); tail = true; } public override bool PreDraw(SpriteBatch spriteBatch, Color drawColor) { Draw("Content/NPCs/DuneWyrm/DuneWyrmTail", spriteBatch, drawColor); return false; } } public abstract class DuneWyrm : Worm { protected const float BaseSpeed = 10f; public override void SetStaticDefaults() { DisplayName.SetDefault("Great Dune Wyrm"); } public override void Init() { minLength = 16; maxLength = 16; tailType = ModContent.NPCType(); bodyType = ModContent.NPCType(); headType = ModContent.NPCType(); speed = BaseSpeed; turnSpeed = 0.045f; npc.value = Item.sellPrice(gold: 16); npc.scale = 1.5f; npc.lavaImmune = true; npc.noGravity = true; npc.noTileCollide = true; npc.behindTiles = true; npc.knockBackResist = 0f; npc.netAlways = true; npc.DeathSound = SoundID.NPCDeath18; npc.HitSound = SoundID.NPCHit1; undergroundSound = mod.GetLegacySoundSlot(SoundType.Custom, "Sounds/Custom/Earthquake"); music = mod.GetSoundSlot(SoundType.Music, "Sounds/Music/DuneWyrm"); } protected override void SendSoundPacket() { GetPacket(DuneWyrmMessageType.UndergroundSound).Send(); } private ModPacket GetPacket(DuneWyrmMessageType type) { ModPacket packet = mod.GetPacket(); packet.Write((byte) DecimationModMessageType.DuneWyrm); packet.Write(npc.whoAmI); packet.Write((byte) type); return packet; } public void HandlePacket(BinaryReader reader) { DuneWyrmMessageType type = (DuneWyrmMessageType) reader.ReadByte(); switch (type) { case DuneWyrmMessageType.UndergroundSound: Main.PlaySound(undergroundSound, npc.Center); break; } } } public enum DuneWyrmMessageType { UndergroundSound } }