diff --git a/AdventureDropDatabase.cs b/AdventureDropDatabase.cs index 92594f5d..aab3eb9c 100644 --- a/AdventureDropDatabase.cs +++ b/AdventureDropDatabase.cs @@ -23,7 +23,12 @@ private static void ModifyDropRate(IItemDropRule rule, int type, int numerator, foreach (var ruleChainAttempt in rule.ChainedRules) ModifyDropRate(ruleChainAttempt.RuleToChain, type, numerator, denominator); } - + public class NotInHardmodeCondition : IItemDropRuleCondition + { + public bool CanDrop(DropAttemptInfo info) => !Main.hardMode; + public bool CanShowItemDropInUI() => true; + public string GetConditionDescription() => "Drops in pre-Hardmode"; + } public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) { var drops = npcLoot.Get(); @@ -218,6 +223,16 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) case NPCID.SkeletronHead: npcLoot.Add(ItemDropRule.Common(ItemID.GoldenKey)); break; + + case NPCID.WallofFlesh: + npcLoot.Add(new LeadingConditionRule(new NotInHardmodeCondition())) + .OnSuccess(ItemDropRule.OneFromOptions(1, + ItemID.SummonerEmblem, + ItemID.RangerEmblem, + ItemID.WarriorEmblem, + ItemID.SorcererEmblem + )); + break; } } } \ No newline at end of file diff --git a/AdventureItem.cs b/AdventureItem.cs index b5c4454a..f22320ed 100644 --- a/AdventureItem.cs +++ b/AdventureItem.cs @@ -16,6 +16,41 @@ public class AdventureItem : GlobalItem ItemID.Sets.Factory.CreateBoolSet(ItemID.MagicMirror, ItemID.CellPhone, ItemID.IceMirror, ItemID.Shellphone, ItemID.ShellphoneSpawn); + public class PickaxeAdjustments : GlobalItem + { + public override void SetDefaults(Item item) + { + if (item.type == ItemID.SpectrePickaxe || item.type == ItemID.ShroomiteDiggingClaw) + { + item.pick = 210; + } + } + } + public class GelatinCrystalRestriction : GlobalItem + { + public override bool CanUseItem(Item item, Player player) + { + if (item.type == ItemID.QueenSlimeCrystal) + { + bool isUnderground = player.position.Y > Main.worldSurface * 16; + bool inUndergroundHallow = isUnderground && player.ZoneHallow; + + if (inUndergroundHallow) + { + Main.NewText("Queen Slime refuses to emerge in the corrupted crystals here!", 255, 50, 50); + return false; + } + + // Still block summon in other underground areas but without message + if (isUnderground) + { + return false; + } + } + return base.CanUseItem(item, player); + } + } + public override void SetDefaults(Item item) { var adventureConfig = ModContent.GetInstance(); diff --git a/AdventurePlayer.cs b/AdventurePlayer.cs index 084d6b08..7c8343f8 100644 --- a/AdventurePlayer.cs +++ b/AdventurePlayer.cs @@ -510,6 +510,58 @@ public override bool PreKill(double damage, int hitDirection, bool pvp, ref bool return true; } + private bool hadShinyStoneLastFrame; + + public override void PostUpdateEquips() + { + // Check if Shiny Stone is equipped + bool hasShinyStone = IsShinyStoneEquipped(); + + // Apply debuff when first equipped or after respawn + if (hasShinyStone && !hadShinyStoneLastFrame) + { + Player.AddBuff(ModContent.BuffType(), 3600); // 60 seconds + } + + // Disable Shiny Stone effects while debuffed + if (Player.HasBuff(ModContent.BuffType())) + { + Player.shinyStone = false; + } + + hadShinyStoneLastFrame = hasShinyStone; + + // Check if wearing full Tiki Armor + if (Player.armor[0].type == ItemID.TikiMask && + Player.armor[1].type == ItemID.TikiShirt && + Player.armor[2].type == ItemID.TikiPants) + { + Player.noKnockback = true; + } + + } + public override void OnRespawn() + { + // Re-apply debuff if equipped during respawn + if (IsShinyStoneEquipped()) + { + Player.AddBuff(ModContent.BuffType(), 900); + } + } + + private bool IsShinyStoneEquipped() + { + for (int i = 3; i < 10; i++) // Check all accessory slots + { + if (Player.armor[i].type == ItemID.ShinyStone && + (i < 7 || !Player.hideVisibleAccessory[i - 3])) + { + return true; + } + } + return false; + } + public override void Kill(double damage, int hitDirection, bool pvp, PlayerDeathReason damageSource) { // Only play kill markers on clients that we hurt that aren't ourselves @@ -851,4 +903,15 @@ public override string ToString() { return $"{Player.whoAmI}/{Player.name}/{DiscordUser?.Id}"; } +} +public class ShinyStoneHotswap : ModBuff +{ + public override string Texture => $"PvPAdventure/Assets/Buff/ShinyStoneHotswap"; + + public override void SetStaticDefaults() + { + Main.debuff[Type] = true; + Main.buffNoSave[Type] = true; + Main.buffNoTimeDisplay[Type] = false; // Show timer + } } \ No newline at end of file diff --git a/AdventureProjectile.cs b/AdventureProjectile.cs index 28058db8..a8985aad 100644 --- a/AdventureProjectile.cs +++ b/AdventureProjectile.cs @@ -83,4 +83,325 @@ public override void PostAI(Projectile projectile) // Ignore net spam restraints. projectile.netSpam = 0; } + + public class SpiderStaffGlobalProjectile : GlobalProjectile + { + public override bool AppliesToEntity(Projectile entity, bool lateInstantiation) + { + return entity.type == ProjectileID.VenomSpider || + entity.type == ProjectileID.JumperSpider || // Note: Fix typo here + entity.type == ProjectileID.DangerousSpider; + } + + public override void PostAI(Projectile projectile) + { + Player owner = Main.player[projectile.owner]; + + // Check inventory (including equipped items) AND mouse slot + bool hasStaff = owner.HasItem(ItemID.SpiderStaff); + bool mouseHasStaff = owner.inventory[58].type == ItemID.SpiderStaff && owner.inventory[58].stack > 0; + + if (!hasStaff && !mouseHasStaff) + { + projectile.Kill(); + } + } + } + + public class ClingerStaffGlobalProjectile : GlobalProjectile + { + public override bool AppliesToEntity(Projectile entity, bool lateInstantiation) + { + return entity.type == ProjectileID.ClingerStaff; + } + + public override void PostAI(Projectile projectile) + { + Player owner = Main.player[projectile.owner]; + + // Check inventory (including equipped items) AND mouse slot + bool hasStaff = owner.HasItem(ItemID.ClingerStaff); + bool mouseHasStaff = owner.inventory[58].type == ItemID.ClingerStaff && owner.inventory[58].stack > 0; + + if (!hasStaff && !mouseHasStaff) + { + projectile.Kill(); + } + } + } + + public class QueenSpiderStaffGlobalProjectile : GlobalProjectile + { + public override bool AppliesToEntity(Projectile entity, bool lateInstantiation) + { + return entity.type == ProjectileID.SpiderHiver; + } + + public override void PostAI(Projectile projectile) + { + Player owner = Main.player[projectile.owner]; + + // Check inventory (including equipped items) AND mouse slot + bool hasStaff = owner.HasItem(ItemID.QueenSpiderStaff); + bool mouseHasStaff = owner.inventory[58].type == ItemID.QueenSpiderStaff && owner.inventory[58].stack > 0; + + if (!hasStaff && !mouseHasStaff) + { + projectile.Kill(); + } + } + } + + public class NimbusRodGlobalProjectile : GlobalProjectile + { + public override bool AppliesToEntity(Projectile entity, bool lateInstantiation) + { + return entity.type == ProjectileID.RainNimbus; + } + + public override void PostAI(Projectile projectile) + { + Player owner = Main.player[projectile.owner]; + + // Check inventory (including equipped items) AND mouse slot + bool hasStaff = owner.HasItem(ItemID.NimbusRod); + bool mouseHasStaff = owner.inventory[58].type == ItemID.NimbusRod && owner.inventory[58].stack > 0; + + if (!hasStaff && !mouseHasStaff) + { + projectile.Kill(); + } + } + } + + public class XenoStaffGlobalProjectile : GlobalProjectile + { + public override bool AppliesToEntity(Projectile entity, bool lateInstantiation) + { + return entity.type == ProjectileID.UFOMinion; + } + + public override void PostAI(Projectile projectile) + { + Player owner = Main.player[projectile.owner]; + + // Check inventory (including equipped items) AND mouse slot + bool hasStaff = owner.HasItem(ItemID.XenoStaff); + bool mouseHasStaff = owner.inventory[58].type == ItemID.XenoStaff && owner.inventory[58].stack > 0; + + if (!hasStaff && !mouseHasStaff) + { + projectile.Kill(); + } + } + } + + public class BladeStaffGlobalProjectile : GlobalProjectile + { + public override bool AppliesToEntity(Projectile entity, bool lateInstantiation) + { + return entity.type == ProjectileID.Smolstar; + } + + public override void PostAI(Projectile projectile) + { + Player owner = Main.player[projectile.owner]; + + // Check inventory (including equipped items) AND mouse slot + bool hasStaff = owner.HasItem(ItemID.Smolstar); + bool mouseHasStaff = owner.inventory[58].type == ItemID.Smolstar && owner.inventory[58].stack > 0; + + if (!hasStaff && !mouseHasStaff) + { + projectile.Kill(); + } + } + } + + public class HornetStaffGlobalProjectile : GlobalProjectile + { + public override bool AppliesToEntity(Projectile entity, bool lateInstantiation) + { + return entity.type == ProjectileID.Hornet; + } + + public override void PostAI(Projectile projectile) + { + Player owner = Main.player[projectile.owner]; + + // Check inventory (including equipped items) AND mouse slot + bool hasStaff = owner.HasItem(ItemID.HornetStaff); + bool mouseHasStaff = owner.inventory[58].type == ItemID.HornetStaff && owner.inventory[58].stack > 0; + + if (!hasStaff && !mouseHasStaff) + { + projectile.Kill(); + } + } + } + + public class ImpStaffGlobalProjectile : GlobalProjectile + { + public override bool AppliesToEntity(Projectile entity, bool lateInstantiation) + { + return entity.type == ProjectileID.FlyingImp; + } + + public override void PostAI(Projectile projectile) + { + Player owner = Main.player[projectile.owner]; + + // Check inventory (including equipped items) AND mouse slot + bool hasStaff = owner.HasItem(ItemID.ImpStaff); + bool mouseHasStaff = owner.inventory[58].type == ItemID.ImpStaff && owner.inventory[58].stack > 0; + + if (!hasStaff && !mouseHasStaff) + { + projectile.Kill(); + } + } + } + + public class PygmyStaffGlobalProjectile : GlobalProjectile + { + public override bool AppliesToEntity(Projectile entity, bool lateInstantiation) + { + return entity.type == ProjectileID.Pygmy || + entity.type == ProjectileID.Pygmy2 || + entity.type == ProjectileID.Pygmy3 || + entity.type == ProjectileID.Pygmy4; + } + + public override void PostAI(Projectile projectile) + { + Player owner = Main.player[projectile.owner]; + + // Check inventory (including equipped items) AND mouse slot + bool hasStaff = owner.HasItem(ItemID.PygmyStaff); + bool mouseHasStaff = owner.inventory[58].type == ItemID.PygmyStaff && owner.inventory[58].stack > 0; + + if (!hasStaff && !mouseHasStaff) + { + projectile.Kill(); + } + } + } + + public class DeadlySphereGlobalProjectile : GlobalProjectile + { + public override bool AppliesToEntity(Projectile entity, bool lateInstantiation) + { + return entity.type == ProjectileID.DeadlySphere; + } + + public override void PostAI(Projectile projectile) + { + Player owner = Main.player[projectile.owner]; + + // Check inventory (including equipped items) AND mouse slot + bool hasStaff = owner.HasItem(ItemID.DeadlySphereStaff); + bool mouseHasStaff = owner.inventory[58].type == ItemID.DeadlySphereStaff && owner.inventory[58].stack > 0; + + if (!hasStaff && !mouseHasStaff) + { + projectile.Kill(); + } + } + } + + public class PirateStaffGlobalProjectile : GlobalProjectile + { + public override bool AppliesToEntity(Projectile entity, bool lateInstantiation) + { + return entity.type == ProjectileID.OneEyedPirate || + entity.type == ProjectileID.SoulscourgePirate || + entity.type == ProjectileID.PirateCaptain; + } + + public override void PostAI(Projectile projectile) + { + Player owner = Main.player[projectile.owner]; + + // Check inventory (including equipped items) AND mouse slot + bool hasStaff = owner.HasItem(ItemID.PirateStaff); + bool mouseHasStaff = owner.inventory[58].type == ItemID.PirateStaff && owner.inventory[58].stack > 0; + + if (!hasStaff && !mouseHasStaff) + { + projectile.Kill(); + } + } + } + + public class TempestStaffGlobalProjectile : GlobalProjectile + { + public override bool AppliesToEntity(Projectile entity, bool lateInstantiation) + { + return entity.type == ProjectileID.Tempest; + } + + public override void PostAI(Projectile projectile) + { + Player owner = Main.player[projectile.owner]; + + // Check inventory (including equipped items) AND mouse slot + bool hasStaff = owner.HasItem(ItemID.TempestStaff); + bool mouseHasStaff = owner.inventory[58].type == ItemID.TempestStaff && owner.inventory[58].stack > 0; + + if (!hasStaff && !mouseHasStaff) + { + projectile.Kill(); + } + } + } + + public class TerraprismaGlobalProjectile : GlobalProjectile + { + public override bool AppliesToEntity(Projectile entity, bool lateInstantiation) + { + return entity.type == ProjectileID.EmpressBlade; + } + + public override void PostAI(Projectile projectile) + { + Player owner = Main.player[projectile.owner]; + + // Check inventory (including equipped items) AND mouse slot + bool hasStaff = owner.HasItem(ItemID.EmpressBlade); + bool mouseHasStaff = owner.inventory[58].type == ItemID.EmpressBlade && owner.inventory[58].stack > 0; + + if (!hasStaff && !mouseHasStaff) + { + projectile.Kill(); + } + } + } + + public class DeadProjectileList : GlobalProjectile + { + public override bool AppliesToEntity(Projectile entity, bool lateInstantiation) + { + return entity.type == ProjectileID.ClingerStaff || + entity.type == ProjectileID.SporeTrap || + entity.type == ProjectileID.SporeTrap2 || + entity.type == ProjectileID.SporeGas || + entity.type == ProjectileID.SporeGas2 || + entity.type == ProjectileID.SporeGas3; + } + + public override void PostAI(Projectile projectile) + { + // Ensure owner index is valid + if (projectile.owner < 0 || projectile.owner >= Main.maxPlayers) + return; + + Player owner = Main.player[projectile.owner]; + + // Kill projectile if owner is dead or inactive + if (owner.dead || !owner.active) + { + projectile.Kill(); + } + } + } } \ No newline at end of file diff --git a/Assets/Buff/ShinyStoneHotswap.png b/Assets/Buff/ShinyStoneHotswap.png new file mode 100644 index 00000000..e18d0f43 Binary files /dev/null and b/Assets/Buff/ShinyStoneHotswap.png differ diff --git a/Localization/en-US.hjson b/Localization/en-US.hjson index 230c7dd0..06092d72 100644 --- a/Localization/en-US.hjson +++ b/Localization/en-US.hjson @@ -665,5 +665,12 @@ Mods: { True: "[c/FF0000:The game has been paused.]" False: "[c/00FF00:The game has been resumed.]" } + + Buffs: { + ShinyStoneHotswap: { + DisplayName: Shiny Stone Hotswap + Description: Shiny Stone is charging up! + } + } } } diff --git a/System/RecipeManager.cs b/System/RecipeManager.cs index 2db8ccb4..716cbe26 100644 --- a/System/RecipeManager.cs +++ b/System/RecipeManager.cs @@ -1,6 +1,9 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Linq; using Terraria; using Terraria.ID; +using Terraria.Localization; using Terraria.ModLoader; namespace PvPAdventure.System; @@ -8,90 +11,496 @@ namespace PvPAdventure.System; [Autoload(Side = ModSide.Both)] public class RecipeManager : ModSystem { + public override void AddRecipes() { - CreateDuplicateDropRecipe([ - ItemID.FlyingKnife, - ItemID.DaedalusStormbow, - ItemID.CrystalVileShard, - ItemID.IlluminantHook - ], 3); - CreateDuplicateDropRecipe([ - ItemID.ChainGuillotines, - ItemID.DartRifle, - ItemID.ClingerStaff, - ItemID.PutridScent, - ItemID.WormHook - ], 3); - - CreateDuplicateDropRecipe([ - ItemID.FetidBaghnakhs, - ItemID.DartPistol, - ItemID.SoulDrain, - ItemID.FleshKnuckles, - ItemID.TendonHook - ], 3); - - CreateDuplicateDropRecipe([ - ItemID.TitanGlove, - ItemID.MagicDagger, - ItemID.StarCloak, - ItemID.CrossNecklace, - ItemID.PhilosophersStone, - ItemID.DualHook - ], 3); - - CreateDuplicateDropRecipe([ - ItemID.RazorbladeTyphoon, - ItemID.Flairon, - ItemID.BubbleGun, - ItemID.Tsunami, - ItemID.TempestStaff - ], 3); + Recipe.Create(ItemID.Headstone) + .AddIngredient(ItemID.StoneBlock, 50) + .AddTile(TileID.HeavyWorkBench) + .Register(); - CreateDuplicateDropRecipe([ - ItemID.BreakerBlade, - ItemID.ClockworkAssaultRifle, - ItemID.LaserRifle, - ItemID.FireWhip - ], 3); + int[] itemsToRemove = new int[] + { + ItemID.TrueNightsEdge, + ItemID.MoonlordArrow + }; - CreateDuplicateDropRecipe([ - ItemID.GolemFist, - ItemID.PossessedHatchet, + for (int i = 0; i < Main.recipe.Length; i++) + { + Recipe recipe = Main.recipe[i]; + if (recipe.createItem.type != ItemID.None && itemsToRemove.Contains(recipe.createItem.type)) + { + recipe.DisableRecipe(); + } + } + + //temp sudo terrablade + Recipe.Create(ItemID.TrueNightsEdge) + .AddIngredient(ItemID.SoulofFright, 20) + .AddIngredient(ItemID.SoulofMight, 20) + .AddIngredient(ItemID.SoulofSight, 20) + .AddIngredient(ItemID.NightsEdge) + .AddIngredient(ItemID.TrueExcalibur) + .AddIngredient(ItemID.BrokenHeroSword) + .AddTile(TileID.MythrilAnvil) + .Register(); + + + } + + public class AnyGolem1 : ModSystem + { + public static RecipeGroup AnyGolemPrimary; + public static int[] PrimaryItems => new int[] { + ItemID.GolemMasterTrophy, ItemID.Stynger, - ItemID.StaffofEarth, + ItemID.PossessedHatchet, ItemID.HeatRay, + ItemID.GolemFist, + ItemID.StaffofEarth + }; + + public override void AddRecipeGroups() + { + // Main group with trophy as first item (for icon) + AnyGolemPrimary = new RecipeGroup(() => Language.GetTextValue("Any Golem Primary"), PrimaryItems); + RecipeGroup.RegisterGroup("PvPAdventure:AnyGolemPrimary", AnyGolemPrimary); + + // Create exclude subgroups while maintaining trophy as first item + foreach (int itemID in PrimaryItems.Where(id => id != ItemID.GolemMasterTrophy)) + { + var validItems = PrimaryItems + .Where(id => id != itemID && id != ItemID.GolemMasterTrophy) + .Prepend(ItemID.GolemMasterTrophy) // Keep trophy first for icon + .ToArray(); + + RecipeGroup group = new RecipeGroup( + () => Language.GetTextValue("Any Golem Primary"), + validItems + ); + RecipeGroup.RegisterGroup($"PvPAdventure:AnyGolemPrimaryExclude{itemID}", group); + } + } + } + + public class AnyGolem2 : ModSystem + { + public static RecipeGroup AnyGolemSecondary; + public static int[] SecondaryItems => new int[] { + ItemID.GolemBossBag, ItemID.SunStone, - ItemID.EyeoftheGolem - ], 3); + ItemID.ShinyStone, + ItemID.EyeoftheGolem, + ItemID.Picksaw + }; - CreateDuplicateDropRecipe([ - ItemID.Flairon, - ItemID.Tsunami, + public override void AddRecipeGroups() + { + // Main group with boss bag as first item (for icon) + AnyGolemSecondary = new RecipeGroup(() => Language.GetTextValue("Any Golem Secondary"), SecondaryItems); + RecipeGroup.RegisterGroup("PvPAdventure:AnyGolemSecondary", AnyGolemSecondary); + + // Create exclude subgroups while maintaining boss bag as first item + foreach (int itemID in SecondaryItems.Where(id => id != ItemID.GolemBossBag)) + { + var validItems = SecondaryItems + .Where(id => id != itemID && id != ItemID.GolemBossBag) + .Prepend(ItemID.GolemBossBag) // Keep boss bag first for icon + .ToArray(); + + RecipeGroup group = new RecipeGroup( + () => Language.GetTextValue("Any Golem Secondary"), + validItems + ); + RecipeGroup.RegisterGroup($"PvPAdventure:AnyGolemSecondaryExclude{itemID}", group); + } + } + } + + public class AnyQueenSlime1 : ModSystem + { + public static RecipeGroup AnyQueenSlimePrimary; + public static int[] PrimaryItems => new int[] { + ItemID.QueenSlimeMasterTrophy, + ItemID.Smolstar, + ItemID.QueenSlimeHook, + ItemID.QueenSlimeMountSaddle, + }; + + public override void AddRecipeGroups() + { + // Main group with trophy as first item (for icon) + AnyQueenSlimePrimary = new RecipeGroup(() => Language.GetTextValue("Any Queen Slime Primary"), PrimaryItems); + RecipeGroup.RegisterGroup("PvPAdventure:AnyQueenSlimePrimary", AnyQueenSlimePrimary); + + // Create exclude subgroups while maintaining icon as first item + foreach (int itemID in PrimaryItems.Where(id => id != ItemID.QueenSlimeMasterTrophy)) + { + var validItems = PrimaryItems + .Where(id => id != itemID && id != ItemID.QueenSlimeMasterTrophy) + .Prepend(ItemID.QueenSlimeMasterTrophy) // Keep item first for icon + .ToArray(); + + RecipeGroup group = new RecipeGroup( + () => Language.GetTextValue("Any Queen Slime Primary"), + validItems + ); + RecipeGroup.RegisterGroup($"PvPAdventure:AnyQueenSlimePrimaryExclude{itemID}", group); + } + } + } + + public class AnyPlantera1 : ModSystem + { + public static RecipeGroup AnyPlanteraPrimary; + public static int[] PrimaryItems => new int[] { + ItemID.PlanteraMasterTrophy, + ItemID.GrenadeLauncher, + ItemID.LeafBlower, + ItemID.WaspGun, + ItemID.NettleBurst, + ItemID.FlowerPow, + ItemID.VenusMagnum, + ItemID.Seedler, + }; + + public override void AddRecipeGroups() + { + // Main group with trophy as first item (for icon) + AnyPlanteraPrimary = new RecipeGroup(() => Language.GetTextValue("Any Plantera Drop"), PrimaryItems); + RecipeGroup.RegisterGroup("PvPAdventure:AnyPlanteraPrimary", AnyPlanteraPrimary); + + // Create exclude subgroups while maintaining icon as first item + foreach (int itemID in PrimaryItems.Where(id => id != ItemID.PlanteraMasterTrophy)) + { + var validItems = PrimaryItems + .Where(id => id != itemID && id != ItemID.PlanteraMasterTrophy) + .Prepend(ItemID.PlanteraMasterTrophy) // Keep item first for icon + .ToArray(); + + RecipeGroup group = new RecipeGroup( + () => Language.GetTextValue("Any Plantera Drop"), + validItems + ); + RecipeGroup.RegisterGroup($"PvPAdventure:AnyPlanteraPrimaryExclude{itemID}", group); + } + } + } + + public class AnyDuke1 : ModSystem + { + public static RecipeGroup AnyDukePrimary; + public static int[] PrimaryItems => new int[] { + ItemID.DukeFishronMasterTrophy, ItemID.RazorbladeTyphoon, ItemID.BubbleGun, - ItemID.TempestStaff - ], 3); + ItemID.Flairon, + ItemID.Tsunami, + ItemID.TempestStaff, + }; - Recipe.Create(ItemID.Headstone) - .AddIngredient(ItemID.StoneBlock, 50) - .AddTile(TileID.HeavyWorkBench) - .Register(); + public override void AddRecipeGroups() + { + // Main group with trophy as first item (for icon) + AnyDukePrimary = new RecipeGroup(() => Language.GetTextValue("Any Duke Primary"), PrimaryItems); + RecipeGroup.RegisterGroup("PvPAdventure:AnyDukePrimary", AnyDukePrimary); + + // Create exclude subgroups while maintaining icon as first item + foreach (int itemID in PrimaryItems.Where(id => id != ItemID.DukeFishronMasterTrophy)) + { + var validItems = PrimaryItems + .Where(id => id != itemID && id != ItemID.DukeFishronMasterTrophy) + .Prepend(ItemID.DukeFishronMasterTrophy) // Keep item first for icon + .ToArray(); + + RecipeGroup group = new RecipeGroup( + () => Language.GetTextValue("Any Duke Primary"), + validItems + ); + RecipeGroup.RegisterGroup($"PvPAdventure:AnyDukePrimaryExclude{itemID}", group); + } + } } - private static void CreateDuplicateDropRecipe(List lootTable, int amountOfMaterial) + public class AnyEmpress1 : ModSystem { - for (var i = 0; i < lootTable.Count; i++) + public static RecipeGroup AnyEmpressPrimary; + public static int[] PrimaryItems => new int[] { + ItemID.FairyQueenMasterTrophy, + ItemID.FairyQueenMagicItem, + ItemID.FairyQueenRangedItem, + ItemID.PiercingStarlight, + ItemID.RainbowWhip, + ItemID.EmpressBlade, + }; + + public override void AddRecipeGroups() { - for (var j = 0; j < lootTable.Count; j++) + // Main group with trophy as first item (for icon) + AnyEmpressPrimary = new RecipeGroup(() => Language.GetTextValue("Any Empress Primary"), PrimaryItems); + RecipeGroup.RegisterGroup("PvPAdventure:AnyEmpressPrimary", AnyEmpressPrimary); + + // Create exclude subgroups while maintaining icon as first item + foreach (int itemID in PrimaryItems.Where(id => id != ItemID.FairyQueenMasterTrophy)) { - if (j == i) - continue; + var validItems = PrimaryItems + .Where(id => id != itemID && id != ItemID.FairyQueenMasterTrophy) + .Prepend(ItemID.FairyQueenMasterTrophy) // Keep item first for icon + .ToArray(); + + RecipeGroup group = new RecipeGroup( + () => Language.GetTextValue("Any Empress Primary"), + validItems + ); + RecipeGroup.RegisterGroup($"PvPAdventure:AnyEmpressPrimaryExclude{itemID}", group); + } + } + } - Recipe.Create(lootTable[i]) - .AddIngredient(lootTable[j], amountOfMaterial) + public class AnyWall1 : ModSystem + { + public static RecipeGroup AnyWallPrimary; + public static int[] PrimaryItems => new int[] { + ItemID.WallofFleshMasterTrophy, + ItemID.FireWhip, + ItemID.ClockworkAssaultRifle, + ItemID.BreakerBlade, + ItemID.LaserRifle, + }; + + public override void AddRecipeGroups() + { + // Main group with trophy as first item (for icon) + AnyWallPrimary = new RecipeGroup(() => Language.GetTextValue("Any Wall of Flesh Primary"), PrimaryItems); + RecipeGroup.RegisterGroup("PvPAdventure:AnyWallPrimary", AnyWallPrimary); + + // Create exclude subgroups while maintaining icon as first item + foreach (int itemID in PrimaryItems.Where(id => id != ItemID.WallofFleshMasterTrophy)) + { + var validItems = PrimaryItems + .Where(id => id != itemID && id != ItemID.WallofFleshMasterTrophy) + .Prepend(ItemID.WallofFleshMasterTrophy) // Keep item first for icon + .ToArray(); + + RecipeGroup group = new RecipeGroup( + () => Language.GetTextValue("Any Wall of Flesh Primary"), + validItems + ); + RecipeGroup.RegisterGroup($"PvPAdventure:AnyWallPrimaryExclude{itemID}", group); + } + } + } + + public class AnySaucer1 : ModSystem + { + public static RecipeGroup AnySaucerPrimary; + public static int[] PrimaryItems => new int[] { + ItemID.UFOMasterTrophy, + ItemID.XenoStaff, + ItemID.LaserMachinegun, + ItemID.InfluxWaver, + ItemID.ElectrosphereLauncher, + ItemID.Xenopopper, + }; + + public override void AddRecipeGroups() + { + // Main group with trophy as first item (for icon) + AnySaucerPrimary = new RecipeGroup(() => Language.GetTextValue("Any Saucer Primary"), PrimaryItems); + RecipeGroup.RegisterGroup("PvPAdventure:AnySaucerPrimary", AnySaucerPrimary); + + // Create exclude subgroups while maintaining icon as first item + foreach (int itemID in PrimaryItems.Where(id => id != ItemID.UFOMasterTrophy)) + { + var validItems = PrimaryItems + .Where(id => id != itemID && id != ItemID.UFOMasterTrophy) + .Prepend(ItemID.UFOMasterTrophy) // Keep item first for icon + .ToArray(); + + RecipeGroup group = new RecipeGroup( + () => Language.GetTextValue("Any Saucer Primary"), + validItems + ); + RecipeGroup.RegisterGroup($"PvPAdventure:AnySaucerPrimaryExclude{itemID}", group); + } + } + } + + public class AnyCorruptionMimic1 : ModSystem + { + public static RecipeGroup AnyCorruptionMimicPrimary; + public static int[] PrimaryItems => new int[] { + ItemID.Fake_CorruptionChest, + ItemID.PutridScent, + ItemID.DartRifle, + ItemID.ClingerStaff, + ItemID.ChainGuillotines, + ItemID.WormHook, + }; + + public override void AddRecipeGroups() + { + // Main group with trophy as first item (for icon) + AnyCorruptionMimicPrimary = new RecipeGroup(() => Language.GetTextValue("Any Corrupt Mimic Primary"), PrimaryItems); + RecipeGroup.RegisterGroup("PvPAdventure:AnyCorruptionMimicPrimary", AnyCorruptionMimicPrimary); + + // Create exclude subgroups while maintaining icon as first item + foreach (int itemID in PrimaryItems.Where(id => id != ItemID.Fake_CorruptionChest)) + { + var validItems = PrimaryItems + .Where(id => id != itemID && id != ItemID.Fake_CorruptionChest) + .Prepend(ItemID.Fake_CorruptionChest) // Keep item first for icon + .ToArray(); + + RecipeGroup group = new RecipeGroup( + () => Language.GetTextValue("Any Corrupt Mimic Primary"), + validItems + ); + RecipeGroup.RegisterGroup($"PvPAdventure:AnyCorruptionMimicPrimaryExclude{itemID}", group); + } + } + } + + public class AnyHallowedMimic1 : ModSystem + { + public static RecipeGroup AnyHallowedMimicPrimary; + public static int[] PrimaryItems => new int[] { + ItemID.Fake_HallowedChest, + ItemID.DaedalusStormbow, + ItemID.CrystalVileShard, + ItemID.FlyingKnife, + ItemID.IlluminantHook, + }; + + public override void AddRecipeGroups() + { + // Main group with trophy as first item (for icon) + AnyHallowedMimicPrimary = new RecipeGroup(() => Language.GetTextValue("Any Hallowed Mimic Primary"), PrimaryItems); + RecipeGroup.RegisterGroup("PvPAdventure:AnyHallowedMimicPrimary", AnyHallowedMimicPrimary); + + // Create exclude subgroups while maintaining icon as first item + foreach (int itemID in PrimaryItems.Where(id => id != ItemID.Fake_HallowedChest)) + { + var validItems = PrimaryItems + .Where(id => id != itemID && id != ItemID.Fake_HallowedChest) + .Prepend(ItemID.Fake_HallowedChest) // Keep item first for icon + .ToArray(); + + RecipeGroup group = new RecipeGroup( + () => Language.GetTextValue("Any Hallowed Mimic Primary"), + validItems + ); + RecipeGroup.RegisterGroup($"PvPAdventure:AnyHallowedMimicPrimaryExclude{itemID}", group); + } + } + } + + public class RecipeSystem : ModSystem + { + public override void AddRecipes() + { + var shimmerCondition = new Condition( + Language.GetText("Mods.PvPAdventure.Conditions.NearShimmer"), + () => Main.LocalPlayer.adjShimmer + ); + + // Primary recipes (trophy remains icon) + foreach (int itemID in AnyGolem1.PrimaryItems.Where(id => id != ItemID.GolemMasterTrophy)) + { + Recipe.Create(itemID) + .AddRecipeGroup($"PvPAdventure:AnyGolemPrimaryExclude{itemID}", 3) + .AddCondition(shimmerCondition) + .DisableDecraft() + .Register(); + } + + // Secondary recipes (boss bag remains icon) + foreach (int itemID in AnyGolem2.SecondaryItems.Where(id => id != ItemID.GolemBossBag)) + { + Recipe.Create(itemID) + .AddRecipeGroup($"PvPAdventure:AnyGolemSecondaryExclude{itemID}", 3) + .AddCondition(shimmerCondition) + .DisableDecraft() + .Register(); + } + + // Primary QS recipes (Relic remains icon) + foreach (int itemID in AnyQueenSlime1.PrimaryItems.Where(id => id != ItemID.QueenSlimeMasterTrophy)) + { + Recipe.Create(itemID) + .AddRecipeGroup($"PvPAdventure:AnyQueenSlimePrimaryExclude{itemID}", 3) + .AddCondition(shimmerCondition) + .DisableDecraft() + .Register(); + } + + // Primary Plantera recipes (Relic remains icon) + foreach (int itemID in AnyPlantera1.PrimaryItems.Where(id => id != ItemID.PlanteraMasterTrophy)) + { + Recipe.Create(itemID) + .AddRecipeGroup($"PvPAdventure:AnyPlanteraPrimaryExclude{itemID}", 4) + .AddCondition(shimmerCondition) + .DisableDecraft() + .Register(); + } + + // Primary Duke recipes (Relic remains icon) + foreach (int itemID in AnyDuke1.PrimaryItems.Where(id => id != ItemID.DukeFishronMasterTrophy)) + { + Recipe.Create(itemID) + .AddRecipeGroup($"PvPAdventure:AnyDukePrimaryExclude{itemID}", 3) + .AddCondition(shimmerCondition) + .DisableDecraft() + .Register(); + } + + // Primary Empress recipes (Relic remains icon) + foreach (int itemID in AnyEmpress1.PrimaryItems.Where(id => id != ItemID.FairyQueenMasterTrophy)) + { + Recipe.Create(itemID) + .AddRecipeGroup($"PvPAdventure:AnyEmpressPrimaryExclude{itemID}", 2) + .AddCondition(shimmerCondition) + .DisableDecraft() + .Register(); + } + + // Primary Wall recipes (Relic remains icon) + foreach (int itemID in AnyWall1.PrimaryItems.Where(id => id != ItemID.WallofFleshMasterTrophy)) + { + Recipe.Create(itemID) + .AddRecipeGroup($"PvPAdventure:AnyWallPrimaryExclude{itemID}", 2) + .AddCondition(shimmerCondition) + .DisableDecraft() + .Register(); + } + + // Primary UFO recipes (Relic remains icon) + foreach (int itemID in AnySaucer1.PrimaryItems.Where(id => id != ItemID.UFOMasterTrophy)) + { + Recipe.Create(itemID) + .AddRecipeGroup($"PvPAdventure:AnySaucerPrimaryExclude{itemID}", 3) + .AddCondition(shimmerCondition) + .DisableDecraft() + .Register(); + } + + // Primary Corro mimic recipes (Relic remains icon) + foreach (int itemID in AnyCorruptionMimic1.PrimaryItems.Where(id => id != ItemID.Fake_CorruptionChest)) + { + Recipe.Create(itemID) + .AddRecipeGroup($"PvPAdventure:AnyCorruptionMimicPrimaryExclude{itemID}", 3) + .AddCondition(shimmerCondition) + .DisableDecraft() + .Register(); + } + + // Primary Hallow mimic recipes (Relic remains icon) + foreach (int itemID in AnyHallowedMimic1.PrimaryItems.Where(id => id != ItemID.Fake_HallowedChest)) + { + Recipe.Create(itemID) + .AddRecipeGroup($"PvPAdventure:AnyHallowedMimicPrimaryExclude{itemID}", 2) + .AddCondition(shimmerCondition) .DisableDecraft() .Register(); }