Files
ForgottenWawiTech/Content/NPCs/OriginalNiko/Niko.cs
T

268 lines
12 KiB
C#

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 = 2000;
NPC.defense = 300;
NPC.lifeMax = 1000000;
NPC.HitSound = SoundID.NPCHit1;
NPC.DeathSound = SoundID.NPCDeath1;
NPC.knockBackResist = 0f;
NPC.boss = true;
NPC.aiStyle = -1;
NPC.value = Item.buyPrice(0, 1, 0, 0);
}
public override void AI()
{
/*
IDEA:
Phase 1: Somewhat tame, false sense of security. 75% HP
Phase 1.5: Invulnerable, drifts around, monologue for ~1 minute
Phase 2: Heal 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: Final behaviour
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?
Nintendo don't sue me - I am only copying Inner Agent 3 here. Alongside rough ideas of the Uzi and Cyn fight from Murder Drones.
Music (if legality allows) is planned to be a rock-ier remix of "In The End" by Linkin Park, fitting Niko's emo ass.
*/
/*
IDEA: Enraged Behaviour
Attack 1:
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.
Each attack will be used in a semi-random order, with ~0.5 second gaps between each attack to allow the player to reposition.
This will repeat until the player is defeated or Niko is defeated.
*/
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<ForgottenWawiTech>());
}
}
public override void ModifyNPCLoot(NPCLoot npcLoot)
{
npcLoot.Add(ItemDropRule.BossBag(ModContent.ItemType<NikoBossBag>()));
}
}
}