244 lines
9.8 KiB
C#
244 lines
9.8 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.
|
|
*/
|
|
|
|
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
|
|
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>()));
|
|
}
|
|
}
|
|
}
|