304 lines
13 KiB
C#
304 lines
13 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;
|
|
}
|
|
|
|
}
|
|
} |