using Terraria; using Terraria.ID; using Terraria.ModLoader; using Microsoft.Xna.Framework; using Terraria.Chat; using Terraria.Localization; using Terraria.GameContent.ItemDropRules; using ForgottenWawiTech.Content.Items.TreasureBags; namespace ForgottenWawiTech.Content.NPCs.OriginalNiko { [AutoloadBossHead] public class Niko : ModNPC { public override void SetStaticDefaults() { Main.npcFrameCount[NPC.type] = 1; } public override void SetDefaults() { NPC.width = 40; NPC.height = 40; NPC.damage = 20000; NPC.defense = 500; NPC.lifeMax = 10000000; NPC.HitSound = SoundID.NPCHit1; NPC.DeathSound = SoundID.NPCDeath1; NPC.knockBackResist = 0.5f; NPC.boss = true; NPC.aiStyle = -1; NPC.value = Item.buyPrice(100, 0, 0, 0); } public override void AI() { /* IDEA: Phase 1: Somewhat tame, false sense of security. Until 75% HP Phase 1.5: Invulnerable, drifts around, monologue for ~1 minute Phase 2: Heal 50% HP back, more aggressive behaviour until 50% HP Phase 3: Spawn other bosses if undefeated Phase 3.5: After other bosses are defeated (or if they aren't spawned), short pause for dialogue Phase 4: More aggressive behaviour until 20% HP Phase 5: Final behaviour. Practically no restrictions on movement or attacks. Each individual phase I have yet to fully plan out, but the main idea is simple. What if we uncapped a Player's limitations and slapped them as a boss with near end-game gear? Starting music will be a piano remix of "Famous Last Words" by My Chemical Romance, transitioning into a metal-ier remix of "In The End" by Linkin Park for phase 2 onwards, finishing with a more sombre remix of "My Way" by Frank Sinatra for the ending. */ /* IDEA: Attacks Attack 1 (Phase 2 onwards): Niko will use the Shockwave Hammer (fortnite) and start rapidly bouncing towards the closest player, making large arcs in the air while rapidly spinning. They can not change direction while in the air. They will throw out Nyananades while in this state, designed to either overwhelm or lag the player to death. When nearing a player, they will slam on/next to the player, inflicting extremely high damage. If this doesn't kill the player, Niko will then throw/swing the hammer at the player with predictive aiming, which on hit will launch the player at high speeds and completely negating wing time. If the player is launched, this is practically instadeath for the player. Niko will teleport behind them and slam them into the ground at high speed, on impact will kill the player. Its escapable if the player is launched into a hole going down to hell, as terminal velocity will eventually slow the player down enough to survive the impact. Attack 2: Niko will summon a large amount of floating speakers to orbit around them, launching sound waves at the player at quite high speeds periodically. The speakers can be destroyed with enough damage. Each sound wave that hits the player will inflict a stacking debuff that increases damage taken by 5% per stack, up to 10 stacks (50% increased damage taken). Attack 3: Niko will charge up the Last Prism from Vanilla Terraria, tracking the player with the beam. This will last for ~30 seconds, dealing massive damage to players caught in the beam. Attack 4: Niko will grab a cannon and start launching Avali Scouts at the player with high velocity. These Avali Scouts will have 1/10th of Niko's health and deal 1/10th of Niko's damage, but will swarm the player in large numbers. They will prioritise players with the lowest health. Attack 5: Niko will throw out a large number of black holes that will slowly drift towards the player. These black holes will pull players in slowly, dealing high DOT damage to players caught in the pull. Players can escape the pull with enough movement speed (or rod of discord). Attack 6: Niko will summon a large number of holographic clones of themself that will mimic their movements. These clones will deal 1/20th of Niko's damage and have 1/20th of Niko's health, but will swarm the player in large numbers. The clones can not use attack 1 (bounce slam) but can use all other attacks. Attack 7: Niko will use a modified and uncapped version of the Zenith, allowing them to fire three large arcs of swords that home in on the player. These swords will deal high damage on hit and fully pierce through players, hitting multiple times. Attack 8: Niko will use an uncapped Meowmere/True Nyanageddon, allowing them to bombard the player with a large number of cat projectiles. These cat projectiles will home in on the player, dealing moderate damage on hit. The cats will also inflict a stacking debuff that increases damage taken by 2% per stack, up to 25 stacks (50% increased damage taken). Each attack will be used in a semi-random order, with ~0.5 second gaps between each attack to allow the player to reposition. All attacks will have their damage and health scaled based on the current phase, with later phases having higher damage and health for all attacks. Plus, all projectiles will use predictive aiming to make dodging more difficult. */ NPC.TargetClosest(false); Player target = Main.player[NPC.target]; if (!target.active || target.dead) { NPC.timeLeft = 300; return; } int phase = (int)NPC.ai[0]; int flags = (int)NPC.ai[1]; // bit0=Lyyka spawned, bit1=Neptune spawned, bit2=Lexy spawned int timer = (int)NPC.ai[2]; // Simple dummy movement helper void DoDummyMovement(float speed) { Vector2 dir = target.Center - NPC.Center; if (dir.Length() > 8f) { dir.Normalize(); NPC.velocity = Vector2.Lerp(NPC.velocity, dir * speed, 0.02f); } } // Phase 0: initial until 50% HP if (phase == 0) { DoDummyMovement(3f); if (NPC.life <= NPC.lifeMax / 2) { // Enter invulnerable phase NPC.ai[0] = 1; NPC.ai[2] = 0; // reset timer NPC.dontTakeDamage = true; NPC.netUpdate = true; string announce = "Niko envelopes themself in a strange silence..."; if (Main.netMode != NetmodeID.MultiplayerClient) Main.NewText(announce, 200, 100, 255); else ChatHelper.BroadcastChatMessage(NetworkText.FromLiteral(announce), new Color(200, 100, 255)); } } // Phase 1: invulnerable waiting (~1 minute) for dialogue else if (phase == 1) { NPC.ai[2]++; // Idle drift NPC.velocity *= 0.98f; // Periodic short dialogue during invulnerable phase int t = (int)NPC.ai[2]; if (t == 120) { string line = "...silence stretches, an uneasy calm."; if (Main.netMode != NetmodeID.MultiplayerClient) Main.NewText(line, 200, 120, 255); else ChatHelper.BroadcastChatMessage(NetworkText.FromLiteral(line), new Color(200, 120, 255)); } else if (t == 900) { string line = "Impressive..."; if (Main.netMode != NetmodeID.MultiplayerClient) Main.NewText(line, 220, 160, 255); else ChatHelper.BroadcastChatMessage(NetworkText.FromLiteral(line), new Color(220, 160, 255)); } else if (t == 1000) { string line = "But this has already gone on long enough."; if (Main.netMode != NetmodeID.MultiplayerClient) Main.NewText(line, 180, 130, 255); else ChatHelper.BroadcastChatMessage(NetworkText.FromLiteral(line), new Color(180, 130, 255)); } // TODO: Audio and VO lines here else if (t == 1500) { string line = "Sky has rated the following film 12 - suitable for ages 12 and above."; if (Main.netMode != NetmodeID.MultiplayerClient) Main.NewText(line, 210, 150, 255); else ChatHelper.BroadcastChatMessage(NetworkText.FromLiteral(line), new Color(210, 150, 255)); } else if (t == 1800) { string line = "This film contains violence, explicit language, and flashing images."; // this is such a random reference that ill be surprised if anyone gets it especially outside gb if (Main.netMode != NetmodeID.MultiplayerClient) Main.NewText(line, 230, 180, 255); else ChatHelper.BroadcastChatMessage(NetworkText.FromLiteral(line), new Color(230, 180, 255)); } // TODO: When audio is finished, switch to Noctis Boss 2 theme (remix of In The End? Or something new? TBA) // After approx 42 seconds (2500 ticks), end invulnerability if (NPC.ai[2] >= 2500) { NPC.dontTakeDamage = false; NPC.ai[0] = 2; NPC.netUpdate = true; string announce = "Now get out of my sight."; if (Main.netMode != NetmodeID.MultiplayerClient) Main.NewText(announce, 255, 150, 100); else ChatHelper.BroadcastChatMessage(NetworkText.FromLiteral(announce), new Color(255, 150, 100)); } } // Phase 2: dummy AI after invul until 30% HP else if (phase == 2) { DoDummyMovement(4f); if (NPC.life <= (int)(NPC.lifeMax * 0.3f)) { NPC.ai[0] = 3; // go to spawn phase NPC.netUpdate = true; } } // Phase 3: spawn other bosses if undefeated else if (phase == 3) { // Spawn Lyyka if undefeated and not already spawned if (!WorldDefeatedBosses.Lyyka && (flags & 1) == 0) { flags |= 1; string announceL = "Lyyka is called to the fray!"; } // Spawn Neptune if undefeated and not already spawned if (!WorldDefeatedBosses.Neptune && (flags & 2) == 0) { flags |= 2; string announceN = "The waves answer Niko's call: Neptune arrives!"; } // Spawn Lexy if undefeated and not already spawned if (!WorldDefeatedBosses.Lexy && (flags & 4) == 0) { flags |= 4; string announceX = "Lexy emerges to twist the battlefield!"; } // Save flags and move to final phase NPC.ai[1] = flags; NPC.ai[0] = 4; NPC.netUpdate = true; } // Phase 4+: final behaviour (dummy) else { DoDummyMovement(5f); } } public override void OnKill() { // Ending monologue before playing the final track // Only if Niko was actually defeated (not fled) and hasn't been defeated before // Final track to be a remix of "My Way" by Frank Sinatra, referencing Perfect Cell's death in DBZA. if (!WorldDefeatedBosses.Niko) { string line1 = "With a final breath, Niko whispers..."; string line2 = "\"gg, no re\""; string line3 = "The battlefield falls silent as Niko vanishes."; if (Main.netMode != NetmodeID.MultiplayerClient) { Main.NewText(line1, 255, 100, 100); Main.NewText(line2, 200, 50, 50); Main.NewText(line3, 255, 150, 150); } else { ChatHelper.BroadcastChatMessage(NetworkText.FromLiteral(line1), new Color(255, 100, 100)); ChatHelper.BroadcastChatMessage(NetworkText.FromLiteral(line2), new Color(200, 50, 50)); ChatHelper.BroadcastChatMessage(NetworkText.FromLiteral(line3), new Color(255, 150, 150)); } // Set a world flag or similar to indicate Niko has been defeated WorldDefeatedBosses.Niko = true; // Immediate sync of world flags WorldDefeatedBosses.Sync(ModContent.GetInstance()); } } public override void ModifyNPCLoot(NPCLoot npcLoot) { npcLoot.Add(ItemDropRule.BossBag(ModContent.ItemType())); } } }