268 lines
12 KiB
C#
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>()));
|
|
}
|
|
}
|
|
}
|