Files
ForgottenWawiTech/Content/NPCs/TownNPCs/AvalianTrader.cs
T
2025-11-27 12:17:35 +00:00

303 lines
12 KiB
C#

using System.Collections.Generic;
using System.Reflection;
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;
using Terraria.GameContent.Personalities;
using Terraria.Localization;
using ForgottenWawiTech;
namespace ForgottenWawiTech.Content.NPCs.TownNPCs
{
public class AvalianTrader : ModNPC
{
private static readonly Condition HasDefeatedAnyMechBoss = new("Mods.ForgottenWawiTech.Conditions.HasDefeatedAnyMechBoss", () =>
NPC.downedMechBoss1 || NPC.downedMechBoss2 || NPC.downedMechBoss3);
private static readonly Condition HasDefeatedLexy = new("Mods.ForgottenWawiTech.Conditions.HasDefeatedLexy", () =>
Main.hardMode && WorldDefeatedBosses.Lexy);
private static readonly Condition HasDefeatedNiko = new("Mods.ForgottenWawiTech.Conditions.HasDefeatedNiko", () =>
Main.hardMode && WorldDefeatedBosses.Niko);
private static readonly Condition HasDefeatedNeptune = new("Mods.ForgottenWawiTech.Conditions.HasDefeatedNeptune", () =>
Main.hardMode && WorldDefeatedBosses.Neptune);
private static readonly Condition HasDefeatedLyyka = new("Mods.ForgottenWawiTech.Conditions.HasDefeatedLyyka", () =>
Main.hardMode && WorldDefeatedBosses.Lyyka);
private static readonly Condition HasDefeatedCorruptedSwarm = new("Mods.ForgottenWawiTech.Conditions.HasDefeatedCorruptedSwarm", () =>
Main.hardMode && WorldDefeatedBosses.Niko); // TODO: Replace with Corrupted Swarm flag once implemented.
private static readonly Condition HasDefeatedExoMechs = new("Mods.ForgottenWawiTech.Conditions.HasDefeatedExoMechs", CheckExoMechsDowned);
private static readonly Condition HasDefeatedMoonLord = new("Mods.ForgottenWawiTech.Conditions.HasDefeatedMoonLord", () =>
NPC.downedMoonlord);
private static bool CheckExoMechsDowned()
{
if (!ModLoader.TryGetMod("CalamityMod", out Mod calamityMod))
{
return false;
}
var calamityWorldType = calamityMod.Code?.GetType("CalamityMod.World.CalamityWorld");
if (calamityWorldType == null)
{
return false;
}
const BindingFlags flags = BindingFlags.Public | BindingFlags.Static;
var field = calamityWorldType.GetField("downedExoMechs", flags);
if (field?.GetValue(null) is bool fieldValue)
{
return fieldValue;
}
var property = calamityWorldType.GetProperty("downedExoMechs", flags);
if (property?.GetValue(null) is bool propertyValue)
{
return propertyValue;
}
return false;
}
public override void SetStaticDefaults()
{
Main.npcFrameCount[NPC.type] = 25; // The amount of frames the NPC has
NPCID.Sets.ExtraFramesCount[NPC.type] = 9; // Generally for Town NPCs, this should be 9
NPCID.Sets.AttackFrameCount[NPC.type] = 4;
NPCID.Sets.DangerDetectRange[NPC.type] = 700; // The amount of pixels away from the center of the npc that it tries to attack enemies
NPCID.Sets.AttackType[NPC.type] = 0;
NPCID.Sets.AttackTime[NPC.type] = 90; // The amount of time it takes for the NPC's attack animation to be over
NPCID.Sets.AttackAverageChance[NPC.type] = 30;
NPCID.Sets.HatOffsetY[NPC.type] = 4; // For when a party is active, the party hat spawns at a Y offset
NPC.Happiness
.SetNPCAffection(NPCID.Merchant, AffectionLevel.Love)
.SetNPCAffection(NPCID.Demolitionist, AffectionLevel.Like)
.SetNPCAffection(NPCID.GoblinTinkerer, AffectionLevel.Like)
.SetNPCAffection(NPCID.SkeletonMerchant, AffectionLevel.Dislike);
// Influences how the NPC looks in the Bestiary
NPCID.Sets.NPCBestiaryDrawModifiers drawModifiers = new NPCID.Sets.NPCBestiaryDrawModifiers(0)
{
Velocity = 1f, // Draws the NPC in the bestiary as if its walking +1 tiles in the x direction
Direction = 1 // -1 is left and 1 is right. NPCs are drawn facing the left by default
};
NPCID.Sets.NPCBestiaryDrawOffset.Add(Type, drawModifiers);
}
public override void SetDefaults()
{
NPC.townNPC = true;
NPC.friendly = true;
NPC.width = 18;
NPC.height = 40;
NPC.aiStyle = 7;
NPC.damage = 30;
NPC.defense = 10;
NPC.lifeMax = 500;
NPC.HitSound = SoundID.NPCHit1;
NPC.DeathSound = SoundID.NPCDeath6;
NPC.knockBackResist = 0.5f;
AnimationType = NPCID.Guide;
}
public override bool CanTownNPCSpawn(int numTownNPCs)
{
// Only spawn if a player has obtained RGBass in this world
//return ForgottenWawiTechSystem.hasObtainedRGBass;
return true; // Temporary for testing
}
public override List<string> SetNPCNameList()
{
return new List<string>() {
"Kivuli",
"Sekai",
"Taerik",
"Nykra",
"Vekir",
"Shyrik",
"Kaelis",
"Nyxal",
"Verik",
"Skyris",
"Taeli",
"Nyrik",
"Kaevi",
"Vyxen",
"Syrrik",
"Nykai"
};
}
public override void SetChatButtons(ref string button, ref string button2)
{
button = Language.GetTextValue("LegacyInterface.28"); // "Shop"
button2 = "Talk";
}
public override void OnChatButtonClicked(bool firstButton, ref string shop)
{
if (firstButton)
{
shop = "Shop";
}
else;
{
// TODO: Bring up a UI for a player to give an item to the NPC which will explain lore.
shop = "Shop"; // Placeholder to avoid errors
}
}
public override void AddShops()
{
Item rainbowBrick = new();
rainbowBrick.SetDefaults(ItemID.RainbowBrick);
rainbowBrick.value = Item.buyPrice(silver: 90);
new NPCShop(Type)
.Add<Items.Materials.VisorShard>(HasDefeatedLexy)
.Add<Items.Materials.FallenAngelFeather>(HasDefeatedNiko)
.Add<Items.Materials.HalfEatenFish>(HasDefeatedNeptune)
.Add<Items.Materials.LyykaBossDrop>(HasDefeatedLyyka)
.Add<Items.Materials.UnstableMatter>(HasDefeatedCorruptedSwarm) // TODO: Replace with Corrupted Swarm flag once implemented.
.Add(rainbowBrick, Condition.Hardmode)
.Add<Items.Materials.AvaliFeather>()
.Add<Items.Materials.RGBAlloy>(HasDefeatedMoonLord)
.Add<Items.Materials.EnergyCore>(HasDefeatedAnyMechBoss)
.Add<Items.Materials.ContainmentUnit>(HasDefeatedExoMechs)
.Add<Items.Materials.ControlledSingularity>(HasDefeatedExoMechs)
.Add<Items.Materials.MiniSingularity>(HasDefeatedExoMechs)
.Add<Items.Materials.SingularityAlloy>(HasDefeatedExoMechs)
.Add<Items.Materials.RGBass>(HasDefeatedMoonLord)
.Register();
}
public override string GetChat()
{
List<string> lines = new()
{
"*avalian chirping*",
"Welcome! I've traveled far from Avalon to bring you the finest technology.",
"My pack may be small, but I've traversed dimensions to get here.",
"*chirps excitedly* Oh, you're interested in our wares?",
"RGBass - it's not just a material, it's a lifestyle.",
"Those rainbow bricks? Ninety silver each. I have transport costs, you know.",
"The journey here was long, but your world has such fascinating resources!",
"Need something? My shop is always open!",
"Avalian markets never sleep; neither does my inventory.",
"If you see a hover sled parked outside, please don't touch the controls.",
"Try not to lick the stock. Some of it bites back.",
"The atmosphere here is thick, but profits make it worth the acclimation.",
"I keep a thermal blanket under the clothes —these nights get cold even for an Avali.",
"Do you have any idea how much customs paperwork interstellar trade requires?",
"If you hear humming, that's just the containment field. Probably."
};
if (HasDefeatedLexy.IsMet())
{
lines.Add("Defeated Lexy, have you? His visor shards always sell out fast.");
lines.Add("Lexy's visor tech makes for excellent souvenirs. Stock up while I have them.");
}
else if (Main.hardMode)
{
lines.Add("Still hunting Lexy? Bring me his visor and I'll unlock some premium stock.");
}
if (HasDefeatedNiko.IsMet())
{
lines.Add("Astramora's Angel Feathers? Delicate, pricey, worth every coin.");
lines.Add("I've reinforced the shipping crates just for Astramora's volatile feathers.");
}
else if (Main.hardMode)
{
lines.Add("I've heard whispers of a faux angel around these parts of the galaxy...");
}
if (HasDefeatedNeptune.IsMet())
{
lines.Add("Neptune leaves quite the mess. Half-eaten fish, anyone?");
lines.Add("Neptune's half-eaten catches sell faster than I'd like—apparently otter bites add flavor.");
}
else if (Main.hardMode)
{
lines.Add("If you're braving the tides, bring Neptune down and I'll import his catches.");
}
if (HasDefeatedLyyka.IsMet())
{
lines.Add("Avalon sends its regards! Lyyka's gear is highly sought after.");
lines.Add("Lyyka's encore was explosive. Her gear? Even more so.");
}
else if (Main.hardMode)
{
lines.Add("Bring down Lyyka and I'll uncrate her signature alloys.");
}
if (HasDefeatedCorruptedSwarm.IsMet())
{
lines.Add("Unstable Matter? Just delicate enough for my clientele.");
lines.Add("Careful with the Unstable Matter; Avalon still has a watchful eye on it. Especially you.");
}
else if (Main.hardMode)
{
lines.Add("Manage to defeat the Corrupted Swarm, and I am sure I can sneak some of the best material your way.");
}
if (HasDefeatedAnyMechBoss.IsMet())
{
lines.Add("Mechanical husks make great recycling. Fancy some RGB alloys?");
}
if (HasDefeatedMoonLord.IsMet())
{
lines.Add("You have some Moon Lord tech? Excellent. His trinkets pair nicely with Avalian engineering.");
}
if (HasDefeatedExoMechs.IsMet())
{
lines.Add("The Exo Mechs are no more? Splendid! I've got singularities ready for purchase.");
lines.Add("You walked away from the Exo Mechs? Take these singularities before they destabilize.");
}
else if (ModLoader.TryGetMod("CalamityMod", out _))
{
lines.Add("Ground that stupid exo-worm and my singularity cache is yours.");
}
return lines.Count > 0 ? lines[Main.rand.Next(lines.Count)] : "Need something? My shop is always open!";
}
public override void TownNPCAttackStrength(ref int damage, ref float knockback)
{
damage = 50;
knockback = 4f;
}
public override void TownNPCAttackCooldown(ref int cooldown, ref int randExtraCooldown)
{
cooldown = 10;
randExtraCooldown = 30;
}
public override void TownNPCAttackProj(ref int projType, ref int attackDelay)
{
projType = 502;
attackDelay = 1;
}
public override void TownNPCAttackProjSpeed(ref float multiplier, ref float gravityCorrection, ref float randomOffset)
{
multiplier = 12f;
randomOffset = 2f;
}
}
}