From bb28f7ffa7d179dce187ae6a2a27ccb686738db7 Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Fri, 23 May 2025 18:01:20 -0700 Subject: [PATCH 001/206] AdventureItem.cs: Spectre Pickaxe can break Temple brick --- AdventureItem.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/AdventureItem.cs b/AdventureItem.cs index aeb57c7c..8ba468ab 100644 --- a/AdventureItem.cs +++ b/AdventureItem.cs @@ -16,6 +16,17 @@ 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 override void SetDefaults(Item item) { var adventureConfig = ModContent.GetInstance(); From aaeaf6477430f47d6f16c273567989f4f871fc4e Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Fri, 23 May 2025 18:02:46 -0700 Subject: [PATCH 002/206] AdventurePlayer.cs: Added Shiny stone switch penalty --- AdventurePlayer.cs | 57 ++++++++++++++++++++++++++++++ Assets/Buff/ShinyStoneHotswap.png | Bin 0 -> 1253 bytes 2 files changed, 57 insertions(+) create mode 100644 Assets/Buff/ShinyStoneHotswap.png diff --git a/AdventurePlayer.cs b/AdventurePlayer.cs index e622aef4..679325e6 100644 --- a/AdventurePlayer.cs +++ b/AdventurePlayer.cs @@ -590,6 +590,52 @@ 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 + + } + 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 @@ -957,4 +1003,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/Assets/Buff/ShinyStoneHotswap.png b/Assets/Buff/ShinyStoneHotswap.png new file mode 100644 index 0000000000000000000000000000000000000000..e18d0f432eb900f533369f1c190e7a5f9748976e GIT binary patch literal 1253 zcmV#dBtE(XoR>JmOeS?cH=`Hg4jzO=bJh z?B_rn006p@gYpG5?SKwYXJURPXxb)@&#m4FfrZGs-|$D28#KBW1${n7XN$SKGy(ZQ z)jr9MqB1(uG7}#cgzxi8ZQVAlSOMdVz(5g*83v0fg*7Okg1s!t$>>~+$Xl#!kmm)& z+;%L>ZQSRv1c*SBz!E0$IxZcCRMO~@i!dzO3&`S^!g$`5jmBObzDX(<FAM11Qy*{H^kx^&K`uZr;>zrYAA%|0-b$ym=VO%1_k z7l}ksbp6=SIkOMsAX4TOewogFITDMCJ<h#G7WD19z z!ZHfDQA~$|ZnV?s%dd;jp)MnEwGjAue#ujrPQ9saQ1*WNWCU^$DI*F`e44hNtG8F% z>KA@2l=TAmof9LFDI8J?<54y}(vL^QIa*tN?u6ss;{}^d*oDsNa9f@A{N_W(M&aC? zDj0z!&qQis0)aXw(qR`mmzvmeHgK{JWiFmeD#CQ#pF9|Mj%tTj413T zO}kTh(VEg;75R!Gl#29>4^LredK%mUYThZpVt_#W*KBmrqvvh(8Ieg*p>v|_RoC>q zk58mIh^%o6BQ@&C3p*G%yf|l_6sed($4p;7GNC>rkSQE;3ez(_Ox5UlpqovYM3!pO zJtMlHytnl6HzWKzkyS?E(CuBevXsaDlFSwW;N+<~m zm$T!h58j4=@sC$irCCdxGx|40s=y zU17W@8E>n#-RP|;g*W|#RmR?p=k4>X`A(_Ufe{$255)hSfQ3(ER#pB30%Ga Date: Fri, 23 May 2025 18:04:16 -0700 Subject: [PATCH 003/206] AdventurePlayer.cs: Tiki armor KB immunity buff --- AdventurePlayer.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/AdventurePlayer.cs b/AdventurePlayer.cs index 679325e6..f4bddba2 100644 --- a/AdventurePlayer.cs +++ b/AdventurePlayer.cs @@ -612,6 +612,12 @@ public override void PostUpdateEquips() 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() From 7d7928502573fdf336564c9652407a91af03d7ae Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Fri, 23 May 2025 20:10:17 -0700 Subject: [PATCH 004/206] added psudo terra blade --- System/RecipeManager.cs | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/System/RecipeManager.cs b/System/RecipeManager.cs index 2db8ccb4..6899c4a2 100644 --- a/System/RecipeManager.cs +++ b/System/RecipeManager.cs @@ -1,13 +1,16 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using Terraria; using Terraria.ID; using Terraria.ModLoader; +using System.Linq; namespace PvPAdventure.System; [Autoload(Side = ModSide.Both)] public class RecipeManager : ModSystem { + public override void AddRecipes() { CreateDuplicateDropRecipe([ @@ -79,6 +82,37 @@ public override void AddRecipes() .AddIngredient(ItemID.StoneBlock, 50) .AddTile(TileID.HeavyWorkBench) .Register(); + + + + + int[] itemsToRemove = new int[] + { + ItemID.TrueNightsEdge, + ItemID.MoonlordArrow + }; + + 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(); + + } private static void CreateDuplicateDropRecipe(List lootTable, int amountOfMaterial) From e78cb7b977924ecfb445fd6fd2b51073affa1e6f Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Fri, 23 May 2025 20:12:47 -0700 Subject: [PATCH 005/206] updated shiny stone localization --- Localization/en-US.hjson | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Localization/en-US.hjson b/Localization/en-US.hjson index 6c2953dc..72a598c1 100644 --- a/Localization/en-US.hjson +++ b/Localization/en-US.hjson @@ -685,6 +685,13 @@ 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! + } + } } } From cb091b7f81be5109e0a2c6a94e92d28337b8a282 Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Fri, 23 May 2025 20:03:43 -0700 Subject: [PATCH 006/206] Replaced garmon's SHITTY ASS code with my COOL SHIT that makes it so that you can craft 3 of any item in a pool into any other item from that pool at shimmer. Also has some qol that can be worked on later. --- System/RecipeManager.cs | 373 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 371 insertions(+), 2 deletions(-) diff --git a/System/RecipeManager.cs b/System/RecipeManager.cs index 6899c4a2..a42430b1 100644 --- a/System/RecipeManager.cs +++ b/System/RecipeManager.cs @@ -1,9 +1,9 @@ -using System; using System.Collections.Generic; +using System.Linq; using Terraria; using Terraria.ID; +using Terraria.Localization; using Terraria.ModLoader; -using System.Linq; namespace PvPAdventure.System; @@ -131,4 +131,373 @@ private static void CreateDuplicateDropRecipe(List lootTable, int amountOfM } } } + + public class AnyGolem1 : ModSystem + { + public static RecipeGroup AnyGolemPrimary; + public static int[] PrimaryItems => new int[] { + ItemID.GolemMasterTrophy, + ItemID.Stynger, + 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.ShinyStone, + ItemID.EyeoftheGolem, + ItemID.Picksaw + }; + + 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.Flairon, + ItemID.Tsunami, + ItemID.TempestStaff, + }; + + 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); + } + } + } + + public class AnyEmpress1 : ModSystem + { + 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() + { + // 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)) + { + 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); + } + } + } + + 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 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(); + } + } + } } \ No newline at end of file From 00b1bbd9cbb61072002eddc9536e93d5047c4ec0 Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Fri, 23 May 2025 20:26:27 -0700 Subject: [PATCH 007/206] AdventureItem.cs: No Underground QS --- AdventureItem.cs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/AdventureItem.cs b/AdventureItem.cs index 8ba468ab..4a8a36f8 100644 --- a/AdventureItem.cs +++ b/AdventureItem.cs @@ -26,6 +26,30 @@ public override void SetDefaults(Item item) } } } + 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) { From 2a25d027b6913f6dcd0fda7d363937e05e848063 Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Mon, 26 May 2025 15:18:39 -0700 Subject: [PATCH 008/206] Makes first wof drop 2 emblems --- AdventureDropDatabase.cs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/AdventureDropDatabase.cs b/AdventureDropDatabase.cs index 5f90b018..a5808956 100644 --- a/AdventureDropDatabase.cs +++ b/AdventureDropDatabase.cs @@ -37,7 +37,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(); @@ -272,6 +277,16 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) foreach (var drop in drops) ModifyDropRate(drop, ItemID.ShadowJoustingLance, 1, 12); 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 From 2eb139331705cc76504d62194c51c21fcfc1e865 Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Mon, 26 May 2025 15:36:52 -0700 Subject: [PATCH 009/206] Updating this to account for Biome mimics --- System/RecipeManager.cs | 89 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/System/RecipeManager.cs b/System/RecipeManager.cs index a42430b1..e8e4cb26 100644 --- a/System/RecipeManager.cs +++ b/System/RecipeManager.cs @@ -410,6 +410,75 @@ public override void AddRecipeGroups() } } + 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() @@ -498,6 +567,26 @@ public override void AddRecipes() .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(); + } } } } \ No newline at end of file From ece09e26e4cf26b5e21854a2846056897bf89276 Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Mon, 26 May 2025 16:41:33 -0700 Subject: [PATCH 010/206] Makes all summons* dissapear when not in invetory to prevent sharing --- AdventureProjectile.cs | 294 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 294 insertions(+) diff --git a/AdventureProjectile.cs b/AdventureProjectile.cs index 5385b1be..3dc32d3d 100644 --- a/AdventureProjectile.cs +++ b/AdventureProjectile.cs @@ -88,6 +88,7 @@ public override void PostAI(Projectile projectile) projectile.netSpam = 0; } + private void OnProjectileghostHeal(On_Projectile.orig_ghostHeal orig, Projectile self, int dmg, Vector2 position, Entity victim) { @@ -152,4 +153,297 @@ private void OnProjectileghostHeal(On_Projectile.orig_ghostHeal orig, Projectile ); } } + + 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(); + } + } + } } \ No newline at end of file From 3bd2f22866bd5640e9d4d171ed792dcd2ef3da45 Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Wed, 28 May 2025 17:27:23 -0700 Subject: [PATCH 011/206] skeletron hand garenteed --- AdventureDropDatabase.cs | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/AdventureDropDatabase.cs b/AdventureDropDatabase.cs index a5808956..0e969ca2 100644 --- a/AdventureDropDatabase.cs +++ b/AdventureDropDatabase.cs @@ -37,12 +37,7 @@ 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(); @@ -270,7 +265,7 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) case NPCID.GiantTortoise: foreach (var drop in drops) - ModifyDropRate(drop, ItemID.TurtleShell, 1, 5); + ModifyDropRate(drop, ItemID.TurtleShell, 1, 4); break; case NPCID.GiantCursedSkull: @@ -278,15 +273,7 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) ModifyDropRate(drop, ItemID.ShadowJoustingLance, 1, 12); 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 From 8d62979c342b83273f1ebd81864d9a7990370ac3 Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Wed, 28 May 2025 17:27:45 -0700 Subject: [PATCH 012/206] no empress underground --- AdventureItem.cs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/AdventureItem.cs b/AdventureItem.cs index 4a8a36f8..4afe3251 100644 --- a/AdventureItem.cs +++ b/AdventureItem.cs @@ -50,6 +50,26 @@ public override bool CanUseItem(Item item, Player player) return base.CanUseItem(item, player); } } + public class PrismaticLacewingRestriction : GlobalItem + { + public override bool CanUseItem(Item item, Player player) + { + // Target Prismatic Lacewing (Empress summon item) + if (item.type == ItemID.EmpressButterfly) + { + // Check if player is below surface level + bool isUnderground = player.position.Y > Main.worldSurface * 16; + bool inUndergroundHallow = isUnderground && player.ZoneHallow; + + if (isUnderground) + { + Main.NewText("The sacred light refuses to manifest in these corrupted depths!", 200, 150, 255); + return false; + } + } + return base.CanUseItem(item, player); + } + } public override void SetDefaults(Item item) { From 2922e72d6c5f4e51ed56eb0bb71d256aa09568b3 Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Wed, 28 May 2025 16:50:11 -0700 Subject: [PATCH 013/206] Makes the spac and claff projectiles disappear on dead --- AdventureProjectile.cs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/AdventureProjectile.cs b/AdventureProjectile.cs index 3dc32d3d..25d174c8 100644 --- a/AdventureProjectile.cs +++ b/AdventureProjectile.cs @@ -446,4 +446,32 @@ public override void PostAI(Projectile projectile) } } } + + 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 From 4a6479d0c1c0a082cfc4c5d17ff833a527fb8bd8 Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Sat, 31 May 2025 11:12:40 -0700 Subject: [PATCH 014/206] updated shiny stone cooldown bebuff icon --- Assets/Buff/ShinyStoneHotswap.png | Bin 1253 -> 321 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/Assets/Buff/ShinyStoneHotswap.png b/Assets/Buff/ShinyStoneHotswap.png index e18d0f432eb900f533369f1c190e7a5f9748976e..ec96c433ac82733ea81160e81a711ed7df61bde0 100644 GIT binary patch literal 321 zcmV-H0lxl;P)SiYTGa33}GX0QlQV|FE@p$*QGra%+;&cVoTE-Os007lVL_t(Y$L-TG z3c@fH2H-5>+|dgtuI){{fs3P)h{tg2QJlPtV>c(IAQ4~lXZZC|Ym-#Lz(0iay$@be zW8Pfb+1$R03B962XlTp4NmVv+`(R*nNCjM~)l||O{6oDVZpctwOeDVp0q~%M0MyG| z^1aa0$mj=U;I>~&I)l-nMK-pNT+cfR3ebQd4M08m4G&!og~UTNs-rOy?D=`0HY3UK z5Q8XS&_kaB$sisbE|ozJ&QaI-j)Ft{tg&YpKQ6x08grcolSA4}`CLm|T{7qnTPV}6 TDPy{T00000NkvXXu0mjftx<>R literal 1253 zcmV#dBtE(XoR>JmOeS?cH=`Hg4jzO=bJh z?B_rn006p@gYpG5?SKwYXJURPXxb)@&#m4FfrZGs-|$D28#KBW1${n7XN$SKGy(ZQ z)jr9MqB1(uG7}#cgzxi8ZQVAlSOMdVz(5g*83v0fg*7Okg1s!t$>>~+$Xl#!kmm)& z+;%L>ZQSRv1c*SBz!E0$IxZcCRMO~@i!dzO3&`S^!g$`5jmBObzDX(<FAM11Qy*{H^kx^&K`uZr;>zrYAA%|0-b$ym=VO%1_k z7l}ksbp6=SIkOMsAX4TOewogFITDMCJ<h#G7WD19z z!ZHfDQA~$|ZnV?s%dd;jp)MnEwGjAue#ujrPQ9saQ1*WNWCU^$DI*F`e44hNtG8F% z>KA@2l=TAmof9LFDI8J?<54y}(vL^QIa*tN?u6ss;{}^d*oDsNa9f@A{N_W(M&aC? zDj0z!&qQis0)aXw(qR`mmzvmeHgK{JWiFmeD#CQ#pF9|Mj%tTj413T zO}kTh(VEg;75R!Gl#29>4^LredK%mUYThZpVt_#W*KBmrqvvh(8Ieg*p>v|_RoC>q zk58mIh^%o6BQ@&C3p*G%yf|l_6sed($4p;7GNC>rkSQE;3ez(_Ox5UlpqovYM3!pO zJtMlHytnl6HzWKzkyS?E(CuBevXsaDlFSwW;N+<~m zm$T!h58j4=@sC$irCCdxGx|40s=y zU17W@8E>n#-RP|;g*W|#RmR?p=k4>X`A(_Ufe{$255)hSfQ3(ER#pB30%Ga Date: Sat, 31 May 2025 20:49:43 -0700 Subject: [PATCH 015/206] added config link --- PvPAdventure_AdventureConfig.json | 1176 +++++++++++++++++++++++++++++ 1 file changed, 1176 insertions(+) create mode 100644 PvPAdventure_AdventureConfig.json diff --git a/PvPAdventure_AdventureConfig.json b/PvPAdventure_AdventureConfig.json new file mode 100644 index 00000000..ad383ddc --- /dev/null +++ b/PvPAdventure_AdventureConfig.json @@ -0,0 +1,1176 @@ +{ + "Points": { + "Npc": { + "Terraria/Golem": { + "First": 1, + "Additional": 1, + "Repeatable": true + }, + "Terraria/CultistBoss": { + "First": 4, + "Additional": 4, + "Repeatable": true + }, + "Terraria/DukeFishron": { + "First": 3, + "Additional": 3, + "Repeatable": true + }, + "Terraria/HallowBoss": { + "First": 4, + "Additional": 4, + "Repeatable": true + }, + "Terraria/BigMimicCorruption": { + "First": 1, + "Additional": 1 + }, + "Terraria/BigMimicHallow": { + "First": 1, + "Additional": 1 + }, + "Terraria/BigMimicCrimson": { + "First": 1, + "Additional": 1 + }, + "Terraria/DD2Betsy": { + "First": 10, + "Additional": 8, + "Repeatable": true + }, + "Terraria/EyeofCthulhu": { + "First": 1, + "Additional": 1 + }, + "Terraria/SkeletronHead": { + "First": 1, + "Additional": 1 + }, + "Terraria/KingSlime": { + "First": 1, + "Additional": 1 + }, + "Terraria/MartianSaucerCore": { + "First": 1, + "Additional": 1, + "Repeatable": true + } + }, + "Boss": { + "First": 2, + "Additional": 2 + }, + "PlayerKill": 1 + }, + "Bounties": [ + { + "Items": [ + { + "Item": { + "Name": "GoldWorm", + "DisplayName": "Gold Worm" + }, + "Stack": 3 + } + ], + "Conditions": { + "WorldProgression": 1 + } + }, + { + "Items": [ + { + "Item": { + "Name": "HermesBoots", + "DisplayName": "Hermes Boots" + }, + "Stack": 1 + }, + { + "Item": { + "Name": "CloudinaBottle", + "DisplayName": "Cloud in a Bottle" + }, + "Stack": 1 + }, + { + "Item": { + "Name": "SapphireHook", + "DisplayName": "Sapphire Hook" + }, + "Stack": 1 + } + ], + "Conditions": {} + }, + { + "Items": [ + { + "Item": { + "Name": "LifeCrystal", + "DisplayName": "Life Crystal" + }, + "Stack": 3 + } + ], + "Conditions": {} + }, + { + "Items": [ + { + "Item": { + "Name": "WormholePotion", + "DisplayName": "Wormhole Potion" + }, + "Stack": 3 + } + ], + "Conditions": {} + }, + { + "Items": [ + { + "Item": { + "Name": "GoldWorm", + "DisplayName": "Gold Worm" + }, + "Stack": 5 + } + ], + "Conditions": { + "WorldProgression": 2 + } + }, + { + "Items": [ + { + "Item": { + "Name": "GuideVoodooDoll", + "DisplayName": "Guide Voodoo Doll" + }, + "Stack": 1 + } + ], + "Conditions": { + "WorldProgression": 2 + } + }, + { + "Items": [ + { + "Item": { + "Name": "Hellforge", + "DisplayName": "Hellforge" + }, + "Prefix": { + "Name": "Precise", + "DisplayName": "Precise" + }, + "Stack": 1 + } + ], + "Conditions": { + "WorldProgression": 2 + } + }, + { + "Items": [ + { + "Item": { + "Name": "FallenStar", + "DisplayName": "Fallen Star" + }, + "Stack": 20 + } + ], + "Conditions": { + "WorldProgression": 2 + } + }, + { + "Items": [ + { + "Item": { + "Name": "SoulofFlight", + "DisplayName": "Soul of Flight" + }, + "Stack": 18 + }, + { + "Item": { + "Name": "Feather", + "DisplayName": "Feather" + }, + "Stack": 20 + } + ], + "Conditions": { + "WorldProgression": 2 + } + }, + { + "Items": [ + { + "Item": { + "Name": "SoulofLight", + "DisplayName": "Soul of Light" + }, + "Stack": 6 + }, + { + "Item": { + "Name": "CrystalShard", + "DisplayName": "Crystal Shard" + }, + "Stack": 40 + }, + { + "Item": { + "Name": "LightShard", + "DisplayName": "Light Shard" + }, + "Stack": 2 + } + ], + "Conditions": { + "WorldProgression": 2 + } + }, + { + "Items": [ + { + "Item": { + "Name": "SoulofNight", + "DisplayName": "Soul of Night" + }, + "Stack": 6 + }, + { + "Item": { + "Name": "CursedFlame", + "DisplayName": "Cursed Flame" + }, + "Stack": 40 + }, + { + "Item": { + "Name": "DarkShard", + "DisplayName": "Dark Shard" + }, + "Stack": 2 + } + ], + "Conditions": { + "WorldProgression": 2 + } + }, + { + "Items": [ + { + "Item": { + "Name": "PixieDust", + "DisplayName": "Pixie Dust" + }, + "Stack": 90 + }, + { + "Item": { + "Name": "UnicornHorn", + "DisplayName": "Unicorn Horn" + }, + "Stack": 2 + } + ], + "Conditions": { + "WorldProgression": 2 + } + }, + { + "Items": [ + { + "Item": { + "Name": "Ichor", + "DisplayName": "Ichor" + }, + "Stack": 40 + } + ], + "Conditions": { + "WorldProgression": 2 + } + }, + { + "Items": [ + { + "Item": { + "Name": "TurtleShell", + "DisplayName": "Turtle Shell" + }, + "Stack": 1 + } + ], + "Conditions": { + "WorldProgression": 2 + } + }, + { + "Items": [ + { + "Item": { + "Name": "SoulofSight", + "DisplayName": "Soul of Sight" + }, + "Stack": 6 + } + ], + "Conditions": { + "WorldProgression": 2, + "CollectedAllMechanicalBossSouls": true + } + }, + { + "Items": [ + { + "Item": { + "Name": "SoulofMight", + "DisplayName": "Soul of Might" + }, + "Stack": 26 + } + ], + "Conditions": { + "WorldProgression": 2, + "CollectedAllMechanicalBossSouls": true + } + }, + { + "Items": [ + { + "Item": { + "Name": "SoulofFright", + "DisplayName": "Soul of Fright" + }, + "Stack": 46 + } + ], + "Conditions": { + "WorldProgression": 2, + "CollectedAllMechanicalBossSouls": true + } + }, + { + "Items": [ + { + "Item": { + "Name": "LihzahrdPowerCell", + "DisplayName": "Lihzahrd Power Cell" + }, + "Prefix": { + "Name": "Powerful", + "DisplayName": "Powerful" + }, + "Stack": 1 + } + ], + "Conditions": { + "WorldProgression": 2, + "PlanteraDefeated": true + } + }, + { + "Items": [ + { + "Item": { + "Name": "LifeFruit", + "DisplayName": "Life Fruit" + }, + "Stack": 4 + } + ], + "Conditions": { + "WorldProgression": 2, + "SkeletronPrimeDefeated": true, + "TwinsDefeated": true, + "DestroyerDefeated": true + } + }, + { + "Items": [ + { + "Item": { + "Name": "LockBox", + "DisplayName": "Golden Lock Box" + }, + "Stack": 1 + }, + { + "Item": { + "Name": "ObsidianLockbox", + "DisplayName": "Obsidian Lock Box" + }, + "Stack": 1 + } + ], + "Conditions": { + "SkeletronDefeated": true + } + }, + { + "Items": [ + { + "Item": { + "Name": "RottenChunk", + "DisplayName": "Rotten Chunk" + }, + "Stack": 20 + }, + { + "Item": { + "Name": "VileMushroom", + "DisplayName": "Vile Mushroom" + }, + "Stack": 5 + }, + { + "Item": { + "Name": "Lens", + "DisplayName": "Lens" + }, + "Stack": 3 + }, + { + "Item": { + "Name": "Bone", + "DisplayName": "Bone" + }, + "Stack": 30 + }, + { + "Item": { + "Name": "IronBar", + "DisplayName": "Iron Bar" + }, + "Stack": 15 + } + ], + "Conditions": { + "WorldProgression": 2, + "SkeletronDefeated": true + } + }, + { + "Items": [ + { + "Item": { + "Name": "BottledWater", + "DisplayName": "Bottled Water" + }, + "Stack": 30 + }, + { + "Item": { + "Name": "Blinkroot", + "DisplayName": "Blinkroot" + }, + "Stack": 6 + }, + { + "Item": { + "Name": "Daybloom", + "DisplayName": "Daybloom" + }, + "Stack": 8 + }, + { + "Item": { + "Name": "Moonglow", + "DisplayName": "Moonglow" + }, + "Stack": 4 + }, + { + "Item": { + "Name": "Deathweed", + "DisplayName": "Deathweed" + }, + "Stack": 1 + }, + { + "Item": { + "Name": "Waterleaf", + "DisplayName": "Waterleaf" + }, + "Stack": 4 + }, + { + "Item": { + "Name": "AntlionMandible", + "DisplayName": "Antlion Mandible" + }, + "Stack": 4 + }, + { + "Item": { + "Name": "SharkFin", + "DisplayName": "Shark Fin" + }, + "Stack": 4 + } + ], + "Conditions": { + "WorldProgression": 2 + } + }, + { + "Items": [ + { + "Item": { + "Name": "Blinkroot", + "DisplayName": "Blinkroot" + }, + "Stack": 3 + }, + { + "Item": { + "Name": "Daybloom", + "DisplayName": "Daybloom" + }, + "Stack": 4 + }, + { + "Item": { + "Name": "Moonglow", + "DisplayName": "Moonglow" + }, + "Stack": 1 + }, + { + "Item": { + "Name": "Deathweed", + "DisplayName": "Deathweed" + }, + "Stack": 1 + }, + { + "Item": { + "Name": "Shiverthorn", + "DisplayName": "Shiverthorn" + }, + "Stack": 2 + }, + { + "Item": { + "Name": "AntlionMandible", + "DisplayName": "Antlion Mandible" + }, + "Stack": 2 + }, + { + "Item": { + "Name": "BottledWater", + "DisplayName": "Bottled Water" + }, + "Stack": 15 + }, + { + "Item": { + "Name": "Waterleaf", + "DisplayName": "Waterleaf" + }, + "Stack": 1 + } + ], + "Conditions": { + "WorldProgression": 1 + } + }, + { + "Items": [ + { + "Item": { + "Name": "TruffleWorm", + "DisplayName": "Truffle Worm" + }, + "Prefix": { + "Name": "Nimble", + "DisplayName": "Nimble" + }, + "Stack": 1 + } + ], + "Conditions": { + "WorldProgression": 2, + "GolemDefeated": true + } + }, + { + "Items": [ + { + "Item": { + "Name": "QueenSlimeCrystal", + "DisplayName": "Gelatin Crystal" + }, + "Stack": 2 + } + ], + "Conditions": { + "WorldProgression": 2 + } + } + ], + "Combat": { + "MeleeInvincibilityFrames": 0, + "PlayerDamageBalance": { + "ItemDamageMultipliers": { + "Terraria/Tsunami": 1.0, + "Terraria/StaffofEarth": 0.79999995, + "Terraria/ChlorophyteShotbow": 1.2, + "Terraria/FairyQueenRangedItem": 0.84999996, + "Terraria/MaceWhip": 0.55, + "Terraria/HeatRay": 0.5, + "Terraria/SniperRifle": 0.55, + "Terraria/ShadowbeamStaff": 0.6, + "Terraria/ToxicFlask": 1.0, + "Terraria/LaserMachinegun": 0.79999995, + "Terraria/Xenopopper": 1.75, + "Terraria/ProximityMineLauncher": 0.11, + "Terraria/ChargedBlasterCannon": 0.0, + "Terraria/TheEyeOfCthulhu": 0.7, + "Terraria/Kraken": 0.75, + "Terraria/VenusMagnum": 0.84999996, + "Terraria/PirateStaff": 0.79999995, + "Terraria/DaedalusStormbow": 0.65, + "Terraria/SoulDrain": 0.0, + "Terraria/MeteorStaff": 0.39999998, + "Terraria/DD2SquireBetsySword": 0.0, + "Terraria/StaffoftheFrostHydra": 0.0, + "Terraria/DD2BallistraTowerT3Popper": 0.0, + "Terraria/DD2BallistraTowerT2Popper": 0.0, + "Terraria/DD2BallistraTowerT1Popper": 0.0, + "Terraria/DD2FlameburstTowerT3Popper": 0.0, + "Terraria/DD2FlameburstTowerT2Popper": 0.0, + "Terraria/DD2FlameburstTowerT1Popper": 0.0, + "Terraria/RainbowRod": 1.0, + "Terraria/TempestStaff": 0.61, + "Terraria/DirtRod": 1000.0, + "Terraria/CursedFlames": 1.0, + "Terraria/FlyingKnife": 0.65, + "Terraria/RainbowWhip": 0.5, + "Terraria/TacticalShotgun": 2.0, + "Terraria/VenomStaff": 3.0, + "Terraria/PearlwoodSword": 1.1, + "Terraria/MagicMissile": 0.85999995, + "Terraria/Gungnir": 1.0, + "Terraria/TrueNightsEdge": 0.91999996, + "Terraria/RocketLauncher": 0.79999995, + "Terraria/OnyxBlaster": 1.5, + "Terraria/ScourgeoftheCorruptor": 0.9 + }, + "ProjectileDamageMultipliers": { + "Terraria/TinyEater": 0.5, + "Terraria/ClusterFragmentsI": 1.0, + "Terraria/ClusterFragmentsII": 0.96, + "Terraria/ClusterSnowmanFragmentsI": 1.0, + "Terraria/ClusterSnowmanFragmentsII": 1.0, + "Terraria/StyngerShrapnel": 1.0, + "Terraria/CrystalShard": 1.0, + "Terraria/TerraBlade2Shot": 0.5, + "Terraria/Starfury": 0.0, + "Terraria/SporeCloud": 1.0, + "Terraria/CursedDartFlame": 1.0 + }, + "ItemFalloff": { + "Terraria/SniperRifle": { + "Coefficient": 0.5, + "Forward": 100.0 + }, + "Terraria/ChlorophyteShotbow": { + "Coefficient": 1.5, + "Forward": 40.0 + }, + "Terraria/TacticalShotgun": { + "Coefficient": 1.75, + "Forward": 25.0 + }, + "Terraria/VenomStaff": { + "Coefficient": 1.7321, + "Forward": 8.95 + }, + "Terraria/OnyxBlaster": { + "Coefficient": 1.5, + "Forward": 25.0 + }, + "Terraria/Xenopopper": { + "Coefficient": 1.5, + "Forward": 25.0 + }, + "Terraria/TrueNightsEdge": { + "Coefficient": 1.75, + "Forward": 20.25 + } + }, + "DefaultFalloff": { + "Coefficient": 1.0, + "Forward": 58.350002 + } + } + }, + "PreventUse": [ + { + "Name": "RecallPotion", + "DisplayName": "Recall Potion" + }, + { + "Name": "TeleportationPotion", + "DisplayName": "Teleportation Potion" + }, + { + "Name": "InvisibilityPotion", + "DisplayName": "Invisibility Potion" + }, + { + "Name": "PotionOfReturn", + "DisplayName": "Potion of Return" + }, + { + "Name": "MagicConch", + "DisplayName": "Magic Conch" + }, + { + "Name": "DemonConch", + "DisplayName": "Demon Conch" + }, + { + "Name": "ChlorophyteArrow", + "DisplayName": "Chlorophyte Arrow" + }, + { + "Name": "StrangeBrew", + "DisplayName": "Strange Brew" + }, + { + "Name": "SoulDrain", + "DisplayName": "Life Drain" + }, + { + "Name": "CosmicCarKey", + "DisplayName": "Cosmic Car Key" + }, + { + "Name": "PumpkinMoonMedallion", + "DisplayName": "Pumpkin Moon Medallion" + }, + { + "Name": "NaughtyPresent", + "DisplayName": "Naughty Present" + }, + { + "Name": "FlaskofNanites", + "DisplayName": "Flask of Nanites" + }, + { + "Name": "BorealWoodHammer", + "DisplayName": "Boreal Wood Hammer" + }, + { + "Name": "BeetleShell", + "DisplayName": "Beetle Shell" + }, + { + "Name": "EmpressButterfly", + "DisplayName": "Prismatic Lacewing" + } + ], + "NpcSpawnAnnouncements": [ + { + "Name": "CultistBoss", + "DisplayName": "Lunatic Cultist" + }, + { + "Name": "RuneWizard", + "DisplayName": "Rune Wizard" + }, + { + "Name": "GoldMouse", + "DisplayName": "Gold Mouse" + }, + { + "Name": "MartianSaucer", + "DisplayName": "Martian Saucer" + }, + { + "Name": "CultistTablet", + "DisplayName": "Mysterious Tablet" + }, + { + "Name": "DoctorBones", + "DisplayName": "Doctor Bones" + }, + { + "Name": "SandElemental", + "DisplayName": "Sand Elemental" + }, + { + "Name": "IceGolem", + "DisplayName": "Ice Golem" + } + ], + "BossInvulnerableProjectiles": [ + { + "Name": "Dynamite", + "DisplayName": "Dynamite" + }, + { + "Name": "StickyDynamite", + "DisplayName": "Sticky Dynamite" + }, + { + "Name": "BouncyDynamite", + "DisplayName": "Bouncy Dynamite" + }, + { + "Name": "Bomb", + "DisplayName": "Bomb" + }, + { + "Name": "StickyBomb", + "DisplayName": "Sticky Bomb" + }, + { + "Name": "BouncyBomb", + "DisplayName": "Bouncy Bomb" + } + ], + "InvasionSizes": { + "1": { + "Value": 250 + }, + "3": { + "Value": 150 + }, + "4": { + "Value": 320 + } + }, + "SpawnImmuneFrames": 90, + "ShareWorldMap": false, + "AllowConfigModification": [ + "168209541136121856" + ], + "RemovePrefixes": true, + "ItemStatistics": { + "Terraria/Tsunami": { + "Damage": { + "Value": 45 + } + }, + "Terraria/Flairon": { + "Damage": { + "Value": 60 + } + }, + "Terraria/BubbleGun": { + "Mana": { + "Value": 10 + } + }, + "Terraria/DaedalusStormbow": { + "Damage": { + "Value": 34 + } + }, + "Terraria/TrueNightsEdge": { + "Damage": { + "Value": 150 + }, + "ShootSpeed": { + "Value": 20.85 + }, + "Scale": { + "Value": 1.2 + } + }, + "Terraria/Jetpack": { + "Value": { + "Value": 1000000 + } + }, + "Terraria/Megashark": { + "Damage": { + "Value": 30 + }, + "UseTime": { + "Value": 8 + }, + "UseAnimation": { + "Value": 8 + } + }, + "Terraria/ClockworkAssaultRifle": { + "UseTime": { + "Value": 10 + }, + "UseAnimation": { + "Value": 40 + } + }, + "Terraria/XenoStaff": { + "Damage": { + "Value": 26 + } + } + }, + "WorldGeneration": { + "PlanteraBulbChanceDenominator": 20, + "ChlorophyteSpreadChanceModifier": 15 + }, + "PreventAutoReuse": [ + { + "Name": "MagicMissile", + "DisplayName": "Magic Missile" + }, + { + "Name": "Flamelash", + "DisplayName": "Flamelash" + }, + { + "Name": "RainbowRod", + "DisplayName": "Rainbow Rod" + } + ], + "NpcBalance": { + "LifeMaxMultipliers": { + "Terraria/SkeletronHead": { + "Value": 1.49 + }, + "Terraria/SkeletronHand": { + "Value": 1.52 + }, + "Terraria/WallofFlesh": { + "Value": 1.49 + }, + "Terraria/Plantera": { + "Value": 1.52 + }, + "Terraria/HallowBoss": { + "Value": 1.49 + }, + "Terraria/Golem": { + "Value": 1.31 + }, + "Terraria/GolemFistLeft": { + "Value": 1.31 + }, + "Terraria/GolemFistRight": { + "Value": 1.31 + }, + "Terraria/CultistBoss": { + "Value": 1.49 + }, + "Terraria/MartianSaucerCore": { + "Value": 1.25 + } + } + }, + "ChestItemReplacements": { + "Terraria/MagicMirror": { + "Items": [ + { + "Item": { + "Name": "HermesBoots", + "DisplayName": "Hermes Boots" + }, + "Stack": 1 + }, + { + "Item": { + "Name": "CloudinaBottle", + "DisplayName": "Cloud in a Bottle" + }, + "Stack": 1 + }, + { + "Item": { + "Name": "Mace", + "DisplayName": "Mace" + }, + "Stack": 1 + }, + { + "Item": { + "Name": "BandofRegeneration", + "DisplayName": "Band of Regeneration" + }, + "Stack": 1 + }, + { + "Item": { + "Name": "ShoeSpikes", + "DisplayName": "Shoe Spikes" + }, + "Stack": 1 + } + ] + }, + "Terraria/PiranhaGun": { + "Items": [ + { + "Item": { + "Name": "VenusMagnum", + "DisplayName": "Venus Magnum" + }, + "Stack": 1 + } + ] + }, + "Terraria/StaffoftheFrostHydra": { + "Items": [ + { + "Item": { + "Name": "FrozenShield", + "DisplayName": "Frozen Shield" + }, + "Stack": 1 + } + ] + }, + "Terraria/LihzahrdPowerCell": { + "Items": [ + { + "Item": { + "Name": "LihzahrdPowerCell", + "DisplayName": "Lihzahrd Power Cell" + }, + "Stack": 2 + } + ] + }, + "Terraria/MagicConch": { + "Items": [ + { + "Item": { + "Name": "AncientChisel", + "DisplayName": "Ancient Chisel" + }, + "Stack": 1 + }, + { + "Item": { + "Name": "SandBoots", + "DisplayName": "Dunerider Boots" + }, + "Stack": 1 + } + ] + }, + "Terraria/Seaweed": { + "Items": [ + { + "Item": { + "Name": "FeralClaws", + "DisplayName": "Feral Claws" + }, + "Stack": 1 + } + ] + }, + "Terraria/Fish": { + "Items": [ + { + "Item": { + "Name": "BlizzardinaBottle", + "DisplayName": "Blizzard in a Bottle" + }, + "Stack": 1 + } + ] + }, + "Terraria/CatBast": { + "Items": [ + { + "Item": { + "Name": "SandstorminaBottle", + "DisplayName": "Sandstorm in a Bottle" + }, + "Stack": 1 + } + ] + }, + "Terraria/Extractinator": { + "Items": [ + { + "Item": { + "Name": "HermesBoots", + "DisplayName": "Hermes Boots" + }, + "Stack": 1 + }, + { + "Item": { + "Name": "CloudinaBottle", + "DisplayName": "Cloud in a Bottle" + }, + "Stack": 1 + }, + { + "Item": { + "Name": "Mace", + "DisplayName": "Mace" + }, + "Stack": 1 + }, + { + "Item": { + "Name": "BandofRegeneration", + "DisplayName": "Band of Regeneration" + }, + "Stack": 1 + } + ] + }, + "Terraria/TeleportationPotion": { + "Items": [ + { + "Item": { + "Name": "ThornsPotion", + "DisplayName": "Thorns Potion" + }, + "Stack": 2 + }, + { + "Item": { + "Name": "WaterWalkingPotion", + "DisplayName": "Water Walking Potion" + }, + "Stack": 2 + }, + { + "Item": { + "Name": "HunterPotion", + "DisplayName": "Hunter Potion" + }, + "Stack": 2 + }, + { + "Item": { + "Name": "TrapsightPotion", + "DisplayName": "Dangersense Potion" + }, + "Stack": 2 + } + ] + }, + "Terraria/PotionOfReturn": { + "Items": [ + { + "Item": { + "Name": "RecallPotion", + "DisplayName": "Recall Potion" + }, + "Stack": 1 + } + ] + } + }, + "MinimumDamageReceivedByPlayersFromPlayer": 5 +} \ No newline at end of file From 119a14276f0922002a51ea65be8c9a05a0429537 Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Sat, 31 May 2025 21:06:10 -0700 Subject: [PATCH 016/206] Spectre Hood setbonus works in pvp! --- AdventureProjectile.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/AdventureProjectile.cs b/AdventureProjectile.cs index 25d174c8..fd1239b0 100644 --- a/AdventureProjectile.cs +++ b/AdventureProjectile.cs @@ -1,10 +1,15 @@ +using System; +using System.Reflection; using Microsoft.Xna.Framework; +using MonoMod.Cil; +using MonoMod.RuntimeDetour; using PvPAdventure.System; using Terraria; using Terraria.DataStructures; using Terraria.Enums; using Terraria.ID; using Terraria.ModLoader; +using Mono.Cecil.Cil; namespace PvPAdventure; @@ -88,7 +93,6 @@ public override void PostAI(Projectile projectile) projectile.netSpam = 0; } - private void OnProjectileghostHeal(On_Projectile.orig_ghostHeal orig, Projectile self, int dmg, Vector2 position, Entity victim) { From ee7f6a157d6394bf68a387f5f475e85ebf6ad451 Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Sun, 1 Jun 2025 10:07:21 -0700 Subject: [PATCH 017/206] Revert "Merge branch 'pr/34' into feature/missinginmaster" This reverts commit 09cc7830c4ed74cc9a44b8e780381227fe7f0729, reversing changes made to 350e1d2cb0c8cf7163ec9b1e639e118dd9fb985c. --- AdventureProjectile.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/AdventureProjectile.cs b/AdventureProjectile.cs index fd1239b0..9d3f369b 100644 --- a/AdventureProjectile.cs +++ b/AdventureProjectile.cs @@ -1,15 +1,10 @@ -using System; -using System.Reflection; using Microsoft.Xna.Framework; -using MonoMod.Cil; -using MonoMod.RuntimeDetour; using PvPAdventure.System; using Terraria; using Terraria.DataStructures; using Terraria.Enums; using Terraria.ID; using Terraria.ModLoader; -using Mono.Cecil.Cil; namespace PvPAdventure; From 7d087c119386e7a0e1835ae8843fc7144b1b2a52 Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Mon, 2 Jun 2025 17:11:29 -0700 Subject: [PATCH 018/206] Update PvPAdventure_AdventureConfig.json --- PvPAdventure_AdventureConfig.json | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/PvPAdventure_AdventureConfig.json b/PvPAdventure_AdventureConfig.json index ad383ddc..eff492b3 100644 --- a/PvPAdventure_AdventureConfig.json +++ b/PvPAdventure_AdventureConfig.json @@ -625,7 +625,7 @@ "Terraria/Tsunami": 1.0, "Terraria/StaffofEarth": 0.79999995, "Terraria/ChlorophyteShotbow": 1.2, - "Terraria/FairyQueenRangedItem": 0.84999996, + "Terraria/FairyQueenRangedItem": 0.75, "Terraria/MaceWhip": 0.55, "Terraria/HeatRay": 0.5, "Terraria/SniperRifle": 0.55, @@ -775,10 +775,6 @@ { "Name": "BeetleShell", "DisplayName": "Beetle Shell" - }, - { - "Name": "EmpressButterfly", - "DisplayName": "Prismatic Lacewing" } ], "NpcSpawnAnnouncements": [ From 1064993e306959ed65345de43d7b24ec773c9910 Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Wed, 4 Jun 2025 21:21:03 -0700 Subject: [PATCH 019/206] removed extra code --- AdventureItem.cs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/AdventureItem.cs b/AdventureItem.cs index 4afe3251..fafa1b02 100644 --- a/AdventureItem.cs +++ b/AdventureItem.cs @@ -16,16 +16,6 @@ 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) From ba1f33d9e16e94ec5d39ad7fb7752c213619bb11 Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Sat, 7 Jun 2025 15:32:45 -0700 Subject: [PATCH 020/206] new drop rules --- AdventureDropDatabase.cs | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/AdventureDropDatabase.cs b/AdventureDropDatabase.cs index 0e969ca2..df95e39f 100644 --- a/AdventureDropDatabase.cs +++ b/AdventureDropDatabase.cs @@ -63,6 +63,11 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) ModifyDropRate(drop, ItemID.Stinger, 1, 1); break; + case NPCID.GiantTortoise: + foreach (var drop in drops) + ModifyDropRate(drop, ItemID.TurtleShell, 1, 4); + break; + case NPCID.Necromancer: case NPCID.NecromancerArmored: foreach (var drop in drops) @@ -139,6 +144,11 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) ModifyDropRate(drop, ItemID.ButterflyDust, 1, 1); break; + case NPCID.GiantCursedSkull: + foreach (var drop in drops) + ModifyDropRate(drop, ItemID.ShadowJoustingLance, 1, 12); + break; + case NPCID.Mothron: foreach (var drop in drops) ModifyDropRate(drop, ItemID.BrokenHeroSword, 1, 2); @@ -263,17 +273,6 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) ])); break; - case NPCID.GiantTortoise: - foreach (var drop in drops) - ModifyDropRate(drop, ItemID.TurtleShell, 1, 4); - break; - - case NPCID.GiantCursedSkull: - foreach (var drop in drops) - ModifyDropRate(drop, ItemID.ShadowJoustingLance, 1, 12); - break; - - } } } \ No newline at end of file From fa7e02f27626d7c67211a8c4ba8282b0655e2ad6 Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Mon, 9 Jun 2025 14:36:59 -0700 Subject: [PATCH 021/206] ADDED new money trough shimmer recipe --- AdventureItem.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/AdventureItem.cs b/AdventureItem.cs index fafa1b02..62f9f216 100644 --- a/AdventureItem.cs +++ b/AdventureItem.cs @@ -95,7 +95,6 @@ public override void SetDefaults(Item item) if (statistics.Value != null) item.value = statistics.Value.Value; } - if (item.type == ItemID.SpectrePickaxe || item.type == ItemID.ShroomiteDiggingClaw) item.pick = 210; } From 64cc63ab6d00160927bb67b2ca3496f4485c84e4 Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Mon, 9 Jun 2025 14:37:42 -0700 Subject: [PATCH 022/206] remvoed tikki kb immuinkty --- AdventurePlayer.cs | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/AdventurePlayer.cs b/AdventurePlayer.cs index f4bddba2..59e0beb3 100644 --- a/AdventurePlayer.cs +++ b/AdventurePlayer.cs @@ -611,12 +611,17 @@ public override void PostUpdateEquips() 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) + if (Player.beetleOffense) { - Player.noKnockback = true; + Player.GetDamage() += 0.10f; + Player.GetAttackSpeed() += 0.10f; + } + else + { + // If we don't have the beetle offense set bonus, remove all possible buffs. + Player.ClearBuff(BuffID.BeetleMight1); + Player.ClearBuff(BuffID.BeetleMight2); + Player.ClearBuff(BuffID.BeetleMight3); } } @@ -926,16 +931,6 @@ public override void UpdateBadLifeRegen() } } - public override void PostUpdateEquips() - { - if (!Player.beetleOffense) - { - // If we don't have the beetle offense set bonus, remove all possible buffs. - Player.ClearBuff(BuffID.BeetleMight1); - Player.ClearBuff(BuffID.BeetleMight2); - Player.ClearBuff(BuffID.BeetleMight3); - } - } private void SendPingPong() { From 6c742512543097839fc95a76d44823668eaa4f74 Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Sun, 8 Jun 2025 03:20:04 -0700 Subject: [PATCH 023/206] Makes Flask Buffs go away on death --- AdventureBuff.cs | 38 ++++++++++++++++++++++++++++++++++++++ AdventurePlayer.cs | 1 + 2 files changed, 39 insertions(+) diff --git a/AdventureBuff.cs b/AdventureBuff.cs index a97e136d..8d976782 100644 --- a/AdventureBuff.cs +++ b/AdventureBuff.cs @@ -1,4 +1,6 @@ +using System; using Terraria; +using Terraria.DataStructures; using Terraria.ID; using Terraria.ModLoader; @@ -48,4 +50,40 @@ public override bool RightClick(int type, int buffIndex) return true; } + 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 + } + } + public class RemoveFlaskBuffsOnDeath : ModPlayer + { + // Array of buff IDs to remove on death + private readonly int[] buffsToRemove = { 71, 73, 74, 75, 76, 77, 78, 79 }; //Every single Flask buff that doesn't go away on death for some reason + + public override void Kill(double damage, int hitDirection, bool pvp, PlayerDeathReason damageSource) + { + + for (int i = 0; i < Player.MaxBuffs; i++) + { + int buffType = Player.buffType[i]; + + + foreach (int buffId in buffsToRemove) + { + if (buffType == buffId) + { + Player.DelBuff(i); // Remove the buff + i--; // Adjust index since we removed a buff + break; + } + } + } + } + } } \ No newline at end of file diff --git a/AdventurePlayer.cs b/AdventurePlayer.cs index 59e0beb3..2dfb5a44 100644 --- a/AdventurePlayer.cs +++ b/AdventurePlayer.cs @@ -932,6 +932,7 @@ public override void UpdateBadLifeRegen() } + private void SendPingPong() { _pingPongStopwatch = Stopwatch.StartNew(); From 1c14f86f075972f13b4c5756dac1c7a4778f469a Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Sun, 8 Jun 2025 02:17:01 -0700 Subject: [PATCH 024/206] When you have tier 3 beetleoffense you get the glowing eye vanity --- AdventurePlayer.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/AdventurePlayer.cs b/AdventurePlayer.cs index 2dfb5a44..abdc7697 100644 --- a/AdventurePlayer.cs +++ b/AdventurePlayer.cs @@ -624,6 +624,12 @@ public override void PostUpdateEquips() Player.ClearBuff(BuffID.BeetleMight3); } + if (Player.HasBuff(BuffID.BeetleMight3)) + { + // we apply the glowing eye effect from Yoraiz0rsSpell item + Player.yoraiz0rEye = 33; + } + } public override void OnRespawn() { From 65eedde480d6d310cc521234ac3de70a4d8d19a8 Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Mon, 9 Jun 2025 21:26:07 -0700 Subject: [PATCH 025/206] nerfed beetle armor --- AdventurePlayer.cs | 4 ++-- Localization/en-US.hjson | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/AdventurePlayer.cs b/AdventurePlayer.cs index abdc7697..7becd7d7 100644 --- a/AdventurePlayer.cs +++ b/AdventurePlayer.cs @@ -613,8 +613,8 @@ public override void PostUpdateEquips() if (Player.beetleOffense) { - Player.GetDamage() += 0.10f; - Player.GetAttackSpeed() += 0.10f; + Player.GetDamage() += 0; + Player.GetAttackSpeed() += 0; } else { diff --git a/Localization/en-US.hjson b/Localization/en-US.hjson index 72a598c1..7a14ed5a 100644 --- a/Localization/en-US.hjson +++ b/Localization/en-US.hjson @@ -698,11 +698,12 @@ Mods: { BuffDescription: { BeetleMight1: Melee damage and speed increase by 15% BeetleMight2: Melee damage and speed increase by 25% - BeetleMight3: Melee damage increase by 30% and melee speed increase by 50% + BeetleMight3: Melee damage increase by 30% and melee speed increase by 45% } ArmorSetBonus.BeetleDamage: ''' + Gain Beetles from player kills Beetles increase your melee damage and attack speed ''' From 5304b78a754b00afb9e7786a9b41a6d7a0019bac Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Mon, 9 Jun 2025 21:26:20 -0700 Subject: [PATCH 026/206] remvoed lingereing rainclouds on death --- AdventureProjectile.cs | 238 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 237 insertions(+), 1 deletion(-) diff --git a/AdventureProjectile.cs b/AdventureProjectile.cs index 9d3f369b..c5a8ec1c 100644 --- a/AdventureProjectile.cs +++ b/AdventureProjectile.cs @@ -238,6 +238,7 @@ public override void PostAI(Projectile projectile) if (!hasStaff && !mouseHasStaff) { + projectile.Kill(); } } @@ -455,6 +456,8 @@ public override bool AppliesToEntity(Projectile entity, bool lateInstantiation) entity.type == ProjectileID.SporeTrap2 || entity.type == ProjectileID.SporeGas || entity.type == ProjectileID.SporeGas2 || + entity.type == ProjectileID.RainCloudRaining || + entity.type == ProjectileID.BloodCloudRaining || entity.type == ProjectileID.SporeGas3; } @@ -473,4 +476,237 @@ public override void PostAI(Projectile projectile) } } } -} \ No newline at end of file +} + + + 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(); + } + } + } + From 2e817fa2f76b7eab9eecab9daff8739aef84d49e Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Mon, 9 Jun 2025 21:26:28 -0700 Subject: [PATCH 027/206] config update --- PvPAdventure_AdventureConfig.json | 119 +++++++++++++++++++----------- 1 file changed, 74 insertions(+), 45 deletions(-) diff --git a/PvPAdventure_AdventureConfig.json b/PvPAdventure_AdventureConfig.json index eff492b3..109e5bf0 100644 --- a/PvPAdventure_AdventureConfig.json +++ b/PvPAdventure_AdventureConfig.json @@ -623,8 +623,8 @@ "PlayerDamageBalance": { "ItemDamageMultipliers": { "Terraria/Tsunami": 1.0, - "Terraria/StaffofEarth": 0.79999995, - "Terraria/ChlorophyteShotbow": 1.2, + "Terraria/StaffofEarth": 0.87, + "Terraria/ChlorophyteShotbow": 1.0, "Terraria/FairyQueenRangedItem": 0.75, "Terraria/MaceWhip": 0.55, "Terraria/HeatRay": 0.5, @@ -634,7 +634,7 @@ "Terraria/LaserMachinegun": 0.79999995, "Terraria/Xenopopper": 1.75, "Terraria/ProximityMineLauncher": 0.11, - "Terraria/ChargedBlasterCannon": 0.0, + "Terraria/ChargedBlasterCannon": 0.45, "Terraria/TheEyeOfCthulhu": 0.7, "Terraria/Kraken": 0.75, "Terraria/VenusMagnum": 0.84999996, @@ -642,7 +642,7 @@ "Terraria/DaedalusStormbow": 0.65, "Terraria/SoulDrain": 0.0, "Terraria/MeteorStaff": 0.39999998, - "Terraria/DD2SquireBetsySword": 0.0, + "Terraria/DD2SquireBetsySword": 1.0, "Terraria/StaffoftheFrostHydra": 0.0, "Terraria/DD2BallistraTowerT3Popper": 0.0, "Terraria/DD2BallistraTowerT2Popper": 0.0, @@ -677,7 +677,10 @@ "Terraria/TerraBlade2Shot": 0.5, "Terraria/Starfury": 0.0, "Terraria/SporeCloud": 1.0, - "Terraria/CursedDartFlame": 1.0 + "Terraria/CursedDartFlame": 1.0, + "Terraria/ChlorophyteArrow": 0.0, + "Terraria/DD2SquireSonicBoom": 0.0, + "Terraria/ChargedBlasterLaser": 0.0 }, "ItemFalloff": { "Terraria/SniperRifle": { @@ -713,49 +716,24 @@ "Coefficient": 1.0, "Forward": 58.350002 } - } + }, + "GhostHealMultiplier": 0.79999995, + "GhostHealMultiplierWearers": 0.5, + "GhostHealMaxDistance": 1500.0 }, "PreventUse": [ { "Name": "RecallPotion", "DisplayName": "Recall Potion" }, - { - "Name": "TeleportationPotion", - "DisplayName": "Teleportation Potion" - }, { "Name": "InvisibilityPotion", "DisplayName": "Invisibility Potion" }, - { - "Name": "PotionOfReturn", - "DisplayName": "Potion of Return" - }, - { - "Name": "MagicConch", - "DisplayName": "Magic Conch" - }, - { - "Name": "DemonConch", - "DisplayName": "Demon Conch" - }, { "Name": "ChlorophyteArrow", "DisplayName": "Chlorophyte Arrow" }, - { - "Name": "StrangeBrew", - "DisplayName": "Strange Brew" - }, - { - "Name": "SoulDrain", - "DisplayName": "Life Drain" - }, - { - "Name": "CosmicCarKey", - "DisplayName": "Cosmic Car Key" - }, { "Name": "PumpkinMoonMedallion", "DisplayName": "Pumpkin Moon Medallion" @@ -768,13 +746,21 @@ "Name": "FlaskofNanites", "DisplayName": "Flask of Nanites" }, - { - "Name": "BorealWoodHammer", - "DisplayName": "Boreal Wood Hammer" - }, { "Name": "BeetleShell", "DisplayName": "Beetle Shell" + }, + { + "Name": "PotionOfReturn", + "DisplayName": "Potion of Return" + }, + { + "Name": "TeleportationPotion", + "DisplayName": "Teleportation Potion" + }, + { + "Name": "FrozenShield", + "DisplayName": "Frozen Shield" } ], "NpcSpawnAnnouncements": [ @@ -880,7 +866,7 @@ "Value": 150 }, "ShootSpeed": { - "Value": 20.85 + "Value": 10.7 }, "Scale": { "Value": 1.2 @@ -910,15 +896,16 @@ "Value": 40 } }, - "Terraria/XenoStaff": { - "Damage": { - "Value": 26 + "Terraria/XenoStaff": {}, + "Terraria/MoneyTrough": { + "Value": { + "Value": 10000 } } }, "WorldGeneration": { "PlanteraBulbChanceDenominator": 20, - "ChlorophyteSpreadChanceModifier": 15 + "ChlorophyteSpreadChanceModifier": 100 }, "PreventAutoReuse": [ { @@ -965,6 +952,9 @@ }, "Terraria/MartianSaucerCore": { "Value": 1.25 + }, + "Terraria/DukeFishron": { + "Value": 1.49 } } }, @@ -1023,8 +1013,8 @@ "Items": [ { "Item": { - "Name": "FrozenShield", - "DisplayName": "Frozen Shield" + "Name": "FrozenTurtleShell", + "DisplayName": "Frozen Turtle Shell" }, "Stack": 1 } @@ -1166,6 +1156,45 @@ "Stack": 1 } ] + }, + "Terraria/CordageGuide": { + "Items": [ + { + "Item": { + "Name": "Blowpipe", + "DisplayName": "Blowpipe" + }, + "Stack": 1 + }, + { + "Item": { + "Name": "ClimbingClaws", + "DisplayName": "Climbing Claws" + }, + "Stack": 1 + }, + { + "Item": { + "Name": "Aglet", + "DisplayName": "Aglet" + }, + "Stack": 1 + }, + { + "Item": { + "Name": "Umbrella", + "DisplayName": "Umbrella" + }, + "Stack": 1 + }, + { + "Item": { + "Name": "MoonLordLegs", + "DisplayName": "Moon Lord Legs" + }, + "Stack": 1 + } + ] } }, "MinimumDamageReceivedByPlayersFromPlayer": 5 From 04b6247d94aa5823c6cd67a7e568261c9251149c Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Tue, 10 Jun 2025 09:53:45 -0700 Subject: [PATCH 028/206] config update --- PvPAdventure_AdventureConfig.json | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/PvPAdventure_AdventureConfig.json b/PvPAdventure_AdventureConfig.json index 109e5bf0..4c8401cf 100644 --- a/PvPAdventure_AdventureConfig.json +++ b/PvPAdventure_AdventureConfig.json @@ -661,7 +661,7 @@ "Terraria/PearlwoodSword": 1.1, "Terraria/MagicMissile": 0.85999995, "Terraria/Gungnir": 1.0, - "Terraria/TrueNightsEdge": 0.91999996, + "Terraria/TrueNightsEdge": 1.0, "Terraria/RocketLauncher": 0.79999995, "Terraria/OnyxBlaster": 1.5, "Terraria/ScourgeoftheCorruptor": 0.9 @@ -706,10 +706,6 @@ "Terraria/Xenopopper": { "Coefficient": 1.5, "Forward": 25.0 - }, - "Terraria/TrueNightsEdge": { - "Coefficient": 1.75, - "Forward": 20.25 } }, "DefaultFalloff": { @@ -730,10 +726,6 @@ "Name": "InvisibilityPotion", "DisplayName": "Invisibility Potion" }, - { - "Name": "ChlorophyteArrow", - "DisplayName": "Chlorophyte Arrow" - }, { "Name": "PumpkinMoonMedallion", "DisplayName": "Pumpkin Moon Medallion" @@ -863,13 +855,19 @@ }, "Terraria/TrueNightsEdge": { "Damage": { - "Value": 150 + "Value": 250 + }, + "UseTime": { + "Value": 54 + }, + "UseAnimation": { + "Value": 54 }, "ShootSpeed": { - "Value": 10.7 + "Value": 22.6 }, "Scale": { - "Value": 1.2 + "Value": 0.6 } }, "Terraria/Jetpack": { From 3ae80c2546a73e5dbe6a2e4fca80a1026844dabf Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Sun, 15 Jun 2025 11:24:02 -0700 Subject: [PATCH 029/206] Revert "AdventureInventory: Remove armor vanity slots" This reverts commit bfc8677c8d2d7228d6e9cc57c462072ce06518b1. --- System/AdventureInventory.cs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/System/AdventureInventory.cs b/System/AdventureInventory.cs index 7dc12a5b..e25905e1 100644 --- a/System/AdventureInventory.cs +++ b/System/AdventureInventory.cs @@ -45,13 +45,10 @@ public override void Load() private static bool IsPlayerDyeContext(int context) => context is ItemSlot.Context.EquipDye or ItemSlot.Context.EquipMiscDye or ItemSlot.Context.ModdedDyeSlot; - private static bool IsUnusableContext(int context) => - IsPlayerDyeContext(context) || context == ItemSlot.Context.EquipArmorVanity; - private void OnAccessorySlotLoaderDrawSlot(AccessorySlotLoaderDrawSlotDelegate orig, AccessorySlotLoader self, Item[] items, int context, int slot, bool flag3, int xLoc, int yLoc, bool skipCheck) { - if (IsUnusableContext(context)) + if (IsPlayerDyeContext(context)) return; orig(self, items, context, slot, flag3, xLoc, yLoc, skipCheck); @@ -60,7 +57,7 @@ private void OnAccessorySlotLoaderDrawSlot(AccessorySlotLoaderDrawSlotDelegate o private void OnItemSlotDraw(On_ItemSlot.orig_Draw_SpriteBatch_ItemArray_int_int_Vector2_Color orig, SpriteBatch spriteBatch, Item[] inv, int context, int slot, Vector2 position, Color lightColor) { - if (IsUnusableContext(context)) + if (IsPlayerDyeContext(context)) return; orig(spriteBatch, inv, context, slot, position, lightColor); @@ -68,7 +65,7 @@ private void OnItemSlotDraw(On_ItemSlot.orig_Draw_SpriteBatch_ItemArray_int_int_ private void OnItemSlotHandle(On_ItemSlot.orig_Handle_ItemArray_int_int orig, Item[] inv, int context, int slot) { - if (IsUnusableContext(context)) + if (IsPlayerDyeContext(context)) return; orig(inv, context, slot); @@ -77,7 +74,7 @@ private void OnItemSlotHandle(On_ItemSlot.orig_Handle_ItemArray_int_int orig, It private void OnItemSlotOverrideHover(On_ItemSlot.orig_OverrideHover_ItemArray_int_int orig, Item[] inv, int context, int slot) { - if (IsUnusableContext(context)) + if (IsPlayerDyeContext(context)) return; orig(inv, context, slot); @@ -86,7 +83,7 @@ private void OnItemSlotOverrideHover(On_ItemSlot.orig_OverrideHover_ItemArray_in private void OnItemSlotRightClick(On_ItemSlot.orig_RightClick_ItemArray_int_int orig, Item[] inv, int context, int slot) { - if (IsUnusableContext(context)) + if (IsPlayerDyeContext(context)) return; orig(inv, context, slot); @@ -95,7 +92,7 @@ private void OnItemSlotRightClick(On_ItemSlot.orig_RightClick_ItemArray_int_int private void OnItemSlotLeftClick(On_ItemSlot.orig_LeftClick_ItemArray_int_int orig, Item[] inv, int context, int slot) { - if (IsUnusableContext(context)) + if (IsPlayerDyeContext(context)) return; orig(inv, context, slot); @@ -104,7 +101,7 @@ private void OnItemSlotLeftClick(On_ItemSlot.orig_LeftClick_ItemArray_int_int or private void OnItemSlotMouseHover(On_ItemSlot.orig_MouseHover_ItemArray_int_int orig, Item[] inv, int context, int slot) { - if (IsUnusableContext(context)) + if (IsPlayerDyeContext(context)) return; orig(inv, context, slot); From 6cd504b8392345845fbdc95624668231eeaf461f Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Wed, 18 Jun 2025 17:21:45 -0700 Subject: [PATCH 030/206] added new chloro rate options --- AdventureConfig.cs | 6 ++++++ Localization/en-US.hjson | 10 ++++++++++ System/DiscordIdentification.cs | 2 +- System/WorldGenerationManager.cs | 33 ++++++++++++++++++++++++++++++++ 4 files changed, 50 insertions(+), 1 deletion(-) diff --git a/AdventureConfig.cs b/AdventureConfig.cs index 5bd789b0..8d5b7715 100644 --- a/AdventureConfig.cs +++ b/AdventureConfig.cs @@ -313,6 +313,12 @@ public class WorldGenerationConfig [DefaultValue(30)] public int PlanteraBulbChanceDenominator { get; set; } = 30; [DefaultValue(8)] public int ChlorophyteSpreadChanceModifier { get; set; } = 8; + + [Range(1, 1000)] + [DefaultValue(300)] public int ChlorophyteGrowChanceModifier { get; set; } = 300; + + [Range(1, 999999)] + [DefaultValue(300)] public int ChlorophyteGrowLimitModifier { get; set; } = 300; } public WorldGenerationConfig WorldGeneration { get; set; } = new(); diff --git a/Localization/en-US.hjson b/Localization/en-US.hjson index 7a14ed5a..5e96a71b 100644 --- a/Localization/en-US.hjson +++ b/Localization/en-US.hjson @@ -599,6 +599,16 @@ Mods: { Label: Chlorophyte Spread Chance Modifier Tooltip: "" } + + ChlorophyteGrowChanceModifier: { + Label: Chlorophyte Grow Chance Modifier + Tooltip: "" + } + + ChlorophyteGrowLimitModifier: { + Label: Chlorophyte Grow Limit Modifier + Tooltip: "" + } } NpcBalanceConfig: { diff --git a/System/DiscordIdentification.cs b/System/DiscordIdentification.cs index 4be689a1..47bb501f 100644 --- a/System/DiscordIdentification.cs +++ b/System/DiscordIdentification.cs @@ -15,7 +15,7 @@ namespace PvPAdventure.System; [Autoload(Side = ModSide.Both)] public class DiscordIdentification : ModSystem { - private const bool Enabled = true; + private const bool Enabled = false; public delegate void PlayerJoinEventHandler(DiscordIdentification source, PlayerJoinArgs args); diff --git a/System/WorldGenerationManager.cs b/System/WorldGenerationManager.cs index 6fa3e1fa..3823ed77 100644 --- a/System/WorldGenerationManager.cs +++ b/System/WorldGenerationManager.cs @@ -12,6 +12,7 @@ public override void Load() IL_WorldGen.UpdateWorld_GrassGrowth += EditWorldGenUpdateWorld_GrassGrowth; IL_WorldGen.hardUpdateWorld += OnWorldGenhardUpdateWorld; IL_WorldGen.AddBuriedChest_int_int_int_bool_int_bool_ushort += EditWorldGenAddBuriedChest; + IL_WorldGen.Chlorophyte += OnWorldGenChlorophyte; } private void EditWorldGenUpdateWorld_GrassGrowth(ILContext il) @@ -66,6 +67,16 @@ private void OnWorldGenhardUpdateWorld(ILContext il) { var cursor = new ILCursor(il); + // Find the call to WorldGen.genRand.Next(300)... + cursor.GotoNext(i => i.MatchCallvirt("Next") && i.Previous.MatchLdcI4(300)); + // ...and go back to the constant load... + cursor.Index -= 1; + // ... to remove it... + cursor.Remove() + // ...and replace it with a delegate that loads from our config instance. + .EmitDelegate(() => + ModContent.GetInstance().WorldGeneration.ChlorophyteGrowChanceModifier); + // Find the call to WorldGen.genRand.Next(3)... cursor.GotoNext(i => i.MatchCallvirt("Next") && i.Previous.MatchLdcI4(3)); // ...and go back to the constant load... @@ -77,6 +88,28 @@ private void OnWorldGenhardUpdateWorld(ILContext il) ModContent.GetInstance().WorldGeneration.ChlorophyteSpreadChanceModifier); } + private void OnWorldGenChlorophyte(ILContext il) + { + var cursor = new ILCursor(il); + + // Find the call to WorldGen.genRand.Next(300)... + cursor.GotoNext(i => i.MatchLdcI4(40)); + // ... to remove it... + cursor.Remove() + // ...and replace it with a delegate that loads from our config instance. + .EmitDelegate(() => + ModContent.GetInstance().WorldGeneration.ChlorophyteGrowLimitModifier); + cursor.Index = 0; + + cursor.GotoNext(i => i.MatchLdcI4(130)); + // ... to remove it... + cursor.Remove() + // ...and replace it with a delegate that loads from our config instance. + .EmitDelegate(() => + ModContent.GetInstance().WorldGeneration.ChlorophyteGrowLimitModifier); + + } + private void EditWorldGenAddBuriedChest(ILContext il) { var cursor = new ILCursor(il); From dab65d8536f6c903302d0508f691d4484483aaab Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Wed, 18 Jun 2025 17:19:34 -0700 Subject: [PATCH 031/206] Added shimmer crafting for regualr ass mimics. Also changed plantera required items from 4 to three. --- System/RecipeManager.cs | 248 ++++++++++++++++++++++++---------------- 1 file changed, 147 insertions(+), 101 deletions(-) diff --git a/System/RecipeManager.cs b/System/RecipeManager.cs index e8e4cb26..51c34d01 100644 --- a/System/RecipeManager.cs +++ b/System/RecipeManager.cs @@ -477,115 +477,161 @@ public override void AddRecipeGroups() RecipeGroup.RegisterGroup($"PvPAdventure:AnyHallowedMimicPrimaryExclude{itemID}", group); } } - } - public class RecipeSystem : ModSystem - { - public override void AddRecipes() + public class AnyMimic1 : ModSystem { - 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(); - } + public static RecipeGroup AnyMimicPrimary; + public static int[] PrimaryItems => new int[] { + ItemID.DeadMansChest, + ItemID.TitanGlove, + ItemID.CrossNecklace, + ItemID.StarCloak, + ItemID.PhilosophersStone, + ItemID.MagicDagger, + ItemID.DualHook, + }; - // Primary UFO recipes (Relic remains icon) - foreach (int itemID in AnySaucer1.PrimaryItems.Where(id => id != ItemID.UFOMasterTrophy)) + public override void AddRecipeGroups() { - Recipe.Create(itemID) - .AddRecipeGroup($"PvPAdventure:AnySaucerPrimaryExclude{itemID}", 3) - .AddCondition(shimmerCondition) - .DisableDecraft() - .Register(); + // Main group with trophy as first item (for icon) + AnyMimicPrimary = new RecipeGroup(() => Language.GetTextValue("Any Mimic Primary"), PrimaryItems); + RecipeGroup.RegisterGroup("PvPAdventure:AnyMimicPrimary", AnyMimicPrimary); + + // Create exclude subgroups while maintaining icon as first item + foreach (int itemID in PrimaryItems.Where(id => id != ItemID.DeadMansChest)) + { + var validItems = PrimaryItems + .Where(id => id != itemID && id != ItemID.DeadMansChest) + .Prepend(ItemID.DeadMansChest) // Keep item first for icon + .ToArray(); + + RecipeGroup group = new RecipeGroup( + () => Language.GetTextValue("Any Mimic Primary"), + validItems + ); + RecipeGroup.RegisterGroup($"PvPAdventure:AnyMimicPrimaryExclude{itemID}", group); + } } + } - // Primary Corro mimic recipes (Relic remains icon) - foreach (int itemID in AnyCorruptionMimic1.PrimaryItems.Where(id => id != ItemID.Fake_CorruptionChest)) + public class RecipeSystem : ModSystem + { + public override void AddRecipes() { - Recipe.Create(itemID) - .AddRecipeGroup($"PvPAdventure:AnyCorruptionMimicPrimaryExclude{itemID}", 3) - .AddCondition(shimmerCondition) - .DisableDecraft() - .Register(); - } + var shimmerCondition = new Condition( + Language.GetText("Mods.PvPAdventure.Conditions.NearShimmer"), + () => Main.LocalPlayer.adjShimmer + ); - // 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(); + // 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}", 3) + .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(); + } + + // Primary Mimic recipes (Relic remains icon) + foreach (int itemID in AnyMimic1.PrimaryItems.Where(id => id != ItemID.DeadMansChest)) + { + Recipe.Create(itemID) + .AddRecipeGroup($"PvPAdventure:AnyMimicPrimaryExclude{itemID}", 3) + .AddCondition(shimmerCondition) + .DisableDecraft() + .Register(); + } } } } From 8088c7ee6f1b63cf05824337ca7667c15d59666c Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Fri, 20 Jun 2025 21:41:11 -0700 Subject: [PATCH 032/206] readded tikki no kb --- AdventurePlayer.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/AdventurePlayer.cs b/AdventurePlayer.cs index 7becd7d7..dd21a1bb 100644 --- a/AdventurePlayer.cs +++ b/AdventurePlayer.cs @@ -630,6 +630,14 @@ public override void PostUpdateEquips() Player.yoraiz0rEye = 33; } + // 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() { From 53cf98646fcbd694ef91e91cb310fd59db778cd8 Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Sun, 22 Jun 2025 11:21:04 -0700 Subject: [PATCH 033/206] remnoved duplicate code --- AdventureBuff.cs | 10 -- AdventureProjectile.cs | 232 +---------------------------------------- 2 files changed, 1 insertion(+), 241 deletions(-) diff --git a/AdventureBuff.cs b/AdventureBuff.cs index 8d976782..4609529c 100644 --- a/AdventureBuff.cs +++ b/AdventureBuff.cs @@ -50,17 +50,7 @@ public override bool RightClick(int type, int buffIndex) return true; } - 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 - } - } public class RemoveFlaskBuffsOnDeath : ModPlayer { // Array of buff IDs to remove on death diff --git a/AdventureProjectile.cs b/AdventureProjectile.cs index c5a8ec1c..397fcf83 100644 --- a/AdventureProjectile.cs +++ b/AdventureProjectile.cs @@ -479,234 +479,4 @@ public override void PostAI(Projectile projectile) } - 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 From 194f1da182d0f9316bf300f53bf4715b928c0626 Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Wed, 2 Jul 2025 11:46:13 -0700 Subject: [PATCH 034/206] updated icon --- icon.png | Bin 1253 -> 8192 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/icon.png b/icon.png index e18d0f432eb900f533369f1c190e7a5f9748976e..2619499b2fe801e9854976de40cf46ee13323ebe 100644 GIT binary patch literal 8192 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 From 81558059bc4492e83ba217b3bdb63cc5371cf03c Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Wed, 2 Jul 2025 11:46:29 -0700 Subject: [PATCH 035/206] nerfged beetle might buff --- AdventureBuff.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/AdventureBuff.cs b/AdventureBuff.cs index 4609529c..2b897438 100644 --- a/AdventureBuff.cs +++ b/AdventureBuff.cs @@ -21,8 +21,8 @@ public override void Update(int type, Player player, ref int buffIndex) if (player.beetleOrbs >= 1) { - damage += 0.15f; - attackSpeed += 0.15f; + damage += 0.10f; + attackSpeed += 0.10f; } if (player.beetleOrbs >= 2) @@ -33,8 +33,8 @@ public override void Update(int type, Player player, ref int buffIndex) if (player.beetleOrbs >= 3) { - damage += 0.05f; - attackSpeed += 0.20f; + damage += 0.10f; + attackSpeed += 0.10f; } player.GetDamage() += damage; From f836cc944aad1c138740a3029c2524fec9280bc1 Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Wed, 2 Jul 2025 11:46:53 -0700 Subject: [PATCH 036/206] upped unholy trident drop rates --- AdventureDropDatabase.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/AdventureDropDatabase.cs b/AdventureDropDatabase.cs index df95e39f..98dde302 100644 --- a/AdventureDropDatabase.cs +++ b/AdventureDropDatabase.cs @@ -159,6 +159,11 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) ModifyDropRate(drop, ItemID.MagicQuiver, 1, 30); break; + case NPCID.RedDevil: + foreach (var drop in drops) + ModifyDropRate(drop, ItemID.UnholyTrident, 1, 10); + break; + case NPCID.Lihzahrd: case NPCID.LihzahrdCrawler: case NPCID.FlyingSnake: From 2dfdde9b36bfd9066c6a14128cfab707dc3c42ce Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Wed, 2 Jul 2025 11:47:48 -0700 Subject: [PATCH 037/206] added bad luck shimmer recipes for dungeon for brick wall dungoen drops --- System/RecipeManager.cs | 43 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/System/RecipeManager.cs b/System/RecipeManager.cs index 51c34d01..28b16e3d 100644 --- a/System/RecipeManager.cs +++ b/System/RecipeManager.cs @@ -514,6 +514,39 @@ public override void AddRecipeGroups() } } + public class AnyBrickwall1: ModSystem + { + public static RecipeGroup AnyBrickwall; + public static int[] PrimaryItems => new int[] { + ItemID.NecromanticSign, + ItemID.ShadowbeamStaff, + ItemID.RocketLauncher, + ItemID.PaladinsHammer + }; + + public override void AddRecipeGroups() + { + // Main group with trophy as first item (for icon) + AnyBrickwall = new RecipeGroup(() => Language.GetTextValue("Any Brick Wall"), PrimaryItems); + RecipeGroup.RegisterGroup("PvPAdventure:AnyBrickWall", AnyBrickwall); + + // Create exclude subgroups while maintaining icon as first item + foreach (int itemID in PrimaryItems.Where(id => id != ItemID.NecromanticSign)) + { + var validItems = PrimaryItems + .Where(id => id != itemID && id != ItemID.NecromanticSign) + .Prepend(ItemID.NecromanticSign) // Keep item first for icon + .ToArray(); + + RecipeGroup group = new RecipeGroup( + () => Language.GetTextValue("Any Brick Wall"), + validItems + ); + RecipeGroup.RegisterGroup($"PvPAdventure:AnyBrickWallExclude{itemID}", group); + } + } + } + public class RecipeSystem : ModSystem { public override void AddRecipes() @@ -632,6 +665,16 @@ public override void AddRecipes() .DisableDecraft() .Register(); } + // Primary Mimic recipes (Relic remains icon) + foreach (int itemID in AnyBrickwall1.PrimaryItems.Where(id => id != ItemID.NecromanticSign)) + { + Recipe.Create(itemID) + .AddRecipeGroup($"PvPAdventure:AnyBrickWallExclude{itemID}", 3) + .AddCondition(shimmerCondition) + .DisableDecraft() + .Register(); + } + } } } From ef8ae4b8d66217cf386d130ce417bd072a88c70c Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Wed, 9 Jul 2025 09:34:03 -0700 Subject: [PATCH 038/206] plant first drop chagned --- AdventureDropDatabase.cs | 43 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/AdventureDropDatabase.cs b/AdventureDropDatabase.cs index 74ee9c79..c78255aa 100644 --- a/AdventureDropDatabase.cs +++ b/AdventureDropDatabase.cs @@ -1,8 +1,12 @@ using System.Linq; +using MonoMod.Cil; +using MonoMod.RuntimeDetour; +using System.Reflection; using Terraria; using Terraria.GameContent.ItemDropRules; using Terraria.ID; using Terraria.ModLoader; +using Mono.Cecil.Cil; namespace PvPAdventure; @@ -301,4 +305,43 @@ public static IItemDropRule OnItemDropDatabaseRegisterToGlobal(On_ItemDropDataba return entry; } + public class PlanteraDropEdit : ModSystem + { + private static ILHook planteraHook; + + public override void PostSetupContent() + { + // Apply the IL edit to change Plantera's first-time drop from item 758 to 1255 + MethodInfo method = typeof(Terraria.GameContent.ItemDropRules.ItemDropDatabase).GetMethod("RegisterBoss_Plantera", + BindingFlags.NonPublic | BindingFlags.Instance); + + planteraHook = new ILHook(method, PlanteraDropILEdit); + } + + public override void Unload() + { + planteraHook?.Dispose(); + } + + private static void PlanteraDropILEdit(ILContext il) + { + ILCursor cursor = new ILCursor(il); + + // Look for the instruction that loads the value 758 (Grenade Launcher ID) + // This should be: ldc.i4 758 (or ldc.i4.s 758 if it's a short form) + if (cursor.TryGotoNext(MoveType.Before, + i => i.MatchLdcI4(758))) // Match loading the constant 758 + { + // Replace the 758 with 1255 + cursor.Remove(); // Remove the ldc.i4 758 instruction + cursor.Emit(OpCodes.Ldc_I4, 1255); // Emit ldc.i4 1255 instead + + ModContent.GetInstance().Logger.Info("Successfully changed Plantera's first-time drop from item 758 to 1255"); + } + else + { + ModContent.GetInstance().Logger.Error("Failed to find item ID 758 in RegisterBoss_Plantera method"); + } + } + } } \ No newline at end of file From fa960e9cb64eed5a12b53a53df5a48820e514b5e Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Wed, 9 Jul 2025 09:36:12 -0700 Subject: [PATCH 039/206] power cell now yellow rarity --- AdventureItem.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/AdventureItem.cs b/AdventureItem.cs index 62f9f216..2616a9a4 100644 --- a/AdventureItem.cs +++ b/AdventureItem.cs @@ -65,6 +65,12 @@ public override void SetDefaults(Item item) { var adventureConfig = ModContent.GetInstance(); + if (item.type == ItemID.LihzahrdPowerCell) + { + + item.rare = ItemRarityID.Yellow; + } + if (RecallItems[item.type]) { var recallTime = adventureConfig.RecallFrames; From 73fafcd4b893559ec1fa4c0d739ea66728781583 Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Thu, 10 Jul 2025 20:07:53 -0700 Subject: [PATCH 040/206] Added bad luck crafting to Gold, Desert, Ice, Jungle, and Sky chests --- System/RecipeManager.cs | 260 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 259 insertions(+), 1 deletion(-) diff --git a/System/RecipeManager.cs b/System/RecipeManager.cs index 28b16e3d..1022d22f 100644 --- a/System/RecipeManager.cs +++ b/System/RecipeManager.cs @@ -547,6 +547,211 @@ public override void AddRecipeGroups() } } + public class AnyGold1 : ModSystem + { + public static RecipeGroup AnyGold; + public static int[] PrimaryItems => new int[] { + ItemID.CloudinaBottle, + ItemID.HermesBoots, + ItemID.FlareGun, + ItemID.ShoeSpikes, + ItemID.BandofRegeneration, + ItemID.Mace + }; + + public override void AddRecipeGroups() + { + // Main group with trophy as first item (for icon) + AnyGold = new RecipeGroup(() => Language.GetTextValue("Any Gold Chest Item"), PrimaryItems); + RecipeGroup.RegisterGroup("PvPAdventure:AnyGold", AnyGold); + + // Create exclude subgroups while maintaining icon as first item + foreach (int itemID in PrimaryItems.Where(id => id != ItemID.GoldenChest)) + { + var validItems = PrimaryItems + .Where(id => id != itemID && id != ItemID.GoldenChest) + .Prepend(ItemID.GoldenChest) // Keep item first for icon + .ToArray(); + + RecipeGroup group = new RecipeGroup( + () => Language.GetTextValue("Any Gold Chest Item"), + validItems + ); + RecipeGroup.RegisterGroup($"PvPAdventure:AnyGoldExclude{itemID}", group); + } + } + } + + public class AnyJungle1 : ModSystem + { + public static RecipeGroup AnyJungle; + public static int[] PrimaryItems => new int[] { + ItemID.AnkletoftheWind, + ItemID.Boomstick, + ItemID.StaffofRegrowth, + ItemID.FlowerBoots, + ItemID.FiberglassFishingPole, + ItemID.FeralClaws + }; + + public override void AddRecipeGroups() + { + // Main group with trophy as first item (for icon) + AnyJungle = new RecipeGroup(() => Language.GetTextValue("Any Gold Chest Item"), PrimaryItems); + RecipeGroup.RegisterGroup("PvPAdventure:AnyJungle", AnyJungle); + + // Create exclude subgroups while maintaining icon as first item + foreach (int itemID in PrimaryItems.Where(id => id != ItemID.SwampThingBanner)) + { + var validItems = PrimaryItems + .Where(id => id != itemID && id != ItemID.SwampThingBanner) + .Prepend(ItemID.SwampThingBanner) // Keep item first for icon + .ToArray(); + + RecipeGroup group = new RecipeGroup( + () => Language.GetTextValue("Any Jungle Chest Item"), + validItems + ); + RecipeGroup.RegisterGroup($"PvPAdventure:AnyJungleExclude{itemID}", group); + } + } + } + + public class AnyDesert1 : ModSystem + { + public static RecipeGroup AnyHighDesert; + public static int[] PrimaryItems => new int[] { + ItemID.MysticCoilSnake, + ItemID.SandBoots, + ItemID.AncientChisel + }; + + public override void AddRecipeGroups() + { + // Main group with trophy as first item (for icon) + AnyHighDesert = new RecipeGroup(() => Language.GetTextValue("Any High Desert Chest Item"), PrimaryItems); + RecipeGroup.RegisterGroup("PvPAdventure:AnyHighDesert", AnyHighDesert); + + // Create exclude subgroups while maintaining icon as first item + foreach (int itemID in PrimaryItems.Where(id => id != ItemID.PharaohsMask)) + { + var validItems = PrimaryItems + .Where(id => id != itemID && id != ItemID.PharaohsMask) + .Prepend(ItemID.PharaohsMask) // Keep item first for icon + .ToArray(); + + RecipeGroup group = new RecipeGroup( + () => Language.GetTextValue("Any High Desert Chest Item"), + validItems + ); + RecipeGroup.RegisterGroup($"PvPAdventure:AnyHighDesertExclude{itemID}", group); + } + } + } + + public class AnyDesert2 : ModSystem + { + public static RecipeGroup AnyLowDesert; + public static int[] PrimaryItems => new int[] { + ItemID.SandstorminaBottle, + ItemID.ThunderSpear, + ItemID.ThunderStaff + }; + + public override void AddRecipeGroups() + { + // Main group with trophy as first item (for icon) + AnyLowDesert = new RecipeGroup(() => Language.GetTextValue("Any Low Desert Chest Item"), PrimaryItems); + RecipeGroup.RegisterGroup("PvPAdventure:AnyLowDesert", AnyLowDesert); + + // Create exclude subgroups while maintaining icon as first item + foreach (int itemID in PrimaryItems.Where(id => id != ItemID.PharaohsRobe)) + { + var validItems = PrimaryItems + .Where(id => id != itemID && id != ItemID.PharaohsRobe) + .Prepend(ItemID.PharaohsRobe) // Keep item first for icon + .ToArray(); + + RecipeGroup group = new RecipeGroup( + () => Language.GetTextValue("Any Low Desert Chest Item"), + validItems + ); + RecipeGroup.RegisterGroup($"PvPAdventure:AnyLowDesertExclude{itemID}", group); + } + } + } + + public class AnyIce1 : ModSystem + { + public static RecipeGroup AnyIce; + public static int[] PrimaryItems => new int[] { + ItemID.FlurryBoots, + ItemID.BlizzardinaBottle, + ItemID.SnowballCannon, + ItemID.IceSkates, + ItemID.IceBlade, + ItemID.IceBoomerang, + ItemID.Fish + + }; + + public override void AddRecipeGroups() + { + // Main group with trophy as first item (for icon) + AnyIce = new RecipeGroup(() => Language.GetTextValue("Any Ice Chest Item"), PrimaryItems); + RecipeGroup.RegisterGroup("PvPAdventure:AnyIce", AnyIce); + + // Create exclude subgroups while maintaining icon as first item + foreach (int itemID in PrimaryItems.Where(id => id != ItemID.SnowballLauncher)) + { + var validItems = PrimaryItems + .Where(id => id != itemID && id != ItemID.SnowballLauncher) + .Prepend(ItemID.SnowballLauncher) // Keep item first for icon + .ToArray(); + + RecipeGroup group = new RecipeGroup( + () => Language.GetTextValue("Any Ice Chest Item"), + validItems + ); + RecipeGroup.RegisterGroup($"PvPAdventure:AnyIceExclude{itemID}", group); + } + } + } + + public class AnySky1 : ModSystem + { + public static RecipeGroup AnySky; + public static int[] PrimaryItems => new int[] { + ItemID.ShinyRedBalloon, + ItemID.Starfury, + ItemID.CelestialMagnet, + ItemID.CreativeWings, + ItemID.LuckyHorseshoe + + }; + + public override void AddRecipeGroups() + { + // Main group with trophy as first item (for icon) + AnySky = new RecipeGroup(() => Language.GetTextValue("Any Sky Chest Item"), PrimaryItems); + RecipeGroup.RegisterGroup("PvPAdventure:AnySky", AnySky); + + // Create exclude subgroups while maintaining icon as first item + foreach (int itemID in PrimaryItems.Where(id => id != ItemID.CreativeWings)) + { + var validItems = PrimaryItems + .Where(id => id != itemID && id != ItemID.CreativeWings) + .Prepend(ItemID.CreativeWings) // Keep item first for icon + .ToArray(); + + RecipeGroup group = new RecipeGroup( + () => Language.GetTextValue("Any Sky Chest Item"), + validItems + ); + RecipeGroup.RegisterGroup($"PvPAdventure:AnySkyExclude{itemID}", group); + } + } + } public class RecipeSystem : ModSystem { public override void AddRecipes() @@ -674,7 +879,60 @@ public override void AddRecipes() .DisableDecraft() .Register(); } - + // Primary Mimic recipes (Relic remains icon) + foreach (int itemID in AnyGold1.PrimaryItems.Where(id => id != ItemID.GoldChest)) + { + Recipe.Create(itemID) + .AddRecipeGroup($"PvPAdventure:AnyGoldExclude{itemID}", 3) + .AddCondition(shimmerCondition) + .DisableDecraft() + .Register(); + } + // Primary Mimic recipes (Relic remains icon) + foreach (int itemID in AnyJungle1.PrimaryItems.Where(id => id != ItemID.SwampThingBanner)) + { + Recipe.Create(itemID) + .AddRecipeGroup($"PvPAdventure:AnyJungleExclude{itemID}", 3) + .AddCondition(shimmerCondition) + .DisableDecraft() + .Register(); + } + // Primary Mimic recipes (Relic remains icon) + foreach (int itemID in AnyDesert1.PrimaryItems.Where(id => id != ItemID.PharaohsMask)) + { + Recipe.Create(itemID) + .AddRecipeGroup($"PvPAdventure:AnyHighDesertExclude{itemID}", 3) + .AddCondition(shimmerCondition) + .DisableDecraft() + .Register(); + } + // Primary Mimic recipes (Relic remains icon) + foreach (int itemID in AnyDesert2.PrimaryItems.Where(id => id != ItemID.PharaohsRobe)) + { + Recipe.Create(itemID) + .AddRecipeGroup($"PvPAdventure:AnyLowDesertExclude{itemID}", 3) + .AddCondition(shimmerCondition) + .DisableDecraft() + .Register(); + } + // Primary Mimic recipes (Relic remains icon) + foreach (int itemID in AnyIce1.PrimaryItems.Where(id => id != ItemID.SnowballLauncher)) + { + Recipe.Create(itemID) + .AddRecipeGroup($"PvPAdventure:AnyIceExclude{itemID}", 2) + .AddCondition(shimmerCondition) + .DisableDecraft() + .Register(); + } + // Primary Mimic recipes (Relic remains icon) + foreach (int itemID in AnySky1.PrimaryItems.Where(id => id != ItemID.CreativeWings)) + { + Recipe.Create(itemID) + .AddRecipeGroup($"PvPAdventure:AnySkyExclude{itemID}", 2) + .AddCondition(shimmerCondition) + .DisableDecraft() + .Register(); + } } } } From 02e6e56b4783d0301348f99b3de9a300812bb748 Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Thu, 10 Jul 2025 20:09:59 -0700 Subject: [PATCH 041/206] removed dungeon farming --- AdventureDropDatabase.cs | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/AdventureDropDatabase.cs b/AdventureDropDatabase.cs index c78255aa..56252c5a 100644 --- a/AdventureDropDatabase.cs +++ b/AdventureDropDatabase.cs @@ -50,14 +50,14 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) { case NPCID.BoneLee: foreach (var drop in drops) - ModifyDropRate(drop, ItemID.Tabi, 1, 4); + ModifyDropRate(drop, ItemID.Tabi, 1, 1); break; case NPCID.Paladin: foreach (var drop in drops) { - ModifyDropRate(drop, ItemID.PaladinsHammer, 3, 20); - ModifyDropRate(drop, ItemID.PaladinsShield, 3, 20); + ModifyDropRate(drop, ItemID.PaladinsHammer, 3, 3); + ModifyDropRate(drop, ItemID.PaladinsShield, 3, 3); } break; @@ -75,35 +75,36 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) case NPCID.Necromancer: case NPCID.NecromancerArmored: foreach (var drop in drops) - ModifyDropRate(drop, ItemID.ShadowbeamStaff, 1, 10); + ModifyDropRate(drop, ItemID.ShadowbeamStaff, 1, 1); break; case NPCID.RaggedCaster: case NPCID.RaggedCasterOpenCoat: foreach (var drop in drops) - ModifyDropRate(drop, ItemID.SpectreStaff, 1, 10); + ModifyDropRate(drop, ItemID.SpectreStaff, 1, 1); break; case NPCID.DiabolistRed: case NPCID.DiabolistWhite: foreach (var drop in drops) - ModifyDropRate(drop, ItemID.InfernoFork, 1, 10); + ModifyDropRate(drop, ItemID.InfernoFork, 1, 1); break; case NPCID.SkeletonSniper: foreach (var drop in drops) - ModifyDropRate(drop, ItemID.SniperRifle, 1, 10); + ModifyDropRate(drop, ItemID.SniperRifle, 1, 1); + npcLoot.Add(ItemDropRule.Common(ItemID.RifleScope, 1)); break; case NPCID.TacticalSkeleton: foreach (var drop in drops) - ModifyDropRate(drop, ItemID.TacticalShotgun, 1, 10); - npcLoot.Add(ItemDropRule.Common(ItemID.RifleScope, 6)); + ModifyDropRate(drop, ItemID.TacticalShotgun, 1, 1); + npcLoot.Add(ItemDropRule.Common(ItemID.RifleScope, 1)); break; case NPCID.SkeletonCommando: foreach (var drop in drops) - ModifyDropRate(drop, ItemID.RocketLauncher, 1, 10); + ModifyDropRate(drop, ItemID.RocketLauncher, 1, 1); break; case NPCID.RustyArmoredBonesAxe: From 1399db51dd7dd74a57b91df9d578650d02dd94db Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Thu, 10 Jul 2025 20:16:11 -0700 Subject: [PATCH 042/206] Reworked nightblow behavior --- AdventureProjectile.cs | 48 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/AdventureProjectile.cs b/AdventureProjectile.cs index 397fcf83..cadaee70 100644 --- a/AdventureProjectile.cs +++ b/AdventureProjectile.cs @@ -476,6 +476,54 @@ public override void PostAI(Projectile projectile) } } } + public class NightglowMouseHoming : GlobalProjectile + { + public override bool AppliesToEntity(Projectile projectile, bool lateInstantiation) + { + return projectile.type == ProjectileID.FairyQueenMagicItemShot; + } + + // We Initialize timer in SetDefaults + public override void SetDefaults(Projectile projectile) + { + if (projectile.type == ProjectileID.FairyQueenMagicItemShot) + { + projectile.localAI[0] = 0f; // Homing delay timer + projectile.netUpdate = true; + } + } + + public override void AI(Projectile projectile) + { + if (projectile.owner != Main.myPlayer) return; + Player player = Main.player[projectile.owner]; + if (player.dead || !player.active) return; + + // Increment homing delay timer + projectile.localAI[0]++; + + // Only start homing after 60 frames + if (projectile.localAI[0] < 60f) return; + + Vector2 cursorPosition = Main.MouseWorld; + Vector2 toCursor = cursorPosition - projectile.Center; + float distance = toCursor.Length(); + + // Only home when cursor is beyond minimum distance + + + float baseSpeed = 20f; + float accelerationFactor = 1.5f; + float turnStrength = 0.05f; + + Vector2 direction = toCursor.SafeNormalize(Vector2.Zero); + Vector2 targetVelocity = direction * baseSpeed * accelerationFactor; + + projectile.velocity = Vector2.Lerp(projectile.velocity, targetVelocity, turnStrength); + projectile.rotation = projectile.velocity.ToRotation() + MathHelper.PiOver2; + + } + } } From c3aab9a197c91ed2434642b314262bac9eb79fd7 Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Thu, 10 Jul 2025 20:16:13 -0700 Subject: [PATCH 043/206] removed extra code --- AdventureItem.cs | 62 +++++++++++++----------------------------------- 1 file changed, 16 insertions(+), 46 deletions(-) diff --git a/AdventureItem.cs b/AdventureItem.cs index 2616a9a4..5318ec56 100644 --- a/AdventureItem.cs +++ b/AdventureItem.cs @@ -16,51 +16,6 @@ public class AdventureItem : GlobalItem ItemID.Sets.Factory.CreateBoolSet(ItemID.MagicMirror, ItemID.CellPhone, ItemID.IceMirror, ItemID.Shellphone, ItemID.ShellphoneSpawn); - 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 class PrismaticLacewingRestriction : GlobalItem - { - public override bool CanUseItem(Item item, Player player) - { - // Target Prismatic Lacewing (Empress summon item) - if (item.type == ItemID.EmpressButterfly) - { - // Check if player is below surface level - bool isUnderground = player.position.Y > Main.worldSurface * 16; - bool inUndergroundHallow = isUnderground && player.ZoneHallow; - - if (isUnderground) - { - Main.NewText("The sacred light refuses to manifest in these corrupted depths!", 200, 150, 255); - return false; - } - } - return base.CanUseItem(item, player); - } - } - public override void SetDefaults(Item item) { var adventureConfig = ModContent.GetInstance(); @@ -145,7 +100,22 @@ public override bool CanUseItem(Item item, Player player) } else if (item.type == ItemID.QueenSlimeCrystal) { - if (isUnderground && isHallow) + if (isUnderground) + return false; + } + else if (item.type == ItemID.MechanicalEye) + { + if (isUnderground) + return false; + } + else if (item.type == ItemID.MechanicalSkull) + { + if (isUnderground) + return false; + } + else if (item.type == ItemID.MechanicalWorm) + { + if (isUnderground) return false; } From 07c5be5abd0dce3bbdaa10813af66a855a4211fc Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Thu, 10 Jul 2025 20:40:10 -0700 Subject: [PATCH 044/206] Thanks resin! he fixed it! --- AdventureProjectile.cs | 54 ++++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 31 deletions(-) diff --git a/AdventureProjectile.cs b/AdventureProjectile.cs index cadaee70..005f6115 100644 --- a/AdventureProjectile.cs +++ b/AdventureProjectile.cs @@ -476,52 +476,44 @@ public override void PostAI(Projectile projectile) } } } - public class NightglowMouseHoming : GlobalProjectile + public class AdventureNightglow : GlobalProjectile { - public override bool AppliesToEntity(Projectile projectile, bool lateInstantiation) - { - return projectile.type == ProjectileID.FairyQueenMagicItemShot; - } + public override bool AppliesToEntity(Projectile entity, bool lateInstantiation) => + entity.type == ProjectileID.FairyQueenMagicItemShot; - // We Initialize timer in SetDefaults - public override void SetDefaults(Projectile projectile) + public override void SetDefaults(Projectile entity) { - if (projectile.type == ProjectileID.FairyQueenMagicItemShot) - { - projectile.localAI[0] = 0f; // Homing delay timer - projectile.netUpdate = true; - } + entity.localAI[0] = 0; } public override void AI(Projectile projectile) { - if (projectile.owner != Main.myPlayer) return; - Player player = Main.player[projectile.owner]; - if (player.dead || !player.active) return; - - // Increment homing delay timer - projectile.localAI[0]++; + if (projectile.localAI[0] <= 60) + { + projectile.localAI[0]++; + return; + } - // Only start homing after 60 frames - if (projectile.localAI[0] < 60f) return; - Vector2 cursorPosition = Main.MouseWorld; - Vector2 toCursor = cursorPosition - projectile.Center; - float distance = toCursor.Length(); + if (!projectile.TryGetOwner(out var owner)) + return; - // Only home when cursor is beyond minimum distance + if (owner.whoAmI != Main.myPlayer) + return; + var cursorPosition = Main.MouseWorld; + var toCursor = cursorPosition - projectile.Center; - float baseSpeed = 20f; - float accelerationFactor = 1.5f; - float turnStrength = 0.05f; + var baseSpeed = 20.0f; + var accelerationFactor = 1.5f; + var turnStrength = 0.05f; - Vector2 direction = toCursor.SafeNormalize(Vector2.Zero); - Vector2 targetVelocity = direction * baseSpeed * accelerationFactor; + var direction = toCursor.SafeNormalize(Vector2.Zero); + var targetVelocity = direction * baseSpeed * accelerationFactor; projectile.velocity = Vector2.Lerp(projectile.velocity, targetVelocity, turnStrength); - projectile.rotation = projectile.velocity.ToRotation() + MathHelper.PiOver2; - + projectile.rotation = projectile.velocity.ToRotation() * MathHelper.PiOver2; + projectile.netUpdate = true; } } } From e3af842e2105fe40c3c65064b0eb592d0ec1c7ef Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Thu, 10 Jul 2025 21:54:10 -0700 Subject: [PATCH 045/206] Decreased rotation strength and requires usage to home to mouse now --- AdventureProjectile.cs | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/AdventureProjectile.cs b/AdventureProjectile.cs index 005f6115..43f2a1b2 100644 --- a/AdventureProjectile.cs +++ b/AdventureProjectile.cs @@ -494,26 +494,28 @@ public override void AI(Projectile projectile) return; } - if (!projectile.TryGetOwner(out var owner)) return; if (owner.whoAmI != Main.myPlayer) return; - var cursorPosition = Main.MouseWorld; - var toCursor = cursorPosition - projectile.Center; + if (owner.itemAnimation > 0 && owner.HeldItem.type == ItemID.FairyQueenMagicItem) + { + var cursorPosition = Main.MouseWorld; + var toCursor = cursorPosition - projectile.Center; - var baseSpeed = 20.0f; - var accelerationFactor = 1.5f; - var turnStrength = 0.05f; + var baseSpeed = 30.0f; + var accelerationFactor = 2.5f; + var turnStrength = 0.01f; - var direction = toCursor.SafeNormalize(Vector2.Zero); - var targetVelocity = direction * baseSpeed * accelerationFactor; + var direction = toCursor.SafeNormalize(Vector2.Zero); + var targetVelocity = direction * baseSpeed * accelerationFactor; - projectile.velocity = Vector2.Lerp(projectile.velocity, targetVelocity, turnStrength); - projectile.rotation = projectile.velocity.ToRotation() * MathHelper.PiOver2; - projectile.netUpdate = true; + projectile.velocity = Vector2.Lerp(projectile.velocity, targetVelocity, turnStrength); + projectile.rotation = projectile.velocity.ToRotation() * MathHelper.PiOver2; + projectile.netUpdate = true; + } } } } From d711dcfaa1d4d23a8a89cc1d4a5f5f881198e8e5 Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Fri, 11 Jul 2025 16:58:55 -0700 Subject: [PATCH 046/206] changed some stats --- AdventureProjectile.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/AdventureProjectile.cs b/AdventureProjectile.cs index 43f2a1b2..388ace88 100644 --- a/AdventureProjectile.cs +++ b/AdventureProjectile.cs @@ -505,9 +505,9 @@ public override void AI(Projectile projectile) var cursorPosition = Main.MouseWorld; var toCursor = cursorPosition - projectile.Center; - var baseSpeed = 30.0f; - var accelerationFactor = 2.5f; - var turnStrength = 0.01f; + var baseSpeed = 20.0f; + var accelerationFactor = 1.5f; + var turnStrength = 0.035f; var direction = toCursor.SafeNormalize(Vector2.Zero); var targetVelocity = direction * baseSpeed * accelerationFactor; From cb262d039975f4d9e185cfce16aa231e92fbeead Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Fri, 25 Jul 2025 19:49:08 -0700 Subject: [PATCH 047/206] aaaaaaaaaaaaaaaaa --- AdventureProjectile.cs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/AdventureProjectile.cs b/AdventureProjectile.cs index 0e4e81e9..c2626da8 100644 --- a/AdventureProjectile.cs +++ b/AdventureProjectile.cs @@ -523,9 +523,23 @@ public override void AI(Projectile projectile) } } - + public class MorningStarRange : GlobalProjectile + { + public override bool AppliesToEntity(Projectile projectile, bool lateInstantiation) + { + return projectile.type == ProjectileID.MaceWhip; + } + public override void SetDefaults(Projectile projectile) + { + if (projectile.type == ProjectileID.MaceWhip) + { + projectile.WhipSettings.RangeMultiplier = 1.58f; // this is like 20% range + + } + } + } + - private void EditProjectileDamage(ILContext il) { From c0d960b588059f68155d031ddd918027994eaa82 Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Fri, 25 Jul 2025 20:58:13 -0700 Subject: [PATCH 048/206] FUCK YOU NO COMMIT MESSAGE --- AdventureDropDatabase.cs | 3 +++ AdventureProjectile.cs | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/AdventureDropDatabase.cs b/AdventureDropDatabase.cs index 56252c5a..3fe56b10 100644 --- a/AdventureDropDatabase.cs +++ b/AdventureDropDatabase.cs @@ -46,6 +46,9 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) { var drops = npcLoot.Get(); + foreach (var drop in drops) + ModifyDropRate(drop, ItemID.Kraken, 1, 20); + switch (npc.type) { case NPCID.BoneLee: diff --git a/AdventureProjectile.cs b/AdventureProjectile.cs index 0e4e81e9..7da34ec2 100644 --- a/AdventureProjectile.cs +++ b/AdventureProjectile.cs @@ -511,7 +511,7 @@ public override void AI(Projectile projectile) var baseSpeed = 20.0f; var accelerationFactor = 1.5f; - var turnStrength = 0.035f; + var turnStrength = 0.05f; var direction = toCursor.SafeNormalize(Vector2.Zero); var targetVelocity = direction * baseSpeed * accelerationFactor; From 3cf1594e32c827772de11302c031cd8db05ae8bc Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Fri, 1 Aug 2025 16:59:34 -0700 Subject: [PATCH 049/206] Its like shiny sytone hotswap but its aneicnt chisel also its not at all its kinda like curse of binding but also its only after you take it offf so its more like curse of invonciencing --- AdventurePlayer.cs | 97 +++++++++++++++++++++++ Assets/Buff/AncientChiselHotswapBuff.png | Bin 0 -> 427 bytes Localization/en-US.hjson | 5 ++ PvPAdventure.csproj | 1 - 4 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 Assets/Buff/AncientChiselHotswapBuff.png diff --git a/AdventurePlayer.cs b/AdventurePlayer.cs index ea67ace0..1df0bd47 100644 --- a/AdventurePlayer.cs +++ b/AdventurePlayer.cs @@ -591,7 +591,92 @@ public override bool PreKill(double damage, int hitDirection, bool pvp, ref bool } private bool hadShinyStoneLastFrame; + public class AncientChiselHotswap : ModPlayer + { + private bool hadAncientChiselLastFrame; + private int ancientChiselSlot = -1; // Track which slot had the Ancient Chisel + private int disabledSlot = -1; // Track which slot is currently disabled + + public override void PostUpdateEquips() + { + // Check if Ancient Chisel is equipped and in which slot + int currentChiselSlot = GetAncientChiselSlot(); + bool hasAncientChisel = currentChiselSlot != -1; + + // Apply debuff when Ancient Chisel is removed (transition from equipped to not equipped) + if (hadAncientChiselLastFrame && !hasAncientChisel) + { + Player.AddBuff(ModContent.BuffType(), 15 * 60 * 60); // 60 seconds + disabledSlot = ancientChiselSlot; // Remember which slot to disable + } + + // Update tracking variables for next frame + if (hasAncientChisel) + { + ancientChiselSlot = currentChiselSlot; + hadAncientChiselLastFrame = true; + } + else + { + hadAncientChiselLastFrame = false; + } + + // Handle disabled slot restrictions + if (Player.HasBuff(ModContent.BuffType()) && disabledSlot != -1) + { + RestrictDisabledSlot(disabledSlot); + } + else if (!Player.HasBuff(ModContent.BuffType())) + { + // Reset disabled slot when debuff expires + disabledSlot = -1; + } + } + + private int GetAncientChiselSlot() + { + for (int i = 3; i < 10; i++) // Check all accessory slots + { + if (Player.armor[i].type == ItemID.AncientChisel && + (i < 7 || !Player.hideVisibleAccessory[i - 3])) + { + return i; + } + } + return -1; + } + private void RestrictDisabledSlot(int slotIndex) + { + if (slotIndex >= 3 && slotIndex < 10) + { + // Check if there's a non-Ancient Chisel item in the disabled slot + if (!Player.armor[slotIndex].IsAir && Player.armor[slotIndex].type != ItemID.AncientChisel) + { + // Remove non-Ancient Chisel items from the disabled slot + // and return them to the player's inventory + Item removedItem = Player.armor[slotIndex].Clone(); + Player.armor[slotIndex] = new Item(); // Clear the slot + + // Try to add the item to the player's inventory + Item leftoverItem = Player.GetItem(Player.whoAmI, removedItem, GetItemSettings.InventoryEntityToPlayerInventorySettings); + + // If inventory is full and there are leftovers, drop them on the ground + if (!leftoverItem.IsAir) + { + Player.DropItem(Player.GetSource_Misc("SlotRestriction"), Player.position, ref leftoverItem); + } + } + } + } + + // Method to check if a slot is disabled (can be used by other systems) + public bool IsSlotDisabled(int slotIndex) + { + return Player.HasBuff(ModContent.BuffType()) && + disabledSlot == slotIndex; + } + } public override void PostUpdateEquips() { // Check if Shiny Stone is equipped @@ -1030,4 +1115,16 @@ public override void SetStaticDefaults() Main.buffNoSave[Type] = true; Main.buffNoTimeDisplay[Type] = false; // Show timer } +} +public class AncientChiselHotswapBuff : ModBuff +{ + public override string Texture => $"PvPAdventure/Assets/Buff/AncientChiselHotswapBuff"; + + public override void SetStaticDefaults() + { + Main.debuff[Type] = true; + Main.buffNoSave[Type] = true; + Main.buffNoTimeDisplay[Type] = false; // Show timer + Main.persistentBuff[Type] = true; + } } \ No newline at end of file diff --git a/Assets/Buff/AncientChiselHotswapBuff.png b/Assets/Buff/AncientChiselHotswapBuff.png new file mode 100644 index 0000000000000000000000000000000000000000..4d5a2000552c40d020052b240805d04137098115 GIT binary patch literal 427 zcmeAS@N?(olHy`uVBq!ia0vp^Vn8gz!VDy*GX~`WDTQQ@AYTTCDm4a%h86~fUqGRT z7Yq!g1`G_Z5*Qe)W-u^_7tGleXakf`5AX?b1=0?Biu?QXr)PU>%86El+9bOhiHeG5 zW@Z{08O@qC>&~4!|NsBrB&6{csFblJ$S;_|;n|He5GTpo-G!%db6_%%!(QU)>&pI; zgHc?~Siodejl#~EjAZONN#3eW|L;9Xwc5Lf5`n0XtrvJ zYeY#(Vo9o1a#1RfVlXl=GSxM(&^0g&F*3F?wy-ia&^9ozGBBuHJNF8ThTQy=%(P0} s8u&k`W&ky4z-=hW%uOvWNz5(4qQ?+o$-hbbph#fwboFyt=akR{0ER|*kpKVy literal 0 HcmV?d00001 diff --git a/Localization/en-US.hjson b/Localization/en-US.hjson index 4dff9902..3c85737e 100644 --- a/Localization/en-US.hjson +++ b/Localization/en-US.hjson @@ -711,6 +711,11 @@ Mods: { DisplayName: Shiny Stone Hotswap Description: Shiny Stone is charging up! } + + AncientChiselHotswapBuff: { + DisplayName: THE CURSE OF THE ANCIENT CHISEL + Description: YOU CAN'T USE THAT heckin' ACCESSORY SLOT! + } } } } diff --git a/PvPAdventure.csproj b/PvPAdventure.csproj index cc33f564..3ccc18c4 100644 --- a/PvPAdventure.csproj +++ b/PvPAdventure.csproj @@ -7,7 +7,6 @@ - From 4892a7228964fcb76d56b62caff08a9dcd24ee76 Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Fri, 1 Aug 2025 21:18:39 -0700 Subject: [PATCH 050/206] UPDTEASES WHIPS RANGE --- AdventureProjectile.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AdventureProjectile.cs b/AdventureProjectile.cs index 22b2da99..c121fb2b 100644 --- a/AdventureProjectile.cs +++ b/AdventureProjectile.cs @@ -533,7 +533,7 @@ public override void SetDefaults(Projectile projectile) { if (projectile.type == ProjectileID.MaceWhip) { - projectile.WhipSettings.RangeMultiplier = 1.58f; // this is like 20% range + projectile.WhipSettings.RangeMultiplier = 1.33f; // this is like 20% range } } From 2acde774b6d9f0a9c4102a8415d9437ce457fc88 Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Fri, 1 Aug 2025 22:41:57 -0700 Subject: [PATCH 051/206] manipulation imp imp imp --- AdventureTile.cs | 85 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/AdventureTile.cs b/AdventureTile.cs index bf5f54ce..79e42a9f 100644 --- a/AdventureTile.cs +++ b/AdventureTile.cs @@ -1,5 +1,7 @@ using System.Linq; using PvPAdventure.System; +using Terraria.ID; +using Terraria; using Terraria.ModLoader; namespace PvPAdventure; @@ -29,4 +31,87 @@ public override bool CanReplace(int i, int j, int type, int tileTypeBeingPlaced) return !ModContent.GetInstance().GetRegionsContaining(new(i, j)) .Any(region => !region.CanModifyTiles); } +} +public class AncientManipulatorGlobalTile : GlobalTile +{ + public override void SetStaticDefaults() + { + // Make Ancient Manipulator count as all crafting stations + TileID.Sets.CountsAsWaterSource[TileID.LunarCraftingStation] = true; + TileID.Sets.CountsAsShimmerSource[TileID.LunarCraftingStation] = true; + TileID.Sets.CountsAsHoneySource[TileID.LunarCraftingStation] = true; + TileID.Sets.CountsAsLavaSource[TileID.LunarCraftingStation] = true; + // Set it as all the basic crafting station types + Main.tileTable[TileID.LunarCraftingStation] = true; + Main.tileLighted[TileID.LunarCraftingStation] = true; + // Make it provide adjacency for all crafting stations + TileID.Sets.BasicChest[TileID.LunarCraftingStation] = false; + TileID.Sets.BasicChestFake[TileID.LunarCraftingStation] = false; + } + + public override int[] AdjTiles(int type) + { + if (type == TileID.LunarCraftingStation) + { + return new int[] { + TileID.WorkBenches, + TileID.Furnaces, + TileID.Anvils, + TileID.AdamantiteForge, + TileID.MythrilAnvil, + TileID.Chairs, + TileID.Tables, + TileID.Loom, + TileID.Kegs, + TileID.Bookcases, + TileID.TinkerersWorkbench, + TileID.ImbuingStation, + TileID.DyeVat, + TileID.HeavyWorkBench, + TileID.GlassKiln, + TileID.LivingLoom, + TileID.SkyMill, + TileID.Solidifier, + TileID.FleshCloningVat, + TileID.SteampunkBoiler, + TileID.HoneyDispenser, + TileID.IceMachine, + TileID.Campfire, + TileID.BewitchingTable, + TileID.AlchemyTable, + TileID.CrystalBall, + TileID.Autohammer, + TileID.BoneWelder, + TileID.LesionStation, + TileID.Sinks, + TileID.Sawmill, + TileID.CookingPots, + TileID.DemonAltar, + TileID.TeaKettle, + TileID.Blendomatic, + TileID.MeatGrinder, + TileID.AlchemyTable, + TileID.AlchemyTable, + TileID.AlchemyTable, + TileID.AlchemyTable, + TileID.AlchemyTable, + TileID.Bottles, + TileID.AlchemyTable + + + }; + + } + return base.AdjTiles(type); + } + public override void NearbyEffects(int i, int j, int type, bool closer) + { + if (type == TileID.LunarCraftingStation && closer) + { + Player player = Main.LocalPlayer; + + // Apply Alchemy Table effect (33% chance to not consume ingredients when crafting potions) + player.alchemyTable = true; + } + } } \ No newline at end of file From ad57ecbc59de2eb6c75f7aca663436088fd9a416 Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Fri, 1 Aug 2025 23:20:07 -0700 Subject: [PATCH 052/206] simple shiny stone --- AdventurePlayer.cs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/AdventurePlayer.cs b/AdventurePlayer.cs index 1df0bd47..ec24aaac 100644 --- a/AdventurePlayer.cs +++ b/AdventurePlayer.cs @@ -724,14 +724,6 @@ public override void PostUpdateEquips() } } - public override void OnRespawn() - { - // Re-apply debuff if equipped during respawn - if (IsShinyStoneEquipped()) - { - Player.AddBuff(ModContent.BuffType(), 900); - } - } private bool IsShinyStoneEquipped() { From 03a944d169062485f87def9c71c7e92e5fb908f7 Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Sun, 3 Aug 2025 04:03:29 -0700 Subject: [PATCH 053/206] makes whip buffs work in pvp (NOT DEBUFFS) --- AdventureProjectile.cs | 44 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/AdventureProjectile.cs b/AdventureProjectile.cs index c121fb2b..bbeae422 100644 --- a/AdventureProjectile.cs +++ b/AdventureProjectile.cs @@ -559,5 +559,49 @@ private void EditProjectileDamage(ILContext il) return 40; }); } + public class WhipBuffs : GlobalProjectile + { + public override void ModifyHitPlayer(Projectile projectile, Player target, ref Player.HurtModifiers modifiers) + { + if (projectile.type == ProjectileID.SwordWhip && target.hostile) + { + if (projectile.owner >= 0 && projectile.owner < Main.maxPlayers) + { + Player attacker = Main.player[projectile.owner]; + if (attacker != null && attacker.active && attacker != target && attacker.hostile) + { + int buffDuration = 420; + attacker.AddBuff(BuffID.SwordWhipPlayerBuff, buffDuration); + } + } + } + if (projectile.type == ProjectileID.ThornWhip && target.hostile) + { + if (projectile.owner >= 0 && projectile.owner < Main.maxPlayers) + { + Player attacker = Main.player[projectile.owner]; + + if (attacker != null && attacker.active && attacker != target && attacker.hostile) + { + int buffDuration = 420; + attacker.AddBuff(BuffID.ThornWhipPlayerBuff, buffDuration); + } + } + } + if (projectile.type == ProjectileID.ScytheWhip && target.hostile) + { + if (projectile.owner >= 0 && projectile.owner < Main.maxPlayers) + { + Player attacker = Main.player[projectile.owner]; + + if (attacker != null && attacker.active && attacker != target && attacker.hostile) + { + int buffDuration = 420; + attacker.AddBuff(BuffID.ScytheWhipPlayerBuff, buffDuration); + } + } + } + } + } } From daaa89293c481d5ddda69b9e92abeac10e0b5ff4 Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Wed, 13 Aug 2025 22:47:11 -0700 Subject: [PATCH 054/206] RAHHAHAHHA --- AdventurePlayer.cs | 62 ++++++++++++++++++++++++++- Assets/Buff/NewIchorPlayerDebuff.png | Bin 0 -> 491 bytes Localization/en-US.hjson | 7 ++- 3 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 Assets/Buff/NewIchorPlayerDebuff.png diff --git a/AdventurePlayer.cs b/AdventurePlayer.cs index ec24aaac..5d7a082a 100644 --- a/AdventurePlayer.cs +++ b/AdventurePlayer.cs @@ -1097,6 +1097,53 @@ public override string ToString() return $"{Player.whoAmI}/{Player.name}/{DiscordUser?.Id}"; } } +public class NewIchorPlayer : ModPlayer +{ + public bool hasDefenseReduction = false; + + public override void ResetEffects() + { + hasDefenseReduction = false; + } + + public override void PostUpdateBuffs() + { + // Convert vanilla Ichor to our custom debuff + if (Player.HasBuff(BuffID.Ichor)) + { + // Get the remaining time of the vanilla Ichor debuff + int ichorBuffIndex = Player.FindBuffIndex(BuffID.Ichor); + if (ichorBuffIndex != -1) + { + int remainingTime = Player.buffTime[ichorBuffIndex]; + + // Remove vanilla Ichor + Player.DelBuff(ichorBuffIndex); + + // Add our custom debuff with the same duration + Player.AddBuff(ModContent.BuffType(), remainingTime); + } + } + + // Check if player has our custom debuff + if (Player.HasBuff(ModContent.BuffType())) + { + hasDefenseReduction = true; + } + } + + public override void PostUpdateEquips() + { + if (hasDefenseReduction) + { + // Calculate 33% reduction (rounded down) + int originalDefense = Player.statDefense; + int reduction = (int)(originalDefense * 0.33f); + Player.statDefense -= reduction; + Player.ichor = true; + } + } +} public class ShinyStoneHotswap : ModBuff { public override string Texture => $"PvPAdventure/Assets/Buff/ShinyStoneHotswap"; @@ -1115,8 +1162,21 @@ public class AncientChiselHotswapBuff : ModBuff public override void SetStaticDefaults() { Main.debuff[Type] = true; - Main.buffNoSave[Type] = true; + Main.buffNoSave[Type] = false; Main.buffNoTimeDisplay[Type] = false; // Show timer Main.persistentBuff[Type] = true; } +} + +public class NewIchorPlayerDebuff : ModBuff +{ + public override string Texture => $"PvPAdventure/Assets/Buff/NewIchorPlayerDebuff"; + + public override void SetStaticDefaults() + { + Main.debuff[Type] = true; + Main.buffNoSave[Type] = false; + Main.buffNoTimeDisplay[Type] = false; + Main.persistentBuff[Type] = false; + } } \ No newline at end of file diff --git a/Assets/Buff/NewIchorPlayerDebuff.png b/Assets/Buff/NewIchorPlayerDebuff.png new file mode 100644 index 0000000000000000000000000000000000000000..6cb8175de4275c32b1a7b9024cf65eb6008eb230 GIT binary patch literal 491 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vO2U$sR$z3=CCj3=9n|3=F@3LJcn% z7)lKo7+xhXFj&oCU=S~uvn$XBD4`PI6XFV_f#Cnrj{imB&w&hS)+1@0e`hcpU(WyU zRKWk=%l`lWFL!sp1!W^FFE*F6!`U- ze7^&QCVRR#hG?8`ofyc=Y{=v6y->vIph%yS<_sr|7AFmnr+2=ZWR~C5lVAHuCED*& z)c;l2@)k(*iGIu8%Wy!VLGlHQRsm16t>jCaEQVF(f_+jt=2dJ@BboNxt!ZnqJ}#;e z=wY~YWAQZU0FC+e4MqA#*;X`^Z5I9MS;ZQ~Z)~h)SjSLl7?y8(!+TjcE?b literal 0 HcmV?d00001 diff --git a/Localization/en-US.hjson b/Localization/en-US.hjson index 3c85737e..55c0cc62 100644 --- a/Localization/en-US.hjson +++ b/Localization/en-US.hjson @@ -716,12 +716,17 @@ Mods: { DisplayName: THE CURSE OF THE ANCIENT CHISEL Description: YOU CAN'T USE THAT heckin' ACCESSORY SLOT! } + + NewIchorPlayerDebuff: { + DisplayName: Ichor + Description: Defense reduced by one third + } } } } BuffDescription: { - BeetleMight1: Melee damage and speed increase by 15% + BeetleMight1: Melee damage and speed increase by 15% BeetleMight2: Melee damage and speed increase by 25% BeetleMight3: Melee damage increase by 30% and melee speed increase by 45% } From d2d16ea0fc6ad9cd1714f204c0dab9f738065fe2 Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Fri, 15 Aug 2025 17:34:58 -0700 Subject: [PATCH 055/206] shroomite bar --- System/RecipeManager.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/System/RecipeManager.cs b/System/RecipeManager.cs index 1022d22f..2b304a0e 100644 --- a/System/RecipeManager.cs +++ b/System/RecipeManager.cs @@ -85,11 +85,11 @@ public override void AddRecipes() - int[] itemsToRemove = new int[] { ItemID.TrueNightsEdge, - ItemID.MoonlordArrow + ItemID.MoonlordArrow, + ItemID.ShroomiteBar }; for (int i = 0; i < Main.recipe.Length; i++) @@ -101,6 +101,14 @@ public override void AddRecipes() } } + //shroomite bar crafting cost reduction + + Recipe.Create(ItemID.ShroomiteBar) + .AddIngredient(ItemID.GlowingMushroom, 3) + .AddIngredient(ItemID.ChlorophyteBar, 1) + .AddTile(TileID.Autohammer) + .Register(); + //temp sudo terrablade Recipe.Create(ItemID.TrueNightsEdge) .AddIngredient(ItemID.SoulofFright, 20) From 1bf0a43f253d55358e74df864a6420cc2b674354 Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Fri, 15 Aug 2025 22:34:56 -0700 Subject: [PATCH 056/206] no more old men selling drinks --- AdventureNpc.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/AdventureNpc.cs b/AdventureNpc.cs index 11afa92a..4aa83bf2 100644 --- a/AdventureNpc.cs +++ b/AdventureNpc.cs @@ -489,4 +489,17 @@ public static bool IsPartOfEaterOfWorlds(short type) => public static bool IsPartOfTheDestroyer(short type) => type is NPCID.TheDestroyer or NPCID.TheDestroyerBody or NPCID.TheDestroyerTail; + + public class TavernkeepDespawn : GlobalNPC + { + public override void PostAI(NPC npc) + { + if (npc.type == NPCID.BartenderUnconscious) + { + npc.active = false; + npc.life = 0; + + } + } + } } \ No newline at end of file From 5a4094e8f5bebad766bf1813f38f559a410024b6 Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Sat, 16 Aug 2025 09:02:49 -0700 Subject: [PATCH 057/206] chagned dungoen rates --- AdventureDropDatabase.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AdventureDropDatabase.cs b/AdventureDropDatabase.cs index 3fe56b10..17c3d743 100644 --- a/AdventureDropDatabase.cs +++ b/AdventureDropDatabase.cs @@ -123,7 +123,7 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) case NPCID.HellArmoredBonesMace: case NPCID.HellArmoredBonesSword: foreach (var drop in drops) - ModifyDropRate(drop, ItemID.MaceWhip, 3, 400); + ModifyDropRate(drop, ItemID.MaceWhip, 1, 10); break; case NPCID.BlackRecluse: @@ -154,7 +154,7 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) case NPCID.GiantCursedSkull: foreach (var drop in drops) - ModifyDropRate(drop, ItemID.ShadowJoustingLance, 1, 12); + ModifyDropRate(drop, ItemID.ShadowJoustingLance, 1, 1); break; case NPCID.Mothron: From 307137780187c860b49d0bd9279e33833257f0cd Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Fri, 22 Aug 2025 14:41:26 -0700 Subject: [PATCH 058/206] reducedrecipecost --- System/RecipeManager.cs | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/System/RecipeManager.cs b/System/RecipeManager.cs index 2b304a0e..8a7a801d 100644 --- a/System/RecipeManager.cs +++ b/System/RecipeManager.cs @@ -89,7 +89,10 @@ public override void AddRecipes() { ItemID.TrueNightsEdge, ItemID.MoonlordArrow, - ItemID.ShroomiteBar + ItemID.ShroomiteBar, + ItemID.WormFood, + ItemID.ChlorophyteBar, + ItemID.SpectreBar }; for (int i = 0; i < Main.recipe.Length; i++) @@ -109,6 +112,23 @@ public override void AddRecipes() .AddTile(TileID.Autohammer) .Register(); + Recipe.Create(ItemID.WormFood) + .AddIngredient(ItemID.RottenChunk, 6) + .AddIngredient(ItemID.VilePowder, 10) + .AddTile(TileID.DemonAltar) + .Register(); + + Recipe.Create(ItemID.ChlorophyteBar) + .AddIngredient(ItemID.ChlorophyteOre, 4) + .AddTile(TileID.AdamantiteForge) + .Register(); + + Recipe.Create(ItemID.SpectreBar, 3) + .AddIngredient(ItemID.ChlorophyteBar, 3) + .AddIngredient(ItemID.Ectoplasm, 1) + .AddTile(TileID.AdamantiteForge) + .Register(); + //temp sudo terrablade Recipe.Create(ItemID.TrueNightsEdge) .AddIngredient(ItemID.SoulofFright, 20) From cd70ebf631292d69ce94aa62b8d121e82e6d7416 Mon Sep 17 00:00:00 2001 From: James Puleo Date: Sat, 12 Jul 2025 03:51:18 -0400 Subject: [PATCH 059/206] WIP GameManager: Correct behavior when managing game phases Previously, entering a multiplayer game in the `Playing` phase would cause loading a singleplayer world to break. --- System/GameManager.cs | 53 +++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/System/GameManager.cs b/System/GameManager.cs index b0de2999..b4c2e46f 100644 --- a/System/GameManager.cs +++ b/System/GameManager.cs @@ -37,7 +37,7 @@ private set _currentPhase = value; - if (Main.netMode != NetmodeID.MultiplayerClient) + if (Main.dedServ) NetMessage.SendData(MessageID.WorldData); } } @@ -176,11 +176,15 @@ private void OnPhaseChange(Phase newPhase) { case Phase.Waiting: { - // NOTE: We currently have one region, which is the spawn region. We'll use this assumption for now. - var spawnRegion = ModContent.GetInstance().Regions[0]; - spawnRegion.CanRandomTeleport = false; - spawnRegion.CanUseWormhole = false; - spawnRegion.CanExit = false; + var regions = ModContent.GetInstance().Regions; + if (regions.Count >= 1) + { + // NOTE: We currently have one region, which is the spawn region. We'll use this assumption for now. + var spawnRegion = regions[0]; + spawnRegion.CanRandomTeleport = false; + spawnRegion.CanUseWormhole = false; + spawnRegion.CanExit = false; + } // Remove everything that is hostile foreach (var npc in Main.ActiveNPCs) @@ -190,7 +194,9 @@ private void OnPhaseChange(Phase newPhase) npc.life = 0; npc.netSkip = -1; - NetMessage.SendData(MessageID.SyncNPC, number: npc.whoAmI); + + if (Main.dedServ) + NetMessage.SendData(MessageID.SyncNPC, number: npc.whoAmI); } var spawnPosition = new Vector2(Main.spawnTileX, Main.spawnTileY - 3).ToWorldCoordinates(); @@ -198,8 +204,10 @@ private void OnPhaseChange(Phase newPhase) { player.Teleport(spawnPosition, TeleportationStyleID.RecallPotion); // FIXME: I think this is right-ish? - NetMessage.SendData(MessageID.TeleportEntity, -1, -1, null, 0, player.whoAmI, spawnPosition.X, - spawnPosition.Y, 2); + + if (Main.dedServ) + NetMessage.SendData(MessageID.TeleportEntity, -1, -1, null, 0, player.whoAmI, spawnPosition.X, + spawnPosition.Y, 2); } UpdateFreezeTime(true); @@ -225,9 +233,13 @@ private void UpdateFreezeTime(bool value) { var freezeTimeModule = CreativePowerManager.Instance.GetPower(); freezeTimeModule.SetPowerInfo(value); - var packet = NetCreativePowersModule.PreparePacket(freezeTimeModule.PowerId, 1); - packet.Writer.Write(freezeTimeModule.Enabled); - NetManager.Instance.Broadcast(packet); + + if (Main.dedServ) + { + var packet = NetCreativePowersModule.PreparePacket(freezeTimeModule.PowerId, 1); + packet.Writer.Write(freezeTimeModule.Enabled); + NetManager.Instance.Broadcast(packet); + } } public override void ClearWorld() @@ -235,19 +247,10 @@ public override void ClearWorld() _startGameCountdown = null; TimeRemaining = 0; - if (Main.dedServ) - { - // If we are already waiting, we need to do a subset of things we would have done during phase change. - if (CurrentPhase == Phase.Waiting) - { - UpdateFreezeTime(true); - } - // ...but otherwise, simply changing our phase will handle it. - else - { - CurrentPhase = Phase.Waiting; - } - } + // Always run the on-change regardless of if it actually changes. + if (Main.netMode != NetmodeID.MultiplayerClient && CurrentPhase != Phase.Waiting) + OnPhaseChange(Phase.Waiting); + CurrentPhase = Phase.Waiting; } public override void NetSend(BinaryWriter writer) From 6b49cc45c6666faff32e29629e1198852e18f4ee Mon Sep 17 00:00:00 2001 From: James Puleo Date: Sun, 3 Aug 2025 20:58:11 -0400 Subject: [PATCH 060/206] WIP MVP of team health bars debuffs and unteamed damage make it so teams get behind themselves --- AdventureNpc.cs | 103 +++++++++++++++++++++++++++++++++++ AdventurePacketIdentifier.cs | 3 +- AdventureProjectile.cs | 8 +-- PvPAdventure.cs | 10 ++++ System/CombatManager.cs | 23 +++++++- 5 files changed, 140 insertions(+), 7 deletions(-) diff --git a/AdventureNpc.cs b/AdventureNpc.cs index 11afa92a..af0263a7 100644 --- a/AdventureNpc.cs +++ b/AdventureNpc.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Linq; using Mono.Cecil.Cil; @@ -20,6 +21,9 @@ public class AdventureNpc : GlobalNPC { public override bool InstancePerEntity => true; public DamageInfo LastDamageFromPlayer { get; set; } + private readonly Dictionary _life = new(); + // FIXME: Not public + public Team? _lastHitTeam = Team.None; public class DamageInfo(byte who) { @@ -49,6 +53,9 @@ public override void Load() On_Item.CheckLavaDeath += OnItemCheckLavaDeath; // Prevent some global drop rules from being registered. On_ItemDropDatabase.RegisterToGlobal += AdventureDropDatabase.OnItemDropDatabaseRegisterToGlobal; + + On_NPC.StrikeNPC_HitInfo_bool_bool += OnNPCStrikeNPC; + On_NetMessage.SendStrikeNPC += OnNetMessageSendStrikeNPC; } private void OnNPCScaleStats(On_NPC.orig_ScaleStats orig, NPC self, int? activeplayerscount, @@ -115,6 +122,9 @@ public override void SetDefaults(NPC entity) entity.damage = (int)(entity.damage * multiplier.Value); } } + + foreach (var team in Enum.GetValues()) + _life[team] = entity.lifeMax; } public override void OnSpawn(NPC npc, IEntitySource source) @@ -325,6 +335,66 @@ private void OnItemCheckLavaDeath(On_Item.orig_CheckLavaDeath orig, Item self, i } } + private int OnNPCStrikeNPC(On_NPC.orig_StrikeNPC_HitInfo_bool_bool orig, NPC self, NPC.HitInfo hit, bool fromNet, + bool noPlayerInteraction) + { + var adventureSelf = self.GetGlobalNPC(); + Mod.Logger.Info($"StrikeNPC {adventureSelf._lastHitTeam}"); + + if (adventureSelf._lastHitTeam == null) + { + foreach (var team in adventureSelf._life.Keys) + adventureSelf._life[team] = Math.Max(0, adventureSelf._life[team] - hit.Damage); + + return orig(self, hit, fromNet, noPlayerInteraction); + } + + var previousImmortal = self.immortal; + + try + { + // FIXME: wrong place to get damage sorta, what abt InstantKill etc? + var teamLife = Math.Max(0, adventureSelf._life[adventureSelf._lastHitTeam.Value] - hit.Damage); + adventureSelf._life[adventureSelf._lastHitTeam.Value] = teamLife; + + var damage = Math.Max(0, self.life - teamLife); + if (damage == 0) + self.immortal = true; + + hit.Damage = damage; + + return orig(self, hit, fromNet, noPlayerInteraction); + } + finally + { + self.immortal = previousImmortal; + if (!fromNet) + adventureSelf._lastHitTeam = null; + Mod.Logger.Info(string.Join(",", adventureSelf._life)); + } + } + + private void OnNetMessageSendStrikeNPC(On_NetMessage.orig_SendStrikeNPC orig, NPC npc, ref NPC.HitInfo hit, + int ignoreClient) + { + var adventureNpc = npc.GetGlobalNPC(); + Mod.Logger.Info($"SendStrikeNPC {adventureNpc._lastHitTeam}"); + + if (Main.dedServ && adventureNpc._lastHitTeam.HasValue) + { + var packet = Mod.GetPacket(); + packet.Write((byte)AdventurePacketIdentifier.NpcStrikeTeam); + packet.Write((short)npc.whoAmI); + packet.Write((byte)adventureNpc._lastHitTeam.Value); + + packet.Send(ignoreClient: ignoreClient); + + adventureNpc._lastHitTeam = null; + } + + orig(npc, ref hit, ignoreClient); + } + public override bool? CanBeHitByProjectile(NPC npc, Projectile projectile) { var config = ModContent.GetInstance(); @@ -415,6 +485,26 @@ void AddNonExpertBossLoot(int id) AdventureDropDatabase.ModifyNPCLoot(npc, npcLoot); } + // Although this looks like a side effect (and therefore should use OnHit), the order of operations matters here. + // This needs to happen before the strike to the NPC. + public override void ModifyHitByItem(NPC npc, Player player, Item item, ref NPC.HitModifiers modifiers) + { + _lastHitTeam = (Team)player.team; + Mod.Logger.Info($"{npc.FullName} last hit by {_lastHitTeam}"); + } + + // Although this looks like a side effect (and therefore should use OnHit), the order of operations matters here. + // This needs to happen before the strike to the NPC. + public override void ModifyHitByProjectile(NPC npc, Projectile projectile, ref NPC.HitModifiers modifiers) + { + if (projectile.GetGlobalProjectile() + .EntitySource is EntitySource_Parent parent && parent.Entity is Player player) + { + _lastHitTeam = (Team)player.team; + Mod.Logger.Info($"{npc.FullName} last hit by {_lastHitTeam}"); + } + } + // This only runs on the attacking player public override void OnHitByItem(NPC npc, Player player, Item item, NPC.HitInfo hit, int damageDone) { @@ -489,4 +579,17 @@ public static bool IsPartOfEaterOfWorlds(short type) => public static bool IsPartOfTheDestroyer(short type) => type is NPCID.TheDestroyer or NPCID.TheDestroyerBody or NPCID.TheDestroyerTail; + + public class DumpNPCCommand : ModCommand + { + public override void Action(CommandCaller caller, string input, string[] args) + { + Mod.Logger.Info($"netMode {Main.netMode}"); + foreach (var npc in Main.ActiveNPCs) + Mod.Logger.Info(string.Join(",", npc.GetGlobalNPC()._life)); + } + + public override string Command => "dump"; + public override CommandType Type => CommandType.Server; + } } \ No newline at end of file diff --git a/AdventurePacketIdentifier.cs b/AdventurePacketIdentifier.cs index 034d4310..e7190430 100644 --- a/AdventurePacketIdentifier.cs +++ b/AdventurePacketIdentifier.cs @@ -7,5 +7,6 @@ public enum AdventurePacketIdentifier : byte WorldMapLighting, PingPong, PlayerItemPickup, - PlayerTeam + PlayerTeam, + NpcStrikeTeam } \ No newline at end of file diff --git a/AdventureProjectile.cs b/AdventureProjectile.cs index 598d1563..c639ec23 100644 --- a/AdventureProjectile.cs +++ b/AdventureProjectile.cs @@ -11,7 +11,7 @@ namespace PvPAdventure; public class AdventureProjectile : GlobalProjectile { - private IEntitySource _entitySource; + public IEntitySource EntitySource { get; private set; } public override bool InstancePerEntity => true; public override void Load() @@ -29,10 +29,10 @@ private static EntitySource_ItemUse GetItemUseSource(Projectile projectile, Proj { var adventureProjectile = projectile.GetGlobalProjectile(); - if (adventureProjectile._entitySource is EntitySource_ItemUse entitySourceItemUse) + if (adventureProjectile.EntitySource is EntitySource_ItemUse entitySourceItemUse) return entitySourceItemUse; - if (adventureProjectile._entitySource is EntitySource_Parent entitySourceParent && + if (adventureProjectile.EntitySource is EntitySource_Parent entitySourceParent && entitySourceParent.Entity is Projectile projectileParent && projectileParent != lastProjectile) return GetItemUseSource(projectileParent, projectile); @@ -55,7 +55,7 @@ private PlayerDeathReason OnPlayerDeathReasonByProjectile(On_PlayerDeathReason.o public override void OnSpawn(Projectile projectile, IEntitySource source) { - _entitySource = source; + EntitySource = source; } public override bool? CanCutTiles(Projectile projectile) diff --git a/PvPAdventure.cs b/PvPAdventure.cs index 594c18f8..0b0721db 100644 --- a/PvPAdventure.cs +++ b/PvPAdventure.cs @@ -208,6 +208,16 @@ public override void HandlePacket(BinaryReader reader, int whoAmI) player.team = (int)team.Value; break; } + case AdventurePacketIdentifier.NpcStrikeTeam: + { + var npc = reader.ReadInt16(); + var team = (Team)reader.ReadByte(); + + Main.npc[npc].GetGlobalNPC()._lastHitTeam = team; + Logger.Info($"Strike team {team} from network"); + + break; + } } } } \ No newline at end of file diff --git a/System/CombatManager.cs b/System/CombatManager.cs index f76dd19f..0e1b54ba 100644 --- a/System/CombatManager.cs +++ b/System/CombatManager.cs @@ -4,6 +4,7 @@ using MonoMod.Cil; using Terraria; using Terraria.DataStructures; +using Terraria.Enums; using Terraria.ID; using Terraria.ModLoader; @@ -89,8 +90,26 @@ public override void Load() public override bool HijackGetData(ref byte messageType, ref BinaryReader reader, int playerNumber) { - return PreventPersonalCombatModifications && Main.dedServ && - (messageType is MessageID.TogglePVP or MessageID.PlayerTeam); + if (PreventPersonalCombatModifications && Main.dedServ && + (messageType is MessageID.TogglePVP or MessageID.PlayerTeam)) + return true; + + if (Main.dedServ && messageType == MessageID.DamageNPC) + { + var previousPosition = reader.BaseStream.Position; + + try + { + Main.npc[reader.ReadInt16()].GetGlobalNPC()._lastHitTeam = + (Team)Main.player[playerNumber].team; + } + finally + { + reader.BaseStream.Position = previousPosition; + } + } + + return false; } private void OnPlayerHurt(On_Player.orig_Hurt_HurtInfo_bool orig, Player self, Player.HurtInfo info, bool quiet) From 3682e31f23b65dc875bdac7430245d320e25e192 Mon Sep 17 00:00:00 2001 From: James Puleo Date: Sun, 3 Aug 2025 22:39:33 -0400 Subject: [PATCH 061/206] Make it less shit. need to fix hitmarker pitch --- AdventureNpc.cs | 65 ++++++++++++++++++++--------------------- PvPAdventure.cs | 3 +- System/CombatManager.cs | 4 +-- 3 files changed, 35 insertions(+), 37 deletions(-) diff --git a/AdventureNpc.cs b/AdventureNpc.cs index af0263a7..60983aab 100644 --- a/AdventureNpc.cs +++ b/AdventureNpc.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Xna.Framework; using Mono.Cecil.Cil; using MonoMod.Cil; using PvPAdventure.System; @@ -21,9 +22,9 @@ public class AdventureNpc : GlobalNPC { public override bool InstancePerEntity => true; public DamageInfo LastDamageFromPlayer { get; set; } + private readonly Dictionary _life = new(); - // FIXME: Not public - public Team? _lastHitTeam = Team.None; + private Team? _strikeTeam; public class DamageInfo(byte who) { @@ -339,9 +340,9 @@ private int OnNPCStrikeNPC(On_NPC.orig_StrikeNPC_HitInfo_bool_bool orig, NPC sel bool noPlayerInteraction) { var adventureSelf = self.GetGlobalNPC(); - Mod.Logger.Info($"StrikeNPC {adventureSelf._lastHitTeam}"); - if (adventureSelf._lastHitTeam == null) + // If this was a non-player strike, treat it as damage for all teams. + if (adventureSelf._strikeTeam == null) { foreach (var team in adventureSelf._life.Keys) adventureSelf._life[team] = Math.Max(0, adventureSelf._life[team] - hit.Damage); @@ -349,15 +350,26 @@ private int OnNPCStrikeNPC(On_NPC.orig_StrikeNPC_HitInfo_bool_bool orig, NPC sel return orig(self, hit, fromNet, noPlayerInteraction); } + hit.HideCombatText = true; + CombatText.NewText(new Rectangle( + (int)self.position.X, + (int)self.position.Y, + self.width, + self.height + ), Main.teamColor[(int)adventureSelf._strikeTeam.Value], hit.Damage, hit.Crit); + + // Save the previous immortal value, we might clobber it later. var previousImmortal = self.immortal; try { // FIXME: wrong place to get damage sorta, what abt InstantKill etc? - var teamLife = Math.Max(0, adventureSelf._life[adventureSelf._lastHitTeam.Value] - hit.Damage); - adventureSelf._life[adventureSelf._lastHitTeam.Value] = teamLife; + var teamLife = Math.Max(0, adventureSelf._life[adventureSelf._strikeTeam.Value] - hit.Damage); + adventureSelf._life[adventureSelf._strikeTeam.Value] = teamLife; var damage = Math.Max(0, self.life - teamLife); + + // Can't deal 0 damage, so help the game out a bit. if (damage == 0) self.immortal = true; @@ -368,9 +380,9 @@ private int OnNPCStrikeNPC(On_NPC.orig_StrikeNPC_HitInfo_bool_bool orig, NPC sel finally { self.immortal = previousImmortal; + if (!fromNet) - adventureSelf._lastHitTeam = null; - Mod.Logger.Info(string.Join(",", adventureSelf._life)); + adventureSelf._strikeTeam = null; } } @@ -378,18 +390,17 @@ private void OnNetMessageSendStrikeNPC(On_NetMessage.orig_SendStrikeNPC orig, NP int ignoreClient) { var adventureNpc = npc.GetGlobalNPC(); - Mod.Logger.Info($"SendStrikeNPC {adventureNpc._lastHitTeam}"); - if (Main.dedServ && adventureNpc._lastHitTeam.HasValue) + if (Main.dedServ && adventureNpc._strikeTeam.HasValue) { var packet = Mod.GetPacket(); packet.Write((byte)AdventurePacketIdentifier.NpcStrikeTeam); packet.Write((short)npc.whoAmI); - packet.Write((byte)adventureNpc._lastHitTeam.Value); + packet.Write((byte)adventureNpc._strikeTeam.Value); packet.Send(ignoreClient: ignoreClient); - adventureNpc._lastHitTeam = null; + adventureNpc._strikeTeam = null; } orig(npc, ref hit, ignoreClient); @@ -489,20 +500,16 @@ void AddNonExpertBossLoot(int id) // This needs to happen before the strike to the NPC. public override void ModifyHitByItem(NPC npc, Player player, Item item, ref NPC.HitModifiers modifiers) { - _lastHitTeam = (Team)player.team; - Mod.Logger.Info($"{npc.FullName} last hit by {_lastHitTeam}"); + MarkNextStrikeForTeam((Team)player.team); } // Although this looks like a side effect (and therefore should use OnHit), the order of operations matters here. // This needs to happen before the strike to the NPC. public override void ModifyHitByProjectile(NPC npc, Projectile projectile, ref NPC.HitModifiers modifiers) { - if (projectile.GetGlobalProjectile() - .EntitySource is EntitySource_Parent parent && parent.Entity is Player player) - { - _lastHitTeam = (Team)player.team; - Mod.Logger.Info($"{npc.FullName} last hit by {_lastHitTeam}"); - } + if (projectile.GetGlobalProjectile().EntitySource is EntitySource_Parent parent && + parent.Entity is Player player) + MarkNextStrikeForTeam((Team)player.team); } // This only runs on the attacking player @@ -567,6 +574,11 @@ public override bool CheckDead(NPC npc) return true; } + public void MarkNextStrikeForTeam(Team team) + { + _strikeTeam = team; + } + private static void PlayHitMarker(int damage) { var marker = ModContent.GetInstance().SoundEffect.NpcHitMarker; @@ -579,17 +591,4 @@ public static bool IsPartOfEaterOfWorlds(short type) => public static bool IsPartOfTheDestroyer(short type) => type is NPCID.TheDestroyer or NPCID.TheDestroyerBody or NPCID.TheDestroyerTail; - - public class DumpNPCCommand : ModCommand - { - public override void Action(CommandCaller caller, string input, string[] args) - { - Mod.Logger.Info($"netMode {Main.netMode}"); - foreach (var npc in Main.ActiveNPCs) - Mod.Logger.Info(string.Join(",", npc.GetGlobalNPC()._life)); - } - - public override string Command => "dump"; - public override CommandType Type => CommandType.Server; - } } \ No newline at end of file diff --git a/PvPAdventure.cs b/PvPAdventure.cs index 0b0721db..ba867fa8 100644 --- a/PvPAdventure.cs +++ b/PvPAdventure.cs @@ -213,8 +213,7 @@ public override void HandlePacket(BinaryReader reader, int whoAmI) var npc = reader.ReadInt16(); var team = (Team)reader.ReadByte(); - Main.npc[npc].GetGlobalNPC()._lastHitTeam = team; - Logger.Info($"Strike team {team} from network"); + Main.npc[npc].GetGlobalNPC().MarkNextStrikeForTeam(team); break; } diff --git a/System/CombatManager.cs b/System/CombatManager.cs index 0e1b54ba..7158c52e 100644 --- a/System/CombatManager.cs +++ b/System/CombatManager.cs @@ -100,8 +100,8 @@ public override bool HijackGetData(ref byte messageType, ref BinaryReader reader try { - Main.npc[reader.ReadInt16()].GetGlobalNPC()._lastHitTeam = - (Team)Main.player[playerNumber].team; + Main.npc[reader.ReadInt16()].GetGlobalNPC() + .MarkNextStrikeForTeam((Team)Main.player[playerNumber].team); } finally { From 3dba46ee55594a5c08621ad6045e274fe56f04c9 Mon Sep 17 00:00:00 2001 From: James Puleo Date: Wed, 6 Aug 2025 16:01:11 -0400 Subject: [PATCH 062/206] WIP fix hitsounds + editoral --- AdventureNpc.cs | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/AdventureNpc.cs b/AdventureNpc.cs index 60983aab..8b9b790e 100644 --- a/AdventureNpc.cs +++ b/AdventureNpc.cs @@ -339,6 +339,9 @@ private void OnItemCheckLavaDeath(On_Item.orig_CheckLavaDeath orig, Item self, i private int OnNPCStrikeNPC(On_NPC.orig_StrikeNPC_HitInfo_bool_bool orig, NPC self, NPC.HitInfo hit, bool fromNet, bool noPlayerInteraction) { + if (!Main.dedServ && !fromNet) + PlayHitMarker(hit.Damage); + var adventureSelf = self.GetGlobalNPC(); // If this was a non-player strike, treat it as damage for all teams. @@ -350,7 +353,9 @@ private int OnNPCStrikeNPC(On_NPC.orig_StrikeNPC_HitInfo_bool_bool orig, NPC sel return orig(self, hit, fromNet, noPlayerInteraction); } + // Always hide PvE combat text with a team, we display our own. hit.HideCombatText = true; + CombatText.NewText(new Rectangle( (int)self.position.X, (int)self.position.Y, @@ -369,7 +374,7 @@ private int OnNPCStrikeNPC(On_NPC.orig_StrikeNPC_HitInfo_bool_bool orig, NPC sel var damage = Math.Max(0, self.life - teamLife); - // Can't deal 0 damage, so help the game out a bit. + // Can't deal 0 damage! if (damage == 0) self.immortal = true; @@ -512,20 +517,6 @@ public override void ModifyHitByProjectile(NPC npc, Projectile projectile, ref N MarkNextStrikeForTeam((Team)player.team); } - // This only runs on the attacking player - public override void OnHitByItem(NPC npc, Player player, Item item, NPC.HitInfo hit, int damageDone) - { - if (!Main.dedServ) - PlayHitMarker(damageDone); - } - - // This only runs on the attacking player - public override void OnHitByProjectile(NPC npc, Projectile projectile, NPC.HitInfo hit, int damageDone) - { - if (!Main.dedServ) - PlayHitMarker(damageDone); - } - public override void EditSpawnRate(Player player, ref int spawnRate, ref int maxSpawns) { if (ModContent.GetInstance()?.CurrentPhase == GameManager.Phase.Waiting) From ec486479b6825661c5a1d3a547f106a9e801d6ab Mon Sep 17 00:00:00 2001 From: James Puleo Date: Fri, 22 Aug 2025 17:59:43 -0400 Subject: [PATCH 063/206] WIP some work --- AdventureNpc.cs | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/AdventureNpc.cs b/AdventureNpc.cs index 8b9b790e..cac8d975 100644 --- a/AdventureNpc.cs +++ b/AdventureNpc.cs @@ -23,7 +23,7 @@ public class AdventureNpc : GlobalNPC public override bool InstancePerEntity => true; public DamageInfo LastDamageFromPlayer { get; set; } - private readonly Dictionary _life = new(); + public Dictionary TeamLife { get; } = new(); private Team? _strikeTeam; public class DamageInfo(byte who) @@ -125,7 +125,18 @@ public override void SetDefaults(NPC entity) } foreach (var team in Enum.GetValues()) - _life[team] = entity.lifeMax; + { + if (team == Team.None) + continue; + + TeamLife[team] = entity.lifeMax; + } + } + + public override void BossHeadSlot(NPC npc, ref int index) + { + if (npc.type == NPCID.Paladin) + index = NPCID.Sets.BossHeadTextures[NPCID.KingSlime]; } public override void OnSpawn(NPC npc, IEntitySource source) @@ -345,10 +356,10 @@ private int OnNPCStrikeNPC(On_NPC.orig_StrikeNPC_HitInfo_bool_bool orig, NPC sel var adventureSelf = self.GetGlobalNPC(); // If this was a non-player strike, treat it as damage for all teams. - if (adventureSelf._strikeTeam == null) + if (adventureSelf._strikeTeam is null or Team.None) { - foreach (var team in adventureSelf._life.Keys) - adventureSelf._life[team] = Math.Max(0, adventureSelf._life[team] - hit.Damage); + foreach (var team in adventureSelf.TeamLife.Keys) + adventureSelf.TeamLife[team] = Math.Max(0, adventureSelf.TeamLife[team] - hit.Damage); return orig(self, hit, fromNet, noPlayerInteraction); } @@ -369,8 +380,8 @@ private int OnNPCStrikeNPC(On_NPC.orig_StrikeNPC_HitInfo_bool_bool orig, NPC sel try { // FIXME: wrong place to get damage sorta, what abt InstantKill etc? - var teamLife = Math.Max(0, adventureSelf._life[adventureSelf._strikeTeam.Value] - hit.Damage); - adventureSelf._life[adventureSelf._strikeTeam.Value] = teamLife; + var teamLife = Math.Max(0, adventureSelf.TeamLife[adventureSelf._strikeTeam.Value] - hit.Damage); + adventureSelf.TeamLife[adventureSelf._strikeTeam.Value] = teamLife; var damage = Math.Max(0, self.life - teamLife); From 7105311f8c8070edb1dd5093c753ef1bc98e5bf0 Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Fri, 22 Aug 2025 15:10:03 -0700 Subject: [PATCH 064/206] Removed Dih Fishron Wings but added recipe --- AdventureDropDatabase.cs | 16 ++++++++++++++++ Localization/en-US.hjson | 2 +- System/RecipeManager.cs | 2 +- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/AdventureDropDatabase.cs b/AdventureDropDatabase.cs index 17c3d743..b8a054e8 100644 --- a/AdventureDropDatabase.cs +++ b/AdventureDropDatabase.cs @@ -284,8 +284,24 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) ItemID.SorcererEmblem, ItemID.SummonerEmblem ])); + break; + case NPCID.DukeFishron: + + npcLoot.RemoveWhere(drop => + (drop is CommonDrop commonDrop && commonDrop.itemId == ItemID.FishronWings) || + drop is DropBasedOnExpertMode); + + npcLoot.Add(new LeadingConditionRule(AdventureIsPreHardmode.The)) + .OnSuccess(ItemDropRule.OneFromOptions(1, [ + ItemID.TempestStaff, + ItemID.RazorbladeTyphoon, + ItemID.BubbleGun, + ItemID.Tsunami, + ItemID.Flairon + ])); + break; } } diff --git a/Localization/en-US.hjson b/Localization/en-US.hjson index 55c0cc62..40c9cab4 100644 --- a/Localization/en-US.hjson +++ b/Localization/en-US.hjson @@ -726,7 +726,7 @@ Mods: { } BuffDescription: { - BeetleMight1: Melee damage and speed increase by 15% + BeetleMight1: Melee damage and speed increase by 15% BeetleMight2: Melee damage and speed increase by 25% BeetleMight3: Melee damage increase by 30% and melee speed increase by 45% } diff --git a/System/RecipeManager.cs b/System/RecipeManager.cs index 2b304a0e..d3eba57f 100644 --- a/System/RecipeManager.cs +++ b/System/RecipeManager.cs @@ -139,7 +139,6 @@ private static void CreateDuplicateDropRecipe(List lootTable, int amountOfM } } } - public class AnyGolem1 : ModSystem { public static RecipeGroup AnyGolemPrimary; @@ -289,6 +288,7 @@ public class AnyDuke1 : ModSystem ItemID.Flairon, ItemID.Tsunami, ItemID.TempestStaff, + ItemID.FishronWings, }; public override void AddRecipeGroups() From 79798b8e10ead10cbb661e271b473191efb603e4 Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Fri, 22 Aug 2025 16:21:07 -0700 Subject: [PATCH 065/206] this is so ass --- Dogshit.cs | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 Dogshit.cs diff --git a/Dogshit.cs b/Dogshit.cs new file mode 100644 index 00000000..d406672c --- /dev/null +++ b/Dogshit.cs @@ -0,0 +1,42 @@ +using Terraria; +using Terraria.ModLoader; +using Terraria.ID; + +namespace PvPAdventure +{ + public class RainSystem : ModSystem + { + private bool triggeredToday; + + public override void PreUpdateWorld() + { + if (Main.netMode == NetmodeID.Server) return; + + if (Main.dayTime && Main.time == 0) + { + triggeredToday = false; + } + + if (Main.dayTime && + !triggeredToday && + Main.time >= 17524) + { + + if (Main.rand.NextBool(3)) + { + StartRain(); + } + triggeredToday = true; + } + } + + private void StartRain() + { + Main.rainTime = Main.rand.Next(3600, 18000); + Main.raining = true; + + if (Main.netMode == NetmodeID.MultiplayerClient) + NetMessage.SendData(MessageID.WorldData); + } + } +} \ No newline at end of file From b04b63be5cc3b3fcdbadffbbae6887653e1cceb1 Mon Sep 17 00:00:00 2001 From: minitoast99 Date: Sun, 24 Aug 2025 01:26:54 -0400 Subject: [PATCH 066/206] Added bound demolitionist --- Assets/NPC/Bound/BoundDemolitionist.png | Bin 0 -> 797 bytes BoundNpc.cs | 36 ++++++++++++++++++++++++ PvPAdventure.csproj | 1 + PvPAdventure.sln | 25 ++++++++++++++++ 4 files changed, 62 insertions(+) create mode 100644 Assets/NPC/Bound/BoundDemolitionist.png create mode 100644 PvPAdventure.sln diff --git a/Assets/NPC/Bound/BoundDemolitionist.png b/Assets/NPC/Bound/BoundDemolitionist.png new file mode 100644 index 0000000000000000000000000000000000000000..cb2cfb8c905c166ade740bda612755d84f29e813 GIT binary patch literal 797 zcmV+&1LFLNP)Px%*GWV{R9J=WmrqDkQ5431Q>J6hLeLp;L~tYrLKyrLDHP!%7zlJ36b3B<%gRNF zMXQQv5#pktETlyw<~ovu$`%G{r7|=MK^j;pHP%prDN3)!@s9JJZ^nw48_~CU+;h%7 z_kNsn?m5rF2H06yX(X;~XL{dNFe&CLN2eYYZhEPnOJXd@`5v*Qy#WuG=i>)xg6e3t<*c>O#8(TNe0 z-svs?ATrPmz?9SAT~AxK>wL$NMN9D9I+&)(pS|< zJuxcvq>oYi(PIEyd^rX{N8##+4z{@xB- zRA8>Nh8Brkeyz+D?!5~Dgs(K4?DR9bAFQ^OPtVQ(P!f>Y^lqE{ZJZ2Tmi6&-095$Q z`}8xiLNQcz5^le+s>!jnk7uFwI#N(Khk46dV0{_xH8lZ{C+$pM9sPU#C>|sKOhg2; z@|V4?FO7`@u&;D0*i1cr*PcK^U-Hk$Y!>0N;VZKe+vI+ b@88A`7?kp7*&{ED00000NkvXXu0mjfZE;%3 literal 0 HcmV?d00001 diff --git a/BoundNpc.cs b/BoundNpc.cs index ce6a6ad0..83ac2481 100644 --- a/BoundNpc.cs +++ b/BoundNpc.cs @@ -257,4 +257,40 @@ protected override void Transform(int whoAmI) NetMessage.SendData(MessageID.WorldData); } } + public class Demolitionist : BoundNpc + { + public override int TransformInto => NPCID.Demolitionist; + + public override void SetDefaults() + { + base.SetDefaults(); + + NPC.width = 26; + NPC.height = 46; + NPC.dontTakeDamage = false; + } + + public override float SpawnChance(NPCSpawnInfo spawnInfo) + { + // Don't spawn if we shouldn't. + if (!NPC.SpawnAllowed_Demolitionist()) + return 0.0f; + + // Don't spawn if we aren't in the caverns layer. + if (!spawnInfo.Player.ZoneRockLayerHeight) + return 0.0f; + // FIXME: What is this doing...? this is what bound goblin does! + if (spawnInfo.SpawnTileY >= Main.maxTilesY - 210) + return 0.0f; + + return base.SpawnChance(spawnInfo); + } + + protected override void Transform(int whoAmI) + { + base.Transform(whoAmI); + NPC.unlockedDemolitionistSpawn = true; + NetMessage.SendData(MessageID.WorldData); + } + } } \ No newline at end of file diff --git a/PvPAdventure.csproj b/PvPAdventure.csproj index 3ccc18c4..1cb28763 100644 --- a/PvPAdventure.csproj +++ b/PvPAdventure.csproj @@ -5,6 +5,7 @@ latest + diff --git a/PvPAdventure.sln b/PvPAdventure.sln new file mode 100644 index 00000000..aaf7ab5e --- /dev/null +++ b/PvPAdventure.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.11.35222.181 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PvPAdventure", "PvPAdventure.csproj", "{4B843C62-7DA3-4C31-AA4D-C4C89F713B19}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4B843C62-7DA3-4C31-AA4D-C4C89F713B19}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4B843C62-7DA3-4C31-AA4D-C4C89F713B19}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4B843C62-7DA3-4C31-AA4D-C4C89F713B19}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4B843C62-7DA3-4C31-AA4D-C4C89F713B19}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {5A050508-409F-4B53-9CE4-111ADA59C172} + EndGlobalSection +EndGlobal From f96dd9f37b809520ef5c33e97ee6f9f37c6a0f60 Mon Sep 17 00:00:00 2001 From: minitoast99 Date: Sun, 24 Aug 2025 02:31:56 -0400 Subject: [PATCH 067/206] If player has paladin's shield equipped then they cant receive the buff from other players --- AdventurePlayer.cs | 5 +++++ .../{BoundDemolitionist.png => Demolitionist.png} | Bin Localization/en-US.hjson | 1 + PvPAdventure.csproj | 2 +- 4 files changed, 7 insertions(+), 1 deletion(-) rename Assets/NPC/Bound/{BoundDemolitionist.png => Demolitionist.png} (100%) diff --git a/AdventurePlayer.cs b/AdventurePlayer.cs index 5d7a082a..da49a032 100644 --- a/AdventurePlayer.cs +++ b/AdventurePlayer.cs @@ -723,6 +723,10 @@ public override void PostUpdateEquips() Player.noKnockback = true; } + if (Player.hasPaladinShield) + { + Player.buffImmune[BuffID.PaladinsShield] = true; + } } private bool IsShinyStoneEquipped() @@ -1134,6 +1138,7 @@ public override void PostUpdateBuffs() public override void PostUpdateEquips() { + if (hasDefenseReduction) { // Calculate 33% reduction (rounded down) diff --git a/Assets/NPC/Bound/BoundDemolitionist.png b/Assets/NPC/Bound/Demolitionist.png similarity index 100% rename from Assets/NPC/Bound/BoundDemolitionist.png rename to Assets/NPC/Bound/Demolitionist.png diff --git a/Localization/en-US.hjson b/Localization/en-US.hjson index 40c9cab4..1a94a02f 100644 --- a/Localization/en-US.hjson +++ b/Localization/en-US.hjson @@ -696,6 +696,7 @@ Mods: { } Chat: At long last, I'm saved! The strangest people tied me up, they mentioned something about a hardcore challenge... + Demolitionist.DisplayName: Bound. Demolitionist } } diff --git a/PvPAdventure.csproj b/PvPAdventure.csproj index 1cb28763..9f004e77 100644 --- a/PvPAdventure.csproj +++ b/PvPAdventure.csproj @@ -5,7 +5,7 @@ latest - + From 4ae4d3e2b809da347925e6d2f6c07a574bed21db Mon Sep 17 00:00:00 2001 From: James Puleo Date: Fri, 29 Aug 2025 03:04:57 -0400 Subject: [PATCH 068/206] do like some fuck-shit to make boss drops instanced per killer --- AdventureDropDatabase.cs | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/AdventureDropDatabase.cs b/AdventureDropDatabase.cs index 0c92b5dd..e8d04cee 100644 --- a/AdventureDropDatabase.cs +++ b/AdventureDropDatabase.cs @@ -6,7 +6,7 @@ namespace PvPAdventure; -public static class AdventureDropDatabase +public class AdventureDropDatabase : ModSystem { private class AdventureIsPreHardmode : IItemDropRuleCondition { @@ -21,6 +21,27 @@ private AdventureIsPreHardmode() public string GetConditionDescription() => "Drops pre-hardmode"; } + public override void Load() + { + On_CommonCode._DropItemFromNPC += (orig, npc, id, stack, scattered) => + { + // If we are the server, check if the drops should be instanced instead. + if (Main.dedServ && npc.boss) + { + var number = Item.NewItem(npc.GetSource_Loot(), npc.Hitbox, id, stack, true, -1); + + // FIXME: magic time unit + Main.timeItemSlotCannotBeReusedFor[number] = 54000; + NetMessage.SendData(MessageID.InstancedItem, remoteClient: npc.lastInteraction, number: number); + Main.item[number].active = false; + } + else + { + orig(npc, id, stack, scattered); + } + }; + } + private static void ModifyDropRate(IItemDropRule rule, int type, int numerator, int denominator) { if (rule is CommonDrop commonDrop && commonDrop.itemId == type) From c82df0c1aa826d9cdddc191c6f1234edaa9d6d97 Mon Sep 17 00:00:00 2001 From: James Puleo Date: Fri, 29 Aug 2025 03:05:43 -0400 Subject: [PATCH 069/206] share damage do other teams --- AdventureNpc.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/AdventureNpc.cs b/AdventureNpc.cs index cac8d975..58c73081 100644 --- a/AdventureNpc.cs +++ b/AdventureNpc.cs @@ -385,6 +385,12 @@ private int OnNPCStrikeNPC(On_NPC.orig_StrikeNPC_HitInfo_bool_bool orig, NPC sel var damage = Math.Max(0, self.life - teamLife); + foreach (var team in adventureSelf.TeamLife.Keys) + { + if (team != adventureSelf._strikeTeam.Value) + adventureSelf.TeamLife[team] = Math.Max(self.life, adventureSelf.TeamLife[team] - (damage / 2)); + } + // Can't deal 0 damage! if (damage == 0) self.immortal = true; From 55d318dd26df8752f353b9aab46efb0bcdaad123 Mon Sep 17 00:00:00 2001 From: James Puleo Date: Fri, 29 Aug 2025 03:07:21 -0400 Subject: [PATCH 070/206] WIP FIXME WRONG PLACE null out bossbar when clearing world TML BUG --- System/GameManager.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/System/GameManager.cs b/System/GameManager.cs index b4c2e46f..605b7d94 100644 --- a/System/GameManager.cs +++ b/System/GameManager.cs @@ -1,6 +1,7 @@ using System; using System.IO; using System.Linq; +using System.Reflection; using Humanizer; using Humanizer.Localisation; using Terraria; @@ -11,6 +12,7 @@ using Terraria.GameContent.Creative; using Terraria.GameContent.Events; using Terraria.GameContent.NetModules; +using Terraria.GameContent.UI.BigProgressBar; using Terraria.Localization; using Terraria.ModLoader; using Terraria.Net; @@ -24,6 +26,9 @@ public class GameManager : ModSystem private int? _startGameCountdown = 0; private Phase _currentPhase; + private static readonly FieldInfo _bigProgressBarSystemCurrentBarField = + typeof(BigProgressBarSystem).GetField("_currentBar", BindingFlags.NonPublic | BindingFlags.Instance); + public Phase CurrentPhase { get => _currentPhase; @@ -251,6 +256,10 @@ public override void ClearWorld() if (Main.netMode != NetmodeID.MultiplayerClient && CurrentPhase != Phase.Waiting) OnPhaseChange(Phase.Waiting); CurrentPhase = Phase.Waiting; + + // Terraria/TML bug: Remove boss bar when clearing the world + // FIXME: Don't put this here! + _bigProgressBarSystemCurrentBarField.SetValue(Main.BigBossProgressBar, null); } public override void NetSend(BinaryWriter writer) From 371a31d355ec1fe719f1ae16c237ada9e4dc49f2 Mon Sep 17 00:00:00 2001 From: James Puleo Date: Fri, 29 Aug 2025 03:07:57 -0400 Subject: [PATCH 071/206] here is the boss bar --- AdventureBossBar.cs | 50 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 AdventureBossBar.cs diff --git a/AdventureBossBar.cs b/AdventureBossBar.cs new file mode 100644 index 00000000..90e40458 --- /dev/null +++ b/AdventureBossBar.cs @@ -0,0 +1,50 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using Terraria; +using Terraria.DataStructures; +using Terraria.Enums; +using Terraria.GameContent; +using Terraria.ModLoader; + +namespace PvPAdventure; + +public class AdventureBossBar : GlobalBossBar +{ + public override void PostDraw(SpriteBatch spriteBatch, NPC npc, BossBarDrawParams drawParams) + { + // This is a constant position from BigProgressBarHelper.DrawFancyBar + var bossBarPosition = new Point(456, 22); + + // Calculated as BigProgressBarHelper does + var rectangle = + Utils.CenteredRectangle(Main.ScreenSize.ToVector2() * new Vector2(0.5f, 1f) + new Vector2(0f, -50f), + bossBarPosition.ToVector2()); + + foreach (var (team, life) in npc.GetGlobalNPC().TeamLife) + { + // This isn't normally possibly, but we for sure can't draw this. + if (team == Team.None) + continue; + + var lifePercent = (float)life / npc.lifeMax; + + var frame = TextureAssets.Pvp[1].Value.Frame(6); + frame.X = frame.Width * (int)team; + + // FIXME: looks silly when overlapping, because alpha colors blend... + // maybe stack/stagger them? that takes math. + var color = Color.White; + color *= lifePercent.Remap(0.85f, 1.0f, 1.0f, 0.0f); + + spriteBatch.Draw( + TextureAssets.Pvp[1].Value, + rectangle.TopLeft() + new Vector2( + (bossBarPosition.X * lifePercent) - (frame.Height / 2.0f), + -30.0f + ), + frame, + color + ); + } + } +} \ No newline at end of file From 9bff2ae2e4c086d57c054b587afa511a7789f7a8 Mon Sep 17 00:00:00 2001 From: James Puleo Date: Fri, 29 Aug 2025 04:29:58 -0400 Subject: [PATCH 072/206] var name edit nbc --- AdventureBossBar.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/AdventureBossBar.cs b/AdventureBossBar.cs index 90e40458..af144f78 100644 --- a/AdventureBossBar.cs +++ b/AdventureBossBar.cs @@ -26,7 +26,7 @@ public override void PostDraw(SpriteBatch spriteBatch, NPC npc, BossBarDrawParam if (team == Team.None) continue; - var lifePercent = (float)life / npc.lifeMax; + var lifeRemaining = (float)life / npc.lifeMax; var frame = TextureAssets.Pvp[1].Value.Frame(6); frame.X = frame.Width * (int)team; @@ -34,12 +34,12 @@ public override void PostDraw(SpriteBatch spriteBatch, NPC npc, BossBarDrawParam // FIXME: looks silly when overlapping, because alpha colors blend... // maybe stack/stagger them? that takes math. var color = Color.White; - color *= lifePercent.Remap(0.85f, 1.0f, 1.0f, 0.0f); + color *= lifeRemaining.Remap(0.85f, 1.0f, 1.0f, 0.0f); spriteBatch.Draw( TextureAssets.Pvp[1].Value, rectangle.TopLeft() + new Vector2( - (bossBarPosition.X * lifePercent) - (frame.Height / 2.0f), + (bossBarPosition.X * lifeRemaining) - (frame.Height / 2.0f), -30.0f ), frame, From e832b6348b4f934bbb3520dfb0b8254a36eb60be Mon Sep 17 00:00:00 2001 From: James Puleo Date: Fri, 29 Aug 2025 07:03:55 -0400 Subject: [PATCH 073/206] nit comment --- AdventureBossBar.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AdventureBossBar.cs b/AdventureBossBar.cs index af144f78..6308d074 100644 --- a/AdventureBossBar.cs +++ b/AdventureBossBar.cs @@ -22,7 +22,7 @@ public override void PostDraw(SpriteBatch spriteBatch, NPC npc, BossBarDrawParam foreach (var (team, life) in npc.GetGlobalNPC().TeamLife) { - // This isn't normally possibly, but we for sure can't draw this. + // Shouldn't be possible, but be sure not to draw this. if (team == Team.None) continue; From 3336b3d47b76cc843562c5d9cb365c34abdbcce1 Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Fri, 29 Aug 2025 15:58:40 -0700 Subject: [PATCH 074/206] Bro is a choj when he wears his turtle armor --- AdventurePlayer.cs | 59 +++++++++++++++++++++++++++++++++++++ Assets/Buff/BROISACHOJ.PNG | Bin 0 -> 103916 bytes Localization/en-US.hjson | 7 ++++- 3 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 Assets/Buff/BROISACHOJ.PNG diff --git a/AdventurePlayer.cs b/AdventurePlayer.cs index 5d7a082a..9f25be6f 100644 --- a/AdventurePlayer.cs +++ b/AdventurePlayer.cs @@ -3,10 +3,12 @@ using System.Diagnostics; using System.IO; using System.Linq; +using System.Reflection; using System.Threading.Tasks; using Discord.Rest; using Microsoft.Xna.Framework; using MonoMod.Cil; +using MonoMod.RuntimeDetour; using PvPAdventure.System; using PvPAdventure.System.Client; using Terraria; @@ -19,6 +21,7 @@ using Terraria.ModLoader; using Terraria.ModLoader.Config; using Terraria.ModLoader.IO; +using Mono.Cecil.Cil; namespace PvPAdventure; @@ -1132,6 +1135,49 @@ public override void PostUpdateBuffs() } } + public class TurtleDashPlayer : ModPlayer + { + private bool isWearingFullTurtleArmor = false; + private int dashingTimer = 0; + + // Detect if player is in a dash state + public bool IsInADashState => (Player.dashDelay == -1 || dashingTimer > 0) && Player.grapCount <= 0; + + public override void PostUpdateEquips() + { + + isWearingFullTurtleArmor = Player.armor[0].type == ItemID.TurtleHelmet && + Player.armor[1].type == ItemID.TurtleScaleMail && + Player.armor[2].type == ItemID.TurtleLeggings; + + if (isWearingFullTurtleArmor) + { + Player.AddBuff(ModContent.BuffType(), 15 * 60 * 60); + } + } + + public override void PostUpdate() + { + + if (Player.dashDelay == -1) + { + dashingTimer = 10; + } + else if (dashingTimer > 0) + { + dashingTimer--; + } + + // Apply dash speed reduction if player has the debuff and is dashing + if (Player.HasBuff(ModContent.BuffType()) && IsInADashState) + { + float dashSpeedReduction = Player.velocity.X * 0.2f; + Player.velocity.X -= dashSpeedReduction; + } + //thanks mr fargo + } + } + public override void PostUpdateEquips() { if (hasDefenseReduction) @@ -1144,6 +1190,7 @@ public override void PostUpdateEquips() } } } + public class ShinyStoneHotswap : ModBuff { public override string Texture => $"PvPAdventure/Assets/Buff/ShinyStoneHotswap"; @@ -1179,4 +1226,16 @@ public override void SetStaticDefaults() Main.buffNoTimeDisplay[Type] = false; Main.persistentBuff[Type] = false; } +} +public class BROISACHOJ : ModBuff +{ + public override string Texture => $"PvPAdventure/Assets/Buff/BROISACHOJ"; + + public override void SetStaticDefaults() + { + Main.debuff[Type] = true; + Main.buffNoSave[Type] = false; + Main.buffNoTimeDisplay[Type] = false; + Main.persistentBuff[Type] = true; + } } \ No newline at end of file diff --git a/Assets/Buff/BROISACHOJ.PNG b/Assets/Buff/BROISACHOJ.PNG new file mode 100644 index 0000000000000000000000000000000000000000..98b2fde3506cec162feb4c1d05649391e7fbab6b GIT binary patch literal 103916 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 l}; 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≻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 ei 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 Date: Fri, 29 Aug 2025 16:54:42 -0700 Subject: [PATCH 075/206] cahnghed image --- Assets/Buff/1.PNG | Bin 0 -> 103916 bytes Assets/Buff/BROISACHOJ.PNG | Bin 103916 -> 2839 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 Assets/Buff/1.PNG diff --git a/Assets/Buff/1.PNG b/Assets/Buff/1.PNG new file mode 100644 index 0000000000000000000000000000000000000000..98b2fde3506cec162feb4c1d05649391e7fbab6b GIT binary patch literal 103916 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 l}; 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≻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 ei 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 literal 103916 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 l}; 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≻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 ei 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 Date: Fri, 29 Aug 2025 16:58:11 -0700 Subject: [PATCH 076/206] cahgned dash values --- AdventurePlayer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AdventurePlayer.cs b/AdventurePlayer.cs index 0575c069..35ffe4a8 100644 --- a/AdventurePlayer.cs +++ b/AdventurePlayer.cs @@ -1156,7 +1156,7 @@ public override void PostUpdateEquips() if (isWearingFullTurtleArmor) { - Player.AddBuff(ModContent.BuffType(), 15 * 60 * 60); + Player.AddBuff(ModContent.BuffType(), 1 * 60 * 60); } } @@ -1175,7 +1175,7 @@ public override void PostUpdate() // Apply dash speed reduction if player has the debuff and is dashing if (Player.HasBuff(ModContent.BuffType()) && IsInADashState) { - float dashSpeedReduction = Player.velocity.X * 0.2f; + float dashSpeedReduction = Player.velocity.X * 0.05f; Player.velocity.X -= dashSpeedReduction; } //thanks mr fargo From 9e81e70f715783b4d1c3c34835200f74af5a91f9 Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Fri, 29 Aug 2025 18:19:56 -0700 Subject: [PATCH 077/206] tons of changes and we also added a new system --- AdventureDropDatabase.cs | 54 +++++----- System/FirstKillSystem.cs | 201 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 231 insertions(+), 24 deletions(-) create mode 100644 System/FirstKillSystem.cs diff --git a/AdventureDropDatabase.cs b/AdventureDropDatabase.cs index 3fe56b10..aa5fd288 100644 --- a/AdventureDropDatabase.cs +++ b/AdventureDropDatabase.cs @@ -7,6 +7,9 @@ using Terraria.ID; using Terraria.ModLoader; using Mono.Cecil.Cil; +using static PvPAdventure.System.BountyManager; +using static PvPAdventure.AdventureConfig; +using PvPAdventure.System; namespace PvPAdventure; @@ -190,14 +193,12 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) break; case NPCID.Golem: - // Remove Picksaw drop, and the big loot pool -- we will re-create it ourselves. npcLoot.RemoveWhere(drop => (drop is CommonDrop commonDrop && commonDrop.itemId == ItemID.Picksaw) || drop is LeadingConditionRule); var stynger = ItemDropRule.Common(ItemID.Stynger); stynger.OnSuccess(ItemDropRule.Common(ItemID.StyngerBolt, 1, 60, 99), hideLootReport: true); - npcLoot.Add( new OneFromRulesRule(1, stynger, @@ -208,34 +209,39 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) ) ); - npcLoot.Add(ItemDropRule.OneFromOptions(1, + + var golemFirstKillRule = new LeadingConditionRule(new FirstBossKillCondition(NPCID.Golem)); + golemFirstKillRule.OnSuccess(ItemDropRule.Common(ItemID.Picksaw, 1)); + golemFirstKillRule.OnFailedConditions(ItemDropRule.OneFromOptions(1, ItemID.Picksaw, ItemID.EyeoftheGolem, ItemID.SunStone, - ItemID.ShinyStone) - ); + ItemID.ShinyStone + )); + npcLoot.Add(golemFirstKillRule); break; case NPCID.QueenSlimeBoss: - // Remove the big loot pool -- we will re-create it ourselves. + npcLoot.RemoveWhere(drop => drop is LeadingConditionRule); - // Always get two pieces of the Crystal Ninja set, separate from other drops. - npcLoot.Add(ItemDropRule.FewFromOptions(2, 1, + + var firstKillRule = new LeadingConditionRule(new FirstBossKillCondition(NPCID.QueenSlimeBoss)); + firstKillRule.OnSuccess(ItemDropRule.Common(ItemID.QueenSlimeMountSaddle, 1)); + firstKillRule.OnFailedConditions(ItemDropRule.OneFromOptions(1, + ItemID.Smolstar, + ItemID.QueenSlimeHook, + ItemID.QueenSlimeMountSaddle + )); + + npcLoot.Add(ItemDropRule.FewFromOptions(3, 1, ItemID.CrystalNinjaHelmet, ItemID.CrystalNinjaChestplate, ItemID.CrystalNinjaLeggings ) ); - - npcLoot.Add(ItemDropRule.OneFromOptions(1, - ItemID.Smolstar, - ItemID.QueenSlimeHook, - ItemID.QueenSlimeMountSaddle - ) - ); - + npcLoot.Add(firstKillRule); break; case NPCID.QueenBee: @@ -277,15 +283,15 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) break; case NPCID.WallofFlesh: - npcLoot.Add(new LeadingConditionRule(AdventureIsPreHardmode.The)) - .OnSuccess(ItemDropRule.OneFromOptions(1, [ - ItemID.WarriorEmblem, - ItemID.RangerEmblem, - ItemID.SorcererEmblem, - ItemID.SummonerEmblem - ])); + var wofFirstKillRule = new LeadingConditionRule(new FirstBossKillCondition(NPCID.WallofFlesh)); + wofFirstKillRule.OnSuccess(ItemDropRule.OneFromOptions(1, + ItemID.WarriorEmblem, + ItemID.RangerEmblem, + ItemID.SorcererEmblem, + ItemID.SummonerEmblem + )); + npcLoot.Add(wofFirstKillRule); break; - } } diff --git a/System/FirstKillSystem.cs b/System/FirstKillSystem.cs new file mode 100644 index 00000000..33ad9980 --- /dev/null +++ b/System/FirstKillSystem.cs @@ -0,0 +1,201 @@ +using System; +using System.Collections.Generic; +using Terraria; +using Terraria.ID; +using Terraria.GameContent.ItemDropRules; +using Terraria.ModLoader; +using Microsoft.Xna.Framework; + +namespace PvPAdventure.System +{ + // BossTrackingSystem.cs - Put this in its own file + public class BossTrackingSystem : ModSystem + { + // Dictionary to track first kills for all bosses + public static Dictionary FirstBossKills { get; set; } = new Dictionary(); + + // Dictionary to track previous downed states + public static Dictionary PreviousDownedStates { get; set; } = new Dictionary(); + + // Initialize boss tracking + public override void PostSetupContent() + { + InitializeBossTracking(); + } + + private void InitializeBossTracking() + { + // Initialize all boss first kill flags to false + var bossTypes = new int[] + { + NPCID.KingSlime, + NPCID.EyeofCthulhu, + NPCID.EaterofWorldsHead, + NPCID.BrainofCthulhu, + NPCID.QueenBee, + NPCID.SkeletronHead, + NPCID.WallofFlesh, + NPCID.QueenSlimeBoss, + NPCID.TheDestroyer, + NPCID.Retinazer, + NPCID.Spazmatism, + NPCID.SkeletronPrime, + NPCID.Plantera, + NPCID.Golem, + NPCID.DukeFishron, + NPCID.HallowBoss, // Empress of Light + NPCID.CultistBoss, + NPCID.MoonLordCore + }; + + foreach (int bossType in bossTypes) + { + if (!FirstBossKills.ContainsKey(bossType)) + FirstBossKills[bossType] = false; + } + + // Initialize previous downed states + UpdatePreviousDownedStates(); + } + + private void UpdatePreviousDownedStates() + { + PreviousDownedStates["KingSlime"] = NPC.downedSlimeKing; + PreviousDownedStates["EyeofCthulhu"] = NPC.downedBoss1; + PreviousDownedStates["EvilBoss"] = NPC.downedBoss2; // Eater of Worlds or Brain of Cthulhu + PreviousDownedStates["QueenBee"] = NPC.downedQueenBee; + PreviousDownedStates["Skeletron"] = NPC.downedBoss3; + PreviousDownedStates["WallofFlesh"] = Main.hardMode; + PreviousDownedStates["QueenSlime"] = NPC.downedQueenSlime; + PreviousDownedStates["Destroyer"] = NPC.downedMechBoss1; + PreviousDownedStates["Twins"] = NPC.downedMechBoss2; + PreviousDownedStates["SkeletronPrime"] = NPC.downedMechBoss3; + PreviousDownedStates["Plantera"] = NPC.downedPlantBoss; + PreviousDownedStates["Golem"] = NPC.downedGolemBoss; + PreviousDownedStates["DukeFishron"] = NPC.downedFishron; + PreviousDownedStates["EmpressOfLight"] = NPC.downedEmpressOfLight; + PreviousDownedStates["Cultist"] = NPC.downedAncientCultist; + PreviousDownedStates["MoonLord"] = NPC.downedMoonlord; + } + + public override void PostUpdateWorld() + { + CheckForFirstBossDefeats(); + } + + private void CheckForFirstBossDefeats() + { + CheckBossDefeat("KingSlime", NPCID.KingSlime, NPC.downedSlimeKing); + CheckBossDefeat("EyeofCthulhu", NPCID.EyeofCthulhu, NPC.downedBoss1); + CheckBossDefeat("EvilBoss", NPC.downedBoss2 ? NPCID.EaterofWorldsHead : NPCID.BrainofCthulhu, NPC.downedBoss2); + CheckBossDefeat("QueenBee", NPCID.QueenBee, NPC.downedQueenBee); + CheckBossDefeat("Skeletron", NPCID.SkeletronHead, NPC.downedBoss3); + CheckBossDefeat("WallofFlesh", NPCID.WallofFlesh, Main.hardMode); + CheckBossDefeat("QueenSlime", NPCID.QueenSlimeBoss, NPC.downedQueenSlime); + CheckBossDefeat("Destroyer", NPCID.TheDestroyer, NPC.downedMechBoss1); + CheckBossDefeat("Twins", NPCID.Retinazer, NPC.downedMechBoss2); // Could also use Spazmatism + CheckBossDefeat("SkeletronPrime", NPCID.SkeletronPrime, NPC.downedMechBoss3); + CheckBossDefeat("Plantera", NPCID.Plantera, NPC.downedPlantBoss); + CheckBossDefeat("Golem", NPCID.Golem, NPC.downedGolemBoss); + CheckBossDefeat("DukeFishron", NPCID.DukeFishron, NPC.downedFishron); + CheckBossDefeat("EmpressOfLight", NPCID.HallowBoss, NPC.downedEmpressOfLight); + CheckBossDefeat("Cultist", NPCID.CultistBoss, NPC.downedAncientCultist); + CheckBossDefeat("MoonLord", NPCID.MoonLordCore, NPC.downedMoonlord); + } + + private void CheckBossDefeat(string bossKey, int npcID, bool currentDownedState) + { + if (!FirstBossKills.ContainsKey(npcID)) + return; + + // Get previous state, default to false if not found + bool previousState = false; + if (PreviousDownedStates != null && PreviousDownedStates.ContainsKey(bossKey)) + previousState = PreviousDownedStates[bossKey]; + + // If boss wasn't defeated before but is now, mark first kill as complete + if (!previousState && currentDownedState && !FirstBossKills[npcID]) + { + FirstBossKills[npcID] = true; + } + + // Update previous state + if (PreviousDownedStates != null) + PreviousDownedStates[bossKey] = currentDownedState; + } + + private string GetBossName(int npcID) + { + return npcID switch + { + NPCID.KingSlime => "King Slime", + NPCID.EyeofCthulhu => "Eye of Cthulhu", + NPCID.EaterofWorldsHead => "Eater of Worlds", + NPCID.BrainofCthulhu => "Brain of Cthulhu", + NPCID.QueenBee => "Queen Bee", + NPCID.SkeletronHead => "Skeletron", + NPCID.WallofFlesh => "Wall of Flesh", + NPCID.QueenSlimeBoss => "Queen Slime", + NPCID.TheDestroyer => "The Destroyer", + NPCID.Retinazer => "The Twins", + NPCID.SkeletronPrime => "Skeletron Prime", + NPCID.Plantera => "Plantera", + NPCID.Golem => "Golem", + NPCID.DukeFishron => "Duke Fishron", + NPCID.HallowBoss => "Empress of Light", + NPCID.CultistBoss => "Lunatic Cultist", + NPCID.MoonLordCore => "Moon Lord", + _ => "Unknown Boss" + }; + } + } + public class FirstBossKillCondition : IItemDropRuleCondition + { + private readonly int bossType; + + public FirstBossKillCondition(int bossType) + { + this.bossType = bossType; + } + + public bool CanDrop(DropAttemptInfo info) + { + return BossTrackingSystem.FirstBossKills.ContainsKey(bossType) && !BossTrackingSystem.FirstBossKills[bossType]; + } + + public bool CanShowItemDropInUI() + { + return BossTrackingSystem.FirstBossKills.ContainsKey(bossType) && !BossTrackingSystem.FirstBossKills[bossType]; + } + + public string GetConditionDescription() + { + return $"First {GetBossName(bossType)} kill in this world"; + } + + private string GetBossName(int npcID) + { + return npcID switch + { + NPCID.KingSlime => "King Slime", + NPCID.EyeofCthulhu => "Eye of Cthulhu", + NPCID.EaterofWorldsHead => "Eater of Worlds", + NPCID.BrainofCthulhu => "Brain of Cthulhu", + NPCID.QueenBee => "Queen Bee", + NPCID.SkeletronHead => "Skeletron", + NPCID.WallofFlesh => "Wall of Flesh", + NPCID.QueenSlimeBoss => "Queen Slime", + NPCID.TheDestroyer => "The Destroyer", + NPCID.Retinazer => "The Twins", + NPCID.SkeletronPrime => "Skeletron Prime", + NPCID.Plantera => "Plantera", + NPCID.Golem => "Golem", + NPCID.DukeFishron => "Duke Fishron", + NPCID.HallowBoss => "Empress of Light", + NPCID.CultistBoss => "Lunatic Cultist", + NPCID.MoonLordCore => "Moon Lord", + _ => "Unknown Boss" + }; + } + } +} \ No newline at end of file From 40b79ea66e3f98df2776a37df864f32b26c3b33e Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Fri, 29 Aug 2025 23:03:00 -0700 Subject: [PATCH 078/206] changed biome key droprate to 1/250 removed _'s not working code for biome keys in order to do this --- AdventureDropDatabase.cs | 84 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 78 insertions(+), 6 deletions(-) diff --git a/AdventureDropDatabase.cs b/AdventureDropDatabase.cs index 3fe56b10..977163bd 100644 --- a/AdventureDropDatabase.cs +++ b/AdventureDropDatabase.cs @@ -264,6 +264,13 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) ModifyDropRate(drop, ItemID.SkeletronHand, 1, 1); break; + case NPCID.IceTortoise: + npcLoot.RemoveWhere(drop => + (drop is CommonDrop commonDrop && commonDrop.itemId == ItemID.FrozenTurtleShell)); + npcLoot.Add(ItemDropRule.Common(ItemID.FrozenKey, 40, 1, 1)); + foreach (var drop in drops) ; + break; + case NPCID.MartianSaucerCore: foreach (var drop in drops) { @@ -297,12 +304,6 @@ public static IItemDropRule OnItemDropDatabaseRegisterToGlobal(On_ItemDropDataba var disallowed = false; disallowed |= entry is MechBossSpawnersDropRule && adventureConfig.NpcBalance.NoMechanicalBossSummonDrops; - disallowed |= entry is ItemDropWithConditionRule { itemId: ItemID.JungleKey }; - disallowed |= entry is ItemDropWithConditionRule { itemId: ItemID.CorruptionKey }; - disallowed |= entry is ItemDropWithConditionRule { itemId: ItemID.CrimsonKey }; - disallowed |= entry is ItemDropWithConditionRule { itemId: ItemID.HallowedKey }; - disallowed |= entry is ItemDropWithConditionRule { itemId: ItemID.FrozenKey }; - disallowed |= entry is ItemDropWithConditionRule { itemId: ItemID.DungeonDesertKey }; if (!disallowed) orig(self, entry); @@ -348,4 +349,75 @@ private static void PlanteraDropILEdit(ILContext il) } } } + + public class BiomeKeyDropEdit : ModSystem + { + private static ILHook globalRulesHook; + + public override void PostSetupContent() + { + // Apply the IL edit to change biome key drop rates from 2500 to 250 + MethodInfo method = typeof(Terraria.GameContent.ItemDropRules.ItemDropDatabase).GetMethod("RegisterGlobalRules", + BindingFlags.NonPublic | BindingFlags.Instance); + globalRulesHook = new ILHook(method, BiomeKeyDropILEdit); + } + + public override void Unload() + { + globalRulesHook?.Dispose(); + } + + private static void BiomeKeyDropILEdit(ILContext il) + { + ILCursor cursor = new ILCursor(il); + + int replacedCount = 0; + + // We need to find all instances of 2500 that are used for biome keys + // We'll look for the pattern where 2500 is loaded right before creating ItemDropWithConditionRule + while (cursor.TryGotoNext(MoveType.Before, + i => i.MatchLdcI4(2500))) // Match loading the constant 2500 + { + // Check if this is followed by the pattern that indicates it's a biome key drop rule + // We'll look ahead to see if this leads to ItemDropWithConditionRule construction + var nextCursor = cursor.Clone(); + bool isBiomeKey = false; + + // Look for the ItemDropWithConditionRule constructor call within a reasonable distance + for (int j = 0; j < 250; j++) // Look ahead up to 250 instructions + { + if (nextCursor.TryGotoNext(MoveType.After, + i => i.MatchNewobj())) + { + isBiomeKey = true; + break; + } + } + + if (isBiomeKey) + { + // Replace the 2500 with 250 + cursor.Remove(); // Remove the ldc.i4 2500 instruction + cursor.Emit(OpCodes.Ldc_I4, 250); // Emit ldc.i4 250 instead + replacedCount++; + + ModContent.GetInstance().Logger.Info($"Replaced biome key drop rate 2500 with 250 (instance {replacedCount})"); + } + else + { + // Move past this 2500 if it's not a biome key + cursor.Index++; + } + } + + if (replacedCount > 0) + { + ModContent.GetInstance().Logger.Info($"Successfully changed {replacedCount} biome key drop rates from 2500 to 250"); + } + else + { + ModContent.GetInstance().Logger.Error("Failed to find any biome key drop rates (2500) in RegisterGlobalRules method"); + } + } + } } \ No newline at end of file From 94746d6ca85130d9443a92bca6eb0c9e20fd214b Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Sat, 30 Aug 2025 10:51:25 -0700 Subject: [PATCH 079/206] removed unneeded code --- AdventureConfig.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/AdventureConfig.cs b/AdventureConfig.cs index ce8226ad..fd27fe04 100644 --- a/AdventureConfig.cs +++ b/AdventureConfig.cs @@ -335,7 +335,6 @@ public class FloatStatistic public Dictionary LifeMaxMultipliers { get; set; } = new(); public Dictionary DamageMultipliers { get; set; } = new(); public bool NoMechanicalBossSummonDrops { get; set; } - public bool NoBiomeKeyDrops { get; set; } } public NpcBalanceConfig NpcBalance { get; set; } = new(); From e3a6ecf7e8e990418697c62e15046f17cdf63ff0 Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Sat, 30 Aug 2025 11:19:08 -0700 Subject: [PATCH 080/206] ADDED first kill rule wiht new system for plantera --- AdventureDropDatabase.cs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/AdventureDropDatabase.cs b/AdventureDropDatabase.cs index 77a24288..25c2ab82 100644 --- a/AdventureDropDatabase.cs +++ b/AdventureDropDatabase.cs @@ -244,6 +244,26 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) npcLoot.Add(firstKillRule); break; + case NPCID.Plantera: + + npcLoot.RemoveWhere(drop => drop is LeadingConditionRule); + + + var planteraFirstKillRule = new LeadingConditionRule(new FirstBossKillCondition(NPCID.Plantera)); + planteraFirstKillRule.OnSuccess(ItemDropRule.Common(ItemID.VenusMagnum, 1)); + planteraFirstKillRule.OnFailedConditions(ItemDropRule.OneFromOptions(1, + ItemID.LeafBlower, + ItemID.Seedler, + ItemID.NettleBurst, + ItemID.FlowerPow, + ItemID.GrenadeLauncher, + ItemID.WaspGun + + + )); + npcLoot.Add(planteraFirstKillRule); + break; + case NPCID.QueenBee: // Remove Honey Comb drop, and the big loot pool -- we will re-create it ourselves. npcLoot.RemoveWhere(drop => From 071c8d11e0dd07f9d445ea6e9be047d8666d31d8 Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Sat, 30 Aug 2025 11:45:38 -0700 Subject: [PATCH 081/206] nerfed cell raet --- AdventureDropDatabase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AdventureDropDatabase.cs b/AdventureDropDatabase.cs index 25c2ab82..70454df9 100644 --- a/AdventureDropDatabase.cs +++ b/AdventureDropDatabase.cs @@ -179,7 +179,7 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) case NPCID.LihzahrdCrawler: case NPCID.FlyingSnake: foreach (var drop in drops) - ModifyDropRate(drop, ItemID.LihzahrdPowerCell, 1, 50); + ModifyDropRate(drop, ItemID.LihzahrdPowerCell, 1, 75); break; case NPCID.EyeofCthulhu: From 7d8d73ac08ab17c3231d328782c93f917e83205b Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Sat, 30 Aug 2025 11:52:33 -0700 Subject: [PATCH 082/206] cahnged fire featehr rate and removed extra code --- AdventureDropDatabase.cs | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/AdventureDropDatabase.cs b/AdventureDropDatabase.cs index 70454df9..10ab8aba 100644 --- a/AdventureDropDatabase.cs +++ b/AdventureDropDatabase.cs @@ -173,6 +173,8 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) case NPCID.RedDevil: foreach (var drop in drops) ModifyDropRate(drop, ItemID.UnholyTrident, 1, 10); + npcLoot.Add(ItemDropRule.Common(ItemID.FireFeather, 10, 1, 1)); + break; case NPCID.Lihzahrd: @@ -327,15 +329,31 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) (drop is CommonDrop commonDrop && commonDrop.itemId == ItemID.FishronWings) || drop is DropBasedOnExpertMode); - //what does this do? - npcLoot.Add(new LeadingConditionRule(AdventureIsPreHardmode.The)) - .OnSuccess(ItemDropRule.OneFromOptions(1, [ - ItemID.TempestStaff, - ItemID.RazorbladeTyphoon, - ItemID.BubbleGun, - ItemID.Tsunami, - ItemID.Flairon - ])); + break; + + case NPCID.TheDestroyer: + npcLoot.RemoveWhere(drop => + (drop is CommonDrop commonDrop && commonDrop.itemId == ItemID.HallowedBar)); + npcLoot.Add(ItemDropRule.Common(ItemID.HallowedBar, 1, 18, 30)); + + break; + + case NPCID.SkeletronPrime: + npcLoot.RemoveWhere(drop => + (drop is CommonDrop commonDrop && commonDrop.itemId == ItemID.HallowedBar)); + npcLoot.Add(ItemDropRule.Common(ItemID.HallowedBar, 1, 18, 30)); + + break; + + case NPCID.Retinazer or NPCID.Spazmatism: + { + npcLoot.RemoveWhere(drop => (drop is CommonDrop commonDrop && commonDrop.itemId == ItemID.HallowedBar)); + + LeadingConditionRule noTwin = new(new Conditions.MissingTwin()); + npcLoot.Add(noTwin); + + noTwin.OnSuccess(ItemDropRule.Common(ItemID.HallowedBar, 1, 3, 3)); + } break; } } From 3ecac634c508d0516eda17c49231c32f43534575 Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Tue, 2 Sep 2025 17:40:58 -0700 Subject: [PATCH 083/206] reverted plantera changes --- AdventureDropDatabase.cs | 59 ++++++++++++++++++++++++++-------------- 1 file changed, 39 insertions(+), 20 deletions(-) diff --git a/AdventureDropDatabase.cs b/AdventureDropDatabase.cs index 10ab8aba..a9d84289 100644 --- a/AdventureDropDatabase.cs +++ b/AdventureDropDatabase.cs @@ -246,26 +246,6 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) npcLoot.Add(firstKillRule); break; - case NPCID.Plantera: - - npcLoot.RemoveWhere(drop => drop is LeadingConditionRule); - - - var planteraFirstKillRule = new LeadingConditionRule(new FirstBossKillCondition(NPCID.Plantera)); - planteraFirstKillRule.OnSuccess(ItemDropRule.Common(ItemID.VenusMagnum, 1)); - planteraFirstKillRule.OnFailedConditions(ItemDropRule.OneFromOptions(1, - ItemID.LeafBlower, - ItemID.Seedler, - ItemID.NettleBurst, - ItemID.FlowerPow, - ItemID.GrenadeLauncher, - ItemID.WaspGun - - - )); - npcLoot.Add(planteraFirstKillRule); - break; - case NPCID.QueenBee: // Remove Honey Comb drop, and the big loot pool -- we will re-create it ourselves. npcLoot.RemoveWhere(drop => @@ -373,6 +353,45 @@ public static IItemDropRule OnItemDropDatabaseRegisterToGlobal(On_ItemDropDataba return entry; } + public class PlanteraDropEdit : ModSystem + { + private static ILHook planteraHook; + + public override void PostSetupContent() + { + // Apply the IL edit to change Plantera's first-time drop from item 758 to 1255 + MethodInfo method = typeof(Terraria.GameContent.ItemDropRules.ItemDropDatabase).GetMethod("RegisterBoss_Plantera", + BindingFlags.NonPublic | BindingFlags.Instance); + + planteraHook = new ILHook(method, PlanteraDropILEdit); + } + + public override void Unload() + { + planteraHook?.Dispose(); + } + + private static void PlanteraDropILEdit(ILContext il) + { + ILCursor cursor = new ILCursor(il); + + // Look for the instruction that loads the value 758 (Grenade Launcher ID) + // This should be: ldc.i4 758 (or ldc.i4.s 758 if it's a short form) + if (cursor.TryGotoNext(MoveType.Before, + i => i.MatchLdcI4(758))) // Match loading the constant 758 + { + // Replace the 758 with 1255 + cursor.Remove(); // Remove the ldc.i4 758 instruction + cursor.Emit(OpCodes.Ldc_I4, 1255); // Emit ldc.i4 1255 instead + + ModContent.GetInstance().Logger.Info("Successfully changed Plantera's first-time drop from item 758 to 1255"); + } + else + { + ModContent.GetInstance().Logger.Error("Failed to find item ID 758 in RegisterBoss_Plantera method"); + } + } + } public class BiomeKeyDropEdit : ModSystem { From 2ee11c955ea2c42e809ed874853247abe85163df Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Tue, 2 Sep 2025 18:13:46 -0700 Subject: [PATCH 084/206] removed old non shimmer dupe recipes and buffed Qs --- System/RecipeManager.cs | 83 +---------------------------------------- 1 file changed, 1 insertion(+), 82 deletions(-) diff --git a/System/RecipeManager.cs b/System/RecipeManager.cs index 9873a455..c1f9a4e5 100644 --- a/System/RecipeManager.cs +++ b/System/RecipeManager.cs @@ -13,71 +13,6 @@ 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); - - CreateDuplicateDropRecipe([ - ItemID.BreakerBlade, - ItemID.ClockworkAssaultRifle, - ItemID.LaserRifle, - ItemID.FireWhip - ], 3); - - CreateDuplicateDropRecipe([ - ItemID.GolemFist, - ItemID.PossessedHatchet, - ItemID.Stynger, - ItemID.StaffofEarth, - ItemID.HeatRay, - ItemID.SunStone, - ItemID.EyeoftheGolem - ], 3); - - CreateDuplicateDropRecipe([ - ItemID.Flairon, - ItemID.Tsunami, - ItemID.RazorbladeTyphoon, - ItemID.BubbleGun, - ItemID.TempestStaff - ], 3); - Recipe.Create(ItemID.Headstone) .AddIngredient(ItemID.StoneBlock, 50) .AddTile(TileID.HeavyWorkBench) @@ -143,22 +78,6 @@ public override void AddRecipes() } - private static void CreateDuplicateDropRecipe(List lootTable, int amountOfMaterial) - { - for (var i = 0; i < lootTable.Count; i++) - { - for (var j = 0; j < lootTable.Count; j++) - { - if (j == i) - continue; - - Recipe.Create(lootTable[i]) - .AddIngredient(lootTable[j], amountOfMaterial) - .DisableDecraft() - .Register(); - } - } - } public class AnyGolem1 : ModSystem { public static RecipeGroup AnyGolemPrimary; @@ -813,7 +732,7 @@ public override void AddRecipes() foreach (int itemID in AnyQueenSlime1.PrimaryItems.Where(id => id != ItemID.QueenSlimeMasterTrophy)) { Recipe.Create(itemID) - .AddRecipeGroup($"PvPAdventure:AnyQueenSlimePrimaryExclude{itemID}", 3) + .AddRecipeGroup($"PvPAdventure:AnyQueenSlimePrimaryExclude{itemID}", 2) .AddCondition(shimmerCondition) .DisableDecraft() .Register(); From 1e696205e52de213889eb5b61f4ab8092e7ce224 Mon Sep 17 00:00:00 2001 From: James Puleo Date: Tue, 2 Sep 2025 21:24:55 -0400 Subject: [PATCH 085/206] fix some stuff and damage sharing desync when damage sharing, two or more teams bouncing around the threshold might desync because the local attacker may apply their damage out of order from how it arrives to others. sync team life from server to ensure every player has an accurate copy. --- AdventureNpc.cs | 87 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 57 insertions(+), 30 deletions(-) diff --git a/AdventureNpc.cs b/AdventureNpc.cs index 58c73081..c5c712b0 100644 --- a/AdventureNpc.cs +++ b/AdventureNpc.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using Microsoft.Xna.Framework; using Mono.Cecil.Cil; @@ -15,6 +16,7 @@ using Terraria.Localization; using Terraria.ModLoader; using Terraria.ModLoader.Config; +using Terraria.ModLoader.IO; namespace PvPAdventure; @@ -24,7 +26,7 @@ public class AdventureNpc : GlobalNPC public DamageInfo LastDamageFromPlayer { get; set; } public Dictionary TeamLife { get; } = new(); - private Team? _strikeTeam; + private Team _lastStrikeTeam; public class DamageInfo(byte who) { @@ -355,8 +357,22 @@ private int OnNPCStrikeNPC(On_NPC.orig_StrikeNPC_HitInfo_bool_bool orig, NPC sel var adventureSelf = self.GetGlobalNPC(); + // If this isn't from the network, then we did this ourselves. + if (!fromNet) + adventureSelf._lastStrikeTeam = (Team)Main.LocalPlayer.team; + + var message = + $"Strike {self.whoAmI}/{self.type}/{self.FullName} for {hit.Damage}, last strike team {adventureSelf._lastStrikeTeam}"; + + Mod.Logger.Info(message); + + if (Main.dedServ) + Console.WriteLine(message); + else + ChatHelper.DisplayMessage(NetworkText.FromLiteral(message), Color.White, byte.MaxValue); + // If this was a non-player strike, treat it as damage for all teams. - if (adventureSelf._strikeTeam is null or Team.None) + if (adventureSelf._lastStrikeTeam == Team.None) { foreach (var team in adventureSelf.TeamLife.Keys) adventureSelf.TeamLife[team] = Math.Max(0, adventureSelf.TeamLife[team] - hit.Damage); @@ -372,7 +388,7 @@ private int OnNPCStrikeNPC(On_NPC.orig_StrikeNPC_HitInfo_bool_bool orig, NPC sel (int)self.position.Y, self.width, self.height - ), Main.teamColor[(int)adventureSelf._strikeTeam.Value], hit.Damage, hit.Crit); + ), Main.teamColor[(int)adventureSelf._lastStrikeTeam], hit.Damage, hit.Crit); // Save the previous immortal value, we might clobber it later. var previousImmortal = self.immortal; @@ -380,14 +396,14 @@ private int OnNPCStrikeNPC(On_NPC.orig_StrikeNPC_HitInfo_bool_bool orig, NPC sel try { // FIXME: wrong place to get damage sorta, what abt InstantKill etc? - var teamLife = Math.Max(0, adventureSelf.TeamLife[adventureSelf._strikeTeam.Value] - hit.Damage); - adventureSelf.TeamLife[adventureSelf._strikeTeam.Value] = teamLife; + var teamLife = Math.Max(0, adventureSelf.TeamLife[adventureSelf._lastStrikeTeam] - hit.Damage); + adventureSelf.TeamLife[adventureSelf._lastStrikeTeam] = teamLife; var damage = Math.Max(0, self.life - teamLife); foreach (var team in adventureSelf.TeamLife.Keys) { - if (team != adventureSelf._strikeTeam.Value) + if (team != adventureSelf._lastStrikeTeam) adventureSelf.TeamLife[team] = Math.Max(self.life, adventureSelf.TeamLife[team] - (damage / 2)); } @@ -397,14 +413,14 @@ private int OnNPCStrikeNPC(On_NPC.orig_StrikeNPC_HitInfo_bool_bool orig, NPC sel hit.Damage = damage; + // FIXME: holy fuck + self.netUpdate = true; + return orig(self, hit, fromNet, noPlayerInteraction); } finally { self.immortal = previousImmortal; - - if (!fromNet) - adventureSelf._strikeTeam = null; } } @@ -413,16 +429,14 @@ private void OnNetMessageSendStrikeNPC(On_NetMessage.orig_SendStrikeNPC orig, NP { var adventureNpc = npc.GetGlobalNPC(); - if (Main.dedServ && adventureNpc._strikeTeam.HasValue) + if (Main.dedServ) { var packet = Mod.GetPacket(); packet.Write((byte)AdventurePacketIdentifier.NpcStrikeTeam); packet.Write((short)npc.whoAmI); - packet.Write((byte)adventureNpc._strikeTeam.Value); + packet.Write((byte)adventureNpc._lastStrikeTeam); packet.Send(ignoreClient: ignoreClient); - - adventureNpc._strikeTeam = null; } orig(npc, ref hit, ignoreClient); @@ -518,22 +532,6 @@ void AddNonExpertBossLoot(int id) AdventureDropDatabase.ModifyNPCLoot(npc, npcLoot); } - // Although this looks like a side effect (and therefore should use OnHit), the order of operations matters here. - // This needs to happen before the strike to the NPC. - public override void ModifyHitByItem(NPC npc, Player player, Item item, ref NPC.HitModifiers modifiers) - { - MarkNextStrikeForTeam((Team)player.team); - } - - // Although this looks like a side effect (and therefore should use OnHit), the order of operations matters here. - // This needs to happen before the strike to the NPC. - public override void ModifyHitByProjectile(NPC npc, Projectile projectile, ref NPC.HitModifiers modifiers) - { - if (projectile.GetGlobalProjectile().EntitySource is EntitySource_Parent parent && - parent.Entity is Player player) - MarkNextStrikeForTeam((Team)player.team); - } - public override void EditSpawnRate(Player player, ref int spawnRate, ref int maxSpawns) { if (ModContent.GetInstance()?.CurrentPhase == GameManager.Phase.Waiting) @@ -582,9 +580,38 @@ public override bool CheckDead(NPC npc) return true; } + // FIXME: might be costly! + public override void SendExtraAI(NPC npc, BitWriter bitWriter, BinaryWriter binaryWriter) + { + var adventureNpc = npc.GetGlobalNPC(); + + binaryWriter.Write((byte)adventureNpc.TeamLife.Count); + foreach (var (team, life) in adventureNpc.TeamLife) + { + binaryWriter.Write((byte)team); + binaryWriter.Write7BitEncodedInt(life); + } + } + + // FIXME: might be costly! + public override void ReceiveExtraAI(NPC npc, BitReader bitReader, BinaryReader binaryReader) + { + var adventureNpc = npc.GetGlobalNPC(); + adventureNpc.TeamLife.Clear(); + + var count = binaryReader.ReadByte(); + for (var i = 0; i < count; i++) + { + var team = binaryReader.ReadByte(); + var life = binaryReader.Read7BitEncodedInt(); + + adventureNpc.TeamLife[(Team)team] = life; + } + } + public void MarkNextStrikeForTeam(Team team) { - _strikeTeam = team; + _lastStrikeTeam = team; } private static void PlayHitMarker(int damage) From 0b477222d05e4be4b1ec68bd38bedf14e61a8f98 Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Tue, 2 Sep 2025 18:31:26 -0700 Subject: [PATCH 086/206] chagned mega shark recip --- System/RecipeManager.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/System/RecipeManager.cs b/System/RecipeManager.cs index c1f9a4e5..3289c558 100644 --- a/System/RecipeManager.cs +++ b/System/RecipeManager.cs @@ -64,6 +64,14 @@ public override void AddRecipes() .AddTile(TileID.AdamantiteForge) .Register(); + Recipe.Create(ItemID.Megashark) + .AddIngredient(ItemID.SharkFin, 1) + .AddIngredient(ItemID.IllegalGunParts, 1) + .AddIngredient(ItemID.Minishark, 1) + .AddIngredient(ItemID.SoulofMight, 20) + .AddTile(TileID.MythrilAnvil) + .Register(); + //temp sudo terrablade Recipe.Create(ItemID.TrueNightsEdge) .AddIngredient(ItemID.SoulofFright, 20) From f5a5bee5f10acddfcd9d73e1ac63d520016690bc Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Tue, 2 Sep 2025 18:54:42 -0700 Subject: [PATCH 087/206] fixed dupe hopefully also made it always display time --- AdventurePlayer.cs | 96 ++++++++++++++++++++++++++++++---------------- 1 file changed, 64 insertions(+), 32 deletions(-) diff --git a/AdventurePlayer.cs b/AdventurePlayer.cs index 1df0bd47..8d6c9cbe 100644 --- a/AdventurePlayer.cs +++ b/AdventurePlayer.cs @@ -594,82 +594,114 @@ public override bool PreKill(double damage, int hitDirection, bool pvp, ref bool public class AncientChiselHotswap : ModPlayer { private bool hadAncientChiselLastFrame; - private int ancientChiselSlot = -1; // Track which slot had the Ancient Chisel + private int ancientChiselSlot = -1; private int disabledSlot = -1; // Track which slot is currently disabled + private Item[] lastFrameArmor = new Item[10]; + private int periodicBuffTimer = 0; // Timer for periodic buff application public override void PostUpdateEquips() { - // Check if Ancient Chisel is equipped and in which slot + if (lastFrameArmor[3] == null) + { + for (int i = 0; i < 10; i++) + { + lastFrameArmor[i] = new Item(); + } + } + int currentChiselSlot = GetAncientChiselSlot(); bool hasAncientChisel = currentChiselSlot != -1; - // Apply debuff when Ancient Chisel is removed (transition from equipped to not equipped) + // Check if Ancient Chisel was just equipped (wasn't equipped last frame, but is now) + if (!hadAncientChiselLastFrame && hasAncientChisel) + { + Player.AddBuff(ModContent.BuffType(), 15 * 60 * 60); + disabledSlot = currentChiselSlot; + periodicBuffTimer = 0; // Reset timer when first equipped + } + + // Check if Ancient Chisel was just removed if (hadAncientChiselLastFrame && !hasAncientChisel) { - Player.AddBuff(ModContent.BuffType(), 15 * 60 * 60); // 60 seconds - disabledSlot = ancientChiselSlot; // Remember which slot to disable + Player.AddBuff(ModContent.BuffType(), 15 * 60 * 60); + disabledSlot = ancientChiselSlot; + periodicBuffTimer = 0; // Reset timer when removed } - // Update tracking variables for next frame + // Handle periodic buff application while equipped if (hasAncientChisel) { + periodicBuffTimer++; + + // Apply buff every 59 seconds (59 * 60 ticks) + if (periodicBuffTimer >= 59 * 60) + { + Player.AddBuff(ModContent.BuffType(), 15 * 60 * 60); + disabledSlot = currentChiselSlot; + periodicBuffTimer = 0; // Reset timer + } + ancientChiselSlot = currentChiselSlot; hadAncientChiselLastFrame = true; } else { hadAncientChiselLastFrame = false; + periodicBuffTimer = 0; // Reset timer when not equipped } - // Handle disabled slot restrictions if (Player.HasBuff(ModContent.BuffType()) && disabledSlot != -1) { - RestrictDisabledSlot(disabledSlot); + PreventSlotPlacement(disabledSlot); } else if (!Player.HasBuff(ModContent.BuffType())) { - // Reset disabled slot when debuff expires disabledSlot = -1; } - } - private int GetAncientChiselSlot() - { - for (int i = 3; i < 10; i++) // Check all accessory slots + for (int i = 3; i < 10; i++) { - if (Player.armor[i].type == ItemID.AncientChisel && - (i < 7 || !Player.hideVisibleAccessory[i - 3])) - { - return i; - } + lastFrameArmor[i] = Player.armor[i].Clone(); } - return -1; } - private void RestrictDisabledSlot(int slotIndex) + private void PreventSlotPlacement(int slotIndex) { if (slotIndex >= 3 && slotIndex < 10) { - // Check if there's a non-Ancient Chisel item in the disabled slot - if (!Player.armor[slotIndex].IsAir && Player.armor[slotIndex].type != ItemID.AncientChisel) + Item currentItem = Player.armor[slotIndex]; + Item lastFrameItem = lastFrameArmor[slotIndex]; + bool slotChanged = currentItem.type != lastFrameItem.type || currentItem.stack != lastFrameItem.stack; + bool isNotAncientChisel = currentItem.type != ItemID.AncientChisel; + bool wasEmpty = lastFrameItem.IsAir; + bool nowHasItem = !currentItem.IsAir; + + if (slotChanged && isNotAncientChisel && (wasEmpty && nowHasItem)) { - // Remove non-Ancient Chisel items from the disabled slot - // and return them to the player's inventory - Item removedItem = Player.armor[slotIndex].Clone(); - Player.armor[slotIndex] = new Item(); // Clear the slot - - // Try to add the item to the player's inventory - Item leftoverItem = Player.GetItem(Player.whoAmI, removedItem, GetItemSettings.InventoryEntityToPlayerInventorySettings); + Item rejectedItem = currentItem.Clone(); + Player.armor[slotIndex] = lastFrameItem.Clone(); // Restore previous state - // If inventory is full and there are leftovers, drop them on the ground - if (!leftoverItem.IsAir) + if (Main.netMode != NetmodeID.Server) // Only on client/singleplayer { - Player.DropItem(Player.GetSource_Misc("SlotRestriction"), Player.position, ref leftoverItem); + Item leftoverItem = Player.GetItem(Player.whoAmI, rejectedItem, GetItemSettings.InventoryEntityToPlayerInventorySettings); } } } } + private int GetAncientChiselSlot() + { + for (int i = 3; i < 10; i++) // Check all accessory slots + { + if (Player.armor[i].type == ItemID.AncientChisel && + (i < 7 || !Player.hideVisibleAccessory[i - 3])) + { + return i; + } + } + return -1; + } + // Method to check if a slot is disabled (can be used by other systems) public bool IsSlotDisabled(int slotIndex) { From ecf51d25dc6b509571c3496d90665bd7923a400b Mon Sep 17 00:00:00 2001 From: James Puleo Date: Tue, 2 Sep 2025 21:58:13 -0400 Subject: [PATCH 088/206] AdventureBossBar: Render the highest team in front of others --- AdventureBossBar.cs | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/AdventureBossBar.cs b/AdventureBossBar.cs index 6308d074..d2b54884 100644 --- a/AdventureBossBar.cs +++ b/AdventureBossBar.cs @@ -1,3 +1,4 @@ +using System.Linq; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Terraria; @@ -20,19 +21,34 @@ public override void PostDraw(SpriteBatch spriteBatch, NPC npc, BossBarDrawParam Utils.CenteredRectangle(Main.ScreenSize.ToVector2() * new Vector2(0.5f, 1f) + new Vector2(0f, -50f), bossBarPosition.ToVector2()); + // FIXME: This should just be a sorted dictionary by value so we can render all of them in the correct Z order. + var highest = npc.GetGlobalNPC().TeamLife.MinBy(v => v.Value); + foreach (var (team, life) in npc.GetGlobalNPC().TeamLife) { // Shouldn't be possible, but be sure not to draw this. if (team == Team.None) continue; + // Don't draw the highest team just yet -- ensure it draws in front of everyone else. + if (team == highest.Key) + continue; + + Draw(team, life); + } + + Draw(highest.Key, highest.Value); + + return; + + void Draw(Team team, int life) + { var lifeRemaining = (float)life / npc.lifeMax; var frame = TextureAssets.Pvp[1].Value.Frame(6); frame.X = frame.Width * (int)team; - // FIXME: looks silly when overlapping, because alpha colors blend... - // maybe stack/stagger them? that takes math. + // FIXME: Looks a little silly when overlapping, maybe they should get stacked or staggered when on top. var color = Color.White; color *= lifeRemaining.Remap(0.85f, 1.0f, 1.0f, 0.0f); From 56ea03ff85b071898b8d9e51e71f966cc2759693 Mon Sep 17 00:00:00 2001 From: James Puleo Date: Tue, 2 Sep 2025 22:09:12 -0400 Subject: [PATCH 089/206] Remove paladin hack --- AdventureNpc.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/AdventureNpc.cs b/AdventureNpc.cs index c5c712b0..d4371468 100644 --- a/AdventureNpc.cs +++ b/AdventureNpc.cs @@ -135,12 +135,6 @@ public override void SetDefaults(NPC entity) } } - public override void BossHeadSlot(NPC npc, ref int index) - { - if (npc.type == NPCID.Paladin) - index = NPCID.Sets.BossHeadTextures[NPCID.KingSlime]; - } - public override void OnSpawn(NPC npc, IEntitySource source) { // Due to the new bound NPCs we've added, it's now possible that a town NPC moving in can conflict with a bound From 385585758620c59a2ef372c1a4528ed5216ca4b7 Mon Sep 17 00:00:00 2001 From: James Puleo Date: Tue, 2 Sep 2025 22:57:44 -0400 Subject: [PATCH 090/206] AdventureNpc: Add whitelist config for NPCs that should use Team Life --- AdventureConfig.cs | 7 ++++- AdventureNpc.cs | 65 +++++++++++++++++++++++----------------------- 2 files changed, 38 insertions(+), 34 deletions(-) diff --git a/AdventureConfig.cs b/AdventureConfig.cs index 34789840..adca9ef6 100644 --- a/AdventureConfig.cs +++ b/AdventureConfig.cs @@ -187,12 +187,17 @@ public float CalculateMultiplier(float tileDistance) => [Range(0, 5 * 60)] [DefaultValue(8)] public int StandardInvincibilityFrames { get; set; } [DefaultValue(0.2f)] public float GhostHealMultiplier { get; set; } + [Description("Additional multiplier for any player that can Ghost Heal")] - [DefaultValue(1.0f)] public float GhostHealMultiplierWearers { get; set; } + [DefaultValue(1.0f)] + public float GhostHealMultiplierWearers { get; set; } [Range(0.0f, 3000.0f)] [DefaultValue(3000.0f)] public float GhostHealMaxDistance { get; set; } + + [Description("Require each team to deal the maximum life in total damage to kill this NPC")] + public List TeamLifeNpcs { get; set; } = new(); } public class Statistics : IEquatable diff --git a/AdventureNpc.cs b/AdventureNpc.cs index d4371468..c9c6a9bd 100644 --- a/AdventureNpc.cs +++ b/AdventureNpc.cs @@ -115,23 +115,28 @@ public override void SetDefaults(NPC entity) // Can't construct an NPCDefinition too early -- it'll call GetName and won't be graceful on failure. if (NPCID.Search.TryGetName(entity.type, out var name)) { + var definition = new NPCDefinition(name); + { - if (adventureConfig.NpcBalance.LifeMaxMultipliers.TryGetValue(new(name), out var multiplier)) + if (adventureConfig.NpcBalance.LifeMaxMultipliers.TryGetValue(definition, out var multiplier)) entity.lifeMax = (int)(entity.lifeMax * multiplier.Value); } { - if (adventureConfig.NpcBalance.DamageMultipliers.TryGetValue(new(name), out var multiplier)) + if (adventureConfig.NpcBalance.DamageMultipliers.TryGetValue(definition, out var multiplier)) entity.damage = (int)(entity.damage * multiplier.Value); } - } - foreach (var team in Enum.GetValues()) - { - if (team == Team.None) - continue; + if (adventureConfig.Combat.TeamLifeNpcs.Contains(definition)) + { + foreach (var team in Enum.GetValues()) + { + if (team == Team.None) + continue; - TeamLife[team] = entity.lifeMax; + TeamLife[team] = entity.lifeMax; + } + } } } @@ -343,6 +348,7 @@ private void OnItemCheckLavaDeath(On_Item.orig_CheckLavaDeath orig, Item self, i } } + // FIXME: This only covers strikes, would be good to support DOTs/debuffs private int OnNPCStrikeNPC(On_NPC.orig_StrikeNPC_HitInfo_bool_bool orig, NPC self, NPC.HitInfo hit, bool fromNet, bool noPlayerInteraction) { @@ -355,16 +361,6 @@ private int OnNPCStrikeNPC(On_NPC.orig_StrikeNPC_HitInfo_bool_bool orig, NPC sel if (!fromNet) adventureSelf._lastStrikeTeam = (Team)Main.LocalPlayer.team; - var message = - $"Strike {self.whoAmI}/{self.type}/{self.FullName} for {hit.Damage}, last strike team {adventureSelf._lastStrikeTeam}"; - - Mod.Logger.Info(message); - - if (Main.dedServ) - Console.WriteLine(message); - else - ChatHelper.DisplayMessage(NetworkText.FromLiteral(message), Color.White, byte.MaxValue); - // If this was a non-player strike, treat it as damage for all teams. if (adventureSelf._lastStrikeTeam == Team.None) { @@ -389,26 +385,29 @@ private int OnNPCStrikeNPC(On_NPC.orig_StrikeNPC_HitInfo_bool_bool orig, NPC sel try { - // FIXME: wrong place to get damage sorta, what abt InstantKill etc? - var teamLife = Math.Max(0, adventureSelf.TeamLife[adventureSelf._lastStrikeTeam] - hit.Damage); - adventureSelf.TeamLife[adventureSelf._lastStrikeTeam] = teamLife; + if (adventureSelf.TeamLife.TryGetValue(adventureSelf._lastStrikeTeam, out var life)) + { + // FIXME: wrong place to get damage sorta, what abt InstantKill etc? + var teamLife = Math.Max(0, life - hit.Damage); + adventureSelf.TeamLife[adventureSelf._lastStrikeTeam] = teamLife; - var damage = Math.Max(0, self.life - teamLife); + var damage = Math.Max(0, self.life - teamLife); - foreach (var team in adventureSelf.TeamLife.Keys) - { - if (team != adventureSelf._lastStrikeTeam) - adventureSelf.TeamLife[team] = Math.Max(self.life, adventureSelf.TeamLife[team] - (damage / 2)); - } + foreach (var team in adventureSelf.TeamLife.Keys) + { + if (team != adventureSelf._lastStrikeTeam) + adventureSelf.TeamLife[team] = Math.Max(self.life, adventureSelf.TeamLife[team] - (damage / 2)); + } - // Can't deal 0 damage! - if (damage == 0) - self.immortal = true; + // Can't deal 0 damage! + if (damage == 0) + self.immortal = true; - hit.Damage = damage; + hit.Damage = damage; - // FIXME: holy fuck - self.netUpdate = true; + // FIXME: holy fuck + self.netUpdate = true; + } return orig(self, hit, fromNet, noPlayerInteraction); } From b6d69018addf884a3ceee02dd803dec7af401c2f Mon Sep 17 00:00:00 2001 From: James Puleo Date: Tue, 2 Sep 2025 23:01:21 -0400 Subject: [PATCH 091/206] we dont need to publizie this anymore --- AdventureProjectile.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/AdventureProjectile.cs b/AdventureProjectile.cs index c639ec23..d6f24f6e 100644 --- a/AdventureProjectile.cs +++ b/AdventureProjectile.cs @@ -11,8 +11,8 @@ namespace PvPAdventure; public class AdventureProjectile : GlobalProjectile { - public IEntitySource EntitySource { get; private set; } public override bool InstancePerEntity => true; + private IEntitySource _entitySource; public override void Load() { @@ -29,10 +29,10 @@ private static EntitySource_ItemUse GetItemUseSource(Projectile projectile, Proj { var adventureProjectile = projectile.GetGlobalProjectile(); - if (adventureProjectile.EntitySource is EntitySource_ItemUse entitySourceItemUse) + if (adventureProjectile._entitySource is EntitySource_ItemUse entitySourceItemUse) return entitySourceItemUse; - if (adventureProjectile.EntitySource is EntitySource_Parent entitySourceParent && + if (adventureProjectile._entitySource is EntitySource_Parent entitySourceParent && entitySourceParent.Entity is Projectile projectileParent && projectileParent != lastProjectile) return GetItemUseSource(projectileParent, projectile); @@ -55,7 +55,7 @@ private PlayerDeathReason OnPlayerDeathReasonByProjectile(On_PlayerDeathReason.o public override void OnSpawn(Projectile projectile, IEntitySource source) { - EntitySource = source; + _entitySource = source; } public override bool? CanCutTiles(Projectile projectile) From f7ce42e75eec3593d492c9e23e2e166907654dd4 Mon Sep 17 00:00:00 2001 From: James Puleo Date: Tue, 2 Sep 2025 23:08:19 -0400 Subject: [PATCH 092/206] add comment gotta do this --- AdventureNpc.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/AdventureNpc.cs b/AdventureNpc.cs index c9c6a9bd..add8c6dc 100644 --- a/AdventureNpc.cs +++ b/AdventureNpc.cs @@ -424,6 +424,7 @@ private void OnNetMessageSendStrikeNPC(On_NetMessage.orig_SendStrikeNPC orig, NP if (Main.dedServ) { + // FIXME: Proper packet var packet = Mod.GetPacket(); packet.Write((byte)AdventurePacketIdentifier.NpcStrikeTeam); packet.Write((short)npc.whoAmI); From 708c52907f786b0baebd832eeb5914aed55281cd Mon Sep 17 00:00:00 2001 From: James Puleo Date: Wed, 3 Sep 2025 23:00:54 -0400 Subject: [PATCH 093/206] AdventureNpc: Add configurable percentage of damage to share --- AdventureConfig.cs | 7 ++++++- AdventureNpc.cs | 9 +++++++-- Localization/en-US.hjson | 14 ++++++++++++++ 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/AdventureConfig.cs b/AdventureConfig.cs index adca9ef6..8a4b0b03 100644 --- a/AdventureConfig.cs +++ b/AdventureConfig.cs @@ -196,8 +196,13 @@ public float CalculateMultiplier(float tileDistance) => [DefaultValue(3000.0f)] public float GhostHealMaxDistance { get; set; } + public class TeamLifeConfig + { + [DefaultValue(0.5f)] public float Share { get; set; } = 0.5f; + } + [Description("Require each team to deal the maximum life in total damage to kill this NPC")] - public List TeamLifeNpcs { get; set; } = new(); + public Dictionary TeamLifeNpcs { get; set; } = new(); } public class Statistics : IEquatable diff --git a/AdventureNpc.cs b/AdventureNpc.cs index add8c6dc..438f33ae 100644 --- a/AdventureNpc.cs +++ b/AdventureNpc.cs @@ -127,7 +127,7 @@ public override void SetDefaults(NPC entity) entity.damage = (int)(entity.damage * multiplier.Value); } - if (adventureConfig.Combat.TeamLifeNpcs.Contains(definition)) + if (adventureConfig.Combat.TeamLifeNpcs.ContainsKey(definition)) { foreach (var team in Enum.GetValues()) { @@ -393,10 +393,15 @@ private int OnNPCStrikeNPC(On_NPC.orig_StrikeNPC_HitInfo_bool_bool orig, NPC sel var damage = Math.Max(0, self.life - teamLife); + var adventureConfig = ModContent.GetInstance(); + var npcDefinition = new NPCDefinition(self.type); + foreach (var team in adventureSelf.TeamLife.Keys) { if (team != adventureSelf._lastStrikeTeam) - adventureSelf.TeamLife[team] = Math.Max(self.life, adventureSelf.TeamLife[team] - (damage / 2)); + adventureSelf.TeamLife[team] = Math.Max(self.life, + (int)(adventureSelf.TeamLife[team] - + (damage * adventureConfig.Combat.TeamLifeNpcs[npcDefinition].Share))); } // Can't deal 0 damage! diff --git a/Localization/en-US.hjson b/Localization/en-US.hjson index 8d8adbe9..e116c73b 100644 --- a/Localization/en-US.hjson +++ b/Localization/en-US.hjson @@ -304,6 +304,11 @@ Mods: { Label: Ghost Heal Multiplier Wearers Tooltip: "" } + + TeamLifeNpcs: { + Label: Team Life Npcs + Tooltip: "" + } } AdventureClientConfig: { @@ -651,6 +656,15 @@ Mods: { Tooltip: "" } + + TeamLifeConfig: { + Tooltip: "" + + Share: { + Label: Share + Tooltip: "" + } + } } Item: { From 4f1bda78a589f0c2f75b736510751ca620920429 Mon Sep 17 00:00:00 2001 From: James Puleo Date: Fri, 5 Sep 2025 21:16:02 -0400 Subject: [PATCH 094/206] ok dont show if you dont hit --- AdventureBossBar.cs | 23 +++++++---------------- AdventureNpc.cs | 36 ++++++++++++++++++++++-------------- 2 files changed, 29 insertions(+), 30 deletions(-) diff --git a/AdventureBossBar.cs b/AdventureBossBar.cs index d2b54884..8301734f 100644 --- a/AdventureBossBar.cs +++ b/AdventureBossBar.cs @@ -21,28 +21,19 @@ public override void PostDraw(SpriteBatch spriteBatch, NPC npc, BossBarDrawParam Utils.CenteredRectangle(Main.ScreenSize.ToVector2() * new Vector2(0.5f, 1f) + new Vector2(0f, -50f), bossBarPosition.ToVector2()); - // FIXME: This should just be a sorted dictionary by value so we can render all of them in the correct Z order. - var highest = npc.GetGlobalNPC().TeamLife.MinBy(v => v.Value); + var adventureNpc = npc.GetGlobalNPC(); - foreach (var (team, life) in npc.GetGlobalNPC().TeamLife) + // FIXME: This sort order should be pre-calculated for us so we don't need to do it all the time! + var teamLife = adventureNpc.TeamLife + .Where(kv => adventureNpc.HasBeenHurtByTeam.Contains(kv.Key)) + .OrderByDescending(kv => kv.Value); + + foreach (var (team, life) in teamLife) { // Shouldn't be possible, but be sure not to draw this. if (team == Team.None) continue; - // Don't draw the highest team just yet -- ensure it draws in front of everyone else. - if (team == highest.Key) - continue; - - Draw(team, life); - } - - Draw(highest.Key, highest.Value); - - return; - - void Draw(Team team, int life) - { var lifeRemaining = (float)life / npc.lifeMax; var frame = TextureAssets.Pvp[1].Value.Frame(6); diff --git a/AdventureNpc.cs b/AdventureNpc.cs index 438f33ae..73107d4d 100644 --- a/AdventureNpc.cs +++ b/AdventureNpc.cs @@ -25,7 +25,12 @@ public class AdventureNpc : GlobalNPC public override bool InstancePerEntity => true; public DamageInfo LastDamageFromPlayer { get; set; } - public Dictionary TeamLife { get; } = new(); + private readonly Dictionary _teamLife = new(); + public IReadOnlyDictionary TeamLife => _teamLife; + + private readonly HashSet _hasBeenHurtByTeam = new(); + public IReadOnlySet HasBeenHurtByTeam => _hasBeenHurtByTeam; + private Team _lastStrikeTeam; public class DamageInfo(byte who) @@ -134,7 +139,7 @@ public override void SetDefaults(NPC entity) if (team == Team.None) continue; - TeamLife[team] = entity.lifeMax; + _teamLife[team] = entity.lifeMax; } } } @@ -359,13 +364,13 @@ private int OnNPCStrikeNPC(On_NPC.orig_StrikeNPC_HitInfo_bool_bool orig, NPC sel // If this isn't from the network, then we did this ourselves. if (!fromNet) - adventureSelf._lastStrikeTeam = (Team)Main.LocalPlayer.team; + adventureSelf.MarkNextStrikeForTeam((Team)Main.LocalPlayer.team); // If this was a non-player strike, treat it as damage for all teams. if (adventureSelf._lastStrikeTeam == Team.None) { foreach (var team in adventureSelf.TeamLife.Keys) - adventureSelf.TeamLife[team] = Math.Max(0, adventureSelf.TeamLife[team] - hit.Damage); + adventureSelf._teamLife[team] = Math.Max(0, adventureSelf._teamLife[team] - hit.Damage); return orig(self, hit, fromNet, noPlayerInteraction); } @@ -385,11 +390,11 @@ private int OnNPCStrikeNPC(On_NPC.orig_StrikeNPC_HitInfo_bool_bool orig, NPC sel try { - if (adventureSelf.TeamLife.TryGetValue(adventureSelf._lastStrikeTeam, out var life)) + if (adventureSelf._teamLife.TryGetValue(adventureSelf._lastStrikeTeam, out var life)) { // FIXME: wrong place to get damage sorta, what abt InstantKill etc? var teamLife = Math.Max(0, life - hit.Damage); - adventureSelf.TeamLife[adventureSelf._lastStrikeTeam] = teamLife; + adventureSelf._teamLife[adventureSelf._lastStrikeTeam] = teamLife; var damage = Math.Max(0, self.life - teamLife); @@ -399,8 +404,8 @@ private int OnNPCStrikeNPC(On_NPC.orig_StrikeNPC_HitInfo_bool_bool orig, NPC sel foreach (var team in adventureSelf.TeamLife.Keys) { if (team != adventureSelf._lastStrikeTeam) - adventureSelf.TeamLife[team] = Math.Max(self.life, - (int)(adventureSelf.TeamLife[team] - + adventureSelf._teamLife[team] = Math.Max(self.life, + (int)(adventureSelf._teamLife[team] - (damage * adventureConfig.Combat.TeamLifeNpcs[npcDefinition].Share))); } @@ -596,21 +601,24 @@ public override void SendExtraAI(NPC npc, BitWriter bitWriter, BinaryWriter bina public override void ReceiveExtraAI(NPC npc, BitReader bitReader, BinaryReader binaryReader) { var adventureNpc = npc.GetGlobalNPC(); - adventureNpc.TeamLife.Clear(); + adventureNpc._teamLife.Clear(); - var count = binaryReader.ReadByte(); - for (var i = 0; i < count; i++) { - var team = binaryReader.ReadByte(); - var life = binaryReader.Read7BitEncodedInt(); + var count = binaryReader.ReadByte(); + for (var i = 0; i < count; i++) + { + var team = (Team)binaryReader.ReadByte(); + var life = binaryReader.Read7BitEncodedInt(); - adventureNpc.TeamLife[(Team)team] = life; + adventureNpc._teamLife[team] = life; + } } } public void MarkNextStrikeForTeam(Team team) { _lastStrikeTeam = team; + _hasBeenHurtByTeam.Add(team); } private static void PlayHitMarker(int damage) From 4c799564d8ba0cf1d6b1f7ef6a3b40e295df2933 Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Sat, 6 Sep 2025 07:15:16 -0700 Subject: [PATCH 095/206] updated icons --- Assets/Buff/2.PNG | Bin 0 -> 2839 bytes Assets/Buff/BROISACHOJ.PNG | Bin 2839 -> 563 bytes Assets/Buff/ShinyStoneHotswap.png | Bin 321 -> 412 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 Assets/Buff/2.PNG diff --git a/Assets/Buff/2.PNG b/Assets/Buff/2.PNG new file mode 100644 index 0000000000000000000000000000000000000000..a76df8062881b39720f136c9f9f2c0d6871f1f15 GIT binary patch literal 2839 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 literal 0 HcmV?d00001 diff --git a/Assets/Buff/BROISACHOJ.PNG b/Assets/Buff/BROISACHOJ.PNG index a76df8062881b39720f136c9f9f2c0d6871f1f15..7d5e2d111ff2ab3bc68eaff9877798f7b476a0cf 100644 GIT binary patch literal 563 zcmV-30?hr1P)Px$?MXyIR9J=Om&+~$K@^6+5gTU4bzw+^5IZ4mOA8AxU_)Y$HHq*9E(vSw2^%lq z5nMB|V%#E3lOW7YZ!E^5`i!ZXZr8+A;@?!Cs?$~d|9$GzsSxkT^0x>9l>G6czF(0A z$ga-=P(HT!tqI)mLG`e-`LW~Fh-!Pf)WV}PV1ojs@*vDRyZZrfZZAK4G1kzm-do)P zz+LhNCPKR7iV<4-hni`R0)kBX8S)s4?If=OXl-lP`oD~=Z8gu$tJZCw0;!iL%@*dd z`bGfGPLDPFx3EtEfyrDD4o9@{FJpK}waZ&tchMEdWx}#>4FHj7HRLhPWYWI&eKO%c z<7at577i)DqAQS#0e5X0e9i)sc|r8g^{Mu1&wm9`q^Vc6v%A``JqiTDWG;E4JW>mQ zn|@G^K}wj+Hx{&Eixe=g+01!XW_jzu&RHb}Bpy&z&o&`aWd|)ad zb%MlK~OkosP#Toa;BuzK)zgFOn!jl~^Trejnt zEnX{3?;O1%l7B0H2}6wEKwl8eEFZZ<2NlTuK9C$xFG-l002ovPDHLkV1nis B{rms` literal 2839 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 diff --git a/Assets/Buff/ShinyStoneHotswap.png b/Assets/Buff/ShinyStoneHotswap.png index ec96c433ac82733ea81160e81a711ed7df61bde0..48bdada60691d8378e319ba16fd845eaf66360d1 100644 GIT binary patch delta 397 zcmV;80doGq0-OVo8Gi%-0009+ghc=V00DDSM?wMF$t-^W000DMK}|sb0I`n?{9y$E z001CkNK#Dz0D2|>0Dy!50Qvv`0D$NK0Cg|`0P0`>06Lfe02gqax=}m;0007FOGiWi z|A&vvzW@LL32;bRa{vGf6951U69E94oEQKA00(qQO+^Rk34aC-4jm%@u^IpX0OUzT zK~y-)z0#ph13?sp;cp3Oe3KdsWDUBaYBd4`uRwy~ZJIPZ011LVK~)8sgltk%MerEx zAoeb7cB^)PF?a5qnf!CkOkvNc($9Qd4D|ye#^FB79cFljG^FK|x)j)H`aW$G>HiK5 z(%VICeZBq}>3<|>GkoIs*GX04qT}U0C=*=u-fBFlOg!QmN0^2Y^#sBb|z*W6-}lU`9KHkil45@&Jm r8ZY6e)o$dFbdo94a8q9!Mfw7SjyH?v%EZ9{0000X+(fCi*iO`e8Et zkZw{D2l(-L_qQ{>008221=U){6#xJL)k#D_R7l6|(=iIdFcb#hEaKeJ3n;GbO}v4N zqmzioaO+W=yo_TvC#4_}U-M`9^-*h+RKdVMg!H`+UQ%P;Tz}iy+`ftly`n>CXv@4w zRW@<^U|@7e1zf7tRMH##L%ktx$WUEOB)vD(# From e63d4d59e654a2692dd019d8fffeab4f683db3e1 Mon Sep 17 00:00:00 2001 From: James Puleo Date: Tue, 9 Sep 2025 17:31:05 -0400 Subject: [PATCH 096/206] AdventureNpc: Add FIXME comment about config changes desync --- AdventureNpc.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/AdventureNpc.cs b/AdventureNpc.cs index 73107d4d..0203ad8a 100644 --- a/AdventureNpc.cs +++ b/AdventureNpc.cs @@ -132,6 +132,7 @@ public override void SetDefaults(NPC entity) entity.damage = (int)(entity.damage * multiplier.Value); } + // FIXME: What if config changes mid game? might desync form the config which might break some contracts? if (adventureConfig.Combat.TeamLifeNpcs.ContainsKey(definition)) { foreach (var team in Enum.GetValues()) From 148888a253c900e29c9df695d044f5ff274d71f2 Mon Sep 17 00:00:00 2001 From: James Puleo Date: Tue, 9 Sep 2025 17:33:41 -0400 Subject: [PATCH 097/206] AdventureNpc: Respect `NPC.realLife` when calculating team life This fixes issues with The Destroyer, whose body and tail segments point to the head as the full life pool. --- AdventureNpc.cs | 46 ++++++++++++++++++++++++++--------------- PvPAdventure.cs | 14 ++++++++++--- System/CombatManager.cs | 4 ++-- 3 files changed, 42 insertions(+), 22 deletions(-) diff --git a/AdventureNpc.cs b/AdventureNpc.cs index 0203ad8a..b4fa1aca 100644 --- a/AdventureNpc.cs +++ b/AdventureNpc.cs @@ -361,17 +361,21 @@ private int OnNPCStrikeNPC(On_NPC.orig_StrikeNPC_HitInfo_bool_bool orig, NPC sel if (!Main.dedServ && !fromNet) PlayHitMarker(hit.Damage); - var adventureSelf = self.GetGlobalNPC(); + var adventureNpc = self.GetGlobalNPC(); + var realLifeNpc = self.realLife != -1 ? Main.npc[self.realLife] : null; + var realLifeAdventureNpc = realLifeNpc?.GetGlobalNPC(); + var teamLife = realLifeAdventureNpc?._teamLife ?? adventureNpc._teamLife; + var currentLife = realLifeNpc?.life ?? self.life; // If this isn't from the network, then we did this ourselves. if (!fromNet) - adventureSelf.MarkNextStrikeForTeam((Team)Main.LocalPlayer.team); + adventureNpc.MarkNextStrikeForTeam(self, (Team)Main.LocalPlayer.team); // If this was a non-player strike, treat it as damage for all teams. - if (adventureSelf._lastStrikeTeam == Team.None) + if (adventureNpc._lastStrikeTeam == Team.None) { - foreach (var team in adventureSelf.TeamLife.Keys) - adventureSelf._teamLife[team] = Math.Max(0, adventureSelf._teamLife[team] - hit.Damage); + foreach (var team in teamLife.Keys) + teamLife[team] = Math.Max(0, teamLife[team] - hit.Damage); return orig(self, hit, fromNet, noPlayerInteraction); } @@ -384,29 +388,29 @@ private int OnNPCStrikeNPC(On_NPC.orig_StrikeNPC_HitInfo_bool_bool orig, NPC sel (int)self.position.Y, self.width, self.height - ), Main.teamColor[(int)adventureSelf._lastStrikeTeam], hit.Damage, hit.Crit); + ), Main.teamColor[(int)adventureNpc._lastStrikeTeam], hit.Damage, hit.Crit); // Save the previous immortal value, we might clobber it later. var previousImmortal = self.immortal; try { - if (adventureSelf._teamLife.TryGetValue(adventureSelf._lastStrikeTeam, out var life)) + if (teamLife.TryGetValue(adventureNpc._lastStrikeTeam, out var life)) { // FIXME: wrong place to get damage sorta, what abt InstantKill etc? - var teamLife = Math.Max(0, life - hit.Damage); - adventureSelf._teamLife[adventureSelf._lastStrikeTeam] = teamLife; + var newTeamLife = Math.Max(0, life - hit.Damage); + teamLife[adventureNpc._lastStrikeTeam] = newTeamLife; - var damage = Math.Max(0, self.life - teamLife); + var damage = Math.Max(0, currentLife - newTeamLife); var adventureConfig = ModContent.GetInstance(); - var npcDefinition = new NPCDefinition(self.type); + var npcDefinition = new NPCDefinition((realLifeNpc ?? self).type); - foreach (var team in adventureSelf.TeamLife.Keys) + foreach (var team in teamLife.Keys) { - if (team != adventureSelf._lastStrikeTeam) - adventureSelf._teamLife[team] = Math.Max(self.life, - (int)(adventureSelf._teamLife[team] - + if (team != adventureNpc._lastStrikeTeam) + teamLife[team] = Math.Max(currentLife, + (int)(teamLife[team] - (damage * adventureConfig.Combat.TeamLifeNpcs[npcDefinition].Share))); } @@ -417,7 +421,8 @@ private int OnNPCStrikeNPC(On_NPC.orig_StrikeNPC_HitInfo_bool_bool orig, NPC sel hit.Damage = damage; // FIXME: holy fuck - self.netUpdate = true; + // FIXME: i think we want to update whomever teamlife was reduced + (realLifeNpc ?? self).netUpdate = true; } return orig(self, hit, fromNet, noPlayerInteraction); @@ -616,10 +621,17 @@ public override void ReceiveExtraAI(NPC npc, BitReader bitReader, BinaryReader b } } - public void MarkNextStrikeForTeam(Team team) + public void MarkNextStrikeForTeam(NPC npc, Team team) { _lastStrikeTeam = team; _hasBeenHurtByTeam.Add(team); + + // If our life pool is someone else's, count it as hurting them too. + if (npc.realLife != -1 && npc.realLife != npc.whoAmI) + { + var realLife = Main.npc[npc.realLife]; + realLife.GetGlobalNPC().MarkNextStrikeForTeam(realLife, team); + } } private static void PlayHitMarker(int damage) diff --git a/PvPAdventure.cs b/PvPAdventure.cs index ba867fa8..357d8aca 100644 --- a/PvPAdventure.cs +++ b/PvPAdventure.cs @@ -1,3 +1,4 @@ +using System; using System.IO; using System.Linq; using Microsoft.Xna.Framework; @@ -210,10 +211,17 @@ public override void HandlePacket(BinaryReader reader, int whoAmI) } case AdventurePacketIdentifier.NpcStrikeTeam: { - var npc = reader.ReadInt16(); - var team = (Team)reader.ReadByte(); + var npcIndex = reader.ReadInt16(); + var team = reader.ReadByte(); - Main.npc[npc].GetGlobalNPC().MarkNextStrikeForTeam(team); + if (npcIndex < 0 || npcIndex >= Main.maxNPCs) + return; + + if (team >= Enum.GetValues().Length) + return; + + var npc = Main.npc[npcIndex]; + npc.GetGlobalNPC().MarkNextStrikeForTeam(npc, (Team)team); break; } diff --git a/System/CombatManager.cs b/System/CombatManager.cs index 7158c52e..ca60534e 100644 --- a/System/CombatManager.cs +++ b/System/CombatManager.cs @@ -100,8 +100,8 @@ public override bool HijackGetData(ref byte messageType, ref BinaryReader reader try { - Main.npc[reader.ReadInt16()].GetGlobalNPC() - .MarkNextStrikeForTeam((Team)Main.player[playerNumber].team); + var npc = Main.npc[reader.ReadInt16()]; + npc.GetGlobalNPC().MarkNextStrikeForTeam(npc, (Team)Main.player[playerNumber].team); } finally { From eec9439a27f0f69a98d62bf5cf2bf6ac06163b43 Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Fri, 12 Sep 2025 22:45:45 -0700 Subject: [PATCH 098/206] queen bee isntant;y spaws bound witchy D --- BoundNpc.cs | 1 + System/QueenBeeVore.cs | 49 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 System/QueenBeeVore.cs diff --git a/BoundNpc.cs b/BoundNpc.cs index ce6a6ad0..c40b96a5 100644 --- a/BoundNpc.cs +++ b/BoundNpc.cs @@ -3,6 +3,7 @@ using Terraria.Localization; using Terraria.ModLoader; + namespace PvPAdventure; public abstract class BoundNpc : ModNPC diff --git a/System/QueenBeeVore.cs b/System/QueenBeeVore.cs new file mode 100644 index 00000000..cc5f17de --- /dev/null +++ b/System/QueenBeeVore.cs @@ -0,0 +1,49 @@ +using Terraria; +using Terraria.ID; +using Terraria.ModLoader; +using Terraria.ModLoader.IO; +using PvPAdventure; + +namespace PvPAdventure +{ + + //yes this code is half AI slop dogshit and some of it is stolen from fargos I dont care its temporary anyways + public class BoundWitchDoctorSpawner : ModSystem + { + public bool hasSpawnedBoundWitchDoctor = false; + + public override void SaveWorldData(TagCompound tag) + { + tag["BoundWitchDoctorSpawned"] = hasSpawnedBoundWitchDoctor; + } + + public override void LoadWorldData(TagCompound tag) + { + hasSpawnedBoundWitchDoctor = tag.GetBool("BoundWitchDoctorSpawned"); + } + } + + public class QueenBeeGlobalNPC : GlobalNPC + { + public override void OnKill(NPC npc) + { + if (npc.type == NPCID.QueenBee) + { + var spawner = ModContent.GetInstance(); + + if (!spawner.hasSpawnedBoundWitchDoctor) + { + int npcIndex = NPC.NewNPC(npc.GetSource_Death(), (int)npc.Center.X, (int)npc.Center.Y, ModContent.NPCType()); + + if (npcIndex >= 0 && npcIndex < Main.maxNPCs) + { + NPC boundWitchDoctor = Main.npc[npcIndex]; + boundWitchDoctor.netUpdate = true; + } + + spawner.hasSpawnedBoundWitchDoctor = true; + } + } + } + } +} \ No newline at end of file From 2d0594049f9d869b806cce1e87ec51bf17289c39 Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Fri, 12 Sep 2025 23:45:20 -0700 Subject: [PATCH 099/206] BABY CANDY tsunami now first kill skeletron freaky 1000 marrows no empress wings --- AdventureDropDatabase.cs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/AdventureDropDatabase.cs b/AdventureDropDatabase.cs index 3718e8a0..d00c1cec 100644 --- a/AdventureDropDatabase.cs +++ b/AdventureDropDatabase.cs @@ -288,7 +288,9 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) break; case NPCID.SkeletronHead: - npcLoot.Add(ItemDropRule.Common(ItemID.GoldenKey)); + npcLoot.Add(ItemDropRule.Common(ItemID.GoldenKey, 1, 3, 3)); + npcLoot.Add(ItemDropRule.Common(ItemID.Marrow, 1000, 1000, 1000)); + foreach (var drop in drops) ModifyDropRate(drop, ItemID.SkeletronHand, 1, 1); break; @@ -330,6 +332,21 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) (drop is CommonDrop commonDrop && commonDrop.itemId == ItemID.FishronWings) || drop is DropBasedOnExpertMode); + var dukeFirstKillRule = new LeadingConditionRule(new FirstBossKillCondition(NPCID.DukeFishron)); + dukeFirstKillRule.OnSuccess(ItemDropRule.Common(ItemID.Tsunami, 1)); + dukeFirstKillRule.OnFailedConditions(ItemDropRule.OneFromOptions(1, + ItemID.Tsunami, + ItemID.BubbleGun, + ItemID.RazorbladeTyphoon, + ItemID.Flairon, + ItemID.TempestStaff + )); + break; + + + case NPCID.HallowBoss: + npcLoot.RemoveWhere(drop => + (drop is CommonDrop commonDrop && commonDrop.itemId == ItemID.RainbowWings)); break; case NPCID.TheDestroyer: From f9d782fba5a13653e80b097fd467a0074e002062 Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Sat, 13 Sep 2025 11:58:23 -0700 Subject: [PATCH 100/206] makes magic archers not drop magic quiver. YOu can now get a quiver post-plantera at a 1/7 chance --- AdventureDropDatabase.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/AdventureDropDatabase.cs b/AdventureDropDatabase.cs index 3718e8a0..fa8d3b68 100644 --- a/AdventureDropDatabase.cs +++ b/AdventureDropDatabase.cs @@ -187,8 +187,14 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) break; case NPCID.SkeletonArcher: - foreach (var drop in drops) - ModifyDropRate(drop, ItemID.MagicQuiver, 1, 30); + + npcLoot.RemoveWhere(drop => + (drop is CommonDrop commonDrop && commonDrop.itemId == ItemID.MagicQuiver) || + drop is LeadingConditionRule); + if (NPC.downedPlantBoss == true) + { + npcLoot.Add(ItemDropRule.Common(ItemID.StalkersQuiver, 7)); + } break; case NPCID.RedDevil: From fe0c69a0e81d3011505c13a705d3a91a7fcb72ff Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Sun, 14 Sep 2025 18:44:43 -0700 Subject: [PATCH 101/206] Twins will now be unable to die if they are not both on 1 hp There may be an issue with a 1 damage change I made so honestly mayve I could just remove that if this doesn't work --- AdventureNpc.cs | 75 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/AdventureNpc.cs b/AdventureNpc.cs index efa1b6ed..8d3fbf8b 100644 --- a/AdventureNpc.cs +++ b/AdventureNpc.cs @@ -541,6 +541,81 @@ void AddNonExpertBossLoot(int id) AdventureDropDatabase.ModifyNPCLoot(npc, npcLoot); } + public class TillDeathDoUsPart : GlobalNPC + { + public override bool PreKill(NPC npc) + { + if (npc.type == NPCID.Spazmatism || npc.type == NPCID.Retinazer) + { + NPC otherTwin = FindOtherTwin(npc); + + if (otherTwin != null && otherTwin.life > 1) + { + npc.life = 1; + npc.netUpdate = true; + return false; + } + + return true; + } + return true; + } + + public override bool CheckDead(NPC npc) + { + if (npc.type == NPCID.Spazmatism || npc.type == NPCID.Retinazer) + { + NPC otherTwin = FindOtherTwin(npc); + + if (otherTwin != null && otherTwin.life > 1) + { + npc.life = 1; + npc.netUpdate = true; + return false; + } + } + + return true; + } + + public override void ModifyHitByProjectile(NPC npc, Projectile projectile, ref NPC.HitModifiers modifiers) + { + if (npc.type == NPCID.Spazmatism || npc.type == NPCID.Retinazer) + { + NPC otherTwin = FindOtherTwin(npc); + if (otherTwin != null && otherTwin.life > 1 && npc.life == 1) + { + modifiers.SetMaxDamage(0); + } + } + } + + public override void ModifyHitByItem(NPC npc, Player player, Item item, ref NPC.HitModifiers modifiers) + { + if (npc.type == NPCID.Spazmatism || npc.type == NPCID.Retinazer) + { + NPC otherTwin = FindOtherTwin(npc); + if (otherTwin != null && otherTwin.life > 1 && npc.life == 1) + { + modifiers.SetMaxDamage(0); + } + } + } + private NPC FindOtherTwin(NPC currentTwin) + { + int targetType = currentTwin.type == NPCID.Spazmatism ? NPCID.Retinazer : NPCID.Spazmatism; + + for (int i = 0; i < Main.maxNPCs; i++) + { + NPC npc = Main.npc[i]; + if (npc.active && npc.type == targetType) + { + return npc; + } + } + return null; + } + } public override void EditSpawnRate(Player player, ref int spawnRate, ref int maxSpawns) { From 0a450ab19beb932bc930aec37d35639543aa234c Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Sun, 14 Sep 2025 18:45:05 -0700 Subject: [PATCH 102/206] Update AdventureNpc.cs --- AdventureNpc.cs | 62 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/AdventureNpc.cs b/AdventureNpc.cs index 8d3fbf8b..addb41bb 100644 --- a/AdventureNpc.cs +++ b/AdventureNpc.cs @@ -180,6 +180,68 @@ public override void OnSpawn(NPC npc, IEntitySource source) new(175, 75, 255)); } } + public class TwinsDeathPrevention : GlobalNPC + { + public override bool PreKill(NPC npc) + { + // Check if the NPC is either Spazmatism or Retinazer + if (npc.type == NPCID.Spazmatism || npc.type == NPCID.Retinazer) + { + // Find the other twin + NPC otherTwin = FindOtherTwin(npc); + + // If the other twin exists and is not at 1 HP, prevent this twin from dying + if (otherTwin != null && otherTwin.life > 1) + { + // Set this twin's life to 1 and prevent death + npc.life = 1; + return false; // Prevent death + } + + // If the other twin is at 1 HP or doesn't exist, allow normal death + return true; + } + + // For all other NPCs, allow normal death behavior + return true; + } + + public override bool CheckDead(NPC npc) + { + // Additional check when NPC is about to be marked as dead + if (npc.type == NPCID.Spazmatism || npc.type == NPCID.Retinazer) + { + NPC otherTwin = FindOtherTwin(npc); + + // If other twin exists and has more than 1 HP, prevent death + if (otherTwin != null && otherTwin.life > 1) + { + npc.life = 1; + return false; // Prevent being marked as dead + } + } + + // Allow normal death behavior + return true; + } + + private NPC FindOtherTwin(NPC currentTwin) + { + int targetType = currentTwin.type == NPCID.Spazmatism ? NPCID.Retinazer : NPCID.Spazmatism; + + // Search through all active NPCs to find the other twin + for (int i = 0; i < Main.maxNPCs; i++) + { + NPC npc = Main.npc[i]; + if (npc.active && npc.type == targetType) + { + return npc; + } + } + + return null; // Other twin not found + } + } private static void OnNPCPlayerInteraction(On_NPC.orig_PlayerInteraction orig, NPC self, int player) { From 8eaa7ea9dd8da4b6da5d4f9b158e280c318fbd92 Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Sun, 14 Sep 2025 18:53:08 -0700 Subject: [PATCH 103/206] fixed two problems! Should interact better with team boss HP --- AdventureNpc.cs | 99 +++++-------------------------------------------- 1 file changed, 10 insertions(+), 89 deletions(-) diff --git a/AdventureNpc.cs b/AdventureNpc.cs index addb41bb..e0d6e9fc 100644 --- a/AdventureNpc.cs +++ b/AdventureNpc.cs @@ -180,48 +180,45 @@ public override void OnSpawn(NPC npc, IEntitySource source) new(175, 75, 255)); } } - public class TwinsDeathPrevention : GlobalNPC + public class TillDeathDoUsPart : GlobalNPC { public override bool PreKill(NPC npc) { - // Check if the NPC is either Spazmatism or Retinazer + if (npc.type == NPCID.Spazmatism || npc.type == NPCID.Retinazer) { - // Find the other twin + NPC otherTwin = FindOtherTwin(npc); - // If the other twin exists and is not at 1 HP, prevent this twin from dying + if (otherTwin != null && otherTwin.life > 1) { - // Set this twin's life to 1 and prevent death + npc.life = 1; - return false; // Prevent death + return false; } - // If the other twin is at 1 HP or doesn't exist, allow normal death + return true; } - // For all other NPCs, allow normal death behavior return true; } public override bool CheckDead(NPC npc) { - // Additional check when NPC is about to be marked as dead + if (npc.type == NPCID.Spazmatism || npc.type == NPCID.Retinazer) { NPC otherTwin = FindOtherTwin(npc); - // If other twin exists and has more than 1 HP, prevent death if (otherTwin != null && otherTwin.life > 1) { npc.life = 1; - return false; // Prevent being marked as dead + return false; } } - // Allow normal death behavior return true; } @@ -229,7 +226,6 @@ private NPC FindOtherTwin(NPC currentTwin) { int targetType = currentTwin.type == NPCID.Spazmatism ? NPCID.Retinazer : NPCID.Spazmatism; - // Search through all active NPCs to find the other twin for (int i = 0; i < Main.maxNPCs; i++) { NPC npc = Main.npc[i]; @@ -239,7 +235,7 @@ private NPC FindOtherTwin(NPC currentTwin) } } - return null; // Other twin not found + return null; } } @@ -603,81 +599,6 @@ void AddNonExpertBossLoot(int id) AdventureDropDatabase.ModifyNPCLoot(npc, npcLoot); } - public class TillDeathDoUsPart : GlobalNPC - { - public override bool PreKill(NPC npc) - { - if (npc.type == NPCID.Spazmatism || npc.type == NPCID.Retinazer) - { - NPC otherTwin = FindOtherTwin(npc); - - if (otherTwin != null && otherTwin.life > 1) - { - npc.life = 1; - npc.netUpdate = true; - return false; - } - - return true; - } - return true; - } - - public override bool CheckDead(NPC npc) - { - if (npc.type == NPCID.Spazmatism || npc.type == NPCID.Retinazer) - { - NPC otherTwin = FindOtherTwin(npc); - - if (otherTwin != null && otherTwin.life > 1) - { - npc.life = 1; - npc.netUpdate = true; - return false; - } - } - - return true; - } - - public override void ModifyHitByProjectile(NPC npc, Projectile projectile, ref NPC.HitModifiers modifiers) - { - if (npc.type == NPCID.Spazmatism || npc.type == NPCID.Retinazer) - { - NPC otherTwin = FindOtherTwin(npc); - if (otherTwin != null && otherTwin.life > 1 && npc.life == 1) - { - modifiers.SetMaxDamage(0); - } - } - } - - public override void ModifyHitByItem(NPC npc, Player player, Item item, ref NPC.HitModifiers modifiers) - { - if (npc.type == NPCID.Spazmatism || npc.type == NPCID.Retinazer) - { - NPC otherTwin = FindOtherTwin(npc); - if (otherTwin != null && otherTwin.life > 1 && npc.life == 1) - { - modifiers.SetMaxDamage(0); - } - } - } - private NPC FindOtherTwin(NPC currentTwin) - { - int targetType = currentTwin.type == NPCID.Spazmatism ? NPCID.Retinazer : NPCID.Spazmatism; - - for (int i = 0; i < Main.maxNPCs; i++) - { - NPC npc = Main.npc[i]; - if (npc.active && npc.type == targetType) - { - return npc; - } - } - return null; - } - } public override void EditSpawnRate(Player player, ref int spawnRate, ref int maxSpawns) { From 4d3de04da7ef275deff8db3d97cbecdc465615fc Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Sun, 14 Sep 2025 19:19:16 -0700 Subject: [PATCH 104/206] another update, making both twins die when one dies --- AdventureNpc.cs | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/AdventureNpc.cs b/AdventureNpc.cs index e0d6e9fc..b1b7cc4b 100644 --- a/AdventureNpc.cs +++ b/AdventureNpc.cs @@ -184,48 +184,64 @@ public class TillDeathDoUsPart : GlobalNPC { public override bool PreKill(NPC npc) { - + if (npc.type == NPCID.Spazmatism || npc.type == NPCID.Retinazer) { - + NPC otherTwin = FindOtherTwin(npc); - if (otherTwin != null && otherTwin.life > 1) { - + npc.life = 1; - return false; + return false; } - return true; } - return true; } public override bool CheckDead(NPC npc) { - if (npc.type == NPCID.Spazmatism || npc.type == NPCID.Retinazer) { NPC otherTwin = FindOtherTwin(npc); - if (otherTwin != null && otherTwin.life > 1) { npc.life = 1; return false; } } - return true; } + public override void OnKill(NPC npc) + { + if (npc.type == NPCID.Spazmatism || npc.type == NPCID.Retinazer) + { + NPC otherTwin = FindOtherTwin(npc); + if (otherTwin != null && otherTwin.active && otherTwin.life <= 1) + { + if (npc.lastInteraction != 255) + { + otherTwin.lastInteraction = npc.lastInteraction; + } + + otherTwin.life = 0; + otherTwin.active = false; + + if (Main.netMode != NetmodeID.MultiplayerClient) + { + otherTwin.NPCLoot(); + } + } + } + } + private NPC FindOtherTwin(NPC currentTwin) { int targetType = currentTwin.type == NPCID.Spazmatism ? NPCID.Retinazer : NPCID.Spazmatism; - for (int i = 0; i < Main.maxNPCs; i++) { NPC npc = Main.npc[i]; @@ -234,7 +250,6 @@ private NPC FindOtherTwin(NPC currentTwin) return npc; } } - return null; } } From 8c18ef0722464cf2125a3d04b81ea9b573949b8f Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Sun, 14 Sep 2025 19:33:25 -0700 Subject: [PATCH 105/206] Now properly netsyncs and also attributes kill credit --- AdventureNpc.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/AdventureNpc.cs b/AdventureNpc.cs index b1b7cc4b..d3658653 100644 --- a/AdventureNpc.cs +++ b/AdventureNpc.cs @@ -235,6 +235,11 @@ public override void OnKill(NPC npc) { otherTwin.NPCLoot(); } + + if (Main.netMode == NetmodeID.Server) + { + NetMessage.SendData(MessageID.SyncNPC, -1, -1, null, otherTwin.whoAmI); + } } } } From 23b72b339e1416c24cf3585878efd5234098248e Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Sun, 14 Sep 2025 20:50:45 -0700 Subject: [PATCH 106/206] I'm so fucking sorry underscore ut it works dude --- AdventureNpc.cs | 67 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 49 insertions(+), 18 deletions(-) diff --git a/AdventureNpc.cs b/AdventureNpc.cs index d3658653..13a5c36f 100644 --- a/AdventureNpc.cs +++ b/AdventureNpc.cs @@ -184,19 +184,14 @@ public class TillDeathDoUsPart : GlobalNPC { public override bool PreKill(NPC npc) { - if (npc.type == NPCID.Spazmatism || npc.type == NPCID.Retinazer) { - NPC otherTwin = FindOtherTwin(npc); - if (otherTwin != null && otherTwin.life > 1) { - npc.life = 1; return false; } - return true; } return true; @@ -223,22 +218,59 @@ public override void OnKill(NPC npc) NPC otherTwin = FindOtherTwin(npc); if (otherTwin != null && otherTwin.active && otherTwin.life <= 1) { - if (npc.lastInteraction != 255) - { - otherTwin.lastInteraction = npc.lastInteraction; - } + + int killingPlayer = npc.lastInteraction; - otherTwin.life = 0; - otherTwin.active = false; - - if (Main.netMode != NetmodeID.MultiplayerClient) + if (killingPlayer != 255 && killingPlayer < Main.maxPlayers && Main.player[killingPlayer].active) { - otherTwin.NPCLoot(); + Player player = Main.player[killingPlayer]; + // AI slop solution because I can't figure out how kill credit works + + if (Main.netMode != NetmodeID.MultiplayerClient) + { + int projectile = Projectile.NewProjectile( + npc.GetSource_Death(), + otherTwin.Center.X, + otherTwin.Center.Y, + 0f, + 0f, + 3, + 200, + 0f, + killingPlayer + ); + + + if (projectile >= 0 && projectile < Main.maxProjectiles) + { + Projectile proj = Main.projectile[projectile]; + + proj.penetrate = 1; + proj.timeLeft = 2; + } + + + if (Main.netMode == NetmodeID.Server && projectile >= 0) + { + NetMessage.SendData(MessageID.SyncProjectile, -1, -1, null, projectile); + } + } } - - if (Main.netMode == NetmodeID.Server) + else { - NetMessage.SendData(MessageID.SyncNPC, -1, -1, null, otherTwin.whoAmI); + + otherTwin.life = 0; + otherTwin.active = false; + + if (Main.netMode != NetmodeID.MultiplayerClient) + { + otherTwin.NPCLoot(); + } + + if (Main.netMode == NetmodeID.Server) + { + NetMessage.SendData(MessageID.SyncNPC, -1, -1, null, otherTwin.whoAmI); + } } } } @@ -263,7 +295,6 @@ private static void OnNPCPlayerInteraction(On_NPC.orig_PlayerInteraction orig, N { orig(self, player); - // If this is part of the Eater of Worlds, then mark ALL segments as last damaged by this player. if (IsPartOfEaterOfWorlds((short)self.type)) { foreach (var npc in Main.ActiveNPCs) From ec5abe56332051f06d959daf5b18cb841c4f9f54 Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Tue, 16 Sep 2025 15:12:34 -0700 Subject: [PATCH 107/206] makes it so that the first time a player joins the world, they get the bag and the bag has the starting shit --- AdventureItem.cs | 48 +++++++++++++++++++++++++++++++++++ AdventurePlayer.cs | 27 +++++++++++++++++++- Assets/Item/AdventureBag.png | Bin 0 -> 1243 bytes Localization/en-US.hjson | 7 +++++ 4 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 Assets/Item/AdventureBag.png diff --git a/AdventureItem.cs b/AdventureItem.cs index 5318ec56..b393eee5 100644 --- a/AdventureItem.cs +++ b/AdventureItem.cs @@ -203,4 +203,52 @@ public override void ModifyTooltips(Item item, List tooltips) // This is likely unnecessary if we are overriding PrefixChance, but might as well. public override bool CanReforge(Item item) => !ModContent.GetInstance().RemovePrefixes; + + + public class AdventureBag : ModItem + { + public override string Texture => $"PvPAdventure/Assets/Item/AdventureBag"; + public override void SetStaticDefaults() + { + ItemID.Sets.OpenableBag[Type] = true; + } + + public override void SetDefaults() + { + Item.width = 32; + Item.height = 32; + Item.rare = ItemRarityID.Orange; + Item.maxStack = 1; + Item.consumable = true; + } + + public override bool CanRightClick() + { + return true; + } + + public override void RightClick(Player player) + { + player.QuickSpawnItem(player.GetSource_OpenItem(Type), ItemID.SilverPickaxe, 1); + player.QuickSpawnItem(player.GetSource_OpenItem(Type), ItemID.SilverAxe, 1); + player.QuickSpawnItem(player.GetSource_OpenItem(Type), ItemID.Ambrosia, 1); + player.QuickSpawnItem(player.GetSource_OpenItem(Type), ItemID.SlimeBed, 1); + player.QuickSpawnItem(player.GetSource_OpenItem(Type), ItemID.Torch, 15); + player.QuickSpawnItem(player.GetSource_OpenItem(Type), ItemID.Wood, 20); + player.QuickSpawnItem(player.GetSource_OpenItem(Type), ItemID.LifeCrystal, 5); + player.QuickSpawnItem(player.GetSource_OpenItem(Type), ItemID.ManaCrystal, 4); + player.QuickSpawnItem(player.GetSource_OpenItem(Type), ItemID.MiningPotion, 2); + player.QuickSpawnItem(player.GetSource_OpenItem(Type), ItemID.WormholePotion, 4); + } + + public override bool ConsumeItem(Player player) + { + return true; + } + public override void ModifyTooltips(List tooltips) + { + // Add custom tooltip line + tooltips.Add(new TooltipLine(Mod, "PvPBagInfo", "Contains essential items for your PvP Adventure")); + } + } } \ No newline at end of file diff --git a/AdventurePlayer.cs b/AdventurePlayer.cs index d7c7804f..401c1d14 100644 --- a/AdventurePlayer.cs +++ b/AdventurePlayer.cs @@ -22,7 +22,6 @@ using Terraria.ModLoader.Config; using Terraria.ModLoader.IO; using Mono.Cecil.Cil; - namespace PvPAdventure; public class AdventurePlayer : ModPlayer @@ -1228,6 +1227,32 @@ public override void PostUpdateEquips() } } +public class PvPAdventurePlayer : ModPlayer +{ + public bool hasReceivedStarterBag = false; + + public override void SaveData(TagCompound tag) + { + tag["hasReceivedStarterBag"] = hasReceivedStarterBag; + } + + public override void LoadData(TagCompound tag) + { + hasReceivedStarterBag = tag.GetBool("hasReceivedStarterBag"); + } + + public override void OnEnterWorld() + { + if (!hasReceivedStarterBag) + { + Player.QuickSpawnItem(Player.GetSource_GiftOrReward(), ModContent.ItemType(), 1); + + // Set the flag so they don't get another one + hasReceivedStarterBag = true; + } + } +} + public class ShinyStoneHotswap : ModBuff { public override string Texture => $"PvPAdventure/Assets/Buff/ShinyStoneHotswap"; diff --git a/Assets/Item/AdventureBag.png b/Assets/Item/AdventureBag.png new file mode 100644 index 0000000000000000000000000000000000000000..7499cd357f5cf6168ed6175631e751edccf2ee93 GIT binary patch literal 1243 zcmV<11SI>3P)?KZ3rcfOs>>E7LScc9E>zNguld+*%+ zzI)C+=iGr54;FQC5BTCPa>btib}im_Zi;iT2Z7kw5c8)`9ROf{;Whwo9sUS_pT7AN zfWeQ)f%ue26%eGr;6N7;GA&%bau$Hjy>9}k0(msVJ>aP$QvmGCwE}RlWeEsvAa0}z z2-}z20LawW12D0+20-^KTL9ScSW{fDiXc_sKwDc5U{B6%z+%3o<0b%ydR_;hw{NuC zR~5v@RY1(!HQ#rl0|<9uVQ|3h%ol&X9NbyWLG}B=##KOQ-MZCXtgHa*8Fqf(DsiZ1 zKLBGF;<1UuD^T(J^Vz`Wy{iB;HLgY4U%j4<{7z$`09D(-;=OwS^zYmWz{x9f05k>r zz>%ZTeIU)q3@TP&baBx!8Q4PG!U7QP$PYi>2tey2TO$2rJNf=qBKZo~D#HI=qgIJb zgA?^GcM7(bLR6@Pop16L(8ao(wW1isD)GFh-E^I6cDlpGOubW6Who)%ZEjsV3jF@_ zN#K4ZgmM+R(YzR3Iq!4k3+Mlpu?auS&K4cVu60#AENVvqAzwiY{;{ITN^N6u+pId7t-D-thhKIl!+(?IV0be_0T-vSFH9Gc3qz60d+aCl3E{HV1IxvtNKv2_f{)4n9SEj4N8T z{mZRlBwm5CBTL_YAseyS9aJS`17Xe7!7^=8Zq&PR6wuDQzoi9$`6YMys8dJ_DI+Du zF02-8m!1!l+i+dn?rb55b^HuE@1?4A+%-`l@d~6!vC&brXRuML5B7{qNcVwCzcTdY zt}ndNA8DtWt1_(f1$1GV4CDOhHw~6~F?xPH$QOcMQo=HCZ6UOs zY{B=aM%upn(MUh#%E?zCzxIaagSF-u3p1;z5@Jk@zS`v~a33D~3V@#Og8&R0TM+ZU zs)OKTes0E9_7v4>-icS>KFfcnt1$;KJoaP34%VxP8R7Vu?|@JVLAkVYYe5S7yqKWz zz8%j-=3F}pSmwpFtvU#@5nFN7Z`p*#u~iM*uhe^_j8!7>3N(~rUTfN}eK9KUGB*=# z|M~IvfzVrtd5tS?qW!~X3&%cqJ2K(CZFV2bK@BM2JsFtH94tg&5+WAm! z|5EcvyaN9LUP>Ymkber+0000EWmrjOO-%qQ00008000000002eQ Date: Wed, 17 Sep 2025 11:26:15 -0700 Subject: [PATCH 108/206] better luck in shimmer --- AdventurePlayer.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/AdventurePlayer.cs b/AdventurePlayer.cs index 401c1d14..4e583fcd 100644 --- a/AdventurePlayer.cs +++ b/AdventurePlayer.cs @@ -1253,6 +1253,18 @@ public override void OnEnterWorld() } } +public class AetherLuckPlayer : ModPlayer +{ + public override void ModifyLuck(ref float luck) + { + if (Player.ZoneShimmer) + { + luck += 400; // 400 times the amount of normal luck + } + } +} + + public class ShinyStoneHotswap : ModBuff { public override string Texture => $"PvPAdventure/Assets/Buff/ShinyStoneHotswap"; From ced5155843a1a5aa9fbfbba92f3c52100f662536 Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Wed, 17 Sep 2025 20:59:26 -0700 Subject: [PATCH 109/206] disabled team enforcement --- System/CombatManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/System/CombatManager.cs b/System/CombatManager.cs index ca60534e..c03d52af 100644 --- a/System/CombatManager.cs +++ b/System/CombatManager.cs @@ -13,7 +13,7 @@ namespace PvPAdventure.System; [Autoload(Side = ModSide.Both)] public class CombatManager : ModSystem { - private const bool PreventPersonalCombatModifications = true; + private const bool PreventPersonalCombatModifications = false; private static readonly HashSet BossProjectiles = [ From a77bf05462bc4c03d7a80c2dde5394849f8bb55d Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Wed, 17 Sep 2025 21:44:01 -0700 Subject: [PATCH 110/206] this could've been realllllly bad --- AdventureItem.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/AdventureItem.cs b/AdventureItem.cs index b393eee5..da0087ef 100644 --- a/AdventureItem.cs +++ b/AdventureItem.cs @@ -239,6 +239,7 @@ public override void RightClick(Player player) player.QuickSpawnItem(player.GetSource_OpenItem(Type), ItemID.ManaCrystal, 4); player.QuickSpawnItem(player.GetSource_OpenItem(Type), ItemID.MiningPotion, 2); player.QuickSpawnItem(player.GetSource_OpenItem(Type), ItemID.WormholePotion, 4); + player.QuickSpawnItem(player.GetSource_OpenItem(Type), ItemID.MagicMirror, 1); } public override bool ConsumeItem(Player player) From 4514881815aafad4088d4f99e4d12e064a83c943 Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Wed, 17 Sep 2025 22:55:03 -0700 Subject: [PATCH 111/206] fixes to make things work --- AdventureDropDatabase.cs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/AdventureDropDatabase.cs b/AdventureDropDatabase.cs index d00c1cec..1ccdd877 100644 --- a/AdventureDropDatabase.cs +++ b/AdventureDropDatabase.cs @@ -250,9 +250,9 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) npcLoot.RemoveWhere(drop => drop is LeadingConditionRule); - var firstKillRule = new LeadingConditionRule(new FirstBossKillCondition(NPCID.QueenSlimeBoss)); - firstKillRule.OnSuccess(ItemDropRule.Common(ItemID.QueenSlimeMountSaddle, 1)); - firstKillRule.OnFailedConditions(ItemDropRule.OneFromOptions(1, + var QSfirstKillRule = new LeadingConditionRule(new FirstBossKillCondition(NPCID.QueenSlimeBoss)); + QSfirstKillRule.OnSuccess(ItemDropRule.Common(ItemID.QueenSlimeMountSaddle, 1)); + QSfirstKillRule.OnFailedConditions(ItemDropRule.OneFromOptions(1, ItemID.Smolstar, ItemID.QueenSlimeHook, ItemID.QueenSlimeMountSaddle @@ -264,7 +264,7 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) ItemID.CrystalNinjaLeggings ) ); - npcLoot.Add(firstKillRule); + npcLoot.Add(QSfirstKillRule); break; case NPCID.QueenBee: @@ -328,20 +328,20 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) case NPCID.DukeFishron: - npcLoot.RemoveWhere(drop => - (drop is CommonDrop commonDrop && commonDrop.itemId == ItemID.FishronWings) || - drop is DropBasedOnExpertMode); + npcLoot.RemoveWhere(drop => drop is LeadingConditionRule); - var dukeFirstKillRule = new LeadingConditionRule(new FirstBossKillCondition(NPCID.DukeFishron)); - dukeFirstKillRule.OnSuccess(ItemDropRule.Common(ItemID.Tsunami, 1)); - dukeFirstKillRule.OnFailedConditions(ItemDropRule.OneFromOptions(1, - ItemID.Tsunami, + + var dukefirstKillRule = new LeadingConditionRule(new FirstBossKillCondition(NPCID.QueenSlimeBoss)); + dukefirstKillRule.OnSuccess(ItemDropRule.Common(ItemID.Tsunami, 1)); + dukefirstKillRule.OnFailedConditions(ItemDropRule.OneFromOptions(1, ItemID.BubbleGun, ItemID.RazorbladeTyphoon, - ItemID.Flairon, - ItemID.TempestStaff + ItemID.Tsunami, + ItemID.TempestStaff, + ItemID.Flairon )); - break; + npcLoot.Add(dukefirstKillRule); + break; case NPCID.HallowBoss: From c4878d01e6cdf711683847f907f73e72d92c985b Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Thu, 18 Sep 2025 18:16:49 -0700 Subject: [PATCH 112/206] Random mech spawns! Yikes! --- Dogshit.cs | 185 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 184 insertions(+), 1 deletion(-) diff --git a/Dogshit.cs b/Dogshit.cs index d406672c..afe69b1b 100644 --- a/Dogshit.cs +++ b/Dogshit.cs @@ -1,7 +1,10 @@ using Terraria; using Terraria.ModLoader; using Terraria.ID; - +using System.Collections.Generic; +using Terraria.Chat; +using Terraria.Localization; +using Microsoft.Xna.Framework; namespace PvPAdventure { public class RainSystem : ModSystem @@ -39,4 +42,184 @@ private void StartRain() NetMessage.SendData(MessageID.WorldData); } } + public class MechBossSpawnSystem : ModSystem + { + private bool hasAnnouncedTonight = false; + private bool hasSpawnedTonight = false; + private bool wasDay = true; + private int selectedBoss = -1; + + public override void PostUpdateWorld() + { + bool isNight = !Main.dayTime; + + if (isNight && wasDay) + { + hasAnnouncedTonight = false; + hasSpawnedTonight = false; + selectedBoss = -1; + wasDay = false; + } + + if (!isNight && !wasDay) + { + wasDay = true; + hasAnnouncedTonight = false; + hasSpawnedTonight = false; + selectedBoss = -1; + } + + if (!ShouldSpawnMechBoss()) + return; + + if (Main.time >= 0 && Main.time < 100 && !hasAnnouncedTonight) + { + selectedBoss = ChooseMechanicalBoss(); + if (selectedBoss != -1) + { + ShowAnnouncementMessage(selectedBoss); + hasAnnouncedTonight = true; + } + } + + if (Main.time >= 3600 && Main.time < 3700 && hasAnnouncedTonight && !hasSpawnedTonight) + { + if (selectedBoss != -1) + { + Player targetPlayer = FindClosestPlayerToSpawn(); + if (targetPlayer != null) + { + SpawnMechanicalBoss(selectedBoss, targetPlayer); + hasSpawnedTonight = true; + } + } + } + } + + private bool ShouldSpawnMechBoss() + { + return !Main.dayTime && + Main.hardMode && + !NPC.AnyNPCs(NPCID.TheDestroyer) && + !NPC.AnyNPCs(NPCID.Retinazer) && + !NPC.AnyNPCs(NPCID.Spazmatism) && + !NPC.AnyNPCs(NPCID.SkeletronPrime) && + HasUndefeatedMechBoss() && + FindClosestPlayerToSpawn() != null; + } + + private bool HasUndefeatedMechBoss() + { + return !NPC.downedMechBoss1 || !NPC.downedMechBoss2 || !NPC.downedMechBoss3; + } + + private Player FindClosestPlayerToSpawn() + { + Player closestPlayer = null; + float closestDistance = float.MaxValue; + + Vector2 worldSpawn = new Vector2(Main.spawnTileX * 16f, Main.spawnTileY * 16f); + + for (int i = 0; i < Main.maxPlayers; i++) + { + Player player = Main.player[i]; + if (player.active && !player.dead && player.ZoneOverworldHeight) + { + float distance = Vector2.Distance(player.position, worldSpawn); + if (distance < closestDistance) + { + closestDistance = distance; + closestPlayer = player; + } + } + } + return closestPlayer; + } + + private int ChooseMechanicalBoss() + { + var availableBosses = new List(); + + if (!NPC.downedMechBoss1) availableBosses.Add(NPCID.TheDestroyer); + if (!NPC.downedMechBoss2) availableBosses.Add(NPCID.Retinazer); + if (!NPC.downedMechBoss3) availableBosses.Add(NPCID.SkeletronPrime); + + return availableBosses.Count > 0 ? availableBosses[Main.rand.Next(availableBosses.Count)] : -1; + } + + private void ShowAnnouncementMessage(int bossType) + { + string message; + switch (bossType) + { + case NPCID.TheDestroyer: + message = "You feel vibrations from deep below..."; + break; + case NPCID.Retinazer: + message = "This is going to be a terrible night..."; + break; + case NPCID.SkeletronPrime: + message = "The air is getting colder around you..."; + break; + default: + return; + } + + ShowMessage(message, new Color(50, 255, 130)); + } + + private void SpawnMechanicalBoss(int bossType, Player player) + { + if (Main.netMode == NetmodeID.MultiplayerClient || player == null) + return; + + string spawnMessage; + + switch (bossType) + { + case NPCID.TheDestroyer: + spawnMessage = "Uh oh!"; + NPC.SpawnOnPlayer(player.whoAmI, NPCID.TheDestroyer); + break; + + case NPCID.Retinazer: + spawnMessage = "Better watch out!"; + // Spawn both twins + NPC.SpawnOnPlayer(player.whoAmI, NPCID.Retinazer); + NPC.SpawnOnPlayer(player.whoAmI, NPCID.Spazmatism); + break; + + case NPCID.SkeletronPrime: + spawnMessage = "Yikes!"; + NPC.SpawnOnPlayer(player.whoAmI, NPCID.SkeletronPrime); + break; + + default: + return; + } + + ShowMessage(spawnMessage, new Color(175, 75, 255)); + + Terraria.Audio.SoundEngine.PlaySound(SoundID.Roar, player.position); + } + + private void ShowMessage(string message, Color color) + { + if (Main.netMode == NetmodeID.Server) + { + ChatHelper.BroadcastChatMessage(NetworkText.FromLiteral(message), color); + } + else + { + Main.NewText(message, color.R, color.G, color.B); + } + } + public override void PostSetupContent() + { + hasAnnouncedTonight = false; + hasSpawnedTonight = false; + wasDay = true; + selectedBoss = -1; + } + } } \ No newline at end of file From 5563f7c1b1ccd2ca42ab72137734f1289df46624 Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Fri, 19 Sep 2025 12:39:58 -0700 Subject: [PATCH 113/206] im dumb --- AdventureDropDatabase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AdventureDropDatabase.cs b/AdventureDropDatabase.cs index 1ccdd877..3351d653 100644 --- a/AdventureDropDatabase.cs +++ b/AdventureDropDatabase.cs @@ -331,7 +331,7 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) npcLoot.RemoveWhere(drop => drop is LeadingConditionRule); - var dukefirstKillRule = new LeadingConditionRule(new FirstBossKillCondition(NPCID.QueenSlimeBoss)); + var dukefirstKillRule = new LeadingConditionRule(new FirstBossKillCondition(NPCID.DukeFishron)); dukefirstKillRule.OnSuccess(ItemDropRule.Common(ItemID.Tsunami, 1)); dukefirstKillRule.OnFailedConditions(ItemDropRule.OneFromOptions(1, ItemID.BubbleGun, From 05e62c2bf2f215c3e7fc707bb725c732a6f28963 Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Fri, 19 Sep 2025 15:47:56 -0700 Subject: [PATCH 114/206] nerfed beetle might --- AdventureBuff.cs | 12 +- Localization/en-US.hjson | 813 ++++++++++++++++++++++++++++----------- 2 files changed, 604 insertions(+), 221 deletions(-) diff --git a/AdventureBuff.cs b/AdventureBuff.cs index 2b897438..3c64609c 100644 --- a/AdventureBuff.cs +++ b/AdventureBuff.cs @@ -21,20 +21,20 @@ public override void Update(int type, Player player, ref int buffIndex) if (player.beetleOrbs >= 1) { - damage += 0.10f; - attackSpeed += 0.10f; + damage += 0.8f; + attackSpeed += 0.8f; } if (player.beetleOrbs >= 2) { - damage += 0.10f; - attackSpeed += 0.10f; + damage += 0.8f; + attackSpeed += 0.8f; } if (player.beetleOrbs >= 3) { - damage += 0.10f; - attackSpeed += 0.10f; + damage += 0.8f; + attackSpeed += 0.8f; } player.GetDamage() += damage; diff --git a/Localization/en-US.hjson b/Localization/en-US.hjson index b711635d..9809c0cb 100644 --- a/Localization/en-US.hjson +++ b/Localization/en-US.hjson @@ -195,6 +195,8 @@ Mods: { Label: Conditions Tooltip: "" } + + CollectedAllMechanicalBossSouls: "[c/32FF82:Cries of tortured souls emanate from the Bounty Shop...]" } Condition: { @@ -305,177 +307,562 @@ Mods: { Tooltip: "" } - TeamLifeNpcs: { Label: Team Life Npcs - GhostHealMaxDistanceNpc: { - Label: Ghost Heal Max Distance Npc + GhostHealMaxDistanceNpc: { + Label: Ghost Heal Max Distance Npc + Tooltip: "" + } + + ProjectileCollisionDamageReduction: { + Label: Projectile Collision Damage Reduction + Tooltip: "" + } + + NoLineOfSightDamageReduction: { + Label: No Line Of Sight Damage Reduction + Tooltip: "" + } + Tooltip: "" } - ProjectileCollisionDamageReduction: { - Label: Projectile Collision Damage Reduction + AdventureClientConfig: { + DisplayName: Client + + PlayerOutline: { + Label: Player Outline + Tooltip: "" + } + + ShiftEnterOpensAllChat: { + Label: Shift Enter Opens All Chat + Tooltip: "" + } + + ShowPauseMessage: { + Tooltip: "" + Label: Show Pause Message + } + + SoundEffect: { + Label: Sound Effect + Tooltip: "" + } + } + + PlayerOutlineConfig: { Tooltip: "" + + Self: { + Label: Self + Tooltip: "" + } + + Team: { + Label: Team + Tooltip: "" + } } - NoLineOfSightDamageReduction: { - Label: No Line Of Sight Damage Reduction + CannotModify: You are not permitted to modify this config. + + PlayerDamageBalanceConfig: { Tooltip: "" + + ItemDamageMultipliers: { + Label: Item Damage Multipliers + Tooltip: "" + } + + ProjectileDamageMultipliers: { + Label: Projectile Damage Multipliers + Tooltip: "" + } + + ItemFalloff: { + Label: Item Falloff + Tooltip: "" + } + + ProjectileFalloff: { + Label: Projectile Falloff + Tooltip: "" + } + + DefaultFalloff: { + Tooltip: "" + Label: Default Falloff + } } - } - AdventureClientConfig: { - DisplayName: Client + Falloff: { + Coefficient: { + Tooltip: "" + Label: Coefficient + } + + Forward: { + Label: Forward + Tooltip: "" + } - PlayerOutline: { - Label: Player Outline Tooltip: "" } - ShiftEnterOpensAllChat: { - Label: Shift Enter Opens All Chat + Statistics: { Tooltip: "" + + Damage: { + Label: Damage + Tooltip: "" + } + + UseTime: { + Label: Use Time + Tooltip: "" + } + + UseAnimation: { + Label: Use Animation + Tooltip: "" + } + + ShootSpeed: { + Label: Shoot Speed + Tooltip: "" + } + + Crit: { + Label: Crit + Tooltip: "" + } + + Mana: { + Label: Mana + Tooltip: "" + } + + Scale: { + Label: Scale + Tooltip: "" + } + + Knockback: { + Label: Knockback + Tooltip: "" + } + + Value: { + Tooltip: "" + Label: Value + } } - ShowPauseMessage: { + OptionalInt: { Tooltip: "" - Label: Show Pause Message + + Value: { + Label: Value + Tooltip: "" + } } - SoundEffect: { - Label: Sound Effect + OptionalFloat: { Tooltip: "" + + Value: { + Label: Value + Tooltip: "" + } } - } - PlayerOutlineConfig: { - Tooltip: "" + HitMarkerConfig: { + Sound: { + Label: Sound + Tooltip: "" + } + + Volume: { + Label: Volume + Tooltip: "" + } + + PitchMinimum: { + Label: Pitch Minimum + Tooltip: "" + } + + PitchMaximum: { + Label: Pitch Maximum + Tooltip: "" + } - Self: { - Label: Self Tooltip: "" + + SoundPath: { + Tooltip: "" + Label: Sound Path + } } - Team: { - Label: Team + SoundEffectConfig: { Tooltip: "" - } - } - CannotModify: You are not permitted to modify this config. + NpcHitMarker: { + Label: Npc Hit Marker + Tooltip: "" + } - PlayerDamageBalanceConfig: { - Tooltip: "" + PlayerHitMarker: { + Label: Player Hit Marker + Tooltip: "" + } - ItemDamageMultipliers: { - Label: Item Damage Multipliers + PlayerKillMarker: { + Label: Player Kill Marker + Tooltip: "" + } + } + + PlayerHitMarkerConfig: { Tooltip: "" + + SilenceVanilla: { + Label: Silence Vanilla + Tooltip: "" + } } - ProjectileDamageMultipliers: { - Label: Projectile Damage Multipliers + KillMarkerConfig: { + SoundPath: { + Tooltip: "" + Label: Sound Path + } + } + + PlayerKillMarkerConfig: { + SilenceVanilla: { + Tooltip: "" + Label: Silence Vanilla + } + Tooltip: "" } - ItemFalloff: { - Label: Item Falloff + MarkerConfig`1: { + PitchMaximum: { + Tooltip: "" + Label: Pitch Maximum + } + + PitchMinimum: { + Tooltip: "" + Label: Pitch Minimum + } + + Volume: { + Tooltip: "" + Label: Volume + } + + Sound: { + Tooltip: "" + Label: Sound + } + } + + Killsound: { + Part2.Label: Part2 + FatalCarCrash.Label: Fatal Car Crash + Shronker.Label: Shronker + Sharkron.Label: Sharkron + Ronaldoz.Label: Ronaldoz + Zacharry.Label: Zacharry Tooltip: "" } - ProjectileFalloff: { - Label: Projectile Falloff + Hitsound: { + Part1.Label: Part1 + MarrowMurder.Label: Marrow Murder + Squelchy.Label: Squelchy + Crash.Label: Crash + Blip.Label: Blip + Buwee.Label: BuWEEEEE + OlBetsy.Label: Ol' Betsy Tooltip: "" } - DefaultFalloff: { + WorldGenerationConfig: { + LifeFruitMinimumDistanceBetween: { + Tooltip: "" + Label: Life Fruit Minimum Distance Between + } + + LifeFruitExpertChanceDenominator: { + Tooltip: "" + Label: Life Fruit Expert Chance Denominator + } + + LifeFruitChanceDenominator: { + Tooltip: "" + Label: Life Fruit Chance Denominator + } + Tooltip: "" - Label: Default Falloff + + PlanteraBulbChanceDenominator: { + Label: Plantera Bulb Chance Denominator + Tooltip: "" + } + + ChlorophyteSpreadChanceModifier: { + Label: Chlorophyte Spread Chance Modifier + Tooltip: "" + } + + ChlorophyteGrowChanceModifier: { + Label: Chlorophyte Grow Chance Modifier + Tooltip: "" + } + + ChlorophyteGrowLimitModifier: { + Label: Chlorophyte Grow Limit Modifier + Tooltip: "" + } } - } - Falloff: { - Coefficient: { + NpcBalanceConfig: { Tooltip: "" - Label: Coefficient + + LifeMaxMultipliers: { + Label: Life Max Multipliers + Tooltip: "" + } + + DamageMultipliers: { + Label: Damage Multipliers + Tooltip: "" + } + + NoMechanicalBossSummonDrops: { + Label: No Mechanical Boss Summon Drops + Tooltip: "" + } + + NoBiomeKeyDrops: { + Label: No Biome Key Drops + Tooltip: "" + } } - Forward: { - Label: Forward + FloatStatistic: { Tooltip: "" + + Value: { + Label: Value + Tooltip: "" + } } - Tooltip: "" - } + ChestItemReplacement: { + Tooltip: "" - Statistics: { - Tooltip: "" + Items: { + Label: Items + Tooltip: "" + } + } + + InvasionSizeValue: { + Value: { + Tooltip: "" + Label: Value + } - Damage: { - Label: Damage Tooltip: "" } - UseTime: { - Label: Use Time + TeamLifeConfig: { Tooltip: "" + + Share: { + Label: Share + Tooltip: "" + } } - UseAnimation: { - Label: Use Animation + GhostHealMaxDistanceNpc: { + Label: Ghost Heal Max Distance Npc Tooltip: "" } - ShootSpeed: { - Label: Shoot Speed + ProjectileCollisionDamageReduction: { + Label: Projectile Collision Damage Reduction Tooltip: "" } - Crit: { - Label: Crit + NoLineOfSightDamageReduction: { + Label: No Line Of Sight Damage Reduction Tooltip: "" } + } - Mana: { - Label: Mana + Item: { + Disabled: Cannot be used in this gamemode + NoUndergroundEmpressButterfly: Cannot be released here underground + NoUndergroundQueenSlimeCrystal: Cannot be summoned here underground + } + + Player.CannotRecall: Cannot recall! + Tiles.LockedLihzahrdChest.MapEntry: Locked Lihzahrd Chest + Sandstorm: "[c/FFC864:Desert winds are picking up...]" + Rain: "[c/6496FF:A storm is brewing overhead...]" + + NPCs: { + Bound: { + Merchant.DisplayName: Bound Merchant + ArmsDealer.DisplayName: Bound Arms Dealer + WitchDoctor.DisplayName: Bound Witch Doctor + + Steampunker: { + DisplayName: Chained Steampunker + Chat: At long last, I'm saved! The strangest people chained me up, they mentioned something about a hardcore challenge... + } + + Truffle: { + DisplayName: Buried Truffle + Chat: At long last, I'm saved! The strangest people buried me here, they mentioned something about a hardcore challenge... + } + + Cyborg: { + DisplayName: Deactivated Cyborg + Chat: At long last, I'm saved! The strangest people turned me off, they mentioned something about a hardcore challenge... + } + + Chat: At long last, I'm saved! The strangest people tied me up, they mentioned something about a hardcore challenge... + Demolitionist.DisplayName: Bound. Demolitionist + } + } + + Pause: { + 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! + } + + AncientChiselHotswapBuff: { + DisplayName: THE CURSE OF THE ANCIENT CHISEL + Description: YOU CAN'T USE THAT heckin' ACCESSORY SLOT! + } + + NewIchorPlayerDebuff: { + DisplayName: Ichor + Description: Defense reduced by one third + } + + BROISACHOJ: { + DisplayName: BRO IS A CHOJ + Description: You are too much of a CHOJ to dash effectively + } + + BuffDescription: { + BeetleMight1: Melee damage and speed increase by 8% + BeetleMight2: Melee damage and speed increase by 8% + BeetleMight3: Melee damage and speed increase by 8% + } + + ArmorSetBonus.BeetleDamage: + ''' + Gain Beetles from player kills Beetles + increase your melee damage and attack speed + ''' + } + + Items: { + AdventureBag: { + DisplayName: Adventure Bag + Tooltip: Everything you need to start your PvP Adventure! + } + } + + AdventureClientConfig: { + DisplayName: Adventure Client Config + + PlayerOutline: { + Label: Player Outline Tooltip: "" } - Scale: { - Label: Scale + ShiftEnterOpensAllChat: { + Label: Shift Enter Opens All Chat Tooltip: "" } - Knockback: { - Label: Knockback + ShowPauseMessage: { + Label: Show Pause Message Tooltip: "" } - Value: { + SoundEffect: { + Label: Sound Effect Tooltip: "" - Label: Value } } - OptionalInt: { + PlayerOutlineConfig: { Tooltip: "" - Value: { - Label: Value + Self: { + Label: Self + Tooltip: "" + } + + Team: { + Label: Team Tooltip: "" } } - OptionalFloat: { + SoundEffectConfig: { Tooltip: "" - Value: { - Label: Value + NpcHitMarker: { + Label: Npc Hit Marker + Tooltip: "" + } + + PlayerHitMarker: { + Label: Player Hit Marker + Tooltip: "" + } + + PlayerKillMarker: { + Label: Player Kill Marker Tooltip: "" } } - HitMarkerConfig: { + HitMarkerConfig.Tooltip: "" + + Hitsound: { + Tooltip: "" + OlBetsy.Label: Ol Betsy + Buwee.Label: Buwee + Blip.Label: Blip + Crash.Label: Crash + Squelchy.Label: Squelchy + MarrowMurder.Label: Marrow Murder + Part1.Label: Part1 + } + + MarkerConfig`1: { Sound: { Label: Sound Tooltip: "" @@ -495,120 +882,182 @@ Mods: { Label: Pitch Maximum Tooltip: "" } + } + PlayerHitMarkerConfig: { Tooltip: "" - SoundPath: { + SilenceVanilla: { + Label: Silence Vanilla Tooltip: "" - Label: Sound Path } } - SoundEffectConfig: { + PlayerKillMarkerConfig: { Tooltip: "" - NpcHitMarker: { - Label: Npc Hit Marker + SilenceVanilla: { + Label: Silence Vanilla Tooltip: "" } + } - PlayerHitMarker: { - Label: Player Hit Marker + Killsound: { + Tooltip: "" + Zacharry.Label: Zacharry + Ronaldoz.Label: Ronaldoz + Sharkron.Label: Sharkron + Shronker.Label: Shronker + FatalCarCrash.Label: Fatal Car Crash + Part2.Label: Part2 + } + + PlayerDamageBalanceConfig: { + Tooltip: "" + + ItemDamageMultipliers: { + Label: Item Damage Multipliers Tooltip: "" } - PlayerKillMarker: { - Label: Player Kill Marker + ProjectileDamageMultipliers: { + Label: Projectile Damage Multipliers + Tooltip: "" + } + + ItemFalloff: { + Label: Item Falloff + Tooltip: "" + } + + ProjectileFalloff: { + Label: Projectile Falloff + Tooltip: "" + } + + DefaultFalloff: { + Label: Default Falloff Tooltip: "" } } - PlayerHitMarkerConfig: { + Falloff: { Tooltip: "" - SilenceVanilla: { - Label: Silence Vanilla + Coefficient: { + Label: Coefficient Tooltip: "" } - } - KillMarkerConfig: { - SoundPath: { + Forward: { + Label: Forward Tooltip: "" - Label: Sound Path } } - PlayerKillMarkerConfig: { - SilenceVanilla: { + TeamLifeConfig: { + Tooltip: "" + + Share: { + Label: Share Tooltip: "" - Label: Silence Vanilla } + } + InvasionSizeValue: { Tooltip: "" + + Value: { + Label: Value + Tooltip: "" + } } - MarkerConfig`1: { - PitchMaximum: { + Statistics: { + Tooltip: "" + + Damage: { + Label: Damage Tooltip: "" - Label: Pitch Maximum } - PitchMinimum: { + UseTime: { + Label: Use Time Tooltip: "" - Label: Pitch Minimum } - Volume: { + UseAnimation: { + Label: Use Animation Tooltip: "" - Label: Volume } - Sound: { + ShootSpeed: { + Label: Shoot Speed + Tooltip: "" + } + + Crit: { + Label: Crit + Tooltip: "" + } + + Mana: { + Label: Mana + Tooltip: "" + } + + Scale: { + Label: Scale + Tooltip: "" + } + + Knockback: { + Label: Knockback + Tooltip: "" + } + + Value: { + Label: Value Tooltip: "" - Label: Sound } } - Killsound: { - Part2.Label: Part2 - FatalCarCrash.Label: Fatal Car Crash - Shronker.Label: Shronker - Sharkron.Label: Sharkron - Ronaldoz.Label: Ronaldoz - Zacharry.Label: Zacharry + OptionalInt: { Tooltip: "" + + Value: { + Label: Value + Tooltip: "" + } } - Hitsound: { - Part1.Label: Part1 - MarrowMurder.Label: Marrow Murder - Squelchy.Label: Squelchy - Crash.Label: Crash - Blip.Label: Blip - Buwee.Label: BuWEEEEE - OlBetsy.Label: Ol' Betsy + OptionalFloat: { Tooltip: "" + + Value: { + Label: Value + Tooltip: "" + } } WorldGenerationConfig: { - LifeFruitMinimumDistanceBetween: { + Tooltip: "" + + LifeFruitChanceDenominator: { + Label: Life Fruit Chance Denominator Tooltip: "" - Label: Life Fruit Minimum Distance Between } LifeFruitExpertChanceDenominator: { - Tooltip: "" Label: Life Fruit Expert Chance Denominator + Tooltip: "" } - LifeFruitChanceDenominator: { + LifeFruitMinimumDistanceBetween: { + Label: Life Fruit Minimum Distance Between Tooltip: "" - Label: Life Fruit Chance Denominator } - Tooltip: "" - PlanteraBulbChanceDenominator: { Label: Plantera Bulb Chance Denominator Tooltip: "" @@ -647,11 +1096,6 @@ Mods: { Label: No Mechanical Boss Summon Drops Tooltip: "" } - - NoBiomeKeyDrops: { - Label: No Biome Key Drops - Tooltip: "" - } } FloatStatistic: { @@ -671,89 +1115,29 @@ Mods: { Tooltip: "" } } - - InvasionSizeValue: { - Value: { - Tooltip: "" - Label: Value - } - - Tooltip: "" - } - - TeamLifeConfig: { - Tooltip: "" - - Share: { - Label: Share - Tooltip: "" - } - } - } - - Item: { - Disabled: Cannot be used in this gamemode - NoUndergroundEmpressButterfly: Cannot be released here underground - NoUndergroundQueenSlimeCrystal: Cannot be summoned here underground - } - - Player.CannotRecall: Cannot recall! - Tiles.LockedLihzahrdChest.MapEntry: Locked Lihzahrd Chest - Sandstorm: "[c/FFC864:Desert winds are picking up...]" - Rain: "[c/6496FF:A storm is brewing overhead...]" - - NPCs: { - Bound: { - Merchant.DisplayName: Bound Merchant - ArmsDealer.DisplayName: Bound Arms Dealer - WitchDoctor.DisplayName: Bound Witch Doctor - - Steampunker: { - DisplayName: Chained Steampunker - Chat: At long last, I'm saved! The strangest people chained me up, they mentioned something about a hardcore challenge... - } - - Truffle: { - DisplayName: Buried Truffle - Chat: At long last, I'm saved! The strangest people buried me here, they mentioned something about a hardcore challenge... - } - - Cyborg: { - DisplayName: Deactivated Cyborg - Chat: At long last, I'm saved! The strangest people turned me off, they mentioned something about a hardcore challenge... - } - - Chat: At long last, I'm saved! The strangest people tied me up, they mentioned something about a hardcore challenge... - Demolitionist.DisplayName: Bound. Demolitionist - } } - Bounty.CollectedAllMechanicalBossSouls: "[c/32FF82:Cries of tortured souls emanate from the Bounty Shop...]" - - Pause: { - True: "[c/FF0000:The game has been paused.]" - False: "[c/00FF00:The game has been resumed.]" - } + Tiles.LockedLihzahrdChest.MapEntry: Mods.PvPAdventure.Tiles.LockedLihzahrdChest.MapEntry Buffs: { - ShinyStoneHotswap: { - DisplayName: Shiny Stone Hotswap - Description: Shiny Stone is charging up! + AncientChiselHotswapBuff: { + DisplayName: Ancient Chisel Hotswap Buff + Description: Mods.PvPAdventure.Buffs.AncientChiselHotswapBuff.Description } - AncientChiselHotswapBuff: { - DisplayName: THE CURSE OF THE ANCIENT CHISEL - Description: YOU CAN'T USE THAT heckin' ACCESSORY SLOT! + BROISACHOJ: { + DisplayName: B R O I S A C H O J + Description: Mods.PvPAdventure.Buffs.BROISACHOJ.Description } NewIchorPlayerDebuff: { - DisplayName: Ichor - Description: Defense reduced by one third + DisplayName: New Ichor Player Debuff + Description: Mods.PvPAdventure.Buffs.NewIchorPlayerDebuff.Description } - BROISACHOJ: { - DisplayName: BRO IS A CHOJ - Description: You are too much of a CHOJ to dash effectively + ShinyStoneHotswap: { + DisplayName: Shiny Stone Hotswap + Description: Mods.PvPAdventure.Buffs.ShinyStoneHotswap.Description } } @@ -763,18 +1147,17 @@ Mods: { Tooltip: "" } } - } -} -BuffDescription: { - BeetleMight1: Melee damage and speed increase by 15% - BeetleMight2: Melee damage and speed increase by 25% - BeetleMight3: Melee damage increase by 30% and melee speed increase by 45% + NPCs: { + Bound: { + ArmsDealer.DisplayName: Bound. Arms Dealer + Cyborg.DisplayName: Bound. Cyborg + Demolitionist.DisplayName: Bound. Demolitionist + Merchant.DisplayName: Bound. Merchant + Steampunker.DisplayName: Bound. Steampunker + Truffle.DisplayName: Bound. Truffle + WitchDoctor.DisplayName: Bound. Witch Doctor + } + } + } } - -ArmorSetBonus.BeetleDamage: - ''' - - Gain Beetles from player kills - Beetles increase your melee damage and attack speed - ''' From 076ef7898dab061198594b21169a8f6624f09899 Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Fri, 19 Sep 2025 16:10:48 -0700 Subject: [PATCH 115/206] spoawn debuff --- AdventurePlayer.cs | 40 ++++++++++++++++++++++++++++++++++ Assets/Buff/PlayerInSpawn.png | Bin 0 -> 364 bytes Localization/en-US.hjson | 5 +++++ 3 files changed, 45 insertions(+) create mode 100644 Assets/Buff/PlayerInSpawn.png diff --git a/AdventurePlayer.cs b/AdventurePlayer.cs index d7c7804f..8a5bf1a7 100644 --- a/AdventurePlayer.cs +++ b/AdventurePlayer.cs @@ -23,6 +23,7 @@ using Terraria.ModLoader.IO; using Mono.Cecil.Cil; + namespace PvPAdventure; public class AdventurePlayer : ModPlayer @@ -1228,6 +1229,26 @@ public override void PostUpdateEquips() } } +public class SpawnProtectionPlayer : ModPlayer +{ + public override void PostUpdateMiscEffects() + { + int playerTileX = (int)(Player.position.X / 16f); + int playerTileY = (int)(Player.position.Y / 16f); + + int spawnTileX = Main.spawnTileX; + int spawnTileY = Main.spawnTileY; + + int distanceX = Math.Abs(playerTileX - spawnTileX); + int distanceY = Math.Abs(playerTileY - spawnTileY); + + if (distanceX <= 25 && distanceY <= 25) + { + Player.AddBuff(ModContent.BuffType(), 2); + } + } +} + public class ShinyStoneHotswap : ModBuff { public override string Texture => $"PvPAdventure/Assets/Buff/ShinyStoneHotswap"; @@ -1275,4 +1296,23 @@ public override void SetStaticDefaults() Main.buffNoTimeDisplay[Type] = false; Main.persistentBuff[Type] = true; } +} + +public class PlayerInSpawn : ModBuff +{ + public override string Texture => $"PvPAdventure/Assets/Buff/PlayerInSpawn"; + + public override void SetStaticDefaults() + { + Main.debuff[Type] = true; + Main.buffNoSave[Type] = false; + Main.buffNoTimeDisplay[Type] = true; + Main.persistentBuff[Type] = true; + } + + public override void Update(Player player, ref int buffIndex) + { + player.GetDamage(DamageClass.Generic) *= -999f; + + } } \ No newline at end of file diff --git a/Assets/Buff/PlayerInSpawn.png b/Assets/Buff/PlayerInSpawn.png new file mode 100644 index 0000000000000000000000000000000000000000..1e716a6ad77f0ce17d3aa10d58aba61e5752af92 GIT binary patch literal 364 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k3?#4J%UA`Z7>k44ofy`glX(f`u%tWsIx;Y9 z?C1WI$O_~u2Ka=yn(8PghPuz|soA%3+P4>XO=bA}wZvBBxfMC8=?d}yRlRt*N)t$N zmjw9*|AzwxFMq~QKw-`TkH}&M2EIce%qXhi)c_P+?CIhdV&T8`QXpTm0T1(qDLSfO z{;|jDifc(YXPVc$`LoC@krDLN%`Hgb@jSa}#lEa{IXn{?C(Ybicvd5cA+$K|`nhKT znqiYSSEmeD;UnbVLWA?^~D~9bsx6Hn;Wefe_VyvM$uSH(JXt!R2L&)!brY{@y z8rHFNtha0XkP&LR_V|}AdJXS5n<8au)qQvr&#QDrJQVI!n)5iG<4tzopr03~&P2><{9 literal 0 HcmV?d00001 diff --git a/Localization/en-US.hjson b/Localization/en-US.hjson index defb6769..015e3329 100644 --- a/Localization/en-US.hjson +++ b/Localization/en-US.hjson @@ -741,6 +741,11 @@ Mods: { DisplayName: BRO IS A CHOJ Description: You are too much of a CHOJ to dash effectively } + + PlayerInSpawn: { + Description: You cannot do any other creature any harm while inside of the humble yet mysterious veiol of the spawnnyn box! + DisplayName: You, yeah, you! Are in SPAWN. + } } } } From a9d5cefb235e75c71cd466fb385e387d22591e71 Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Mon, 22 Sep 2025 12:37:46 -0700 Subject: [PATCH 116/206] made ranges make sense --- AdventureConfig.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AdventureConfig.cs b/AdventureConfig.cs index 88cb9791..b09df1b4 100644 --- a/AdventureConfig.cs +++ b/AdventureConfig.cs @@ -207,8 +207,8 @@ public class TeamLifeConfig public Dictionary TeamLifeNpcs { get; set; } = new(); - [Range(0.0f, 3000.0f)] - [DefaultValue(3000.0f)] + [Range(0.0f, 1.0f)] + [DefaultValue(0.0f)] [Description("Reduce the damage of certain projectiles after they have collided or bounced")] From 3ea05e88e4f32de985ad0fc9a640f7ef37e63887 Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Mon, 22 Sep 2025 12:57:26 -0700 Subject: [PATCH 117/206] chagned thing to be not inverted thanks --- AdventureProjectile.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AdventureProjectile.cs b/AdventureProjectile.cs index b4c3d117..0dd27de7 100644 --- a/AdventureProjectile.cs +++ b/AdventureProjectile.cs @@ -609,11 +609,11 @@ public override void ModifyHitPlayer(Projectile projectile, Player target, ref P || projectile.type == ProjectileID.LightDisc && projectile.localAI[0] > 0; if (bounced) - modifiers.SourceDamage *= 1.0f - adventureConfig.Combat.ProjectileCollisionDamageReduction; + modifiers.SourceDamage *= adventureConfig.Combat.ProjectileCollisionDamageReduction; if (adventureConfig.Combat.NoLineOfSightDamageReduction.TryGetValue(new(projectile.type), out var damageReduction) && projectile.TryGetOwner(out var owner) && !Collision.CanHit(owner, target)) - modifiers.SourceDamage *= 1.0f - damageReduction; + modifiers.SourceDamage *= damageReduction; } private void EditProjectileHandleMovement(ILContext il) From f7157103dbc26d55f4ac8a68a67064d9f47c7e44 Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Mon, 22 Sep 2025 12:58:19 -0700 Subject: [PATCH 118/206] fixed meetle bistake --- AdventureBuff.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/AdventureBuff.cs b/AdventureBuff.cs index 3c64609c..104c3fb3 100644 --- a/AdventureBuff.cs +++ b/AdventureBuff.cs @@ -21,20 +21,20 @@ public override void Update(int type, Player player, ref int buffIndex) if (player.beetleOrbs >= 1) { - damage += 0.8f; - attackSpeed += 0.8f; + damage += 0.08f; + attackSpeed += 0.08f; } if (player.beetleOrbs >= 2) { - damage += 0.8f; - attackSpeed += 0.8f; + damage += 0.08f; + attackSpeed += 0.08f; } if (player.beetleOrbs >= 3) { - damage += 0.8f; - attackSpeed += 0.8f; + damage += 0.08f; + attackSpeed += 0.08f; } player.GetDamage() += damage; From 81b4df7394397de824e913767eb3e93e8cee0e65 Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Mon, 22 Sep 2025 14:08:07 -0700 Subject: [PATCH 119/206] up[dated sprite for advventure bag --- Assets/Item/AdventureBag.png | Bin 1243 -> 933 bytes Assets/Item/anchortrophy.png | Bin 0 -> 1243 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 Assets/Item/anchortrophy.png diff --git a/Assets/Item/AdventureBag.png b/Assets/Item/AdventureBag.png index 7499cd357f5cf6168ed6175631e751edccf2ee93..9409c81367bae13ec4faf6fb0425c41020282534 100644 GIT binary patch literal 933 zcmV;W16urvP)MA)>oxNf&E0GYe7kGTB&756jiKPcuas%=usD>@{nzbN+v?z1BX*!CxYEf;0HH zbB3bjlg}}9JYqP({s%@y`a_wfCQUT#o8}|~@Up8PfOGfW0I+_3IsnrX#sCo0*$zNp zViEuct~7+bPt+A~SPja2@A8?zuS^tbj|BBsrLMhc1E8b*GZ4xJ`zfGMCD!G*4ExO& zt;RUtof&ri`8!X;`l-FHvBBmFC{&4}ym6#;{hOb^2H;&&&u`Zzm zVjY<6ni&MxvB7QFmD$0wXTr|YwN|CnUm06-Ch7|Ok^^qnoFIfMo>s6w<$$ieLYW`E zbRU4F)1@vv?(75XxC^Yzb2c^_j(M8{03;@j1t69&VFUV+%BK}?|ITRu%$?O{#Ia2! zjJOLF*L~Xn*t%QRZgu8K08SiE03abY*6?4yMY`kpx-9^7#l->e@X3Wik7mO^`U>dU zFH9Fk+P#urr2_D=<0AkS6%_!Km&?S>B~k}Y9diOu_>*}d0A*!m0F;)N0#Nr%dPq)M zA^^9W2!ah1aHs;F%oG5+{C>k>MV@4Pbz3$tR0)w{P1b1uF4mjOi;If^82E4l0KacM z0B!ve|Mdq^I_e6HYH9Bryc7kjS$*}g?At}l9snU`m6er1C?}M8K|uikabF$*A?D3} za+r=8X+A*o70`?BK;XBI{=fhLt7iCs5YwuvDgZnl4*~f z_-;59m%InSog>UVMJoaDdWE?v;q`g}$j!|K;MSQM0Cw$@u6h4f3;_N9ej~np6i|#9 zEzi``BZ@TCPXb`ib{_yWwU>bqb9Y9IF;?b_vn6!;V)?Z)|9QV*5*Riddg|30tysBM zD&X-$cL6BNmJ>~Rt-KM{)P4n^x?1}Ek|omRl)2SE-X*=p*DB|U-d-sP(N{n(REdnq z!aP4e9)NR49vc%<7ECq9zIxf`&MfnI*?RY_F%CKR-egcH4a+`Qy8x;$OcFSs7aqbp?I^g`G5ccY+#;00000NkvXX Hu0mjfC(EPL literal 1243 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 Date: Sat, 27 Sep 2025 01:20:22 -0700 Subject: [PATCH 120/206] if this was it im gonna be mad also EXPLOSION BOOM BOOOOOOOOOM --- AdventureNpc.cs | 42 +++++++++++++----------------------------- 1 file changed, 13 insertions(+), 29 deletions(-) diff --git a/AdventureNpc.cs b/AdventureNpc.cs index 13a5c36f..fa14bb8a 100644 --- a/AdventureNpc.cs +++ b/AdventureNpc.cs @@ -225,53 +225,37 @@ public override void OnKill(NPC npc) { Player player = Main.player[killingPlayer]; // AI slop solution because I can't figure out how kill credit works - + if (Main.netMode != NetmodeID.MultiplayerClient) { int projectile = Projectile.NewProjectile( npc.GetSource_Death(), - otherTwin.Center.X, - otherTwin.Center.Y, - 0f, - 0f, - 3, - 200, - 0f, - killingPlayer + otherTwin.Center.X, + otherTwin.Center.Y, + 0f, + 0f, + ProjectileID.DD2ExplosiveTrapT3Explosion, + 200, + 0f, + killingPlayer ); - + if (projectile >= 0 && projectile < Main.maxProjectiles) { Projectile proj = Main.projectile[projectile]; - + proj.penetrate = 1; - proj.timeLeft = 2; + proj.timeLeft = 120; } - + if (Main.netMode == NetmodeID.Server && projectile >= 0) { NetMessage.SendData(MessageID.SyncProjectile, -1, -1, null, projectile); } } } - else - { - - otherTwin.life = 0; - otherTwin.active = false; - - if (Main.netMode != NetmodeID.MultiplayerClient) - { - otherTwin.NPCLoot(); - } - - if (Main.netMode == NetmodeID.Server) - { - NetMessage.SendData(MessageID.SyncNPC, -1, -1, null, otherTwin.whoAmI); - } - } } } } From 13962979efa9ed08c3622131c03fa842e47c56bf Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Sun, 5 Oct 2025 18:02:24 -0700 Subject: [PATCH 121/206] FUCK FLASKS --- System/RecipeManager.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/System/RecipeManager.cs b/System/RecipeManager.cs index 3289c558..f883ed0f 100644 --- a/System/RecipeManager.cs +++ b/System/RecipeManager.cs @@ -27,7 +27,15 @@ public override void AddRecipes() ItemID.ShroomiteBar, ItemID.WormFood, ItemID.ChlorophyteBar, + ItemID.FlaskofCursedFlames, + ItemID.FlaskofIchor, + ItemID.FlaskofPoison, + ItemID.FlaskofVenom, + ItemID.FlaskofFire, + ItemID.FlaskofNanites, + ItemID.FlaskofParty, ItemID.SpectreBar + }; for (int i = 0; i < Main.recipe.Length; i++) From a31d3488a01c7fb8d3cfd3516e20442f90e497f3 Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Fri, 10 Oct 2025 19:48:58 -0700 Subject: [PATCH 122/206] It is done. --- AdventurePlayer.cs | 413 +++++++++++++++++++++++++++++---- AdventureProjectile.cs | 35 ++- Assets/Buff/Anathema.png | Bin 0 -> 449 bytes Assets/Buff/Hellhex.png | Bin 0 -> 97759 bytes Assets/Buff/ShatteredArmor.png | Bin 0 -> 441 bytes Localization/en-US.hjson | 15 ++ 6 files changed, 420 insertions(+), 43 deletions(-) create mode 100644 Assets/Buff/Anathema.png create mode 100644 Assets/Buff/Hellhex.png create mode 100644 Assets/Buff/ShatteredArmor.png diff --git a/AdventurePlayer.cs b/AdventurePlayer.cs index d7c7804f..83b718df 100644 --- a/AdventurePlayer.cs +++ b/AdventurePlayer.cs @@ -22,6 +22,7 @@ using Terraria.ModLoader.Config; using Terraria.ModLoader.IO; using Mono.Cecil.Cil; +using static PvPAdventure.AdventurePlayer; namespace PvPAdventure; @@ -750,14 +751,6 @@ public override void PostUpdateEquips() Player.yoraiz0rEye = 33; } - // 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; - } - if (Player.hasPaladinShield) { Player.buffImmune[BuffID.PaladinsShield] = true; @@ -1087,7 +1080,49 @@ public void OnPingPongReceived(PingPong pingPong) _pingPongCanary++; } - private static bool? ShouldSilenceHurtSound(Player target, Player.HurtInfo info) + public class TikiArmorPlayer : ModPlayer + { + public bool hasTikiSet = false; + + public override void PostUpdateEquips() + { + // 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) + { + hasTikiSet = true; + } + else + { + hasTikiSet = false; + } + } + } + + public class WhipRangePlayer : ModPlayer + { + public bool largeWhipIncrease = false; + + public override void PostUpdateEquips() + { + largeWhipIncrease = false; + + for (int i = 3; i < 8 + Player.GetAmountOfExtraAccessorySlotsToShow(); i++) + { + if (Player.armor[i].type == ItemID.PygmyNecklace || Player.armor[i].type == ItemID.HerculesBeetle) + { + largeWhipIncrease = true; + break; + } + } + if (largeWhipIncrease) + { + Player.whipRangeMultiplier += 0.45f; + } + } + } + private static bool? ShouldSilenceHurtSound(Player target, Player.HurtInfo info) { // Only silence hurt sound on clients that we hurt that aren't ourselves if (!Main.dedServ && info.PvP && target.whoAmI != Main.myPlayer && @@ -1136,6 +1171,50 @@ public override string ToString() return $"{Player.whoAmI}/{Player.name}/{DiscordUser?.Id}"; } } + +public class TurtleDashPlayer : ModPlayer +{ + private bool isWearingFullTurtleArmor = false; + private int dashingTimer = 0; + + // Detect if player is in a dash state + public bool IsInADashState => (Player.dashDelay == -1 || dashingTimer > 0) && Player.grapCount <= 0; + + public override void PostUpdateEquips() + { + + isWearingFullTurtleArmor = Player.armor[0].type == ItemID.TurtleHelmet && + Player.armor[1].type == ItemID.TurtleScaleMail && + Player.armor[2].type == ItemID.TurtleLeggings; + + if (isWearingFullTurtleArmor) + { + Player.AddBuff(ModContent.BuffType(), 1 * 60 * 60); + } + } + + public override void PostUpdate() + { + + if (Player.dashDelay == -1) + { + dashingTimer = 10; + } + else if (dashingTimer > 0) + { + dashingTimer--; + } + + // Apply dash speed reduction if player has the debuff and is dashing + if (Player.HasBuff(ModContent.BuffType()) && IsInADashState) + { + float dashSpeedReduction = Player.velocity.X * 0.05f; + Player.velocity.X -= dashSpeedReduction; + } + //thanks mr fargo + } +} + public class NewIchorPlayer : ModPlayer { public bool hasDefenseReduction = false; @@ -1171,59 +1250,270 @@ public override void PostUpdateBuffs() } } - public class TurtleDashPlayer : ModPlayer + public override void PostUpdateEquips() + { + + if (hasDefenseReduction) + { + // Calculate 33% reduction (rounded down) + int originalDefense = Player.statDefense; + int reduction = (int)(originalDefense * 0.33f); + Player.statDefense -= reduction; + Player.ichor = true; + } + } +} +public class CoolWhipBuff : ModPlayer +{ + public override void PostHurt(Player.HurtInfo info) { - private bool isWearingFullTurtleArmor = false; - private int dashingTimer = 0; + if (info.DamageSource.SourceProjectileType == ProjectileID.CoolWhip) + { + Player.AddBuff(BuffID.ScytheWhipPlayerBuff, 1); + } + } - // Detect if player is in a dash state - public bool IsInADashState => (Player.dashDelay == -1 || dashingTimer > 0) && Player.grapCount <= 0; - public override void PostUpdateEquips() +} +public class ShatteredArmorPlayer : ModPlayer +{ + public override void PostHurt(Player.HurtInfo info) + { + // Check if hit by MaceWhip projectile + if (info.DamageSource.SourceProjectileType == ProjectileID.MaceWhip) { + int duration = 420; // 7 seconds base + + // Check if attacker has Tiki set bonus + if (info.DamageSource.SourcePlayerIndex >= 0 && info.DamageSource.SourcePlayerIndex < Main.maxPlayers) + { + Player attacker = Main.player[info.DamageSource.SourcePlayerIndex]; + if (attacker != null && attacker.active) + { + TikiArmorPlayer tikiPlayer = attacker.GetModPlayer(); + if (tikiPlayer.hasTikiSet) + { + duration = (int)(duration * 1.5f); // 50% longer = 10.5 seconds + } + } + } - isWearingFullTurtleArmor = Player.armor[0].type == ItemID.TurtleHelmet && - Player.armor[1].type == ItemID.TurtleScaleMail && - Player.armor[2].type == ItemID.TurtleLeggings; + Player.AddBuff(ModContent.BuffType(), duration); + } + } - if (isWearingFullTurtleArmor) + public override void PostUpdateBuffs() + { + if (Player.HasBuff()) + { + Player.statDefense -= 16; + + for (int i = 0; i < 1; i++) { - Player.AddBuff(ModContent.BuffType(), 1 * 60 * 60); + int dustType = DustID.BatScepter ; + Vector2 dustPosition = Player.position + new Vector2(Main.rand.Next(Player.width), Main.rand.Next(Player.height)); + Vector2 dustVelocity = Player.velocity * 0.3f + new Vector2(Main.rand.NextFloat(-1f, 1f), Main.rand.NextFloat(-1f, 1f)); + + Dust dust = Dust.NewDustDirect(dustPosition, 0, 0, dustType, dustVelocity.X, dustVelocity.Y, 100, Color.Black, Main.rand.NextFloat(0.8f, 1.5f)); + dust.noGravity = Main.rand.NextBool(2); + dust.fadeIn = 1.2f; } } + } - public override void PostUpdate() + public override void ModifyHurt(ref Player.HurtModifiers modifiers) + { + if (Player.HasBuff()) { + bool isSummon = false; - if (Player.dashDelay == -1) + if (modifiers.DamageSource.SourceProjectileLocalIndex >= 0) { - dashingTimer = 10; + Projectile proj = Main.projectile[modifiers.DamageSource.SourceProjectileLocalIndex]; + if (proj != null && proj.active && (proj.minion || proj.sentry || proj.CountsAsClass(DamageClass.SummonMeleeSpeed))) + { + isSummon = true; + } } - else if (dashingTimer > 0) + else if (modifiers.DamageSource.SourceProjectileType > 0) { - dashingTimer--; + int projType = modifiers.DamageSource.SourceProjectileType; + if (projType == ProjectileID.BlandWhip || projType == ProjectileID.FireWhip || + projType == ProjectileID.SwordWhip || projType == ProjectileID.MaceWhip || + projType == ProjectileID.ScytheWhip || projType == ProjectileID.ThornWhip || + projType == ProjectileID.BoneWhip || projType == ProjectileID.RainbowWhip || + projType == ProjectileID.CoolWhip) + { + isSummon = true; + } } - // Apply dash speed reduction if player has the debuff and is dashing - if (Player.HasBuff(ModContent.BuffType()) && IsInADashState) + if (!isSummon) { - float dashSpeedReduction = Player.velocity.X * 0.05f; - Player.velocity.X -= dashSpeedReduction; + modifiers.FinalDamage *= 1.12f; } - //thanks mr fargo } } +} - public override void PostUpdateEquips() +public class HellhexPlayer : ModPlayer +{ + public bool hellhexTriggered = false; + private int storedDamage = 0; + private int lastImmuneTime = 0; + + public override void PostUpdate() + { + // Detect when the player takes damage by checking immune time + if (Player.HasBuff() && Player.immuneTime > lastImmuneTime && Player.immuneTime > 0) + { + // Player just took damage, set flag to remove buff + hellhexTriggered = true; + } + + lastImmuneTime = Player.immuneTime; + } + + public override void PostHurt(Player.HurtInfo info) { + if (info.DamageSource.SourceProjectileType == ProjectileID.FireWhip) + { + int duration = 840; // 14 seconds base - if (hasDefenseReduction) + // Check if attacker has Tiki set bonus + if (info.DamageSource.SourcePlayerIndex >= 0 && info.DamageSource.SourcePlayerIndex < Main.maxPlayers) + { + Player attacker = Main.player[info.DamageSource.SourcePlayerIndex]; + if (attacker != null && attacker.active) + { + TikiArmorPlayer tikiPlayer = attacker.GetModPlayer(); + if (tikiPlayer.hasTikiSet) + { + duration = (int)(duration * 1.5f); + } + } + } + + Player.AddBuff(ModContent.BuffType(), duration); + } + + // If player has Hellhex and takes non-summon damage, remove it + if (Player.HasBuff()) { - // Calculate 33% reduction (rounded down) - int originalDefense = Player.statDefense; - int reduction = (int)(originalDefense * 0.33f); - Player.statDefense -= reduction; - Player.ichor = true; + bool isSummon = false; + + // Check if damage is from summon projectile + if (info.DamageSource.SourceProjectileLocalIndex >= 0) + { + Projectile proj = Main.projectile[info.DamageSource.SourceProjectileLocalIndex]; + if (proj.minion || proj.sentry || proj.CountsAsClass(DamageClass.SummonMeleeSpeed)) + { + isSummon = true; + } + } + + // Only remove buff and trigger effects if NOT summon damage + if (!isSummon) + { + int buffIndex = Player.FindBuffIndex(ModContent.BuffType()); + if (buffIndex >= 0) + { + Player.buffTime[buffIndex] = 0; + } + + // Spawn explosion projectile + if (Main.myPlayer == Player.whoAmI) + { + Vector2 spawnPos = Player.Center; + + Projectile.NewProjectile( + Player.GetSource_Buff(buffIndex), + spawnPos, + Vector2.Zero, + ProjectileID.FireWhipProj, + info.Damage, + 0f, + Player.whoAmI + ); + } + } + } + } + + public override void ModifyHurt(ref Player.HurtModifiers modifiers) + { + // Double damage from non-summon sources while having Hellhex + if (Player.HasBuff()) + { + bool isSummon = false; + + // Check if damage is from summon/whip projectile + if (modifiers.DamageSource.SourceProjectileLocalIndex >= 0) + { + Projectile proj = Main.projectile[modifiers.DamageSource.SourceProjectileLocalIndex]; + if (proj != null && proj.active && (proj.minion || proj.sentry || proj.CountsAsClass(DamageClass.SummonMeleeSpeed))) + { + isSummon = true; + } + } + // Also check by projectile type for whips + else if (modifiers.DamageSource.SourceProjectileType > 0) + { + int projType = modifiers.DamageSource.SourceProjectileType; + // Check if it's a whip projectile type + if (projType == ProjectileID.BlandWhip || projType == ProjectileID.FireWhip || + projType == ProjectileID.SwordWhip || projType == ProjectileID.MaceWhip || + projType == ProjectileID.ScytheWhip || projType == ProjectileID.ThornWhip || + projType == ProjectileID.BoneWhip || projType == ProjectileID.RainbowWhip || + projType == ProjectileID.CoolWhip) + { + isSummon = true; + } + } + + // Only apply double damage for non-summon damage + if (!isSummon) + { + modifiers.FinalDamage *= 2f; // Double damage + modifiers.ModifyHurtInfo += (ref Player.HurtInfo info) => { + storedDamage = info.Damage; + }; + hellhexTriggered = true; + } + } + } + + public override void PostUpdateBuffs() + { + if (Player.HasBuff()) + { + // Create hellfire particle shower + for (int i = 0; i < 2; i++) + { + int dustType = DustID.Torch; // Orange/red fire dust + Vector2 dustPosition = Player.position + new Vector2(Main.rand.Next(Player.width), Main.rand.Next(Player.height)); + Vector2 dustVelocity = new Vector2(Main.rand.NextFloat(-0.5f, 0.5f), Main.rand.NextFloat(-2f, 0f)); // Upward shower + + Dust dust = Dust.NewDustDirect(dustPosition, 0, 0, dustType, dustVelocity.X, dustVelocity.Y, 100, default(Color), Main.rand.NextFloat(1f, 2f)); + dust.noGravity = true; + dust.fadeIn = 1.3f; + } + + // Add some darker fire particles for variety + if (Main.rand.NextBool(2)) + { + int dustType = DustID.Smoke; + Vector2 dustPosition = Player.position + new Vector2(Main.rand.Next(Player.width), Main.rand.Next(Player.height)); + Vector2 dustVelocity = new Vector2(Main.rand.NextFloat(-0.5f, 0.5f), Main.rand.NextFloat(-1.5f, 0f)); + + Dust dust = Dust.NewDustDirect(dustPosition, 0, 0, dustType, dustVelocity.X, dustVelocity.Y, 100, Color.OrangeRed, Main.rand.NextFloat(0.8f, 1.5f)); + dust.noGravity = true; + } + } + else + { + // Reset trigger flag when buff is not active + hellhexTriggered = false; } } } @@ -1236,7 +1526,7 @@ public override void SetStaticDefaults() { Main.debuff[Type] = true; Main.buffNoSave[Type] = true; - Main.buffNoTimeDisplay[Type] = false; // Show timer + Main.buffNoTimeDisplay[Type] = false; } } public class AncientChiselHotswapBuff : ModBuff @@ -1247,7 +1537,7 @@ public override void SetStaticDefaults() { Main.debuff[Type] = true; Main.buffNoSave[Type] = false; - Main.buffNoTimeDisplay[Type] = false; // Show timer + Main.buffNoTimeDisplay[Type] = false; Main.persistentBuff[Type] = true; } } @@ -1275,4 +1565,49 @@ public override void SetStaticDefaults() Main.buffNoTimeDisplay[Type] = false; Main.persistentBuff[Type] = true; } +} +public class ShatteredArmor : ModBuff +{ + public override string Texture => $"PvPAdventure/Assets/Buff/ShatteredArmor"; + + public override void SetStaticDefaults() + { + Main.debuff[Type] = true; + Main.buffNoSave[Type] = false; + Main.buffNoTimeDisplay[Type] = false; + Main.persistentBuff[Type] = true; + BuffID.Sets.IsATagBuff[Type] = false; + } + public override void Update(Player player, ref int buffIndex) + { + } +} +public class Anathema : ModBuff +{ + public override string Texture => $"PvPAdventure/Assets/Buff/Anathema"; + + public override void SetStaticDefaults() + { + Main.debuff[Type] = true; + Main.buffNoSave[Type] = false; + Main.buffNoTimeDisplay[Type] = false; + Main.persistentBuff[Type] = true; + } +} +public class Hellhex : ModBuff +{ + public override string Texture => $"PvPAdventure/Assets/Buff/Hellhex"; + + public override void SetStaticDefaults() + { + Main.debuff[Type] = true; + Main.buffNoSave[Type] = false; + Main.buffNoTimeDisplay[Type] = false; + Main.persistentBuff[Type] = true; + } + + public override void Update(Player player, ref int buffIndex) + { + // Visual effects and buff management handled in ModPlayer + } } \ No newline at end of file diff --git a/AdventureProjectile.cs b/AdventureProjectile.cs index 03beedce..fb8b5356 100644 --- a/AdventureProjectile.cs +++ b/AdventureProjectile.cs @@ -524,18 +524,45 @@ public override void AI(Projectile projectile) } } - public class MorningStarRange : GlobalProjectile + public class WhipRangeChanges : GlobalProjectile { public override bool AppliesToEntity(Projectile projectile, bool lateInstantiation) { - return projectile.type == ProjectileID.MaceWhip; + return projectile.type == ProjectileID.MaceWhip || + projectile.type == ProjectileID.RainbowWhip || + projectile.type == ProjectileID.CoolWhip || + projectile.type == ProjectileID.FireWhip || + projectile.type == ProjectileID.SwordWhip || + projectile.type == ProjectileID.ScytheWhip || + projectile.type == ProjectileID.ThornWhip || + projectile.type == ProjectileID.BoneWhip || + projectile.type == ProjectileID.BlandWhip; } public override void SetDefaults(Projectile projectile) { if (projectile.type == ProjectileID.MaceWhip) { - projectile.WhipSettings.RangeMultiplier = 1.33f; // this is like 20% range - + projectile.WhipSettings.RangeMultiplier = 1.03f; // this is like 20% range + } + if (projectile.type == ProjectileID.RainbowWhip) + { + projectile.WhipSettings.RangeMultiplier = 1.43f; // this is like 20% range + } + if (projectile.type == ProjectileID.CoolWhip) + { + projectile.WhipSettings.RangeMultiplier = 1.18f; // this is like 20% range + } + if (projectile.type == ProjectileID.FireWhip) + { + projectile.WhipSettings.RangeMultiplier = 1.18f; // this is like 20% range + } + if (projectile.type == ProjectileID.SwordWhip) + { + projectile.WhipSettings.RangeMultiplier = 1.4f; // this is like 20% range + } + if (projectile.type == ProjectileID.ScytheWhip) + { + projectile.WhipSettings.RangeMultiplier = 2f; // this is like 20% range } } } diff --git a/Assets/Buff/Anathema.png b/Assets/Buff/Anathema.png new file mode 100644 index 0000000000000000000000000000000000000000..7bd5a55c911f74878f9e6ae1a339debe43850403 GIT binary patch literal 449 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vO2U$sR$z3=CCj3=9n|3=F@3LJcn% z7)lKo7+xhXFj&oCU=S~uvn$XBC?Oi)6XFV_fk0N!_Wyp*nV#DJ|4;k>|NkQGdz?T~ z#*!evUYw#2j@wLlJgiKnkC`%5l1MpZ+t)v_R=3Qrfu5RLP#7ccT2 zP~cz*2uo;PSD?Lt>G%2|{#WfxD?NjMFM1jvXxrw&SZg8j%h$?4@9T{O+k#4_l7_FT ze9C?c9PE6;8m}ht&2HQoc}rF{Veid|9c2^jYu{<9Pf1YymBm+ATFvlHGO1z3wDb&H zmp8S+ynpWf<31s2`7({Cv0IvXk~0} zWn!sqU|?lnaBQZI3yOx^{FKbJO57T@ADQw4s6hj6LrG?CYH>+oZUJsR4=!$12kK$) MboFyt=akR{0CWk9;Q#;t literal 0 HcmV?d00001 diff --git a/Assets/Buff/Hellhex.png b/Assets/Buff/Hellhex.png new file mode 100644 index 0000000000000000000000000000000000000000..e0bc55b94f4e2ebf7c76508e69586a9bfdb53f5e GIT binary patch literal 97759 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

4+e$0sZG_WLBVKfYpIx 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 E17mSI+yDRo diff --git a/Assets/Buff/Marked.png b/Assets/Buff/Marked.png new file mode 100644 index 0000000000000000000000000000000000000000..8e56c319d31acf381ec6f526c3f8efdbdeb00c20 GIT binary patch literal 589 zcmV-T06V6;PsLc9VS3bi|>up!avXiPM*u(t3MNGMGB1Z^!evC@jhn9!JTYG(|w zk>UtqJn1k{SZLhccVx#~l*HtAnt`3&h4<#o?5=4D%UkQ8Mu=JccjmK`ePa}R?8TV( zVpE~card4H$V9sy@5-{ukbA&>ut}iJk%EBIw~FKzlc=((LjN0x=97wb9}0c9tz^AM^z<3)80xpaJxO z!qEovP;aSR3q?!~T0zcjf_QKr(2arMpP?FrTEPs?j7*%Lnwz_e(nc3253)vtsrrCE z4AA=ktp*s7LmM=1D^5{*2B4}A-+G!bpt=vB8ZZuR01>?CTU^2zez>IMR=avZLvCJYvB zqUl#O1ODfE{Qv)d;r4?{Ky{2IL4Lsu4$p3+fjCLt?k+ryn*)=99QG1VUsv{*T-*X? z2A9v)J_ZWad%8G=Xq<1o7|6?_$m1HQldw>1Ljd>rEyhP1j|VV^+b2B9q%&|7}rc(%+&I2vYoF5^PUsGxLQ^! z?$hcxD`IZ9y5+{5=T*$cCuXtA9E^D`Qt|)7IiVlFe~T|UIHfkcu}v4~6x9;fh?11V zl2ohYqEsNoU}Ruqs%vPVYiJl^Xl7+I)to5 kfEqO5Hk4%MrWThZ<`&@AbDv%MG*AzNr>mdKI;Vst0BuB;QUCw| literal 0 HcmV?d00001 diff --git a/Localization/en-US.hjson b/Localization/en-US.hjson index 419f9ccc..58c8cfee 100644 --- a/Localization/en-US.hjson +++ b/Localization/en-US.hjson @@ -1121,23 +1121,63 @@ Mods: { Buffs: { AncientChiselHotswapBuff: { - DisplayName: Ancient Chisel Hotswap Buff - Description: Mods.PvPAdventure.Buffs.AncientChiselHotswapBuff.Description + DisplayName: the curse of the ancient chisel + Description: Broken ahh debuff } BROISACHOJ: { DisplayName: B R O I S A C H O J - Description: Mods.PvPAdventure.Buffs.BROISACHOJ.Description + Description: bro is a choj } NewIchorPlayerDebuff: { - DisplayName: New Ichor Player Debuff - Description: Mods.PvPAdventure.Buffs.NewIchorPlayerDebuff.Description + DisplayName: Ichor + Description: Reduces defense by a third. } ShinyStoneHotswap: { DisplayName: Shiny Stone Hotswap - Description: Mods.PvPAdventure.Buffs.ShinyStoneHotswap.Description + Description: The shiny stone is charging up! + } + + Anathema: { + Description: You are hated by the world. + DisplayName: Anathema + } + + Hellhex: { + Description: You are going to burst with hellfire at any moment! + DisplayName: Hellhex + } + + ShatteredArmor: { + Description: You're armor has been shattered by a brutal blow! + DisplayName: Shattered Armor + } + + PlayerInSpawn: { + DisplayName: spawn + Description: You're in spawn bro + } + + BitingEmbrace: { + DisplayName: Biting Embrace + Description: You are weakened by the cold. + } + + BrittleBones: { + DisplayName: Brittle Bones + Description: Your bones are weakened, and so are you. + } + + Marked: { + DisplayName: Marked + Description: You're the target. + } + + PressurePoints: { + DisplayName: Pressure Points + Description: Thorns press into your skin. } } @@ -1158,26 +1198,6 @@ Mods: { Truffle.DisplayName: Bound. Truffle WitchDoctor.DisplayName: Bound. Witch Doctor } - - PlayerInSpawn: { - Description: You cannot do any other creature any harm while inside of the humble yet mysterious veiol of the spawnnyn box! - DisplayName: You, yeah, you! Are in SPAWN. - } - - ShatteredArmor: { - Description: Mods.PvPAdventure.Buffs.ShatteredArmor.Description - DisplayName: Shattered Armor - } - - Anathema: { - Description: Mods.PvPAdventure.Buffs.Anathema.Description - DisplayName: Anathema - } - - Hellhex: { - Description: Mods.PvPAdventure.Buffs.Hellhex.Description - DisplayName: Hellhex - } } } } From d4acc5bee0f9e45118f16744a282b0d9decfa7eb Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Sat, 11 Oct 2025 10:40:01 -0700 Subject: [PATCH 125/206] makes the damage work --- AdventurePlayer.cs | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/AdventurePlayer.cs b/AdventurePlayer.cs index 5f2b7f2f..6966f7f4 100644 --- a/AdventurePlayer.cs +++ b/AdventurePlayer.cs @@ -1269,9 +1269,7 @@ public override void PostHurt(Player.HurtInfo info) { if (info.DamageSource.SourceProjectileType == ProjectileID.CoolWhip) { - int duration = 300; - if (info.DamageSource.SourcePlayerIndex >= 0 && info.DamageSource.SourcePlayerIndex < Main.maxPlayers) { Player attacker = Main.player[info.DamageSource.SourcePlayerIndex]; @@ -1284,17 +1282,16 @@ public override void PostHurt(Player.HurtInfo info) } } } - Player.AddBuff(ModContent.BuffType(), duration); Player.AddBuff(BuffID.Frozen, duration / 75); } } + public override void ModifyHurt(ref Player.HurtModifiers modifiers) { if (Player.HasBuff()) { bool isSummon = false; - if (modifiers.DamageSource.SourceProjectileLocalIndex >= 0) { Projectile proj = Main.projectile[modifiers.DamageSource.SourceProjectileLocalIndex]; @@ -1315,10 +1312,11 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) isSummon = true; } } - if (!isSummon) { - modifiers.FinalDamage += 6; + modifiers.ModifyHurtInfo += (ref Player.HurtInfo info) => { + info.Damage += 6; + }; } } } @@ -1378,7 +1376,9 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) if (!isSummon) { - modifiers.FinalDamage += 6; + modifiers.ModifyHurtInfo += (ref Player.HurtInfo info) => { + info.Damage += 6; + }; } } } @@ -1438,7 +1438,9 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) if (!isSummon) { - modifiers.FinalDamage += 7; + modifiers.ModifyHurtInfo += (ref Player.HurtInfo info) => { + info.Damage += 7; + }; } } } @@ -1497,7 +1499,9 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) if (!isSummon) { - modifiers.FinalDamage += 9; + modifiers.ModifyHurtInfo += (ref Player.HurtInfo info) => { + info.Damage += 9; + }; } } } @@ -1556,8 +1560,11 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) if (!isSummon) { - modifiers.FinalDamage += 8; + modifiers.ModifyHurtInfo += (ref Player.HurtInfo info) => { + info.Damage += 20; + }; modifiers.FinalDamage *= 1.1f; + } } } @@ -1634,8 +1641,11 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) if (!isSummon) { - modifiers.FinalDamage += 8; + modifiers.ModifyHurtInfo += (ref Player.HurtInfo info) => { + info.Damage += 8; + }; modifiers.FinalDamage *= 1.12f; + } } } From 70d268e64846b657520845bf2b05b219bd40ec35 Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Sat, 11 Oct 2025 11:18:17 -0700 Subject: [PATCH 126/206] CHANGES --- AdventurePlayer.cs | 6 +++--- AdventureProjectile.cs | 2 ++ Localization/en-US.hjson | 20 ++++++++++++++++++++ 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/AdventurePlayer.cs b/AdventurePlayer.cs index fbb039c4..74472938 100644 --- a/AdventurePlayer.cs +++ b/AdventurePlayer.cs @@ -1269,7 +1269,7 @@ public override void PostHurt(Player.HurtInfo info) { if (info.DamageSource.SourceProjectileType == ProjectileID.CoolWhip) { - Player.AddBuff(BuffID.ScytheWhipPlayerBuff, 1); + Player.AddBuff(BuffID.Frozen, 2); } } @@ -1282,7 +1282,7 @@ public override void PostHurt(Player.HurtInfo info) // Check if hit by MaceWhip projectile if (info.DamageSource.SourceProjectileType == ProjectileID.MaceWhip) { - int duration = 420; // 7 seconds base + int duration = 300; // 5 seconds base // Check if attacker has Tiki set bonus if (info.DamageSource.SourcePlayerIndex >= 0 && info.DamageSource.SourcePlayerIndex < Main.maxPlayers) @@ -1293,7 +1293,7 @@ public override void PostHurt(Player.HurtInfo info) TikiArmorPlayer tikiPlayer = attacker.GetModPlayer(); if (tikiPlayer.hasTikiSet) { - duration = (int)(duration * 1.5f); // 50% longer = 10.5 seconds + duration = (int)(duration * 1.5f); // 50% longer = mroes seconds } } } diff --git a/AdventureProjectile.cs b/AdventureProjectile.cs index 6d060561..a5e3eec5 100644 --- a/AdventureProjectile.cs +++ b/AdventureProjectile.cs @@ -702,6 +702,7 @@ public override void ModifyHitPlayer(Projectile projectile, Player target, ref P } } } + if (projectile.type == ProjectileID.ThornWhip && target.hostile) { if (projectile.owner >= 0 && projectile.owner < Main.maxPlayers) @@ -715,6 +716,7 @@ public override void ModifyHitPlayer(Projectile projectile, Player target, ref P } } } + if (projectile.type == ProjectileID.ScytheWhip && target.hostile) { if (projectile.owner >= 0 && projectile.owner < Main.maxPlayers) diff --git a/Localization/en-US.hjson b/Localization/en-US.hjson index 419f9ccc..c4af565d 100644 --- a/Localization/en-US.hjson +++ b/Localization/en-US.hjson @@ -1139,6 +1139,26 @@ Mods: { DisplayName: Shiny Stone Hotswap Description: Mods.PvPAdventure.Buffs.ShinyStoneHotswap.Description } + + Anathema: { + DisplayName: Anathema + Description: Mods.PvPAdventure.Buffs.Anathema.Description + } + + Hellhex: { + DisplayName: Hellhex + Description: Mods.PvPAdventure.Buffs.Hellhex.Description + } + + PlayerInSpawn: { + DisplayName: Player In Spawn + Description: Mods.PvPAdventure.Buffs.PlayerInSpawn.Description + } + + ShatteredArmor: { + DisplayName: Shattered Armor + Description: Mods.PvPAdventure.Buffs.ShatteredArmor.Description + } } Items: { From ace1bbd7acaa994bd2e7b50ffa460ea7cae33988 Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Sat, 11 Oct 2025 11:22:21 -0700 Subject: [PATCH 127/206] Revert "CHANGES" This reverts commit 70d268e64846b657520845bf2b05b219bd40ec35. --- AdventurePlayer.cs | 6 +++--- AdventureProjectile.cs | 2 -- Localization/en-US.hjson | 20 -------------------- 3 files changed, 3 insertions(+), 25 deletions(-) diff --git a/AdventurePlayer.cs b/AdventurePlayer.cs index 74472938..fbb039c4 100644 --- a/AdventurePlayer.cs +++ b/AdventurePlayer.cs @@ -1269,7 +1269,7 @@ public override void PostHurt(Player.HurtInfo info) { if (info.DamageSource.SourceProjectileType == ProjectileID.CoolWhip) { - Player.AddBuff(BuffID.Frozen, 2); + Player.AddBuff(BuffID.ScytheWhipPlayerBuff, 1); } } @@ -1282,7 +1282,7 @@ public override void PostHurt(Player.HurtInfo info) // Check if hit by MaceWhip projectile if (info.DamageSource.SourceProjectileType == ProjectileID.MaceWhip) { - int duration = 300; // 5 seconds base + int duration = 420; // 7 seconds base // Check if attacker has Tiki set bonus if (info.DamageSource.SourcePlayerIndex >= 0 && info.DamageSource.SourcePlayerIndex < Main.maxPlayers) @@ -1293,7 +1293,7 @@ public override void PostHurt(Player.HurtInfo info) TikiArmorPlayer tikiPlayer = attacker.GetModPlayer(); if (tikiPlayer.hasTikiSet) { - duration = (int)(duration * 1.5f); // 50% longer = mroes seconds + duration = (int)(duration * 1.5f); // 50% longer = 10.5 seconds } } } diff --git a/AdventureProjectile.cs b/AdventureProjectile.cs index a5e3eec5..6d060561 100644 --- a/AdventureProjectile.cs +++ b/AdventureProjectile.cs @@ -702,7 +702,6 @@ public override void ModifyHitPlayer(Projectile projectile, Player target, ref P } } } - if (projectile.type == ProjectileID.ThornWhip && target.hostile) { if (projectile.owner >= 0 && projectile.owner < Main.maxPlayers) @@ -716,7 +715,6 @@ public override void ModifyHitPlayer(Projectile projectile, Player target, ref P } } } - if (projectile.type == ProjectileID.ScytheWhip && target.hostile) { if (projectile.owner >= 0 && projectile.owner < Main.maxPlayers) diff --git a/Localization/en-US.hjson b/Localization/en-US.hjson index c4af565d..419f9ccc 100644 --- a/Localization/en-US.hjson +++ b/Localization/en-US.hjson @@ -1139,26 +1139,6 @@ Mods: { DisplayName: Shiny Stone Hotswap Description: Mods.PvPAdventure.Buffs.ShinyStoneHotswap.Description } - - Anathema: { - DisplayName: Anathema - Description: Mods.PvPAdventure.Buffs.Anathema.Description - } - - Hellhex: { - DisplayName: Hellhex - Description: Mods.PvPAdventure.Buffs.Hellhex.Description - } - - PlayerInSpawn: { - DisplayName: Player In Spawn - Description: Mods.PvPAdventure.Buffs.PlayerInSpawn.Description - } - - ShatteredArmor: { - DisplayName: Shattered Armor - Description: Mods.PvPAdventure.Buffs.ShatteredArmor.Description - } } Items: { From a7838f47b0725190653d19ff43f3cda17364396e Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Sun, 12 Oct 2025 23:16:17 -0700 Subject: [PATCH 128/206] big fixes, qol changes, and balancing --- AdventureDropDatabase.cs | 38 ++++++- AdventurePlayer.cs | 235 +++++++++++++++++++++++++++++++++++++-- AdventureProjectile.cs | 25 +++++ 3 files changed, 288 insertions(+), 10 deletions(-) diff --git a/AdventureDropDatabase.cs b/AdventureDropDatabase.cs index 36d4cdd1..fb308da9 100644 --- a/AdventureDropDatabase.cs +++ b/AdventureDropDatabase.cs @@ -286,18 +286,20 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) (drop is CommonDrop commonDrop && commonDrop.itemId == ItemID.HoneyComb) || drop is DropBasedOnExpertMode); - npcLoot.Add(ItemDropRule.OneFromOptions(1, + npcLoot.Add(ItemDropRule.FewFromOptions(1, ItemID.BeeKeeper, ItemID.BeesKnees ) ); - npcLoot.Add(ItemDropRule.OneFromOptions(1, + npcLoot.Add(ItemDropRule.FewFromOptions(1, ItemID.BeeGun, ItemID.HoneyComb ) ); - + npcLoot.Add(ItemDropRule.Common(ItemID.BeeWax, 1, 70, 200)); + npcLoot.Add(ItemDropRule.Common(ItemID.HoneyComb, 1, 1, 2)); + npcLoot.Add(ItemDropRule.Common(ItemID.GoldCoin, 1, 10, 15)); break; case NPCID.SkeletronHead: @@ -329,6 +331,8 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) case NPCID.WallofFlesh: + npcLoot.RemoveWhere(drop => drop is LeadingConditionRule); + var wofFirstKillRule = new LeadingConditionRule(new FirstBossKillCondition(NPCID.WallofFlesh)); wofFirstKillRule.OnSuccess(ItemDropRule.OneFromOptions(1, ItemID.WarriorEmblem, @@ -337,12 +341,40 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) ItemID.SummonerEmblem )); npcLoot.Add(wofFirstKillRule); + npcLoot.Add( + new OneFromRulesRule(1, + ItemDropRule.Common(ItemID.WarriorEmblem), + ItemDropRule.Common(ItemID.RangerEmblem), + ItemDropRule.Common(ItemID.SorcererEmblem), + ItemDropRule.Common(ItemID.SummonerEmblem) + ) + ); + npcLoot.Add( + new OneFromRulesRule(1, + ItemDropRule.Common(ItemID.FireWhip), + ItemDropRule.Common(ItemID.BreakerBlade) + ) + ); + npcLoot.Add( + new OneFromRulesRule(1, + ItemDropRule.Common(ItemID.LaserRifle), + ItemDropRule.Common(ItemID.ClockworkAssaultRifle) + ) + ); break; case NPCID.DukeFishron: npcLoot.RemoveWhere(drop => drop is LeadingConditionRule); + foreach (var drop in drops) + { + if (drop is OneFromOptionsNotScaledWithLuckDropRule oneFromOptionsNotScaledWithLuckDropRule) + { + oneFromOptionsNotScaledWithLuckDropRule.dropIds = oneFromOptionsNotScaledWithLuckDropRule + .dropIds.Where(id => id != ItemID.FishronWings).ToArray(); + } + } var dukefirstKillRule = new LeadingConditionRule(new FirstBossKillCondition(NPCID.DukeFishron)); dukefirstKillRule.OnSuccess(ItemDropRule.Common(ItemID.Tsunami, 1)); diff --git a/AdventurePlayer.cs b/AdventurePlayer.cs index 6966f7f4..6e13df3e 100644 --- a/AdventurePlayer.cs +++ b/AdventurePlayer.cs @@ -1278,7 +1278,7 @@ public override void PostHurt(Player.HurtInfo info) TikiArmorPlayer tikiPlayer = attacker.GetModPlayer(); if (tikiPlayer.hasTikiSet) { - duration = (int)(duration * 1.5f); + duration = (int)(duration * 2.5f); } } } @@ -1286,6 +1286,50 @@ public override void PostHurt(Player.HurtInfo info) Player.AddBuff(BuffID.Frozen, duration / 75); } } + public override void PostUpdateBuffs() + { + if (Player.HasBuff()) + { + float pulseTime = Main.GameUpdateCount % 60f / 60f; + float pulseScale = 1f + (float)Math.Sin(pulseTime * MathHelper.TwoPi) * 0.2f; + + for (int i = 0; i < 4; i++) + { + float angle = (MathHelper.TwoPi / 4f) * i + (Main.GameUpdateCount * 0.07f); + float distance = 21f * pulseScale; + + Vector2 offset = new Vector2( + (float)Math.Cos(angle) * distance, + (float)Math.Sin(angle) * distance + ); + Vector2 dustPosition = Player.Center + offset; + + Dust dust = Dust.NewDustPerfect(dustPosition, DustID.IceTorch, Vector2.Zero, 100, Color.Teal, 1.5f); + dust.noGravity = true; + dust.fadeIn = 1f; + dust.noLight = false; + } + + if (Main.rand.NextBool(3)) + { + for (int i = 0; i < 2; i++) + { + float lineAngle = i * MathHelper.PiOver2; + float lineDistance = Main.rand.NextFloat(10f, 40f); + + Vector2 lineOffset = new Vector2( + (float)Math.Cos(lineAngle) * lineDistance, + (float)Math.Sin(lineAngle) * lineDistance + ); + Vector2 dustPos = Player.Center + lineOffset; + + Dust lineDust = Dust.NewDustPerfect(dustPos, DustID.Torch, Vector2.Zero, 100, Color.Teal, 1f); + lineDust.noGravity = true; + lineDust.fadeIn = 0.5f; + } + } + } + } public override void ModifyHurt(ref Player.HurtModifiers modifiers) { @@ -1338,7 +1382,7 @@ public override void PostHurt(Player.HurtInfo info) TikiArmorPlayer tikiPlayer = attacker.GetModPlayer(); if (tikiPlayer.hasTikiSet) { - duration = (int)(duration * 1.5f); + duration = (int)(duration * 2.5f); } } } @@ -1347,6 +1391,52 @@ public override void PostHurt(Player.HurtInfo info) } } + + public override void PostUpdateBuffs() + { + if (Player.HasBuff()) + { + float pulseTime = Main.GameUpdateCount % 60f / 60f; + float pulseScale = 1f + (float)Math.Sin(pulseTime * MathHelper.TwoPi) * 0.2f; + + for (int i = 0; i < 4; i++) + { + float angle = (MathHelper.TwoPi / 4f) * i + (Main.GameUpdateCount * 0.05f); + float distance = 12f * pulseScale; + + Vector2 offset = new Vector2( + (float)Math.Cos(angle) * distance, + (float)Math.Sin(angle) * distance + ); + Vector2 dustPosition = Player.Center + offset; + + Dust dust = Dust.NewDustPerfect(dustPosition, DustID.CursedTorch, Vector2.Zero, 100, Color.LimeGreen, 1.5f); + dust.noGravity = true; + dust.fadeIn = 1f; + dust.noLight = false; + } + + if (Main.rand.NextBool(3)) + { + for (int i = 0; i < 2; i++) + { + float lineAngle = i * MathHelper.PiOver2; + float lineDistance = Main.rand.NextFloat(10f, 40f); + + Vector2 lineOffset = new Vector2( + (float)Math.Cos(lineAngle) * lineDistance, + (float)Math.Sin(lineAngle) * lineDistance + ); + Vector2 dustPos = Player.Center + lineOffset; + + Dust lineDust = Dust.NewDustPerfect(dustPos, DustID.Torch, Vector2.Zero, 100, Color.LimeGreen, 1f); + lineDust.noGravity = true; + lineDust.fadeIn = 0.5f; + } + } + } + } + public override void ModifyHurt(ref Player.HurtModifiers modifiers) { if (Player.HasBuff()) @@ -1400,7 +1490,7 @@ public override void PostHurt(Player.HurtInfo info) TikiArmorPlayer tikiPlayer = attacker.GetModPlayer(); if (tikiPlayer.hasTikiSet) { - duration = (int)(duration * 1.5f); + duration = (int)(duration * 2.5f); } } } @@ -1409,6 +1499,50 @@ public override void PostHurt(Player.HurtInfo info) } } + public override void PostUpdateBuffs() + { + if (Player.HasBuff()) + { + float pulseTime = Main.GameUpdateCount % 60f / 60f; + float pulseScale = 1f + (float)Math.Sin(pulseTime * MathHelper.TwoPi) * 0.2f; + + for (int i = 0; i < 4; i++) + { + float angle = (MathHelper.TwoPi / 4f) * i + (Main.GameUpdateCount * 0.06f); + float distance = 19f * pulseScale; + + Vector2 offset = new Vector2( + (float)Math.Cos(angle) * distance, + (float)Math.Sin(angle) * distance + ); + Vector2 dustPosition = Player.Center + offset; + + Dust dust = Dust.NewDustPerfect(dustPosition, DustID.BoneTorch, Vector2.Zero, 100, Color.DarkGray, 1.5f); + dust.noGravity = true; + dust.fadeIn = 1f; + dust.noLight = false; + } + + if (Main.rand.NextBool(3)) + { + for (int i = 0; i < 2; i++) + { + float lineAngle = i * MathHelper.PiOver2; + float lineDistance = Main.rand.NextFloat(10f, 40f); + + Vector2 lineOffset = new Vector2( + (float)Math.Cos(lineAngle) * lineDistance, + (float)Math.Sin(lineAngle) * lineDistance + ); + Vector2 dustPos = Player.Center + lineOffset; + + Dust lineDust = Dust.NewDustPerfect(dustPos, DustID.Torch, Vector2.Zero, 100, Color.DarkGray, 1f); + lineDust.noGravity = true; + lineDust.fadeIn = 0.5f; + } + } + } + } public override void ModifyHurt(ref Player.HurtModifiers modifiers) { if (Player.HasBuff()) @@ -1461,7 +1595,7 @@ public override void PostHurt(Player.HurtInfo info) TikiArmorPlayer tikiPlayer = attacker.GetModPlayer(); if (tikiPlayer.hasTikiSet) { - duration = (int)(duration * 1.5f); + duration = (int)(duration * 2.5f); } } } @@ -1470,6 +1604,52 @@ public override void PostHurt(Player.HurtInfo info) } } + + public override void PostUpdateBuffs() + { + if (Player.HasBuff()) + { + float pulseTime = Main.GameUpdateCount % 60f / 60f; + float pulseScale = 1f + (float)Math.Sin(pulseTime * MathHelper.TwoPi) * 0.2f; + + for (int i = 0; i < 4; i++) + { + float angle = (MathHelper.TwoPi / 4f) * i + (Main.GameUpdateCount * 0.08f); + float distance = 26f * pulseScale; + + Vector2 offset = new Vector2( + (float)Math.Cos(angle) * distance, + (float)Math.Sin(angle) * distance + ); + Vector2 dustPosition = Player.Center + offset; + + Dust dust = Dust.NewDustPerfect(dustPosition, DustID.Blood, Vector2.Zero, 100, Color.Red, 1.5f); + dust.noGravity = true; + dust.fadeIn = 1f; + dust.noLight = false; + } + + if (Main.rand.NextBool(3)) + { + for (int i = 0; i < 2; i++) + { + float lineAngle = i * MathHelper.PiOver2; + float lineDistance = Main.rand.NextFloat(10f, 40f); + + Vector2 lineOffset = new Vector2( + (float)Math.Cos(lineAngle) * lineDistance, + (float)Math.Sin(lineAngle) * lineDistance + ); + Vector2 dustPos = Player.Center + lineOffset; + + Dust lineDust = Dust.NewDustPerfect(dustPos, DustID.Torch, Vector2.Zero, 100, Color.DarkRed, 1f); + lineDust.noGravity = true; + lineDust.fadeIn = 0.5f; + } + } + } + } + public override void ModifyHurt(ref Player.HurtModifiers modifiers) { if (Player.HasBuff()) @@ -1522,7 +1702,7 @@ public override void PostHurt(Player.HurtInfo info) TikiArmorPlayer tikiPlayer = attacker.GetModPlayer(); if (tikiPlayer.hasTikiSet) { - duration = (int)(duration * 1.5f); + duration = (int)(duration * 2.5f); } } } @@ -1531,6 +1711,47 @@ public override void PostHurt(Player.HurtInfo info) } } + public override void PostUpdateBuffs() + { + if (Player.HasBuff()) + { + for (int i = 0; i < 3; i++) + { + float distance = Main.rand.NextFloat(40f, 80f); + float angle = Main.rand.NextFloat(0f, MathHelper.TwoPi); + + Vector2 spawnOffset = new Vector2( + (float)Math.Cos(angle) * distance, + (float)Math.Sin(angle) * distance + ); + Vector2 dustPosition = Player.Center + spawnOffset; + + Vector2 towardPlayer = Player.Center - dustPosition; + towardPlayer.Normalize(); + Vector2 dustVelocity = towardPlayer * Main.rand.NextFloat(2f, 4f); + + int dustType; + Color dustColor; + + if (Main.rand.NextBool()) + { + // Light particles + dustType = DustID.PlatinumCoin; + dustColor = Color.White; + } + else + { + // Dark particles + dustType = DustID.Smoke; + dustColor = Color.Black; + } + + Dust dust = Dust.NewDustDirect(dustPosition, 0, 0, dustType, dustVelocity.X, dustVelocity.Y, 100, dustColor, Main.rand.NextFloat(0.6f, 1.2f)); + dust.noGravity = true; + dust.fadeIn = 0.8f; + } + } + } public override void ModifyHurt(ref Player.HurtModifiers modifiers) { if (Player.HasBuff()) @@ -1586,7 +1807,7 @@ public override void PostHurt(Player.HurtInfo info) TikiArmorPlayer tikiPlayer = attacker.GetModPlayer(); if (tikiPlayer.hasTikiSet) { - duration = (int)(duration * 1.5f); + duration = (int)(duration * 2.5f); } } } @@ -1684,7 +1905,7 @@ public override void PostHurt(Player.HurtInfo info) TikiArmorPlayer tikiPlayer = attacker.GetModPlayer(); if (tikiPlayer.hasTikiSet) { - duration = (int)(duration * 1.5f); + duration = (int)(duration * 2.5f); } } } diff --git a/AdventureProjectile.cs b/AdventureProjectile.cs index 6d060561..bd76987c 100644 --- a/AdventureProjectile.cs +++ b/AdventureProjectile.cs @@ -728,6 +728,31 @@ public override void ModifyHitPlayer(Projectile projectile, Player target, ref P } } } + if (projectile.type == ProjectileID.CoolWhip && target.hostile) + { + if (projectile.owner >= 0 && projectile.owner < Main.maxPlayers) + { + Player attacker = Main.player[projectile.owner]; + + if (attacker != null && attacker.active && attacker != target && attacker.hostile) + { + int buffDuration = 420; + attacker.AddBuff(BuffID.CoolWhipPlayerBuff, buffDuration); + } + } + } + } + } + + public class CursedDartDestroyer : GlobalProjectile + { + public override void ModifyHitNPC(Projectile projectile, NPC target, ref NPC.HitModifiers modifiers) + { + if (projectile.type == ProjectileID.CursedDartFlame && + (target.type == NPCID.TheDestroyer || target.type == NPCID.TheDestroyerBody || target.type == NPCID.TheDestroyerTail)) + { + modifiers.SourceDamage *= 0.66f; + } } } } From 5a7bc9caf44a5176f00e863a025c0e90e2da25af Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Mon, 13 Oct 2025 19:42:18 -0700 Subject: [PATCH 129/206] A bunch more changes! Spectre armor hotswap Blight Fruit better bags and better balls Shadowflame weapons now inflict shadowflame Whip debuffs no longer persist after death Goblins always as soon as prehardmode ends --- AdventureItem.cs | 43 ++++++ AdventurePlayer.cs | 255 ++++++++++++++++++++++++++++-------- Assets/Buff/Attuning.png | Bin 0 -> 569 bytes Assets/Item/BlightFruit.png | Bin 0 -> 365 bytes Dogshit.cs | 53 ++++++++ Localization/en-US.hjson | 10 ++ 6 files changed, 310 insertions(+), 51 deletions(-) create mode 100644 Assets/Buff/Attuning.png create mode 100644 Assets/Item/BlightFruit.png diff --git a/AdventureItem.cs b/AdventureItem.cs index da0087ef..9d5cfccc 100644 --- a/AdventureItem.cs +++ b/AdventureItem.cs @@ -252,4 +252,47 @@ public override void ModifyTooltips(List tooltips) tooltips.Add(new TooltipLine(Mod, "PvPBagInfo", "Contains essential items for your PvP Adventure")); } } + public class BlightFruit : ModItem + { + public override string Texture => $"PvPAdventure/Assets/Item/BlightFruit"; + + public override void SetDefaults() + { + Item.width = 18; + Item.height = 18; + Item.maxStack = 9999; + Item.rare = ItemRarityID.Gray; + Item.useStyle = ItemUseStyleID.HoldUp; + Item.useAnimation = 1; + Item.useTime = 1; + Item.consumable = true; + Item.UseSound = SoundID.Item27; + } + public override bool CanUseItem(Player player) + { + return player.ConsumedLifeFruit > 0; + } + + public override bool? UseItem(Player player) + { + if (player.ConsumedLifeFruit > 0) + { + player.ConsumedLifeFruit--; + + player.statLifeMax = 100 + (player.ConsumedLifeCrystals * 20) + (player.ConsumedLifeFruit * 5); + + if (player.statLife > player.statLifeMax) + { + player.statLife = player.statLifeMax; + } + + if (Main.myPlayer == player.whoAmI) + { + player.HealEffect(-5, true); + } + } + + return true; + } + } } \ No newline at end of file diff --git a/AdventurePlayer.cs b/AdventurePlayer.cs index 6e13df3e..01cb6ed7 100644 --- a/AdventurePlayer.cs +++ b/AdventurePlayer.cs @@ -482,8 +482,29 @@ public override void PreUpdate() if (PvPImmuneTime[i] > 0) PvPImmuneTime[i]--; } - } + bool hasSpectreSet = IsSpectreSetEquipped(); + int currentHead = Player.armor[0].type; + bool headChanged = IsSpectreHead(currentHead) && currentHead != lastSpectreHead; + if ((hasSpectreSet && !hadSpectreSetLastFrame) || headChanged) + { + Player.AddBuff(ModContent.BuffType(), 3600); // 60 seconds + } + + hadSpectreSetLastFrame = hasSpectreSet; + if (IsSpectreHead(currentHead)) + { + lastSpectreHead = currentHead; + } + } + public override void PostUpdate() + { + if (Player.HasBuff(ModContent.BuffType())) + { + Player.ghostHurt = false; + Player.ghostHeal = false; + } + } private bool CanRecall() { var region = ModContent.GetInstance().GetRegionIntersecting(Player.Hitbox.ToTileRectangle()); @@ -713,6 +734,29 @@ public bool IsSlotDisabled(int slotIndex) disabledSlot == slotIndex; } } + + + private int lastSpectreHead = 0; + private bool hadSpectreSetLastFrame; + + private bool IsSpectreSetEquipped() + { + int head = Player.armor[0].type; + int body = Player.armor[1].type; + int legs = Player.armor[2].type; + + bool hasSpectreHead = IsSpectreHead(head); + bool hasSpectreBody = body == ItemID.SpectreRobe; + bool hasSpectreLegs = legs == ItemID.SpectrePants; + + return hasSpectreHead && hasSpectreBody && hasSpectreLegs; + } + + private bool IsSpectreHead(int headType) + { + return headType == ItemID.SpectreHood || headType == ItemID.SpectreMask; + } + public override void PostUpdateEquips() { // Check if Shiny Stone is equipped @@ -770,6 +814,8 @@ private bool IsShinyStoneEquipped() 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 @@ -1283,7 +1329,8 @@ public override void PostHurt(Player.HurtInfo info) } } Player.AddBuff(ModContent.BuffType(), duration); - Player.AddBuff(BuffID.Frozen, duration / 75); + Player.AddBuff(BuffID.Frostburn2, duration); + } } public override void PostUpdateBuffs() @@ -1496,6 +1543,7 @@ public override void PostHurt(Player.HurtInfo info) } Player.AddBuff(ModContent.BuffType(), duration); + Player.AddBuff(BuffID.ShadowFlame, duration); } } @@ -1876,27 +1924,60 @@ public class HellhexPlayer : ModPlayer { public bool hellhexTriggered = false; private int storedDamage = 0; - private int lastImmuneTime = 0; - - public override void PostUpdate() + + public override bool PreKill(double damage, int hitDirection, bool pvp, ref bool playSound, ref bool genGore, ref PlayerDeathReason damageSource) { - // Detect when the player takes damage by checking immune time - if (Player.HasBuff() && Player.immuneTime > lastImmuneTime && Player.immuneTime > 0) + // If player has Hellhex when they die from non-summon damage, spawn explosion + if (Player.HasBuff()) { - // Player just took damage, set flag to remove buff - hellhexTriggered = true; + bool isSummon = false; + + // Check if death is from summon/whip damage + if (damageSource.SourceProjectileLocalIndex >= 0) + { + Projectile proj = Main.projectile[damageSource.SourceProjectileLocalIndex]; + if (proj != null && proj.active && (proj.minion || proj.sentry || proj.CountsAsClass(DamageClass.SummonMeleeSpeed))) + { + isSummon = true; + } + } + else if (damageSource.SourceProjectileType > 0) + { + int projType = damageSource.SourceProjectileType; + if (projType == ProjectileID.BlandWhip || projType == ProjectileID.FireWhip || + projType == ProjectileID.SwordWhip || projType == ProjectileID.MaceWhip || + projType == ProjectileID.ScytheWhip || projType == ProjectileID.ThornWhip || + projType == ProjectileID.BoneWhip || projType == ProjectileID.RainbowWhip || + projType == ProjectileID.CoolWhip) + { + isSummon = true; + } + } + + // Spawn explosion on death from non-summon damage + if (!isSummon && Main.myPlayer == Player.whoAmI) + { + Projectile.NewProjectile( + Player.GetSource_Death(), + Player.Center, + Vector2.Zero, + ProjectileID.FireWhipProj, + (int)damage, + 0f, + Player.whoAmI + ); + } } - - lastImmuneTime = Player.immuneTime; + + return true; // Allow death } - + public override void PostHurt(Player.HurtInfo info) { if (info.DamageSource.SourceProjectileType == ProjectileID.FireWhip) { - int duration = 840; // 14 seconds base + int duration = 800; - // Check if attacker has Tiki set bonus if (info.DamageSource.SourcePlayerIndex >= 0 && info.DamageSource.SourcePlayerIndex < Main.maxPlayers) { Player attacker = Main.player[info.DamageSource.SourcePlayerIndex]; @@ -1913,12 +1994,10 @@ public override void PostHurt(Player.HurtInfo info) Player.AddBuff(ModContent.BuffType(), duration); } - // If player has Hellhex and takes non-summon damage, remove it if (Player.HasBuff()) { bool isSummon = false; - - // Check if damage is from summon projectile + if (info.DamageSource.SourceProjectileLocalIndex >= 0) { Projectile proj = Main.projectile[info.DamageSource.SourceProjectileLocalIndex]; @@ -1927,8 +2006,7 @@ public override void PostHurt(Player.HurtInfo info) isSummon = true; } } - - // Only remove buff and trigger effects if NOT summon damage + if (!isSummon) { int buffIndex = Player.FindBuffIndex(ModContent.BuffType()); @@ -1936,12 +2014,11 @@ public override void PostHurt(Player.HurtInfo info) { Player.buffTime[buffIndex] = 0; } - - // Spawn explosion projectile + if (Main.myPlayer == Player.whoAmI) { Vector2 spawnPos = Player.Center; - + Projectile.NewProjectile( Player.GetSource_Buff(buffIndex), spawnPos, @@ -1955,15 +2032,13 @@ public override void PostHurt(Player.HurtInfo info) } } } - + public override void ModifyHurt(ref Player.HurtModifiers modifiers) { - // Double damage from non-summon sources while having Hellhex if (Player.HasBuff()) { bool isSummon = false; - - // Check if damage is from summon/whip projectile + if (modifiers.DamageSource.SourceProjectileLocalIndex >= 0) { Projectile proj = Main.projectile[modifiers.DamageSource.SourceProjectileLocalIndex]; @@ -1972,13 +2047,11 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) isSummon = true; } } - // Also check by projectile type for whips else if (modifiers.DamageSource.SourceProjectileType > 0) { int projType = modifiers.DamageSource.SourceProjectileType; - // Check if it's a whip projectile type - if (projType == ProjectileID.BlandWhip || projType == ProjectileID.FireWhip || - projType == ProjectileID.SwordWhip || projType == ProjectileID.MaceWhip || + if (projType == ProjectileID.BlandWhip || projType == ProjectileID.FireWhip || + projType == ProjectileID.SwordWhip || projType == ProjectileID.MaceWhip || projType == ProjectileID.ScytheWhip || projType == ProjectileID.ThornWhip || projType == ProjectileID.BoneWhip || projType == ProjectileID.RainbowWhip || projType == ProjectileID.CoolWhip) @@ -1986,11 +2059,10 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) isSummon = true; } } - - // Only apply double damage for non-summon damage + if (!isSummon) { - modifiers.FinalDamage *= 2.75f; // Double damage + modifiers.FinalDamage *= 2.75f; modifiers.ModifyHurtInfo += (ref Player.HurtInfo info) => { storedDamage = info.Damage; }; @@ -1998,37 +2070,34 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) } } } - + public override void PostUpdateBuffs() { if (Player.HasBuff()) { - // Create hellfire particle shower for (int i = 0; i < 2; i++) { - int dustType = DustID.Torch; // Orange/red fire dust + int dustType = DustID.Torch; Vector2 dustPosition = Player.position + new Vector2(Main.rand.Next(Player.width), Main.rand.Next(Player.height)); - Vector2 dustVelocity = new Vector2(Main.rand.NextFloat(-0.5f, 0.5f), Main.rand.NextFloat(-2f, 0f)); // Upward shower - + Vector2 dustVelocity = new Vector2(Main.rand.NextFloat(-0.5f, 0.5f), Main.rand.NextFloat(-2f, 0f)); + Dust dust = Dust.NewDustDirect(dustPosition, 0, 0, dustType, dustVelocity.X, dustVelocity.Y, 100, default(Color), Main.rand.NextFloat(1f, 2f)); dust.noGravity = true; dust.fadeIn = 1.3f; } - - // Add some darker fire particles for variety + if (Main.rand.NextBool(2)) { int dustType = DustID.Smoke; Vector2 dustPosition = Player.position + new Vector2(Main.rand.Next(Player.width), Main.rand.Next(Player.height)); Vector2 dustVelocity = new Vector2(Main.rand.NextFloat(-0.5f, 0.5f), Main.rand.NextFloat(-1.5f, 0f)); - + Dust dust = Dust.NewDustDirect(dustPosition, 0, 0, dustType, dustVelocity.X, dustVelocity.Y, 100, Color.OrangeRed, Main.rand.NextFloat(0.8f, 1.5f)); dust.noGravity = true; } } else { - // Reset trigger flag when buff is not active hellhexTriggered = false; } } @@ -2052,9 +2121,14 @@ public override void OnEnterWorld() { if (!hasReceivedStarterBag) { - Player.QuickSpawnItem(Player.GetSource_GiftOrReward(), ModContent.ItemType(), 1); + int itemType = ModContent.ItemType(); + var item = new Item(); + item.SetDefaults(itemType); + Player.inventory[1] = item; // Adds to second inventory slot + var beachBallItem = new Item(); + beachBallItem.SetDefaults(ItemID.BeachBall); + Player.inventory[2] = beachBallItem; // Adds to third inventory slot - // Set the flag so they don't get another one hasReceivedStarterBag = true; } } @@ -2091,8 +2165,76 @@ public override void ModifyLuck(ref float luck) } } } +public class ShadowFlamePlayer : ModPlayer +{ + public override void PostHurt(Player.HurtInfo info) + { + int shadowflameDuration = 0; + + if (info.DamageSource.SourceProjectileType == ProjectileID.ShadowFlameArrow) + { + int maxDuration = 4 * 60; + float damageRatio = Math.Min(info.Damage / 47f, 1f); + shadowflameDuration = (int)(maxDuration * damageRatio); + } + else if (info.DamageSource.SourceProjectileType == ProjectileID.ShadowFlame) + { + shadowflameDuration = 60 * 10; + } + else if (info.DamageSource.SourceProjectileType == ProjectileID.ShadowFlameKnife) + { + int maxDuration = 60 * 5; + float damageRatio = Math.Min(info.Damage / 40f, 1f); + shadowflameDuration = (int)(maxDuration * damageRatio); + } + else if (info.DamageSource.SourceProjectileType == ProjectileID.DarkLance) + { + shadowflameDuration = 66 * 6; // 6.66 seconds + } + + if (shadowflameDuration > 0) + { + Player.AddBuff(BuffID.ShadowFlame, shadowflameDuration); + } + } + + public override void UpdateBadLifeRegen() + { + if (Player.HasBuff(BuffID.ShadowFlame)) + { + if (Player.lifeRegen > 0) + { + Player.lifeRegen = 0; + } + Player.lifeRegenTime = 0; + + Player.lifeRegen -= 30; + } + } + + public override void PostUpdateBuffs() + { + if (Player.HasBuff(BuffID.ShadowFlame)) + { + for (int i = 0; i < 2; i++) + { + Vector2 dustPosition = Player.position + new Vector2(Main.rand.Next(Player.width), Main.rand.Next(Player.height)); + Vector2 dustVelocity = new Vector2(Main.rand.NextFloat(-1f, 1f), Main.rand.NextFloat(-2f, 0f)); + Dust dust = Dust.NewDustDirect(dustPosition, 0, 0, DustID.Shadowflame, dustVelocity.X, dustVelocity.Y, 100, default(Color), Main.rand.NextFloat(1f, 1.5f)); + dust.noGravity = true; + dust.fadeIn = 1.2f; + } + if (Main.rand.NextBool(3)) + { + Vector2 smokePos = Player.position + new Vector2(Main.rand.Next(Player.width), Main.rand.Next(Player.height)); + Dust smoke = Dust.NewDustDirect(smokePos, 0, 0, DustID.Smoke, 0, -1f, 100, Color.Purple, 0.8f); + smoke.noGravity = true; + } + } + } +} public class ShinyStoneHotswap : ModBuff { @@ -2171,9 +2313,8 @@ public override void SetStaticDefaults() { Main.debuff[Type] = true; Main.buffNoSave[Type] = false; - Main.buffNoTimeDisplay[Type] = true; Main.buffNoTimeDisplay[Type] = false; - Main.persistentBuff[Type] = true; + Main.persistentBuff[Type] = false; BuffID.Sets.IsATagBuff[Type] = false; } public override void Update(Player player, ref int buffIndex) @@ -2189,7 +2330,7 @@ public override void SetStaticDefaults() Main.debuff[Type] = true; Main.buffNoSave[Type] = false; Main.buffNoTimeDisplay[Type] = false; - Main.persistentBuff[Type] = true; + Main.persistentBuff[Type] = false; } } public class Hellhex : ModBuff @@ -2201,7 +2342,7 @@ public override void SetStaticDefaults() Main.debuff[Type] = true; Main.buffNoSave[Type] = false; Main.buffNoTimeDisplay[Type] = false; - Main.persistentBuff[Type] = true; + Main.persistentBuff[Type] = false; } public override void Update(Player player, ref int buffIndex) @@ -2218,7 +2359,7 @@ public override void SetStaticDefaults() Main.debuff[Type] = true; Main.buffNoSave[Type] = false; Main.buffNoTimeDisplay[Type] = false; - Main.persistentBuff[Type] = true; + Main.persistentBuff[Type] = false; } } public class BrittleBones : ModBuff @@ -2230,7 +2371,7 @@ public override void SetStaticDefaults() Main.debuff[Type] = true; Main.buffNoSave[Type] = false; Main.buffNoTimeDisplay[Type] = false; - Main.persistentBuff[Type] = true; + Main.persistentBuff[Type] = false; } } public class BitingEmbrace : ModBuff @@ -2242,13 +2383,25 @@ public override void SetStaticDefaults() Main.debuff[Type] = true; Main.buffNoSave[Type] = false; Main.buffNoTimeDisplay[Type] = false; - Main.persistentBuff[Type] = true; + Main.persistentBuff[Type] = false; } } public class Marked : ModBuff { public override string Texture => $"PvPAdventure/Assets/Buff/Marked"; + public override void SetStaticDefaults() + { + Main.debuff[Type] = true; + Main.buffNoSave[Type] = false; + Main.buffNoTimeDisplay[Type] = false; + Main.persistentBuff[Type] = false; + } +} +public class Attuning : ModBuff +{ + public override string Texture => $"PvPAdventure/Assets/Buff/Attuning"; + public override void SetStaticDefaults() { Main.debuff[Type] = true; diff --git a/Assets/Buff/Attuning.png b/Assets/Buff/Attuning.png new file mode 100644 index 0000000000000000000000000000000000000000..c6b7786a843b16f7f4cead120944e36cbfa055c1 GIT binary patch literal 569 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7e6l0AZa85pY67#JE_7#My5g&JNk zFq9fFFuY1&V6d9Oz#v{QXIG#NP{K06C&U#<1HqJpqy+Z}R}Gv0K(Ny1|NXj+;?n=U zER_^Y6eZmgL|#p8{?E!VXoM9LQlW@$_|Nf62wiC~MO3s`eRB=!~a}V~EA+rI!y1H7oGA2DT`)Fhu?PpFEp= zQ|{%Lv6hD&120&X*PK|W|G;7of1`$tYi@k?`XdYlp0`$3@;gkqG%JZ&;!ISJ0)wTo zc<%|m8H^J+9K2G~SQQP{&+fjWHOa(hV{`3qiR|39-@hFB!#yD~`+94;g0)6!jqA zT`ua2-D=fd{AP8i)tuz;wdWqn%s<+g8mZ-fIYsXH#X0@rm9}rbK5B@HxW3isH`g^e z%h$QL&z#YGaJ^CH${_=uG`8e#rs;Co7VjCqCU~9P^M3cttxV4<*PXGG|7ABpesTko z!n$dumd~6wG|h~b^R*DzxUiX_(3R)N6S)s8P7fVwZMgPrYMK!&*R3VfQO8=X@LenP zp@WO#L54i$g#`+q4s34@un^GvVJN`GuJq5WzxhJ_fpx!`8kK{e>Kt|b0Q5D3r>mdK II;Vst06G(mwEzGB literal 0 HcmV?d00001 diff --git a/Dogshit.cs b/Dogshit.cs index afe69b1b..d70aee6b 100644 --- a/Dogshit.cs +++ b/Dogshit.cs @@ -5,6 +5,7 @@ using Terraria.Chat; using Terraria.Localization; using Microsoft.Xna.Framework; +using Terraria.ModLoader.IO; namespace PvPAdventure { public class RainSystem : ModSystem @@ -222,4 +223,56 @@ public override void PostSetupContent() selectedBoss = -1; } } + public class HardmodeGoblinSystem : ModSystem + { + private bool wasHardmode = false; + + public override void PostUpdateWorld() + { + // Check if world just entered hardmode + if (Main.hardMode && !wasHardmode) + { + // Check if goblin army hasn't been defeated yet + if (!NPC.downedGoblins) + { + // Start goblin invasion + Main.StartInvasion(InvasionID.GoblinArmy); + + // Send message to all players + if (Main.netMode == NetmodeID.Server) + { + NetMessage.SendData(MessageID.WorldData); + } + } + + wasHardmode = true; + } + + // Update state + if (!Main.hardMode) + { + wasHardmode = false; + } + } + + public override void SaveWorldData(TagCompound tag) + { + // Save whether we were in hardmode + tag["wasHardmode"] = wasHardmode; + } + + public override void LoadWorldData(TagCompound tag) + { + // Load saved state + wasHardmode = tag.GetBool("wasHardmode"); + + // If loading into hardmode, set flag appropriately + if (Main.hardMode) + { + wasHardmode = true; + } + } + } + + } \ No newline at end of file diff --git a/Localization/en-US.hjson b/Localization/en-US.hjson index 58c8cfee..646d6fb5 100644 --- a/Localization/en-US.hjson +++ b/Localization/en-US.hjson @@ -1179,6 +1179,11 @@ Mods: { DisplayName: Pressure Points Description: Thorns press into your skin. } + + Attuning: { + DisplayName: Attuning + Description: Your Spectre armor is attuning to your magic & mind! + } } Items: { @@ -1186,6 +1191,11 @@ Mods: { DisplayName: Adventure Bag Tooltip: "" } + + BlightFruit: { + DisplayName: Blight Fruit + Tooltip: Permanently decreases maximum life by 5 + } } NPCs: { From ac0bc89573caac8333819e82495fe5feea46517f Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Wed, 15 Oct 2025 10:46:30 -0700 Subject: [PATCH 130/206] fixed localization --- Localization/en-US.hjson | 965 +++++++++++++++------------------------ 1 file changed, 367 insertions(+), 598 deletions(-) diff --git a/Localization/en-US.hjson b/Localization/en-US.hjson index 58c8cfee..2c86d805 100644 --- a/Localization/en-US.hjson +++ b/Localization/en-US.hjson @@ -328,371 +328,6 @@ Mods: { Tooltip: "" } - AdventureClientConfig: { - DisplayName: Client - - PlayerOutline: { - Label: Player Outline - Tooltip: "" - } - - ShiftEnterOpensAllChat: { - Label: Shift Enter Opens All Chat - Tooltip: "" - } - - ShowPauseMessage: { - Tooltip: "" - Label: Show Pause Message - } - - SoundEffect: { - Label: Sound Effect - Tooltip: "" - } - } - - PlayerOutlineConfig: { - Tooltip: "" - - Self: { - Label: Self - Tooltip: "" - } - - Team: { - Label: Team - Tooltip: "" - } - } - - CannotModify: You are not permitted to modify this config. - - PlayerDamageBalanceConfig: { - Tooltip: "" - - ItemDamageMultipliers: { - Label: Item Damage Multipliers - Tooltip: "" - } - - ProjectileDamageMultipliers: { - Label: Projectile Damage Multipliers - Tooltip: "" - } - - ItemFalloff: { - Label: Item Falloff - Tooltip: "" - } - - ProjectileFalloff: { - Label: Projectile Falloff - Tooltip: "" - } - - DefaultFalloff: { - Tooltip: "" - Label: Default Falloff - } - } - - Falloff: { - Coefficient: { - Tooltip: "" - Label: Coefficient - } - - Forward: { - Label: Forward - Tooltip: "" - } - - Tooltip: "" - } - - Statistics: { - Tooltip: "" - - Damage: { - Label: Damage - Tooltip: "" - } - - UseTime: { - Label: Use Time - Tooltip: "" - } - - UseAnimation: { - Label: Use Animation - Tooltip: "" - } - - ShootSpeed: { - Label: Shoot Speed - Tooltip: "" - } - - Crit: { - Label: Crit - Tooltip: "" - } - - Mana: { - Label: Mana - Tooltip: "" - } - - Scale: { - Label: Scale - Tooltip: "" - } - - Knockback: { - Label: Knockback - Tooltip: "" - } - - Value: { - Tooltip: "" - Label: Value - } - } - - OptionalInt: { - Tooltip: "" - - Value: { - Label: Value - Tooltip: "" - } - } - - OptionalFloat: { - Tooltip: "" - - Value: { - Label: Value - Tooltip: "" - } - } - - HitMarkerConfig: { - Sound: { - Label: Sound - Tooltip: "" - } - - Volume: { - Label: Volume - Tooltip: "" - } - - PitchMinimum: { - Label: Pitch Minimum - Tooltip: "" - } - - PitchMaximum: { - Label: Pitch Maximum - Tooltip: "" - } - - Tooltip: "" - - SoundPath: { - Tooltip: "" - Label: Sound Path - } - } - - SoundEffectConfig: { - Tooltip: "" - - NpcHitMarker: { - Label: Npc Hit Marker - Tooltip: "" - } - - PlayerHitMarker: { - Label: Player Hit Marker - Tooltip: "" - } - - PlayerKillMarker: { - Label: Player Kill Marker - Tooltip: "" - } - } - - PlayerHitMarkerConfig: { - Tooltip: "" - - SilenceVanilla: { - Label: Silence Vanilla - Tooltip: "" - } - } - - KillMarkerConfig: { - SoundPath: { - Tooltip: "" - Label: Sound Path - } - } - - PlayerKillMarkerConfig: { - SilenceVanilla: { - Tooltip: "" - Label: Silence Vanilla - } - - Tooltip: "" - } - - MarkerConfig`1: { - PitchMaximum: { - Tooltip: "" - Label: Pitch Maximum - } - - PitchMinimum: { - Tooltip: "" - Label: Pitch Minimum - } - - Volume: { - Tooltip: "" - Label: Volume - } - - Sound: { - Tooltip: "" - Label: Sound - } - } - - Killsound: { - Part2.Label: Part2 - FatalCarCrash.Label: Fatal Car Crash - Shronker.Label: Shronker - Sharkron.Label: Sharkron - Ronaldoz.Label: Ronaldoz - Zacharry.Label: Zacharry - Tooltip: "" - } - - Hitsound: { - Part1.Label: Part1 - MarrowMurder.Label: Marrow Murder - Squelchy.Label: Squelchy - Crash.Label: Crash - Blip.Label: Blip - Buwee.Label: BuWEEEEE - OlBetsy.Label: Ol' Betsy - Tooltip: "" - } - - WorldGenerationConfig: { - LifeFruitMinimumDistanceBetween: { - Tooltip: "" - Label: Life Fruit Minimum Distance Between - } - - LifeFruitExpertChanceDenominator: { - Tooltip: "" - Label: Life Fruit Expert Chance Denominator - } - - LifeFruitChanceDenominator: { - Tooltip: "" - Label: Life Fruit Chance Denominator - } - - Tooltip: "" - - PlanteraBulbChanceDenominator: { - Label: Plantera Bulb Chance Denominator - Tooltip: "" - } - - ChlorophyteSpreadChanceModifier: { - Label: Chlorophyte Spread Chance Modifier - Tooltip: "" - } - - ChlorophyteGrowChanceModifier: { - Label: Chlorophyte Grow Chance Modifier - Tooltip: "" - } - - ChlorophyteGrowLimitModifier: { - Label: Chlorophyte Grow Limit Modifier - Tooltip: "" - } - } - - NpcBalanceConfig: { - Tooltip: "" - - LifeMaxMultipliers: { - Label: Life Max Multipliers - Tooltip: "" - } - - DamageMultipliers: { - Label: Damage Multipliers - Tooltip: "" - } - - NoMechanicalBossSummonDrops: { - Label: No Mechanical Boss Summon Drops - Tooltip: "" - } - - NoBiomeKeyDrops: { - Label: No Biome Key Drops - Tooltip: "" - } - } - - FloatStatistic: { - Tooltip: "" - - Value: { - Label: Value - Tooltip: "" - } - } - - ChestItemReplacement: { - Tooltip: "" - - Items: { - Label: Items - Tooltip: "" - } - } - - InvasionSizeValue: { - Value: { - Tooltip: "" - Label: Value - } - - Tooltip: "" - } - - TeamLifeConfig: { - Tooltip: "" - - Share: { - Label: Share - Tooltip: "" - } - } - GhostHealMaxDistanceNpc: { Label: Ghost Heal Max Distance Npc Tooltip: "" @@ -709,91 +344,8 @@ Mods: { } } - Item: { - Disabled: Cannot be used in this gamemode - NoUndergroundEmpressButterfly: Cannot be released here underground - NoUndergroundQueenSlimeCrystal: Cannot be summoned here underground - } - - Player.CannotRecall: Cannot recall! - Tiles.LockedLihzahrdChest.MapEntry: Locked Lihzahrd Chest - Sandstorm: "[c/FFC864:Desert winds are picking up...]" - Rain: "[c/6496FF:A storm is brewing overhead...]" - - NPCs: { - Bound: { - Merchant.DisplayName: Bound Merchant - ArmsDealer.DisplayName: Bound Arms Dealer - WitchDoctor.DisplayName: Bound Witch Doctor - - Steampunker: { - DisplayName: Chained Steampunker - Chat: At long last, I'm saved! The strangest people chained me up, they mentioned something about a hardcore challenge... - } - - Truffle: { - DisplayName: Buried Truffle - Chat: At long last, I'm saved! The strangest people buried me here, they mentioned something about a hardcore challenge... - } - - Cyborg: { - DisplayName: Deactivated Cyborg - Chat: At long last, I'm saved! The strangest people turned me off, they mentioned something about a hardcore challenge... - } - - Chat: At long last, I'm saved! The strangest people tied me up, they mentioned something about a hardcore challenge... - Demolitionist.DisplayName: Bound. Demolitionist - } - } - - Pause: { - 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! - } - - AncientChiselHotswapBuff: { - DisplayName: THE CURSE OF THE ANCIENT CHISEL - Description: YOU CAN'T USE THAT heckin' ACCESSORY SLOT! - } - - NewIchorPlayerDebuff: { - DisplayName: Ichor - Description: Defense reduced by one third - } - - BROISACHOJ: { - DisplayName: BRO IS A CHOJ - Description: You are too much of a CHOJ to dash effectively - } - - BuffDescription: { - BeetleMight1: Melee damage and speed increase by 8% - BeetleMight2: Melee damage and speed increase by 8% - BeetleMight3: Melee damage and speed increase by 8% - } - - ArmorSetBonus.BeetleDamage: - ''' - Gain Beetles from player kills Beetles - increase your melee damage and attack speed - ''' - } - - Items: { - AdventureBag: { - DisplayName: Adventure Bag - Tooltip: Everything you need to start your PvP Adventure! - } - } - AdventureClientConfig: { - DisplayName: Adventure Client Config + DisplayName: Client PlayerOutline: { Label: Player Outline @@ -806,8 +358,8 @@ Mods: { } ShowPauseMessage: { - Label: Show Pause Message Tooltip: "" + Label: Show Pause Message } SoundEffect: { @@ -830,87 +382,7 @@ Mods: { } } - SoundEffectConfig: { - Tooltip: "" - - NpcHitMarker: { - Label: Npc Hit Marker - Tooltip: "" - } - - PlayerHitMarker: { - Label: Player Hit Marker - Tooltip: "" - } - - PlayerKillMarker: { - Label: Player Kill Marker - Tooltip: "" - } - } - - HitMarkerConfig.Tooltip: "" - - Hitsound: { - Tooltip: "" - OlBetsy.Label: Ol Betsy - Buwee.Label: Buwee - Blip.Label: Blip - Crash.Label: Crash - Squelchy.Label: Squelchy - MarrowMurder.Label: Marrow Murder - Part1.Label: Part1 - } - - MarkerConfig`1: { - Sound: { - Label: Sound - Tooltip: "" - } - - Volume: { - Label: Volume - Tooltip: "" - } - - PitchMinimum: { - Label: Pitch Minimum - Tooltip: "" - } - - PitchMaximum: { - Label: Pitch Maximum - Tooltip: "" - } - } - - PlayerHitMarkerConfig: { - Tooltip: "" - - SilenceVanilla: { - Label: Silence Vanilla - Tooltip: "" - } - } - - PlayerKillMarkerConfig: { - Tooltip: "" - - SilenceVanilla: { - Label: Silence Vanilla - Tooltip: "" - } - } - - Killsound: { - Tooltip: "" - Zacharry.Label: Zacharry - Ronaldoz.Label: Ronaldoz - Sharkron.Label: Sharkron - Shronker.Label: Shronker - FatalCarCrash.Label: Fatal Car Crash - Part2.Label: Part2 - } + CannotModify: You are not permitted to modify this config. PlayerDamageBalanceConfig: { Tooltip: "" @@ -936,41 +408,23 @@ Mods: { } DefaultFalloff: { - Label: Default Falloff Tooltip: "" + Label: Default Falloff } } Falloff: { - Tooltip: "" - Coefficient: { - Label: Coefficient Tooltip: "" + Label: Coefficient } Forward: { Label: Forward Tooltip: "" } - } - - TeamLifeConfig: { - Tooltip: "" - - Share: { - Label: Share - Tooltip: "" - } - } - InvasionSizeValue: { Tooltip: "" - - Value: { - Label: Value - Tooltip: "" - } } Statistics: { @@ -1017,8 +471,8 @@ Mods: { } Value: { - Label: Value Tooltip: "" + Label: Value } } @@ -1040,24 +494,140 @@ Mods: { } } - WorldGenerationConfig: { + HitMarkerConfig: { + Sound: { + Label: Sound + Tooltip: "" + } + + Volume: { + Label: Volume + Tooltip: "" + } + + PitchMinimum: { + Label: Pitch Minimum + Tooltip: "" + } + + PitchMaximum: { + Label: Pitch Maximum + Tooltip: "" + } + Tooltip: "" - LifeFruitChanceDenominator: { - Label: Life Fruit Chance Denominator + SoundPath: { Tooltip: "" + Label: Sound Path } + } - LifeFruitExpertChanceDenominator: { - Label: Life Fruit Expert Chance Denominator + SoundEffectConfig: { + Tooltip: "" + + NpcHitMarker: { + Label: Npc Hit Marker + Tooltip: "" + } + + PlayerHitMarker: { + Label: Player Hit Marker + Tooltip: "" + } + + PlayerKillMarker: { + Label: Player Kill Marker + Tooltip: "" + } + } + + PlayerHitMarkerConfig: { + Tooltip: "" + + SilenceVanilla: { + Label: Silence Vanilla + Tooltip: "" + } + } + + KillMarkerConfig: { + SoundPath: { + Tooltip: "" + Label: Sound Path + } + } + + PlayerKillMarkerConfig: { + SilenceVanilla: { + Tooltip: "" + Label: Silence Vanilla + } + + Tooltip: "" + } + + MarkerConfig`1: { + PitchMaximum: { + Tooltip: "" + Label: Pitch Maximum + } + + PitchMinimum: { + Tooltip: "" + Label: Pitch Minimum + } + + Volume: { + Tooltip: "" + Label: Volume + } + + Sound: { Tooltip: "" + Label: Sound } + } + + Killsound: { + Part2.Label: Part2 + FatalCarCrash.Label: Fatal Car Crash + Shronker.Label: Shronker + Sharkron.Label: Sharkron + Ronaldoz.Label: Ronaldoz + Zacharry.Label: Zacharry + Tooltip: "" + } + + Hitsound: { + Part1.Label: Part1 + MarrowMurder.Label: Marrow Murder + Squelchy.Label: Squelchy + Crash.Label: Crash + Blip.Label: Blip + Buwee.Label: BuWEEEEE + OlBetsy.Label: Ol' Betsy + Tooltip: "" + } + WorldGenerationConfig: { LifeFruitMinimumDistanceBetween: { + Tooltip: "" Label: Life Fruit Minimum Distance Between + } + + LifeFruitExpertChanceDenominator: { Tooltip: "" + Label: Life Fruit Expert Chance Denominator + } + + LifeFruitChanceDenominator: { + Tooltip: "" + Label: Life Fruit Chance Denominator } + Tooltip: "" + PlanteraBulbChanceDenominator: { Label: Plantera Bulb Chance Denominator Tooltip: "" @@ -1096,6 +666,11 @@ Mods: { Label: No Mechanical Boss Summon Drops Tooltip: "" } + + NoBiomeKeyDrops: { + Label: No Biome Key Drops + Tooltip: "" + } } FloatStatistic: { @@ -1115,89 +690,283 @@ Mods: { Tooltip: "" } } + + InvasionSizeValue: { + Value: { + Tooltip: "" + Label: Value + } + + Tooltip: "" + } + + TeamLifeConfig: { + Tooltip: "" + + Share: { + Label: Share + Tooltip: "" + } + } + + GhostHealMaxDistanceNpc: { + Label: Ghost Heal Max Distance Npc + Tooltip: "" + } + + ProjectileCollisionDamageReduction: { + Label: Projectile Collision Damage Reduction + Tooltip: "" + } + + NoLineOfSightDamageReduction: { + Label: No Line Of Sight Damage Reduction + Tooltip: "" + } + } + + Item: { + Disabled: Cannot be used in this gamemode + NoUndergroundEmpressButterfly: Cannot be released here underground + NoUndergroundQueenSlimeCrystal: Cannot be summoned here underground + } + + Player.CannotRecall: Cannot recall! + Tiles.LockedLihzahrdChest.MapEntry: Locked Lihzahrd Chest + Sandstorm: "[c/FFC864:Desert winds are picking up...]" + Rain: "[c/6496FF:A storm is brewing overhead...]" + + NPCs: { + Bound: { + Merchant.DisplayName: Bound Merchant + ArmsDealer.DisplayName: Bound Arms Dealer + WitchDoctor.DisplayName: Bound Witch Doctor + Demolitionist.DisplayName: Bound. Demolitionist + + Steampunker: { + DisplayName: Chained Steampunker + Chat: At long last, I'm saved! The strangest people chained me up, they mentioned something about a hardcore challenge... + } + + Truffle: { + DisplayName: Buried Truffle + Chat: You woke me up. Dont eat children. + } + + Cyborg: { + DisplayName: Deactivated Cyborg + Chat: Press F2 to Enter Setup + } + + Chat: At long last, I'm saved! The strangest people tied me up + + } } - Tiles.LockedLihzahrdChest.MapEntry: Mods.PvPAdventure.Tiles.LockedLihzahrdChest.MapEntry + Pause: { + True: "[c/FF0000:The game has been paused.]" + False: "[c/00FF00:The game has been resumed.]" + } Buffs: { - AncientChiselHotswapBuff: { - DisplayName: the curse of the ancient chisel - Description: Broken ahh debuff + ShinyStoneHotswap: { + DisplayName: Shiny Stone Hotswap + Description: Shiny Stone is charging up! } - BROISACHOJ: { - DisplayName: B R O I S A C H O J - Description: bro is a choj + AncientChiselHotswapBuff: { + DisplayName: THE CURSE OF THE ANCIENT CHISEL + Description: YOU CAN'T USE THAT ACCESSORY SLOT! } NewIchorPlayerDebuff: { DisplayName: Ichor - Description: Reduces defense by a third. + Description: Defense reduced by one third } - ShinyStoneHotswap: { - DisplayName: Shiny Stone Hotswap - Description: The shiny stone is charging up! + BROISACHOJ: { + DisplayName: BRO IS A CHOJ + Description: You are too much of a CHOJ to dash effectively + } + + BuffDescription: { + BeetleMight1: Melee damage and speed increase by 8% + BeetleMight2: Melee damage and speed increase by 8% + BeetleMight3: Melee damage and speed increase by 8% } + ArmorSetBonus.BeetleDamage: + ''' + Gain Beetles from player kills Beetles + increase your melee damage and attack speed + ''' + Anathema: { - Description: You are hated by the world. DisplayName: Anathema + Description: Enemy attacks can seek you out + } + + BitingEmbrace: { + DisplayName: Summon Tagged + Description: Take 7 more damage from enemies + } + + BrittleBones: { + DisplayName: Summon Tagged + Description: Take 6 more damage from enemies } Hellhex: { + DisplayName: Hellhexed Description: You are going to burst with hellfire at any moment! - DisplayName: Hellhex } - ShatteredArmor: { - Description: You're armor has been shattered by a brutal blow! - DisplayName: Shattered Armor + Marked: { + DisplayName: Summon Tagged + Description: Take 9 more damage from enemies } PlayerInSpawn: { - DisplayName: spawn + DisplayName: Spawn Description: You're in spawn bro } - BitingEmbrace: { - DisplayName: Biting Embrace - Description: You are weakened by the cold. + PressurePoints: { + DisplayName: Summon Tagged + Description: Take 6 more damage from enemies } - BrittleBones: { - DisplayName: Brittle Bones - Description: Your bones are weakened, and so are you. + ShatteredArmor: { + DisplayName: Shattered Armor + Description: You're armor has been shattered by a brutal blow! } + } - Marked: { - DisplayName: Marked - Description: You're the target. + Items: { + AdventureBag: { + DisplayName: Adventure Bag + Tooltip: Everything you need to start your PvP Adventure! + } + } + + AdventureClientConfig: { + DisplayName: Adventure Client Config + + PlayerOutline: { + Label: Player Outline + Tooltip: "" } - PressurePoints: { - DisplayName: Pressure Points - Description: Thorns press into your skin. + ShiftEnterOpensAllChat: { + Label: Shift Enter Opens All Chat + Tooltip: "" + } + + ShowPauseMessage: { + Label: Show Pause Message + Tooltip: "" + } + + SoundEffect: { + Label: Sound Effect + Tooltip: "" } } - Items: { - AdventureBag: { - DisplayName: Adventure Bag + PlayerOutlineConfig: { + Tooltip: "" + + Self: { + Label: Self + Tooltip: "" + } + + Team: { + Label: Team Tooltip: "" } } - NPCs: { - Bound: { - ArmsDealer.DisplayName: Bound. Arms Dealer - Cyborg.DisplayName: Bound. Cyborg - Demolitionist.DisplayName: Bound. Demolitionist - Merchant.DisplayName: Bound. Merchant - Steampunker.DisplayName: Bound. Steampunker - Truffle.DisplayName: Bound. Truffle - WitchDoctor.DisplayName: Bound. Witch Doctor + SoundEffectConfig: { + Tooltip: "" + + NpcHitMarker: { + Label: Npc Hit Marker + Tooltip: "" + } + + PlayerHitMarker: { + Label: Player Hit Marker + Tooltip: "" + } + + PlayerKillMarker: { + Label: Player Kill Marker + Tooltip: "" + } + } + + HitMarkerConfig.Tooltip: "" + + Hitsound: { + Tooltip: "" + OlBetsy.Label: Ol Betsy + Buwee.Label: Buwee + Blip.Label: Blip + Crash.Label: Crash + Squelchy.Label: Squelchy + MarrowMurder.Label: Marrow Murder + Part1.Label: Part1 + } + + MarkerConfig`1: { + Sound: { + Label: Sound + Tooltip: "" + } + + Volume: { + Label: Volume + Tooltip: "" + } + + PitchMinimum: { + Label: Pitch Minimum + Tooltip: "" + } + + PitchMaximum: { + Label: Pitch Maximum + Tooltip: "" + } + } + + PlayerHitMarkerConfig: { + Tooltip: "" + + SilenceVanilla: { + Label: Silence Vanilla + Tooltip: "" + } + } + + PlayerKillMarkerConfig: { + Tooltip: "" + + SilenceVanilla: { + Label: Silence Vanilla + Tooltip: "" } } + + Killsound: { + Tooltip: "" + Zacharry.Label: Zacharry + Ronaldoz.Label: Ronaldoz + Sharkron.Label: Sharkron + Shronker.Label: Shronker + FatalCarCrash.Label: Fatal Car Crash + Part2.Label: Part2 + } } } From 37859cac536499a8e8d1989bacda80b6e9fe30e2 Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Fri, 17 Oct 2025 10:43:43 -0700 Subject: [PATCH 131/206] Update en-US.hjson --- Localization/en-US.hjson | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Localization/en-US.hjson b/Localization/en-US.hjson index abc65d63..19987598 100644 --- a/Localization/en-US.hjson +++ b/Localization/en-US.hjson @@ -759,7 +759,6 @@ Mods: { } Chat: At long last, I'm saved! The strangest people tied me up - } } @@ -852,6 +851,11 @@ Mods: { DisplayName: Adventure Bag Tooltip: Everything you need to start your PvP Adventure! } + + BlightFruit: { + Tooltip: "" + DisplayName: Blight Fruit + } } AdventureClientConfig: { @@ -977,6 +981,6 @@ Mods: { Shronker.Label: Shronker FatalCarCrash.Label: Fatal Car Crash Part2.Label: Part2 - } + } } } From d1739fdbe8a3396fad02f796a723b21f723cdb62 Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Fri, 17 Oct 2025 12:50:20 -0700 Subject: [PATCH 132/206] quick fix --- AdventurePlayer.cs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/AdventurePlayer.cs b/AdventurePlayer.cs index 01cb6ed7..921de26b 100644 --- a/AdventurePlayer.cs +++ b/AdventurePlayer.cs @@ -1974,6 +1974,7 @@ public override bool PreKill(double damage, int hitDirection, bool pvp, ref bool public override void PostHurt(Player.HurtInfo info) { + // Apply Hellhex when hit by FireWhip if (info.DamageSource.SourceProjectileType == ProjectileID.FireWhip) { int duration = 800; @@ -1992,8 +1993,11 @@ public override void PostHurt(Player.HurtInfo info) } Player.AddBuff(ModContent.BuffType(), duration); + // Don't process the removal logic on the same hit that applies it + return; } + // Only check for removal if player already has Hellhex if (Player.HasBuff()) { bool isSummon = false; @@ -2001,7 +2005,20 @@ public override void PostHurt(Player.HurtInfo info) if (info.DamageSource.SourceProjectileLocalIndex >= 0) { Projectile proj = Main.projectile[info.DamageSource.SourceProjectileLocalIndex]; - if (proj.minion || proj.sentry || proj.CountsAsClass(DamageClass.SummonMeleeSpeed)) + if (proj != null && proj.active && (proj.minion || proj.sentry || proj.CountsAsClass(DamageClass.SummonMeleeSpeed))) + { + isSummon = true; + } + } + // Add whip check here too + else if (info.DamageSource.SourceProjectileType > 0) + { + int projType = info.DamageSource.SourceProjectileType; + if (projType == ProjectileID.BlandWhip || projType == ProjectileID.FireWhip || + projType == ProjectileID.SwordWhip || projType == ProjectileID.MaceWhip || + projType == ProjectileID.ScytheWhip || projType == ProjectileID.ThornWhip || + projType == ProjectileID.BoneWhip || projType == ProjectileID.RainbowWhip || + projType == ProjectileID.CoolWhip) { isSummon = true; } From 750319e6f1a392b67a535f169c3be2b969d10746 Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Sat, 18 Oct 2025 00:32:11 -0700 Subject: [PATCH 133/206] did so much shit i aint writing allat check the chlog --- AdventureBuff.cs | 10 ++++ AdventureDropDatabase.cs | 10 ++-- AdventureItem.cs | 13 +++++- AdventurePlayer.cs | 77 +++++++++++++++++++++++++++++-- AdventureProjectile.cs | 20 ++++++++ Assets/Buff/uncouthandboring.png | Bin 0 -> 1873 bytes Dogshit.cs | 55 ++++++++++++++++++++++ Localization/en-US.hjson | 5 ++ System/RecipeManager.cs | 8 +++- 9 files changed, 189 insertions(+), 9 deletions(-) create mode 100644 Assets/Buff/uncouthandboring.png diff --git a/AdventureBuff.cs b/AdventureBuff.cs index 104c3fb3..802e6cac 100644 --- a/AdventureBuff.cs +++ b/AdventureBuff.cs @@ -76,4 +76,14 @@ public override void Kill(double damage, int hitDirection, bool pvp, PlayerDeath } } } + public class ArcheryNerf : GlobalItem + { + public override void ModifyWeaponDamage(Item item, Player player, ref StatModifier damage) + { + if (player.HasBuff(BuffID.Archery) && item.useAmmo == AmmoID.Arrow) + { + damage /= 1.1f; + } + } + } } \ No newline at end of file diff --git a/AdventureDropDatabase.cs b/AdventureDropDatabase.cs index fb308da9..62c90729 100644 --- a/AdventureDropDatabase.cs +++ b/AdventureDropDatabase.cs @@ -191,10 +191,7 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) npcLoot.RemoveWhere(drop => (drop is CommonDrop commonDrop && commonDrop.itemId == ItemID.MagicQuiver) || drop is LeadingConditionRule); - if (NPC.downedPlantBoss == true) - { - npcLoot.Add(ItemDropRule.Common(ItemID.StalkersQuiver, 7)); - } + npcLoot.Add(ItemDropRule.Common(ItemID.MagicQuiver, 10)); break; case NPCID.RedDevil: @@ -309,6 +306,11 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) foreach (var drop in drops) ModifyDropRate(drop, ItemID.SkeletronHand, 1, 1); break; + case NPCID.DemonEye: + case NPCID.WanderingEye: + foreach (var drop in drops) + ModifyDropRate(drop, ItemID.Lens, 1, 1); + break; case NPCID.IceTortoise: npcLoot.RemoveWhere(drop => diff --git a/AdventureItem.cs b/AdventureItem.cs index 9d5cfccc..fec42379 100644 --- a/AdventureItem.cs +++ b/AdventureItem.cs @@ -70,7 +70,6 @@ void AddCircularShimmerTransform(params int[] items) ItemID.Sets.ShimmerTransformToItem[items[^1]] = items[0]; } - AddCircularShimmerTransform(ItemID.CursedFlame, ItemID.Ichor); AddCircularShimmerTransform( ItemID.CrystalNinjaHelmet, ItemID.CrystalNinjaChestplate, @@ -295,4 +294,16 @@ public override bool CanUseItem(Player player) return true; } } + public class QuiverNerf : GlobalItem + { + public override void ModifyWeaponDamage(Item item, Player player, ref StatModifier damage) + { + QuiverNerfPlayer modPlayer = player.GetModPlayer(); + + if (modPlayer.hasQuiver && item.useAmmo == AmmoID.Arrow) + { + damage += -0.1f; + } + } + } } \ No newline at end of file diff --git a/AdventurePlayer.cs b/AdventurePlayer.cs index 01cb6ed7..4f161407 100644 --- a/AdventurePlayer.cs +++ b/AdventurePlayer.cs @@ -756,7 +756,7 @@ private bool IsSpectreHead(int headType) { return headType == ItemID.SpectreHood || headType == ItemID.SpectreMask; } - + private bool hadPhilostoneLastFrame; public override void PostUpdateEquips() { // Check if Shiny Stone is equipped @@ -773,8 +773,15 @@ public override void PostUpdateEquips() { Player.shinyStone = false; } - + bool hasPhilostone = IsPhilostoneEquipped(); hadShinyStoneLastFrame = hasShinyStone; + hadPhilostoneLastFrame = hasPhilostone; + + if (hasPhilostone && !hadPhilostoneLastFrame) + { + Player.AddBuff(ModContent.BuffType(), 3600); // 60 seconds + } + if (Player.beetleOffense) { @@ -813,8 +820,19 @@ private bool IsShinyStoneEquipped() } return false; } + private bool IsPhilostoneEquipped() + { + for (int i = 3; i < 10; i++) // Check all accessory slots + { + if (Player.armor[i].type == ItemID.PhilosophersStone || (Player.armor[i].type == ItemID.CharmofMyths) && + (i < 7 || !Player.hideVisibleAccessory[i - 3])) + { + return true; + } + } + return false; + } - public override void Kill(double damage, int hitDirection, bool pvp, PlayerDeathReason damageSource) { @@ -2235,7 +2253,48 @@ public override void PostUpdateBuffs() } } } +public class QuiverNerfPlayer : ModPlayer +{ + public bool hasQuiver = false; + public override void ResetEffects() + { + hasQuiver = false; + } + + public override void PostUpdateEquips() + { + for (int i = 3; i < 8 + Player.GetAmountOfExtraAccessorySlotsToShow(); i++) + { + if (Player.armor[i].type == ItemID.MagicQuiver || Player.armor[i].type == ItemID.MoltenQuiver ) + { + hasQuiver = true; + break; + } + } + } +} +public class HittheChytty : ModPlayer +{ + public override void OnRespawn() + { + bool hasCharmOfMyths = false; + + for (int i = 3; i < 8 + Player.GetAmountOfExtraAccessorySlotsToShow(); i++) + { + if (Player.armor[i].type == ItemID.CharmofMyths) + { + hasCharmOfMyths = true; + break; + } + } + + if (hasCharmOfMyths && !Player.HasBuff()) + { + Player.statLife = Player.statLifeMax2; + } + } +} public class ShinyStoneHotswap : ModBuff { public override string Texture => $"PvPAdventure/Assets/Buff/ShinyStoneHotswap"; @@ -2402,6 +2461,18 @@ public class Attuning : ModBuff { public override string Texture => $"PvPAdventure/Assets/Buff/Attuning"; + public override void SetStaticDefaults() + { + Main.debuff[Type] = true; + Main.buffNoSave[Type] = false; + Main.buffNoTimeDisplay[Type] = false; + Main.persistentBuff[Type] = true; + } +} +public class UncouthandBoring : ModBuff +{ + public override string Texture => $"PvPAdventure/Assets/Buff/uncouthandboring"; + public override void SetStaticDefaults() { Main.debuff[Type] = true; diff --git a/AdventureProjectile.cs b/AdventureProjectile.cs index bd76987c..684aa4bc 100644 --- a/AdventureProjectile.cs +++ b/AdventureProjectile.cs @@ -755,5 +755,25 @@ public override void ModifyHitNPC(Projectile projectile, NPC target, ref NPC.Hit } } } + + + public class EmpressNerf : GlobalProjectile + { + public override bool AppliesToEntity(Projectile entity, bool lateInstantiation) + { + return entity.type == ProjectileID.FairyQueenLance || + entity.type == ProjectileID.FairyQueenSunDance || + entity.type == ProjectileID.FairyQueenMagicItemShot || + entity.type == ProjectileID.FairyQueenRangedItemShot || + entity.type == ProjectileID.HallowBossRainbowStreak || + entity.type == ProjectileID.HallowBossSplitShotCore || + entity.type == ProjectileID.HallowBossLastingRainbow; + } + + public override void ModifyHitPlayer(Projectile projectile, Player target, ref Player.HurtModifiers modifiers) + { + modifiers.SourceDamage *= 0.75f; + } + } } diff --git a/Assets/Buff/uncouthandboring.png b/Assets/Buff/uncouthandboring.png new file mode 100644 index 0000000000000000000000000000000000000000..0def3c1e1355b90157a7295562010bcc1aae3cfb GIT binary patch literal 1873 zcmZ{j3pCX08pi+VB4y_`lu|mjiqIg8%PDiixJ5`28JA%gjJX+ezuyOgT((Y~z1!K_ z$=Q|A4yQ!pMA%W1N{NlMkCOY{{_l0xI%}P^&RO5@`=0f@>wVU{*0;V-9v13vXkcjo z0DvJT0CfgbdvG7o*8|T`q5WM@tdj!Hga82JFaYpG0I&j{?#4geO! z%Z=ea0H7-l3ywtZcly&l$3s@fZ7dzE4?5c(fPRf75R^p~3Qf5jq_9j@P$n%XmE?n5 z600wXR3$=Xu|QcQP!#dy8lGGegTpB_6|%xIX@03#T_R8x^A$y0xrQq%9Ng_k@eu=^}x4l0dH3Q2UpMo%gEH2B_;c61cgGw|JL}&1#r6JlDlwNSQj64=7<_5aiy6$&s^7~MRR6N? z(}k1W^PcUq?rk$C9!xtoe}>*3#bwj-gesw`geg>{Wz!Pz*@^fpEIunCE$d<`NajUc zW;~7%pF)UBCR|9)Akz7Cfs!XLWQkM^fg%rtFQ@Zlxm*w_jU%OUBowxo!V;5N;#{!K zSG4!^clHgkB?a1^erT1e+BC>$A?BPFw?B({Vp zR#Uk$3P(y}Npe_XmRM~OqBIT!QCI{kh)gk&DPo9J#u$YOMs5-y%VvnO7{VNu#P|;@ zHSw2Z1kT1&xoH%x8G>sDXG45hkW-8_3MZA!dDQ*f5(!$S`N_O}zPYJnHjc#3 zVT!XELP9P-mBL9Ou~TwbVettWG#-x3PR?NkoQv7q+`K$P10N}%lNjWWdNEO-UJaV< z6if(u`=o)%_HBAn8|gRz=v~L4;E}K=QBhlCqu@qEL(J%KWB4sd?7#f9?dEz-+AM90 zAIttE1Y(5JrcOKT0@p3*?cX+GskGxG>r1%BPnCc1Cihgp_3fqu&^Jcy#o*mlp%XPf z8FlV|x-FJbH)2zE_g6pjc#{JH3$cgoe)Qt76HGL66mhS}-6;>&9-Gk-O$-mPv)j6& z)7$Y{i-vm)x7pdVB%y8(V6EEYvSS+k0Ypbobu+;&6b55!p1|LJ6E~?fjv)tE6X+<~ zaQ6`+@@& z@XEof(evZT+^$*`gzYOgcZ{vide#sZy!w@uH}z9reeB`^z}%Mv#p>>i48M_jv*8~} zt8-Hp1KgGtxKO%F{R8Ry@mo$4HHJ0_H%oUPcif}LKZjrYrz&KR2dDKBN`h%>U{!4i z%W%WblvG<)g?#o&!nM{6lE-^0uZjfrb~+Jt8Ykn1g!kWRm1Pcb4J>VE)Qy3fxcg4a zr{LD#o!$0DHown3D-bi-obp@4lsB!a>Qi9Eg^~pQJ+9;GKAGy()a=yTI|CE1%kICM zc>Q^i*@*n|mFGQciw-}l>0Z;_WTWvg$uOfN;o%;FT5@f7+acp|{jT2Nvp={9N-xXC zO$VDh?_z6f>uas?ScriHKVY+QE|Jmq@YfR$P93rFa9yQefrmrkXZY=5%kedLaA**0MiUXj{s-#tHaaH>&!PvrB`(y z{vt+uJTNQsv3FdJiT^Uy)DEu?+KRlbn4c#(q_mxOvkGJ3-wxyuYQIfHg6t5&w3MhaJ)Wyxw8S3Z^i-dZ3 zLEXKeF2|ryFDTU6ts?Zl0-4##cwFB95BR1XngIhx|1*Jt&rBgxu$jdFk#YU^klO}3 QE5HnZL5HG#LL>-&2iql4N&o-= literal 0 HcmV?d00001 diff --git a/Dogshit.cs b/Dogshit.cs index d70aee6b..41fdcbd1 100644 --- a/Dogshit.cs +++ b/Dogshit.cs @@ -6,6 +6,11 @@ using Terraria.Localization; using Microsoft.Xna.Framework; using Terraria.ModLoader.IO; +using MonoMod.Cil; +using MonoMod.RuntimeDetour; +using System.Reflection; +using System; +using Mono.Cecil.Cil; namespace PvPAdventure { public class RainSystem : ModSystem @@ -274,5 +279,55 @@ public override void LoadWorldData(TagCompound tag) } } + public class AltarOreIncrease : ModSystem + { + private static ILHook altarHook; + + public override void PostSetupContent() + { + MethodInfo method = typeof(Terraria.WorldGen).GetMethod("SmashAltar", + BindingFlags.Public | BindingFlags.Static); + altarHook = new ILHook(method, AltarOreILEdit); + } + + public override void Unload() + { + altarHook?.Dispose(); + } + + private static void AltarOreILEdit(ILContext il) + { + ILCursor cursor = new ILCursor(il); + try + { + if (cursor.TryGotoNext(MoveType.After, + i => i.MatchLdloc(2), // Load num3 + i => i.MatchLdloc(1), // Load num2 + i => i.MatchConvR8(), // Convert num2 to double + i => i.MatchDiv(), // Divide + i => i.MatchStloc(2) // Store back to num3 + )) + { + ModContent.GetInstance().Logger.Info("Found num3 /= num2 calculation"); + + double multiplier = 2.0; // THIS NUMBER MULTIPLIES IT + + cursor.Emit(OpCodes.Ldloc_2); // Load num3 + cursor.Emit(OpCodes.Ldc_R8, multiplier); // Load multiplier + cursor.Emit(OpCodes.Mul); // Multiply + cursor.Emit(OpCodes.Stloc_2); // Store back to num3 + + ModContent.GetInstance().Logger.Info($"Successfully patched SmashAltar to increase ore generation by {multiplier}x"); + return; + } + + ModContent.GetInstance().Logger.Error("Failed to find num3 calculation in SmashAltar method"); + } + catch (Exception e) + { + ModContent.GetInstance().Logger.Error($"Error patching SmashAltar: {e}"); + } + } + } } \ No newline at end of file diff --git a/Localization/en-US.hjson b/Localization/en-US.hjson index 19987598..420ebd06 100644 --- a/Localization/en-US.hjson +++ b/Localization/en-US.hjson @@ -844,6 +844,11 @@ Mods: { DisplayName: Attuning Description: Your Spectre armor is attuning to your magic & mind! } + + UncouthandBoring: { + DisplayName: Uncouthand Boring + Description: Mods.PvPAdventure.Buffs.UncouthandBoring.Description + } } Items: { diff --git a/System/RecipeManager.cs b/System/RecipeManager.cs index f883ed0f..df2a633a 100644 --- a/System/RecipeManager.cs +++ b/System/RecipeManager.cs @@ -34,7 +34,8 @@ public override void AddRecipes() ItemID.FlaskofFire, ItemID.FlaskofNanites, ItemID.FlaskofParty, - ItemID.SpectreBar + ItemID.SpectreBar, + ItemID.SuspiciousLookingEye }; @@ -55,6 +56,11 @@ public override void AddRecipes() .AddTile(TileID.Autohammer) .Register(); + Recipe.Create(ItemID.SuspiciousLookingEye) + .AddIngredient(ItemID.Lens, 3) + .AddTile(TileID.DemonAltar) + .Register(); + Recipe.Create(ItemID.WormFood) .AddIngredient(ItemID.RottenChunk, 6) .AddIngredient(ItemID.VilePowder, 10) From e4a273c932dbc0d13d66ba32ebf3aa960e2ddb2e Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Sat, 18 Oct 2025 00:52:38 -0700 Subject: [PATCH 134/206] fixed philo stone --- AdventurePlayer.cs | 5 +++-- Localization/en-US.hjson | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/AdventurePlayer.cs b/AdventurePlayer.cs index 4f161407..0ca15b4c 100644 --- a/AdventurePlayer.cs +++ b/AdventurePlayer.cs @@ -775,13 +775,14 @@ public override void PostUpdateEquips() } bool hasPhilostone = IsPhilostoneEquipped(); hadShinyStoneLastFrame = hasShinyStone; - hadPhilostoneLastFrame = hasPhilostone; if (hasPhilostone && !hadPhilostoneLastFrame) { Player.AddBuff(ModContent.BuffType(), 3600); // 60 seconds } + hadPhilostoneLastFrame = hasPhilostone; + if (Player.beetleOffense) { @@ -2282,7 +2283,7 @@ public override void OnRespawn() for (int i = 3; i < 8 + Player.GetAmountOfExtraAccessorySlotsToShow(); i++) { - if (Player.armor[i].type == ItemID.CharmofMyths) + if (Player.armor[i].type == ItemID.CharmofMyths || Player.armor[i].type == ItemID.PhilosophersStone) { hasCharmOfMyths = true; break; diff --git a/Localization/en-US.hjson b/Localization/en-US.hjson index 420ebd06..ab98e965 100644 --- a/Localization/en-US.hjson +++ b/Localization/en-US.hjson @@ -846,8 +846,8 @@ Mods: { } UncouthandBoring: { - DisplayName: Uncouthand Boring - Description: Mods.PvPAdventure.Buffs.UncouthandBoring.Description + DisplayName: Uncouth and Boring + Description: You are no longer a charming and mythical philosopher! } } From 0491dd1bb242646470761f27034b38a9bff05947 Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Fri, 24 Oct 2025 18:43:07 -0700 Subject: [PATCH 135/206] Plantera pools --- AdventureDropDatabase.cs | 70 +++++++++++++++++---------------------- AdventurePlayer.cs | 71 +++++++++++++++++++++++++++++++--------- 2 files changed, 86 insertions(+), 55 deletions(-) diff --git a/AdventureDropDatabase.cs b/AdventureDropDatabase.cs index fb308da9..172e30b9 100644 --- a/AdventureDropDatabase.cs +++ b/AdventureDropDatabase.cs @@ -418,6 +418,36 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) noTwin.OnSuccess(ItemDropRule.Common(ItemID.HallowedBar, 1, 3, 3)); } break; + + case NPCID.Plantera: + npcLoot.RemoveWhere(drop => + (drop is CommonDrop commonDrop && commonDrop.itemId == ItemID.PygmyStaff) || + drop is LeadingConditionRule); + npcLoot.Add(ItemDropRule.Common(ItemID.TempleKey, 1, 1, 1)); + npcLoot.Add( + new OneFromRulesRule(1, + ItemDropRule.Common(ItemID.Seedler), + ItemDropRule.Common(ItemID.LeafBlower), + ItemDropRule.Common(ItemID.WaspGun), + ItemDropRule.Common(ItemID.PygmyStaff) + ) + ); + var plantFirstKillRule = new LeadingConditionRule(new FirstBossKillCondition(NPCID.Plantera)); + plantFirstKillRule.OnSuccess(ItemDropRule.Common(ItemID.VenusMagnum, 1)); + + var grenadelauncher = ItemDropRule.Common(ItemID.GrenadeLauncher); + grenadelauncher.OnSuccess(ItemDropRule.Common(ItemID.RocketIII, 1, 400, 500), hideLootReport: true); + + var afterFirstKill = new OneFromRulesRule(1, + grenadelauncher, + ItemDropRule.Common(ItemID.NettleBurst), + ItemDropRule.Common(ItemID.FlowerPow), + ItemDropRule.Common(ItemID.VenusMagnum) + ); + + plantFirstKillRule.OnFailedConditions(afterFirstKill); + npcLoot.Add(plantFirstKillRule); + break; } } @@ -436,46 +466,6 @@ public static IItemDropRule OnItemDropDatabaseRegisterToGlobal(On_ItemDropDataba return entry; } - public class PlanteraDropEdit : ModSystem - { - private static ILHook planteraHook; - - public override void PostSetupContent() - { - // Apply the IL edit to change Plantera's first-time drop from item 758 to 1255 - MethodInfo method = typeof(Terraria.GameContent.ItemDropRules.ItemDropDatabase).GetMethod("RegisterBoss_Plantera", - BindingFlags.NonPublic | BindingFlags.Instance); - - planteraHook = new ILHook(method, PlanteraDropILEdit); - } - - public override void Unload() - { - planteraHook?.Dispose(); - } - - private static void PlanteraDropILEdit(ILContext il) - { - ILCursor cursor = new ILCursor(il); - - // Look for the instruction that loads the value 758 (Grenade Launcher ID) - // This should be: ldc.i4 758 (or ldc.i4.s 758 if it's a short form) - if (cursor.TryGotoNext(MoveType.Before, - i => i.MatchLdcI4(758))) // Match loading the constant 758 - { - // Replace the 758 with 1255 - cursor.Remove(); // Remove the ldc.i4 758 instruction - cursor.Emit(OpCodes.Ldc_I4, 1255); // Emit ldc.i4 1255 instead - - ModContent.GetInstance().Logger.Info("Successfully changed Plantera's first-time drop from item 758 to 1255"); - } - else - { - ModContent.GetInstance().Logger.Error("Failed to find item ID 758 in RegisterBoss_Plantera method"); - } - } - } - public class BiomeKeyDropEdit : ModSystem { private static ILHook globalRulesHook; diff --git a/AdventurePlayer.cs b/AdventurePlayer.cs index 01cb6ed7..7fc4e660 100644 --- a/AdventurePlayer.cs +++ b/AdventurePlayer.cs @@ -1924,6 +1924,7 @@ public class HellhexPlayer : ModPlayer { public bool hellhexTriggered = false; private int storedDamage = 0; + public int hellhexApplierIndex = -1; // Track who applied the Hellhex debuff public override bool PreKill(double damage, int hitDirection, bool pvp, ref bool playSound, ref bool genGore, ref PlayerDeathReason damageSource) { @@ -1954,22 +1955,31 @@ public override bool PreKill(double damage, int hitDirection, bool pvp, ref bool } } - // Spawn explosion on death from non-summon damage - if (!isSummon && Main.myPlayer == Player.whoAmI) + if (!isSummon && Main.myPlayer == Player.whoAmI && damage >= 60) { - Projectile.NewProjectile( + float scale = (float)damage / 100f; // Scale based on damage + int owner = hellhexApplierIndex >= 0 ? hellhexApplierIndex : Player.whoAmI; + + int proj = Projectile.NewProjectile( Player.GetSource_Death(), Player.Center, Vector2.Zero, ProjectileID.FireWhipProj, (int)damage, 0f, - Player.whoAmI + owner, + 0f, + scale ); + + if (proj >= 0 && proj < Main.maxProjectiles) + { + Main.projectile[proj].scale = scale; + } } } - return true; // Allow death + return true; } public override void PostHurt(Player.HurtInfo info) @@ -1988,10 +1998,13 @@ public override void PostHurt(Player.HurtInfo info) { duration = (int)(duration * 2.5f); } + + hellhexApplierIndex = info.DamageSource.SourcePlayerIndex; } } Player.AddBuff(ModContent.BuffType(), duration); + return; } if (Player.HasBuff()) @@ -2001,13 +2014,26 @@ public override void PostHurt(Player.HurtInfo info) if (info.DamageSource.SourceProjectileLocalIndex >= 0) { Projectile proj = Main.projectile[info.DamageSource.SourceProjectileLocalIndex]; - if (proj.minion || proj.sentry || proj.CountsAsClass(DamageClass.SummonMeleeSpeed)) + if (proj != null && proj.active && (proj.minion || proj.sentry || proj.CountsAsClass(DamageClass.SummonMeleeSpeed))) + { + isSummon = true; + } + } + else if (info.DamageSource.SourceProjectileType > 0) + { + int projType = info.DamageSource.SourceProjectileType; + if (projType == ProjectileID.BlandWhip || projType == ProjectileID.FireWhip || + projType == ProjectileID.SwordWhip || projType == ProjectileID.MaceWhip || + projType == ProjectileID.ScytheWhip || projType == ProjectileID.ThornWhip || + projType == ProjectileID.BoneWhip || projType == ProjectileID.RainbowWhip || + projType == ProjectileID.CoolWhip) { isSummon = true; } } - if (!isSummon) + // Only trigger if damage >= 60 and not summon damage + if (!isSummon && info.Damage >= 60) { int buffIndex = Player.FindBuffIndex(ModContent.BuffType()); if (buffIndex >= 0) @@ -2015,19 +2041,31 @@ public override void PostHurt(Player.HurtInfo info) Player.buffTime[buffIndex] = 0; } - if (Main.myPlayer == Player.whoAmI) + if (Main.netMode != NetmodeID.MultiplayerClient) { Vector2 spawnPos = Player.Center; + float scale = info.Damage / 100f; // Scale based on damage + int owner = hellhexApplierIndex >= 0 ? hellhexApplierIndex : Player.whoAmI; - Projectile.NewProjectile( + int proj = Projectile.NewProjectile( Player.GetSource_Buff(buffIndex), spawnPos, Vector2.Zero, ProjectileID.FireWhipProj, info.Damage, 0f, - Player.whoAmI + owner // Owned by the attacker who applied Hellhex ); + + if (proj >= 0 && proj < Main.maxProjectiles) + { + Main.projectile[proj].scale = scale; + + if (Main.netMode == NetmodeID.Server) + { + NetMessage.SendData(MessageID.SyncProjectile, -1, -1, null, proj); + } + } } } } @@ -2062,11 +2100,13 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) if (!isSummon) { + // Always apply damage multiplier modifiers.FinalDamage *= 2.75f; + modifiers.ModifyHurtInfo += (ref Player.HurtInfo info) => { storedDamage = info.Damage; + hellhexTriggered = true; }; - hellhexTriggered = true; } } } @@ -2099,6 +2139,7 @@ public override void PostUpdateBuffs() else { hellhexTriggered = false; + hellhexApplierIndex = -1; // Reset when buff expires } } } @@ -2173,8 +2214,8 @@ public override void PostHurt(Player.HurtInfo info) if (info.DamageSource.SourceProjectileType == ProjectileID.ShadowFlameArrow) { - int maxDuration = 4 * 60; - float damageRatio = Math.Min(info.Damage / 47f, 1f); + int maxDuration = 3 * 60; + float damageRatio = Math.Min(info.Damage / 30f, 1f); shadowflameDuration = (int)(maxDuration * damageRatio); } else if (info.DamageSource.SourceProjectileType == ProjectileID.ShadowFlame) @@ -2183,8 +2224,8 @@ public override void PostHurt(Player.HurtInfo info) } else if (info.DamageSource.SourceProjectileType == ProjectileID.ShadowFlameKnife) { - int maxDuration = 60 * 5; - float damageRatio = Math.Min(info.Damage / 40f, 1f); + int maxDuration = 60 * 3; + float damageRatio = Math.Min(info.Damage / 25f, 1f); shadowflameDuration = (int)(maxDuration * damageRatio); } else if (info.DamageSource.SourceProjectileType == ProjectileID.DarkLance) From 82f59d8359063c8251f2ae2e992bb5610d0a4836 Mon Sep 17 00:00:00 2001 From: emyhrberg Date: Sat, 25 Oct 2025 04:22:03 +0200 Subject: [PATCH 136/206] Custom dash keybind implementation with proper netcode syncing --- .gitignore | 3 + AdventurePacketIdentifier.cs | 3 +- Core/Features/Dash/DashKeybindSystem.cs | 28 ++ Core/Features/Dash/KeybindSystem.cs | 360 ++++++++++++++++++++++++ Localization/en-US.hjson | 1 + PvPAdventure.cs | 5 + System/DiscordIdentification.cs | 2 +- 7 files changed, 400 insertions(+), 2 deletions(-) create mode 100644 Core/Features/Dash/DashKeybindSystem.cs create mode 100644 Core/Features/Dash/KeybindSystem.cs diff --git a/.gitignore b/.gitignore index cc2f8d65..3a87489f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,6 @@ .vs bin obj + +# we don't need to add the solution to version control +PvPAdventure.sln diff --git a/AdventurePacketIdentifier.cs b/AdventurePacketIdentifier.cs index 034d4310..7ac37d0e 100644 --- a/AdventurePacketIdentifier.cs +++ b/AdventurePacketIdentifier.cs @@ -7,5 +7,6 @@ public enum AdventurePacketIdentifier : byte WorldMapLighting, PingPong, PlayerItemPickup, - PlayerTeam + PlayerTeam, + Dash } \ No newline at end of file diff --git a/Core/Features/Dash/DashKeybindSystem.cs b/Core/Features/Dash/DashKeybindSystem.cs new file mode 100644 index 00000000..c0b6ee1d --- /dev/null +++ b/Core/Features/Dash/DashKeybindSystem.cs @@ -0,0 +1,28 @@ +using Terraria; +using Terraria.ModLoader; + +namespace PvPAdventure.Core.Features.Dash +{ + public class DashKeybind : ModSystem + { + public override void Load() + { + On_Player.DashMovement += CustomDashHandle; + } + + public override void Unload() + { + On_Player.DashMovement -= CustomDashHandle; + } + + private static void CustomDashHandle(On_Player.orig_DashMovement orig, Player self) + { + if (self.whoAmI == Main.myPlayer && KeybindSystem.DashKB?.JustPressed == true) + { + ModContent.GetInstance().Logger.Info($"Dash key pressed on player {self.whoAmI} (dashDelay={self.dashDelay})."); + } + + orig(self); + } + } +} \ No newline at end of file diff --git a/Core/Features/Dash/KeybindSystem.cs b/Core/Features/Dash/KeybindSystem.cs new file mode 100644 index 00000000..a73ee3c5 --- /dev/null +++ b/Core/Features/Dash/KeybindSystem.cs @@ -0,0 +1,360 @@ +using System; +using System.IO; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Input; +using Terraria; +using Terraria.DataStructures; +using Terraria.GameInput; +using Terraria.Graphics.Shaders; +using Terraria.ID; +using Terraria.ModLoader; + +namespace PvPAdventure.Core.Features.Dash +{ + internal enum PvPAdventureMessageType : byte + { + Dash = 0 + } + + internal enum DashPacketType : byte + { + Request = 0, + Perform = 1 + } + + public class KeybindSystem : ModSystem + { + public static ModKeybind DashKB; + + public override void Load() + { + DashKB = KeybindLoader.RegisterKeybind(Mod, "Dash", Keys.Z); + } + + public override void Unload() + { + DashKB = null; + } + + internal static void HandlePacket(BinaryReader reader, int sender) + { + DashPacketType packetType = (DashPacketType)reader.ReadByte(); + + switch (packetType) + { + case DashPacketType.Request: + { + if (Main.netMode != NetmodeID.Server) + break; + + sbyte direction = reader.ReadSByte(); + byte dashTypeHint = reader.ReadByte(); + + direction = ClampDirection(direction); + if (direction == 0) + direction = 1; + + Player player = Main.player[sender]; + if (!player.active || player.dead) + break; + + var dashPlayer = player.GetModPlayer(); + if (dashPlayer.PerformDash(direction, force: false, out byte dashTypeUsed, dashTypeHint > 0 ? dashTypeHint : (int?)null)) + { + dashPlayer.BroadcastDash(direction, dashTypeUsed); + } + break; + } + case DashPacketType.Perform: + { + if (Main.netMode != NetmodeID.MultiplayerClient) + break; + + byte playerIndex = reader.ReadByte(); + sbyte direction = reader.ReadSByte(); + byte dashTypeUsed = reader.ReadByte(); + + if (playerIndex >= Main.maxPlayers) + break; + + Player remotePlayer = Main.player[playerIndex]; + if (!remotePlayer.active) + break; + + direction = ClampDirection(direction); + if (direction == 0) + direction = 1; + + var dashPlayer = remotePlayer.GetModPlayer(); + dashPlayer.PerformDash(direction, force: true, out _, dashTypeUsed > 0 ? dashTypeUsed : (int?)null); + break; + } + } + } + + private static sbyte ClampDirection(int direction) + { + if (direction > 1) + return 1; + if (direction < -1) + return -1; + return (sbyte)direction; + } + } + + public class KeybindPlayer : ModPlayer + { + private const int DefaultDashType = 2; + + private bool restoreDashType; + private int dashTypeToRestore; + + public override void ProcessTriggers(TriggersSet triggers) + { + if (KeybindSystem.DashKB == null || !KeybindSystem.DashKB.JustPressed) + return; + + int inputDirection = NormalizeDirection(GetInputDirection()); + ModContent.GetInstance().Logger.Info($"ProcessTriggers: player {Player.whoAmI} requesting dash dir={inputDirection} dashType={Player.dashType} delay={Player.dashDelay}"); + + if (PerformDash(inputDirection, force: false, out byte dashTypeUsed)) + { + ModContent.GetInstance().Logger.Info($"Dash executed locally on {Player.whoAmI} using type {dashTypeUsed} (netMode={Main.netMode})."); + if (Main.netMode == NetmodeID.MultiplayerClient) + { + SendDashRequest(inputDirection, dashTypeUsed); + } + else if (Main.netMode == NetmodeID.Server) + { + BroadcastDash(inputDirection, dashTypeUsed); + } + } + } + + private int GetInputDirection() + { + if (Player.controlRight && !Player.controlLeft) + return 1; + if (Player.controlLeft && !Player.controlRight) + return -1; + + if (Player.velocity.X > 0f) + return 1; + if (Player.velocity.X < 0f) + return -1; + + return Player.direction; + } + + private int NormalizeDirection(int direction) + { + if (direction > 0) + return 1; + if (direction < 0) + return -1; + return Player.direction == 0 ? 1 : Player.direction; + } + + private bool CanDash() + { + if (Player.dashDelay != 0) + return false; + + if (Player.mount.Active || Player.dead || Player.frozen || Player.webbed || Player.tongued || Player.stoned) + return false; + + return true; + } + + internal bool PerformDash(int direction, bool force, out byte dashTypeUsed, int? overrideDashType = null) + { + dashTypeUsed = 0; + + direction = NormalizeDirection(direction); + + if (!force && !CanDash()) + return false; + + int originalDashType = Player.dashType; + int selectedDashType = overrideDashType.HasValue && overrideDashType.Value > 0 + ? overrideDashType.Value + : (originalDashType != 0 ? originalDashType : DefaultDashType); + + if (selectedDashType < 1 || selectedDashType > 5) + selectedDashType = DefaultDashType; + + dashTypeUsed = (byte)selectedDashType; + + if (selectedDashType != originalDashType) + { + restoreDashType = true; + dashTypeToRestore = originalDashType; + } + else + { + restoreDashType = false; + } + + Player.dashType = selectedDashType; + Player.dash = selectedDashType; + Player.dashTime = 0; + Player.dashDelay = -1; + Player.direction = direction; + Player.timeSinceLastDashStarted = 0; + + ApplyDashEffects(selectedDashType, direction); + + //Player.netUpdate = true; + return true; + } + + private void ApplyDashEffects(int dashType, int direction) + { + switch (dashType) + { + case 1: + ApplyTabiDash(direction); + break; + case 2: + case 4: + ApplyShieldDash(direction); + break; + case 3: + ApplySolarDash(direction); + break; + case 5: + ApplyCrystalDash(direction); + break; + default: + ApplyShieldDash(direction); + break; + } + } + + private void ApplyTabiDash(int direction) + { + ApplyHorizontalVelocity(direction, 16.9f); + + if (Main.netMode == NetmodeID.Server) + return; + + IEntitySource source = Player.GetSource_FromThis(); + + for (int i = 0; i < 20; i++) + { + int dust = Dust.NewDust(new Vector2(Player.position.X, Player.position.Y), Player.width, Player.height, DustID.Smoke, 0f, 0f, 100, default, 2f); + Main.dust[dust].position.X += Main.rand.Next(-5, 6); + Main.dust[dust].position.Y += Main.rand.Next(-5, 6); + Main.dust[dust].velocity *= 0.2f; + Main.dust[dust].scale *= 1f + Main.rand.Next(20) * 0.01f; + } + + int gore = Gore.NewGore(source, new Vector2(Player.position.X + Player.width / 2f - 24f, Player.position.Y + Player.height / 2f - 34f), Vector2.Zero, Main.rand.Next(61, 64)); + Main.gore[gore].velocity.X = Main.rand.Next(-50, 51) * 0.01f; + Main.gore[gore].velocity.Y = Main.rand.Next(-50, 51) * 0.01f; + Main.gore[gore].velocity *= 0.4f; + + gore = Gore.NewGore(source, new Vector2(Player.position.X + Player.width / 2f - 24f, Player.position.Y + Player.height / 2f - 14f), Vector2.Zero, Main.rand.Next(61, 64)); + Main.gore[gore].velocity.X = Main.rand.Next(-50, 51) * 0.01f; + Main.gore[gore].velocity.Y = Main.rand.Next(-50, 51) * 0.01f; + Main.gore[gore].velocity *= 0.4f; + } + + private void ApplyShieldDash(int direction) + { + ApplyHorizontalVelocity(direction, 14.5f); + Player.eocDash = 15; + } + + private void ApplySolarDash(int direction) + { + ApplyHorizontalVelocity(direction, 21.9f); + Player.solarDashing = true; + Player.solarDashConsumedFlare = false; + + if (Main.netMode == NetmodeID.Server) + return; + + for (int i = 0; i < 20; i++) + { + int dust = Dust.NewDust(new Vector2(Player.position.X, Player.position.Y), Player.width, Player.height, DustID.SolarFlare, 0f, 0f, 100, default, 2f); + Main.dust[dust].position.X += Main.rand.Next(-5, 6); + Main.dust[dust].position.Y += Main.rand.Next(-5, 6); + Main.dust[dust].velocity *= 0.2f; + Main.dust[dust].scale *= 1f + Main.rand.Next(20) * 0.01f; + Main.dust[dust].shader = GameShaders.Armor.GetSecondaryShader(Player.ArmorSetDye(), Player); + Main.dust[dust].noGravity = true; + Main.dust[dust].fadeIn = 0.5f; + } + } + + private void ApplyCrystalDash(int direction) + { + ApplyHorizontalVelocity(direction, 16.9f); + + if (Main.netMode == NetmodeID.Server) + return; + + for (int i = 0; i < 20; i++) + { + short dustType = Main.rand.NextFromList((short)68, (short)69, (short)70); + int dust = Dust.NewDust(new Vector2(Player.position.X, Player.position.Y), Player.width, Player.height, dustType, 0f, 0f, 100, default, 1.5f); + Main.dust[dust].position.X += Main.rand.Next(-5, 6); + Main.dust[dust].position.Y += Main.rand.Next(-5, 6); + Main.dust[dust].velocity = Player.DirectionTo(Main.dust[dust].position) * 2f; + Main.dust[dust].scale *= 1f + Main.rand.Next(20) * 0.01f; + Main.dust[dust].fadeIn = 0.5f + Main.rand.Next(20) * 0.01f; + Main.dust[dust].noGravity = true; + Main.dust[dust].shader = GameShaders.Armor.GetSecondaryShader(Player.ArmorSetDye(), Player); + } + } + + private void ApplyHorizontalVelocity(int direction, float speed) + { + Player.velocity.X = speed * direction; + + Point tileAheadUpper = (Player.Center + new Vector2(direction * Player.width / 2f + 2f, Player.gravDir * (-Player.height) / 2f + Player.gravDir * 2f)).ToTileCoordinates(); + Point tileAheadMid = (Player.Center + new Vector2(direction * Player.width / 2f + 2f, 0f)).ToTileCoordinates(); + + if (WorldGen.SolidOrSlopedTile(tileAheadUpper.X, tileAheadUpper.Y) || WorldGen.SolidOrSlopedTile(tileAheadMid.X, tileAheadMid.Y)) + { + Player.velocity.X *= 0.5f; + } + } + + private void SendDashRequest(int direction, byte dashTypeUsed) + { + ModContent.GetInstance().Logger.Info($"SendDashRequest: player {Player.whoAmI} dir={direction} type={dashTypeUsed}"); + ModPacket packet = Mod.GetPacket(); + packet.Write((byte)AdventurePacketIdentifier.Dash); + packet.Write((byte)DashPacketType.Request); + packet.Write((sbyte)direction); + packet.Write(dashTypeUsed); + packet.Send(); + } + + internal void BroadcastDash(int direction, byte dashTypeUsed) + { + ModContent.GetInstance().Logger.Info($"BroadcastDash: player {Player.whoAmI} dir={direction} type={dashTypeUsed}"); + if (Main.netMode != NetmodeID.Server) + return; + + ModPacket packet = Mod.GetPacket(); + packet.Write((byte)AdventurePacketIdentifier.Dash); + packet.Write((byte)DashPacketType.Perform); + packet.Write((byte)Player.whoAmI); + packet.Write((sbyte)direction); + packet.Write(dashTypeUsed); + packet.Send(); + } + + internal void PostDashMovementCleanup() + { + if (restoreDashType && Player.dashDelay >= 0) + { + Player.dashType = dashTypeToRestore; + restoreDashType = false; + } + } + } +} \ No newline at end of file diff --git a/Localization/en-US.hjson b/Localization/en-US.hjson index 8ba2b87f..5434e9e7 100644 --- a/Localization/en-US.hjson +++ b/Localization/en-US.hjson @@ -13,6 +13,7 @@ Mods: { Scoreboard.DisplayName: Scoreboard BountyShop.DisplayName: Bounty Shop AllChat.DisplayName: All Chat + Dash.DisplayName: Dash } Configs: { diff --git a/PvPAdventure.cs b/PvPAdventure.cs index 594c18f8..c93f0864 100644 --- a/PvPAdventure.cs +++ b/PvPAdventure.cs @@ -2,6 +2,7 @@ using System.Linq; using Microsoft.Xna.Framework; using MonoMod.Cil; +using PvPAdventure.Core.Features.Dash; using PvPAdventure.System; using Terraria; using Terraria.Enums; @@ -51,6 +52,10 @@ public override void HandlePacket(BinaryReader reader, int whoAmI) switch (id) { + case AdventurePacketIdentifier.Dash: + KeybindSystem.HandlePacket(reader, whoAmI); + break; + case AdventurePacketIdentifier.BountyTransaction: { var bountyTransaction = BountyManager.Transaction.Deserialize(reader); diff --git a/System/DiscordIdentification.cs b/System/DiscordIdentification.cs index 4be689a1..47bb501f 100644 --- a/System/DiscordIdentification.cs +++ b/System/DiscordIdentification.cs @@ -15,7 +15,7 @@ namespace PvPAdventure.System; [Autoload(Side = ModSide.Both)] public class DiscordIdentification : ModSystem { - private const bool Enabled = true; + private const bool Enabled = false; public delegate void PlayerJoinEventHandler(DiscordIdentification source, PlayerJoinArgs args); From a9c42be3bddd90c987b20fecd8736c884f0dc3a5 Mon Sep 17 00:00:00 2001 From: emyhrberg Date: Sat, 25 Oct 2025 06:21:33 +0200 Subject: [PATCH 137/206] Fixed so dash can only be performed when player has dash items --- Core/Features/Dash/KeybindSystem.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/Core/Features/Dash/KeybindSystem.cs b/Core/Features/Dash/KeybindSystem.cs index a73ee3c5..5e204432 100644 --- a/Core/Features/Dash/KeybindSystem.cs +++ b/Core/Features/Dash/KeybindSystem.cs @@ -178,10 +178,16 @@ internal bool PerformDash(int direction, bool force, out byte dashTypeUsed, int? int originalDashType = Player.dashType; int selectedDashType = overrideDashType.HasValue && overrideDashType.Value > 0 ? overrideDashType.Value - : (originalDashType != 0 ? originalDashType : DefaultDashType); + : originalDashType; + + if (selectedDashType <= 0) + { + ModContent.GetInstance().Logger.Info($"PerformDash aborted: player {Player.whoAmI} has no dash-granting item (override={overrideDashType})."); + return false; + } if (selectedDashType < 1 || selectedDashType > 5) - selectedDashType = DefaultDashType; + selectedDashType = Math.Clamp(selectedDashType, 1, 5); dashTypeUsed = (byte)selectedDashType; @@ -204,7 +210,7 @@ internal bool PerformDash(int direction, bool force, out byte dashTypeUsed, int? ApplyDashEffects(selectedDashType, direction); - //Player.netUpdate = true; + // Player.netUpdate = true; return true; } From 9c3d166a2948ff170f0190c33e06f683c25df8d2 Mon Sep 17 00:00:00 2001 From: emyhrberg Date: Mon, 27 Oct 2025 23:11:44 +0100 Subject: [PATCH 138/206] Fixed double dash + double smoke issue with high latency by excluding the origin (client) so it wont double apply in DashKeybindSystem::BroadcastDash() by using optional params for packet.Send and ignoring client --- Core/Features/Dash/KeybindSystem.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Core/Features/Dash/KeybindSystem.cs b/Core/Features/Dash/KeybindSystem.cs index 5e204432..7cbeeb82 100644 --- a/Core/Features/Dash/KeybindSystem.cs +++ b/Core/Features/Dash/KeybindSystem.cs @@ -77,6 +77,10 @@ internal static void HandlePacket(BinaryReader reader, int sender) if (playerIndex >= Main.maxPlayers) break; + // <-- ignore self to prevent double application + //if (playerIndex == Main.myPlayer) + //break; + Player remotePlayer = Main.player[playerIndex]; if (!remotePlayer.active) break; @@ -351,7 +355,12 @@ internal void BroadcastDash(int direction, byte dashTypeUsed) packet.Write((byte)Player.whoAmI); packet.Write((sbyte)direction); packet.Write(dashTypeUsed); - packet.Send(); + + // <-- exclude the origin so it won’t double-apply + packet.Send(toClient: -1, ignoreClient: Player.whoAmI); + + // old + //packet.Send(); } internal void PostDashMovementCleanup() From 42637fabf79fd5f12a2c1fad2ad6622d7905a76d Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Tue, 28 Oct 2025 23:16:04 -0700 Subject: [PATCH 139/206] bug fixes and nice little things --- AdventureBuff.cs | 10 +++ AdventureDropDatabase.cs | 23 ++++--- AdventureItem.cs | 104 +++++++++++++++++++++++++++++ AdventureNpc.cs | 18 ++--- AdventurePlayer.cs | 26 ++++---- AdventureProjectile.cs | 11 ++++ Dogshit.cs | 139 +++++++++++++++++++++++++++++++++++++-- Localization/en-US.hjson | 8 +-- PvPAdventure.csproj | 3 + 9 files changed, 301 insertions(+), 41 deletions(-) diff --git a/AdventureBuff.cs b/AdventureBuff.cs index 802e6cac..3ecf2703 100644 --- a/AdventureBuff.cs +++ b/AdventureBuff.cs @@ -86,4 +86,14 @@ public override void ModifyWeaponDamage(Item item, Player player, ref StatModifi } } } + public class BuffTextChange : GlobalBuff + { + public override void ModifyBuffText(int type, ref string buffName, ref string tip, ref int rare) + { + if (type == BuffID.Archery) + { + tip = "20% increased arrow speed\nNo longer grants bow damage"; + } + } + } } \ No newline at end of file diff --git a/AdventureDropDatabase.cs b/AdventureDropDatabase.cs index bedfbeff..69ea2cce 100644 --- a/AdventureDropDatabase.cs +++ b/AdventureDropDatabase.cs @@ -133,6 +133,10 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) foreach (var drop in drops) ModifyDropRate(drop, ItemID.RocketLauncher, 1, 1); break; + case NPCID.Vampire: + foreach (var drop in drops) + ModifyDropRate(drop, ItemID.MoonStone, 1, 5); + break; case NPCID.RustyArmoredBonesAxe: case NPCID.RustyArmoredBonesFlail: @@ -278,25 +282,25 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) break; case NPCID.QueenBee: - // Remove Honey Comb drop, and the big loot pool -- we will re-create it ourselves. + npcLoot.Add(ItemDropRule.Common(ItemID.BeeWax, 1, 70, 200)); + npcLoot.Add(ItemDropRule.Common(ItemID.HoneyComb, 1, 1, 2)); + npcLoot.Add(ItemDropRule.Common(ItemID.GoldCoin, 1, 10, 15)); + npcLoot.Add(ItemDropRule.Common(ItemID.Beenade, 1, 22, 32)); npcLoot.RemoveWhere(drop => (drop is CommonDrop commonDrop && commonDrop.itemId == ItemID.HoneyComb) || drop is DropBasedOnExpertMode); - npcLoot.Add(ItemDropRule.FewFromOptions(1, + npcLoot.Add(ItemDropRule.OneFromOptions(1, ItemID.BeeKeeper, ItemID.BeesKnees ) ); - npcLoot.Add(ItemDropRule.FewFromOptions(1, + npcLoot.Add(ItemDropRule.OneFromOptions(1, ItemID.BeeGun, ItemID.HoneyComb ) ); - npcLoot.Add(ItemDropRule.Common(ItemID.BeeWax, 1, 70, 200)); - npcLoot.Add(ItemDropRule.Common(ItemID.HoneyComb, 1, 1, 2)); - npcLoot.Add(ItemDropRule.Common(ItemID.GoldCoin, 1, 10, 15)); break; case NPCID.SkeletronHead: @@ -379,12 +383,15 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) } var dukefirstKillRule = new LeadingConditionRule(new FirstBossKillCondition(NPCID.DukeFishron)); - dukefirstKillRule.OnSuccess(ItemDropRule.Common(ItemID.Tsunami, 1)); - dukefirstKillRule.OnFailedConditions(ItemDropRule.OneFromOptions(1, + dukefirstKillRule.OnSuccess(ItemDropRule.OneFromOptions(1, ItemID.BubbleGun, + ItemID.Tsunami + )); + dukefirstKillRule.OnFailedConditions(ItemDropRule.OneFromOptions(1, ItemID.RazorbladeTyphoon, ItemID.Tsunami, ItemID.TempestStaff, + ItemID.BubbleGun, ItemID.Flairon )); npcLoot.Add(dukefirstKillRule); diff --git a/AdventureItem.cs b/AdventureItem.cs index fec42379..c913cdbc 100644 --- a/AdventureItem.cs +++ b/AdventureItem.cs @@ -306,4 +306,108 @@ public override void ModifyWeaponDamage(Item item, Player player, ref StatModifi } } } + public class ItemTextChanges : GlobalItem + { + public override void ModifyTooltips(Item item, List tooltips) + { + if (item.type == ItemID.BeetleScaleMail || item.type == ItemID.BeetleShell) + { + TooltipLine setBonusLine = tooltips.FirstOrDefault(x => x.Name == "SetBonus" && x.Mod == "Terraria"); + if (setBonusLine != null) + { + setBonusLine.Text = "Set bonus:\nGain Beetles from player kills\nBeetles increase your melee damage and attack speed"; + } + } + + if (item.type == ItemID.TikiMask || item.type == ItemID.TikiShirt || item.type == ItemID.TikiPants) + { + TooltipLine setBonusLine = tooltips.FirstOrDefault(x => x.Name == "SetBonus" && x.Mod == "Terraria"); + if (setBonusLine != null) + { + setBonusLine.Text = "Set bonus:\nIncreases your max number of minions\nIncreases whip range by 20%\nIncreases whip debuff duration against players by 150%"; + } + } + if (item.type == ItemID.BlandWhip || item.type == ItemID.ThornWhip || + item.type == ItemID.BoneWhip || item.type == ItemID.FireWhip || + item.type == ItemID.CoolWhip || item.type == ItemID.SwordWhip || + item.type == ItemID.ScytheWhip || item.type == ItemID.MaceWhip || + item.type == ItemID.RainbowWhip) + { + tooltips.Add(new TooltipLine(Mod, "WhipRangeWarning", "Range greatly reduced without Pygmy Necklace or Hercules Beetle") + { + OverrideColor = new Color(255, 100, 100) + }); + tooltips.Add(new TooltipLine(Mod, "SummonsArePlayers", "All whip debuffs apply to players, and effect all non-summon damage") + { + OverrideColor = new Color(100, 255, 100) + }); + } + + + if (item.type == ItemID.PygmyNecklace || item.type == ItemID.HerculesBeetle) + { + tooltips.Add(new TooltipLine(Mod, "WhipRangeFix", "Prevents whip range penalty")); + } + if (item.type == ItemID.SpectrePickaxe || item.type == ItemID.ShroomiteDiggingClaw) + { + tooltips.Add(new TooltipLine(Mod, "MiningPowerChange", "Capable of mining Lihzahrd Bricks")); + } + if (item.type == ItemID.PhilosophersStone || item.type == ItemID.CharmofMyths) + { + tooltips.Add(new TooltipLine(Mod, "FullHPRespawn", "Gain full health upon returning to the land of the living")); + } + if (item.type == ItemID.MagicQuiver || item.type == ItemID.MoltenQuiver) + { + for (int i = 0; i < tooltips.Count; i++) + { + if (tooltips[i].Text.Contains("Increases arrow damage by 10%") || + tooltips[i].Text.Contains("arrow damage")) + { + tooltips[i].Text = "Greatly increases arrow speed"; + break; + } + } + tooltips.Add(new TooltipLine(Mod, "QuiverNerf", "No longer grants arrow damage.\nPerhaps if it was a little more sneaky?") + { + OverrideColor = new Color(255, 100, 100) + }); + } + if (item.type == ItemID.ArcheryPotion) + { + for (int i = 0; i < tooltips.Count; i++) + { + if (tooltips[i].Text.Contains("10% increased bow damage") || + tooltips[i].Text.Contains("bow damage and 20%")) + { + tooltips[i].Text = "20% increased arrow speed"; + break; + } + } + tooltips.Add(new TooltipLine(Mod, "ArcheryNerf", "No longer grants bow damage") + { + OverrideColor = new Color(255, 100, 100) + }); + } + if (item.type == ItemID.TempleKey) + { + for (int i = 0; i < tooltips.Count; i++) + { + if (tooltips[i].Text.Contains("Opens the jungle temple door") || + tooltips[i].Text.Contains("temple door")) + { + tooltips[i].Text = "Opens the jungle temple"; + break; + } + } + tooltips.Add(new TooltipLine(Mod, "LihzahrdKey", "Opens the jungle temple's chests") + { + OverrideColor = new Color(255, 100, 100) + }); + } + if (item.type == ItemID.LunarCraftingStation) + { + tooltips.Add(new TooltipLine(Mod, "AllCraftTiles", "Counts as all crafting stations")); + } + } + } } \ No newline at end of file diff --git a/AdventureNpc.cs b/AdventureNpc.cs index fa14bb8a..5aea5cc4 100644 --- a/AdventureNpc.cs +++ b/AdventureNpc.cs @@ -650,16 +650,18 @@ public override void PostAI(NPC npc) public override void ModifyShop(NPCShop shop) { + // NOT USING TS FOR NOW // The Steampunker sells the Jetpack at moon phase 4 and after during hardmode. // Change it to be during moon phase 5 and later. - if (shop.NpcType == NPCID.Steampunker && shop.TryGetEntry(ItemID.Jetpack, out var entry)) - { - if (((List)entry.Conditions).Remove(Condition.MoonPhasesHalf1)) - entry.AddCondition(Condition.MoonPhaseWaxingCrescent); - else - Mod.Logger.Warn( - "Failed to remove moon phase condition for Steampunker's Jetpack shop entry -- not changing it any further."); - } + //if (shop.NpcType == NPCID.Steampunker && shop.TryGetEntry(ItemID.Jetpack, out var entry)) + //{ + // if (((List)entry.Conditions).Remove(Condition.MoonPhasesHalf1)) + // entry.AddCondition(Condition.MoonPhaseWaxingCrescent); + // else + // Mod.Logger.Warn( + // "Failed to remove moon phase condition for Steampunker's Jetpack shop entry -- not changing it any further."); + //} + } public override bool CheckDead(NPC npc) diff --git a/AdventurePlayer.cs b/AdventurePlayer.cs index 37335324..ba876007 100644 --- a/AdventurePlayer.cs +++ b/AdventurePlayer.cs @@ -1187,7 +1187,7 @@ public override void PostUpdateEquips() } } } - private static bool? ShouldSilenceHurtSound(Player target, Player.HurtInfo info) + private static bool? ShouldSilenceHurtSound(Player target, Player.HurtInfo info) { // Only silence hurt sound on clients that we hurt that aren't ourselves if (!Main.dedServ && info.PvP && target.whoAmI != Main.myPlayer && @@ -1279,7 +1279,6 @@ public override void PostUpdate() //thanks mr fargo } } - public class NewIchorPlayer : ModPlayer { public bool hasDefenseReduction = false; @@ -1887,12 +1886,12 @@ public override void PostUpdateBuffs() { if (Player.HasBuff()) { - for (int i = 0; i < 1; i++) + for (int i = 0; i < 1; i++) { - int dustType = DustID.BatScepter ; + int dustType = DustID.BatScepter; Vector2 dustPosition = Player.position + new Vector2(Main.rand.Next(Player.width), Main.rand.Next(Player.height)); Vector2 dustVelocity = Player.velocity * 0.3f + new Vector2(Main.rand.NextFloat(-1f, 1f), Main.rand.NextFloat(-1f, 1f)); - + Dust dust = Dust.NewDustDirect(dustPosition, 0, 0, dustType, dustVelocity.X, dustVelocity.Y, 100, Color.Black, Main.rand.NextFloat(0.8f, 1.5f)); dust.noGravity = Main.rand.NextBool(2); dust.fadeIn = 1.2f; @@ -1974,6 +1973,7 @@ public override bool PreKill(double damage, int hitDirection, bool pvp, ref bool } } + // Spawn explosion on death from non-summon damage (if damage >= 60) if (!isSummon && Main.myPlayer == Player.whoAmI && damage >= 60) { float scale = (float)damage / 100f; // Scale based on damage @@ -1986,9 +1986,9 @@ public override bool PreKill(double damage, int hitDirection, bool pvp, ref bool ProjectileID.FireWhipProj, (int)damage, 0f, - owner, + owner, // Owned by the attacker who applied Hellhex 0f, - scale + scale // ai[1] for scale ); if (proj >= 0 && proj < Main.maxProjectiles) @@ -1998,12 +1998,11 @@ public override bool PreKill(double damage, int hitDirection, bool pvp, ref bool } } - return true; + return true; // Allow death } public override void PostHurt(Player.HurtInfo info) { - // Apply Hellhex when hit by FireWhip if (info.DamageSource.SourceProjectileType == ProjectileID.FireWhip) { int duration = 800; @@ -2019,17 +2018,16 @@ public override void PostHurt(Player.HurtInfo info) duration = (int)(duration * 2.5f); } + // Store who applied the debuff hellhexApplierIndex = info.DamageSource.SourcePlayerIndex; } } Player.AddBuff(ModContent.BuffType(), duration); // Don't process the removal logic on the same hit that applies it - return; } - // Only check for removal if player already has Hellhex if (Player.HasBuff()) { bool isSummon = false; @@ -2042,8 +2040,6 @@ public override void PostHurt(Player.HurtInfo info) isSummon = true; } } - // Add whip check here too - else if (info.DamageSource.SourceProjectileType > 0) { int projType = info.DamageSource.SourceProjectileType; @@ -2066,6 +2062,7 @@ public override void PostHurt(Player.HurtInfo info) Player.buffTime[buffIndex] = 0; } + // Spawn on server or singleplayer for proper syncing if (Main.netMode != NetmodeID.MultiplayerClient) { Vector2 spawnPos = Player.Center; @@ -2086,6 +2083,7 @@ public override void PostHurt(Player.HurtInfo info) { Main.projectile[proj].scale = scale; + // Sync the projectile to all clients if (Main.netMode == NetmodeID.Server) { NetMessage.SendData(MessageID.SyncProjectile, -1, -1, null, proj); @@ -2314,7 +2312,7 @@ public override void PostUpdateEquips() { for (int i = 3; i < 8 + Player.GetAmountOfExtraAccessorySlotsToShow(); i++) { - if (Player.armor[i].type == ItemID.MagicQuiver || Player.armor[i].type == ItemID.MoltenQuiver ) + if (Player.armor[i].type == ItemID.MagicQuiver || Player.armor[i].type == ItemID.MoltenQuiver) { hasQuiver = true; break; diff --git a/AdventureProjectile.cs b/AdventureProjectile.cs index 684aa4bc..e7525d9d 100644 --- a/AdventureProjectile.cs +++ b/AdventureProjectile.cs @@ -755,6 +755,17 @@ public override void ModifyHitNPC(Projectile projectile, NPC target, ref NPC.Hit } } } + public class NoMoreDynaWoF : GlobalProjectile + { + public override void ModifyHitNPC(Projectile projectile, NPC target, ref NPC.HitModifiers modifiers) + { + if ((projectile.type == ProjectileID.Dynamite || projectile.type == ProjectileID.StickyDynamite) && + (target.type == NPCID.WallofFlesh || target.type == NPCID.WallofFleshEye)) + { + modifiers.SourceDamage *= 0f; + } + } + } public class EmpressNerf : GlobalProjectile diff --git a/Dogshit.cs b/Dogshit.cs index 41fdcbd1..227c9d0d 100644 --- a/Dogshit.cs +++ b/Dogshit.cs @@ -11,6 +11,9 @@ using System.Reflection; using System; using Mono.Cecil.Cil; +using Terraria.GameContent.Generation; +using Terraria.IO; +using Terraria.WorldBuilding; namespace PvPAdventure { public class RainSystem : ModSystem @@ -105,13 +108,13 @@ public override void PostUpdateWorld() private bool ShouldSpawnMechBoss() { return !Main.dayTime && - Main.hardMode && + Main.hardMode && !NPC.AnyNPCs(NPCID.TheDestroyer) && !NPC.AnyNPCs(NPCID.Retinazer) && !NPC.AnyNPCs(NPCID.Spazmatism) && !NPC.AnyNPCs(NPCID.SkeletronPrime) && - HasUndefeatedMechBoss() && - FindClosestPlayerToSpawn() != null; + HasUndefeatedMechBoss() && + FindClosestPlayerToSpawn() != null; } private bool HasUndefeatedMechBoss() @@ -147,7 +150,7 @@ private int ChooseMechanicalBoss() var availableBosses = new List(); if (!NPC.downedMechBoss1) availableBosses.Add(NPCID.TheDestroyer); - if (!NPC.downedMechBoss2) availableBosses.Add(NPCID.Retinazer); + if (!NPC.downedMechBoss2) availableBosses.Add(NPCID.Retinazer); if (!NPC.downedMechBoss3) availableBosses.Add(NPCID.SkeletronPrime); return availableBosses.Count > 0 ? availableBosses[Main.rand.Next(availableBosses.Count)] : -1; @@ -330,4 +333,132 @@ private static void AltarOreILEdit(ILContext il) } } } + public class RemoveTownNPCInvasionSpawns : ModSystem + { + private static ILHook spawnNPCHook; + + public override void Load() + { + MethodInfo method = typeof(Terraria.NPC).GetMethod("SpawnNPC", + BindingFlags.Public | BindingFlags.Static); + spawnNPCHook = new ILHook(method, RemoveTownNPCCheck); + } + + public override void Unload() + { + spawnNPCHook?.Dispose(); + } + + private static void RemoveTownNPCCheck(ILContext il) + { + ILCursor cursor = new ILCursor(il); + + try + { + // Find where townNPC field is loaded for invasion check + if (cursor.TryGotoNext(MoveType.After, + i => i.MatchLdsfld(typeof(Terraria.Main).GetField("npc")), + i => i.MatchLdloc(out _), + i => i.MatchLdelemRef(), + i => i.MatchLdfld(typeof(Terraria.NPC).GetField("townNPC")) + )) + { + ModContent.GetInstance().Logger.Info("Found townNPC field load in invasion code"); + + // Right after loading townNPC, replace the value with false + cursor.Emit(OpCodes.Pop); // Remove the townNPC value from stack + cursor.Emit(OpCodes.Ldc_I4_0); // Push false (0) + + ModContent.GetInstance().Logger.Info("Successfully made townNPC always false for invasions"); + } + else + { + ModContent.GetInstance().Logger.Error("Could not find townNPC field in SpawnNPC"); + } + } + catch (Exception e) + { + ModContent.GetInstance().Logger.Error($"Error in IL edit: {e}"); + } + } + } +// public class ExtraWorldGen : ModSystem +// { +// public override void ModifyWorldGenTasks(List tasks, ref double totalWeight) +// { +// // Find the original passes to insert after them +// int lifeCrystalIndex = tasks.FindIndex(genpass => genpass.Name.Equals("Life Crystals")); +// int minecartIndex = tasks.FindIndex(genpass => genpass.Name.Equals("Minecart Tracks")); +// int undergroundChestIndex = tasks.FindIndex(genpass => genpass.Name.Equals("Buried Chests")); + +// // Add extra life crystals (2x more) +// if (lifeCrystalIndex != -1) +// { +// tasks.Insert(lifeCrystalIndex + 1, new PassLegacy("Extra Life Crystals", delegate (GenerationProgress progress, GameConfiguration passConfig) +// { +// progress.Message = "Adding extra life crystals..."; + +// double num = (double)(Main.maxTilesX * Main.maxTilesY) * 2E-05; // Same formula as vanilla but e5 for now + +// for (int i = 0; i < (int)num; i++) +// { +// progress.Set((double)i / num); + +// bool placed = false; +// int attempts = 0; + +// while (!placed && attempts < 10000) +// { +// int x = WorldGen.genRand.Next(Main.offLimitBorderTiles, Main.maxTilesX - Main.offLimitBorderTiles); +// int y = WorldGen.genRand.Next((int)(Main.worldSurface * 2.0 + Main.rockLayer) / 3, Main.maxTilesY - 300); + +// if (WorldGen.getGoodWorldGen) //for the worthy +// { +// y = WorldGen.genRand.Next((int)Main.worldSurface, Main.maxTilesY - 400); +// } + +// if (WorldGen.AddLifeCrystal(x, y)) +// { +// placed = true; +// } +// attempts++; +// } +// } +// })); +// } +// // Add extra underground chests (2x more) +// if (undergroundChestIndex != -1) +// { +// tasks.Insert(undergroundChestIndex + 1, new PassLegacy("Extra Underground Chests", delegate (GenerationProgress progress, GameConfiguration passConfig) +// { +// progress.Message = "Adding extra underground chests..."; + +// // Vanilla formula is roughly maxTilesX / 34 +// int extraChests = Main.maxTilesX / 34; + +// for (int i = 0; i < extraChests; i++) +// { +// progress.Set((double)i / extraChests); + +// bool placed = false; +// int attempts = 0; + +// while (!placed && attempts < 1000) +// { +// int x = WorldGen.genRand.Next(Main.offLimitBorderTiles, Main.maxTilesX - Main.offLimitBorderTiles); +// int y = WorldGen.genRand.Next((int)Main.worldSurface + 50, Main.maxTilesY - 350); + +// if (WorldGen.AddBuriedChest(x, y, 0, false, 1)) +// { +// placed = true; +// } +// attempts++; +// } +// } +// })); +// } + +// ModContent.GetInstance().Logger.Info("Added extra worldgen passes for life crystals, and underground chests"); +// } +// } } \ No newline at end of file diff --git a/Localization/en-US.hjson b/Localization/en-US.hjson index a3a66032..1195f963 100644 --- a/Localization/en-US.hjson +++ b/Localization/en-US.hjson @@ -795,12 +795,6 @@ Mods: { BeetleMight3: Melee damage and speed increase by 8% } - ArmorSetBonus.BeetleDamage: - ''' - Gain Beetles from player kills Beetles - increase your melee damage and attack speed - ''' - Anathema: { DisplayName: Anathema Description: Enemy attacks can seek you out @@ -817,7 +811,7 @@ Mods: { } Hellhex: { - DisplayName: Hellhexed + DisplayName: Firecracked Description: You are going to burst with hellfire at any moment! } diff --git a/PvPAdventure.csproj b/PvPAdventure.csproj index 9f004e77..fed5da73 100644 --- a/PvPAdventure.csproj +++ b/PvPAdventure.csproj @@ -11,6 +11,9 @@ + + + lib\Discord.Net.Core.dll From 03f4406e31f48ecb0f584091f946ebb9b6311719 Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Tue, 28 Oct 2025 23:24:40 -0700 Subject: [PATCH 140/206] oops --- AdventurePlayer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AdventurePlayer.cs b/AdventurePlayer.cs index ba876007..8bb5cdb3 100644 --- a/AdventurePlayer.cs +++ b/AdventurePlayer.cs @@ -2005,7 +2005,7 @@ public override void PostHurt(Player.HurtInfo info) { if (info.DamageSource.SourceProjectileType == ProjectileID.FireWhip) { - int duration = 800; + int duration = 420; if (info.DamageSource.SourcePlayerIndex >= 0 && info.DamageSource.SourcePlayerIndex < Main.maxPlayers) { From dbed279b0666e0bcd6d9d5f0176f9feb21039682 Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Fri, 31 Oct 2025 14:58:05 -0700 Subject: [PATCH 141/206] martians fix hopefully --- Dogshit.cs | 166 ++++++++++++++++++++++++++--------------------------- 1 file changed, 82 insertions(+), 84 deletions(-) diff --git a/Dogshit.cs b/Dogshit.cs index 227c9d0d..d6882ab5 100644 --- a/Dogshit.cs +++ b/Dogshit.cs @@ -337,7 +337,7 @@ public class RemoveTownNPCInvasionSpawns : ModSystem { private static ILHook spawnNPCHook; - public override void Load() + public override void PostSetupContent() { MethodInfo method = typeof(Terraria.NPC).GetMethod("SpawnNPC", BindingFlags.Public | BindingFlags.Static); @@ -364,10 +364,8 @@ private static void RemoveTownNPCCheck(ILContext il) )) { ModContent.GetInstance().Logger.Info("Found townNPC field load in invasion code"); - - // Right after loading townNPC, replace the value with false - cursor.Emit(OpCodes.Pop); // Remove the townNPC value from stack - cursor.Emit(OpCodes.Ldc_I4_0); // Push false (0) + cursor.Emit(OpCodes.Pop); + cursor.Emit(OpCodes.Ldc_I4_0); ModContent.GetInstance().Logger.Info("Successfully made townNPC always false for invasions"); } @@ -382,83 +380,83 @@ private static void RemoveTownNPCCheck(ILContext il) } } } -// public class ExtraWorldGen : ModSystem -// { -// public override void ModifyWorldGenTasks(List tasks, ref double totalWeight) -// { -// // Find the original passes to insert after them -// int lifeCrystalIndex = tasks.FindIndex(genpass => genpass.Name.Equals("Life Crystals")); -// int minecartIndex = tasks.FindIndex(genpass => genpass.Name.Equals("Minecart Tracks")); -// int undergroundChestIndex = tasks.FindIndex(genpass => genpass.Name.Equals("Buried Chests")); - -// // Add extra life crystals (2x more) -// if (lifeCrystalIndex != -1) -// { -// tasks.Insert(lifeCrystalIndex + 1, new PassLegacy("Extra Life Crystals", delegate (GenerationProgress progress, GameConfiguration passConfig) -// { -// progress.Message = "Adding extra life crystals..."; - -// double num = (double)(Main.maxTilesX * Main.maxTilesY) * 2E-05; // Same formula as vanilla but e5 for now - -// for (int i = 0; i < (int)num; i++) -// { -// progress.Set((double)i / num); - -// bool placed = false; -// int attempts = 0; - -// while (!placed && attempts < 10000) -// { -// int x = WorldGen.genRand.Next(Main.offLimitBorderTiles, Main.maxTilesX - Main.offLimitBorderTiles); -// int y = WorldGen.genRand.Next((int)(Main.worldSurface * 2.0 + Main.rockLayer) / 3, Main.maxTilesY - 300); - -// if (WorldGen.getGoodWorldGen) //for the worthy -// { -// y = WorldGen.genRand.Next((int)Main.worldSurface, Main.maxTilesY - 400); -// } - -// if (WorldGen.AddLifeCrystal(x, y)) -// { -// placed = true; -// } -// attempts++; -// } -// } -// })); -// } -// // Add extra underground chests (2x more) -// if (undergroundChestIndex != -1) -// { -// tasks.Insert(undergroundChestIndex + 1, new PassLegacy("Extra Underground Chests", delegate (GenerationProgress progress, GameConfiguration passConfig) -// { -// progress.Message = "Adding extra underground chests..."; - -// // Vanilla formula is roughly maxTilesX / 34 -// int extraChests = Main.maxTilesX / 34; - -// for (int i = 0; i < extraChests; i++) -// { -// progress.Set((double)i / extraChests); - -// bool placed = false; -// int attempts = 0; - -// while (!placed && attempts < 1000) -// { -// int x = WorldGen.genRand.Next(Main.offLimitBorderTiles, Main.maxTilesX - Main.offLimitBorderTiles); -// int y = WorldGen.genRand.Next((int)Main.worldSurface + 50, Main.maxTilesY - 350); - -// if (WorldGen.AddBuriedChest(x, y, 0, false, 1)) -// { -// placed = true; -// } -// attempts++; -// } -// } -// })); -// } - -// ModContent.GetInstance().Logger.Info("Added extra worldgen passes for life crystals, and underground chests"); -// } -// } + // public class ExtraWorldGen : ModSystem + // { + // public override void ModifyWorldGenTasks(List tasks, ref double totalWeight) + // { + // // Find the original passes to insert after them + // int lifeCrystalIndex = tasks.FindIndex(genpass => genpass.Name.Equals("Life Crystals")); + // int minecartIndex = tasks.FindIndex(genpass => genpass.Name.Equals("Minecart Tracks")); + // int undergroundChestIndex = tasks.FindIndex(genpass => genpass.Name.Equals("Buried Chests")); + + // // Add extra life crystals (2x more) + // if (lifeCrystalIndex != -1) + // { + // tasks.Insert(lifeCrystalIndex + 1, new PassLegacy("Extra Life Crystals", delegate (GenerationProgress progress, GameConfiguration passConfig) + // { + // progress.Message = "Adding extra life crystals..."; + + // double num = (double)(Main.maxTilesX * Main.maxTilesY) * 2E-05; // Same formula as vanilla but e5 for now + + // for (int i = 0; i < (int)num; i++) + // { + // progress.Set((double)i / num); + + // bool placed = false; + // int attempts = 0; + + // while (!placed && attempts < 10000) + // { + // int x = WorldGen.genRand.Next(Main.offLimitBorderTiles, Main.maxTilesX - Main.offLimitBorderTiles); + // int y = WorldGen.genRand.Next((int)(Main.worldSurface * 2.0 + Main.rockLayer) / 3, Main.maxTilesY - 300); + + // if (WorldGen.getGoodWorldGen) //for the worthy + // { + // y = WorldGen.genRand.Next((int)Main.worldSurface, Main.maxTilesY - 400); + // } + + // if (WorldGen.AddLifeCrystal(x, y)) + // { + // placed = true; + // } + // attempts++; + // } + // } + // })); + // } + // // Add extra underground chests (2x more) + // if (undergroundChestIndex != -1) + // { + // tasks.Insert(undergroundChestIndex + 1, new PassLegacy("Extra Underground Chests", delegate (GenerationProgress progress, GameConfiguration passConfig) + // { + // progress.Message = "Adding extra underground chests..."; + + // // Vanilla formula is roughly maxTilesX / 34 + // int extraChests = Main.maxTilesX / 34; + + // for (int i = 0; i < extraChests; i++) + // { + // progress.Set((double)i / extraChests); + + // bool placed = false; + // int attempts = 0; + + // while (!placed && attempts < 1000) + // { + // int x = WorldGen.genRand.Next(Main.offLimitBorderTiles, Main.maxTilesX - Main.offLimitBorderTiles); + // int y = WorldGen.genRand.Next((int)Main.worldSurface + 50, Main.maxTilesY - 350); + + // if (WorldGen.AddBuriedChest(x, y, 0, false, 1)) + // { + // placed = true; + // } + // attempts++; + // } + // } + // })); + // } + + // ModContent.GetInstance().Logger.Info("Added extra worldgen passes for life crystals, and underground chests"); + // } + // } } \ No newline at end of file From 02777f88f645f45826140867a387ed3288e56ff3 Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Mon, 3 Nov 2025 14:42:34 -0800 Subject: [PATCH 142/206] no more shame bones and firecracker fixed --- AdventurePlayer.cs | 180 +++++++++++++++++++++++++-------------------- 1 file changed, 102 insertions(+), 78 deletions(-) diff --git a/AdventurePlayer.cs b/AdventurePlayer.cs index 8bb5cdb3..a7a7d5f6 100644 --- a/AdventurePlayer.cs +++ b/AdventurePlayer.cs @@ -1561,8 +1561,6 @@ public override void PostHurt(Player.HurtInfo info) } Player.AddBuff(ModContent.BuffType(), duration); - Player.AddBuff(BuffID.ShadowFlame, duration); - } } public override void PostUpdateBuffs() @@ -1944,40 +1942,108 @@ public class HellhexPlayer : ModPlayer private int storedDamage = 0; public int hellhexApplierIndex = -1; // Track who applied the Hellhex debuff - public override bool PreKill(double damage, int hitDirection, bool pvp, ref bool playSound, ref bool genGore, ref PlayerDeathReason damageSource) + // Helper method to check if damage source is from summon/whip (for HurtInfo) + private bool IsSummonOrWhipDamage(Player.HurtInfo info) { - // If player has Hellhex when they die from non-summon damage, spawn explosion - if (Player.HasBuff()) + // Check projectile instance + if (info.DamageSource.SourceProjectileLocalIndex >= 0) { - bool isSummon = false; + Projectile proj = Main.projectile[info.DamageSource.SourceProjectileLocalIndex]; + if (proj != null && proj.active && (proj.minion || proj.sentry || proj.CountsAsClass(DamageClass.SummonMeleeSpeed))) + { + return true; + } + } - // Check if death is from summon/whip damage - if (damageSource.SourceProjectileLocalIndex >= 0) + // Check projectile type for whips + if (info.DamageSource.SourceProjectileType > 0) + { + int projType = info.DamageSource.SourceProjectileType; + if (projType == ProjectileID.BlandWhip || projType == ProjectileID.FireWhip || + projType == ProjectileID.SwordWhip || projType == ProjectileID.MaceWhip || + projType == ProjectileID.ScytheWhip || projType == ProjectileID.ThornWhip || + projType == ProjectileID.BoneWhip || projType == ProjectileID.RainbowWhip || + projType == ProjectileID.CoolWhip) { - Projectile proj = Main.projectile[damageSource.SourceProjectileLocalIndex]; - if (proj != null && proj.active && (proj.minion || proj.sentry || proj.CountsAsClass(DamageClass.SummonMeleeSpeed))) - { - isSummon = true; - } + return true; } - else if (damageSource.SourceProjectileType > 0) + } + + return false; + } + + // Helper method to check if damage source is from summon/whip (for HurtModifiers) + private bool IsSummonOrWhipDamage(ref Player.HurtModifiers modifiers) + { + // Check projectile instance + if (modifiers.DamageSource.SourceProjectileLocalIndex >= 0) + { + Projectile proj = Main.projectile[modifiers.DamageSource.SourceProjectileLocalIndex]; + if (proj != null && proj.active && (proj.minion || proj.sentry || proj.CountsAsClass(DamageClass.SummonMeleeSpeed))) { - int projType = damageSource.SourceProjectileType; - if (projType == ProjectileID.BlandWhip || projType == ProjectileID.FireWhip || - projType == ProjectileID.SwordWhip || projType == ProjectileID.MaceWhip || - projType == ProjectileID.ScytheWhip || projType == ProjectileID.ThornWhip || - projType == ProjectileID.BoneWhip || projType == ProjectileID.RainbowWhip || - projType == ProjectileID.CoolWhip) - { - isSummon = true; - } + return true; + } + } + + // Check projectile type for whips + if (modifiers.DamageSource.SourceProjectileType > 0) + { + int projType = modifiers.DamageSource.SourceProjectileType; + if (projType == ProjectileID.BlandWhip || projType == ProjectileID.FireWhip || + projType == ProjectileID.SwordWhip || projType == ProjectileID.MaceWhip || + projType == ProjectileID.ScytheWhip || projType == ProjectileID.ThornWhip || + projType == ProjectileID.BoneWhip || projType == ProjectileID.RainbowWhip || + projType == ProjectileID.CoolWhip) + { + return true; + } + } + + return false; + } + + // Helper method to check if death reason is from summon/whip (for PlayerDeathReason) + private bool IsSummonOrWhipDeath(PlayerDeathReason damageSource) + { + // Check projectile instance + if (damageSource.SourceProjectileLocalIndex >= 0) + { + Projectile proj = Main.projectile[damageSource.SourceProjectileLocalIndex]; + if (proj != null && proj.active && (proj.minion || proj.sentry || proj.CountsAsClass(DamageClass.SummonMeleeSpeed))) + { + return true; + } + } + + // Check projectile type for whips + if (damageSource.SourceProjectileType > 0) + { + int projType = damageSource.SourceProjectileType; + if (projType == ProjectileID.BlandWhip || projType == ProjectileID.FireWhip || + projType == ProjectileID.SwordWhip || projType == ProjectileID.MaceWhip || + projType == ProjectileID.ScytheWhip || projType == ProjectileID.ThornWhip || + projType == ProjectileID.BoneWhip || projType == ProjectileID.RainbowWhip || + projType == ProjectileID.CoolWhip) + { + return true; } + } + + return false; + } + + public override bool PreKill(double damage, int hitDirection, bool pvp, ref bool playSound, ref bool genGore, ref PlayerDeathReason damageSource) + { + // If player has Hellhex when they die from non-summon damage, spawn explosion + if (Player.HasBuff()) + { + bool isSummon = IsSummonOrWhipDeath(damageSource); - // Spawn explosion on death from non-summon damage (if damage >= 60) if (!isSummon && Main.myPlayer == Player.whoAmI && damage >= 60) { float scale = (float)damage / 100f; // Scale based on damage - int owner = hellhexApplierIndex >= 0 ? hellhexApplierIndex : Player.whoAmI; + // Use stored applier index, fallback to -1 (no owner) if not set + int owner = hellhexApplierIndex >= 0 && hellhexApplierIndex < Main.maxPlayers ? hellhexApplierIndex : -1; int proj = Projectile.NewProjectile( Player.GetSource_Death(), @@ -1986,9 +2052,9 @@ public override bool PreKill(double damage, int hitDirection, bool pvp, ref bool ProjectileID.FireWhipProj, (int)damage, 0f, - owner, // Owned by the attacker who applied Hellhex + owner, 0f, - scale // ai[1] for scale + scale ); if (proj >= 0 && proj < Main.maxProjectiles) @@ -1998,11 +2064,12 @@ public override bool PreKill(double damage, int hitDirection, bool pvp, ref bool } } - return true; // Allow death + return true; } public override void PostHurt(Player.HurtInfo info) { + // Apply Hellhex when hit by FireWhip if (info.DamageSource.SourceProjectileType == ProjectileID.FireWhip) { int duration = 420; @@ -2018,42 +2085,20 @@ public override void PostHurt(Player.HurtInfo info) duration = (int)(duration * 2.5f); } - // Store who applied the debuff hellhexApplierIndex = info.DamageSource.SourcePlayerIndex; } } Player.AddBuff(ModContent.BuffType(), duration); - // Don't process the removal logic on the same hit that applies it return; } + // Only check for removal if player already has Hellhex if (Player.HasBuff()) { - bool isSummon = false; - - if (info.DamageSource.SourceProjectileLocalIndex >= 0) - { - Projectile proj = Main.projectile[info.DamageSource.SourceProjectileLocalIndex]; - if (proj != null && proj.active && (proj.minion || proj.sentry || proj.CountsAsClass(DamageClass.SummonMeleeSpeed))) - { - isSummon = true; - } - } - else if (info.DamageSource.SourceProjectileType > 0) - { - int projType = info.DamageSource.SourceProjectileType; - if (projType == ProjectileID.BlandWhip || projType == ProjectileID.FireWhip || - projType == ProjectileID.SwordWhip || projType == ProjectileID.MaceWhip || - projType == ProjectileID.ScytheWhip || projType == ProjectileID.ThornWhip || - projType == ProjectileID.BoneWhip || projType == ProjectileID.RainbowWhip || - projType == ProjectileID.CoolWhip) - { - isSummon = true; - } - } + bool isSummon = IsSummonOrWhipDamage(info); - // Only trigger if damage >= 60 and not summon damage + // Only trigger if damage >= 60 and not summon/whip damage if (!isSummon && info.Damage >= 60) { int buffIndex = Player.FindBuffIndex(ModContent.BuffType()); @@ -2062,12 +2107,12 @@ public override void PostHurt(Player.HurtInfo info) Player.buffTime[buffIndex] = 0; } - // Spawn on server or singleplayer for proper syncing if (Main.netMode != NetmodeID.MultiplayerClient) { Vector2 spawnPos = Player.Center; float scale = info.Damage / 100f; // Scale based on damage - int owner = hellhexApplierIndex >= 0 ? hellhexApplierIndex : Player.whoAmI; + // Use stored applier index, fallback to -1 (no owner) if not set + int owner = hellhexApplierIndex >= 0 && hellhexApplierIndex < Main.maxPlayers ? hellhexApplierIndex : -1; int proj = Projectile.NewProjectile( Player.GetSource_Buff(buffIndex), @@ -2083,7 +2128,6 @@ public override void PostHurt(Player.HurtInfo info) { Main.projectile[proj].scale = scale; - // Sync the projectile to all clients if (Main.netMode == NetmodeID.Server) { NetMessage.SendData(MessageID.SyncProjectile, -1, -1, null, proj); @@ -2098,29 +2142,9 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) { if (Player.HasBuff()) { - bool isSummon = false; - - if (modifiers.DamageSource.SourceProjectileLocalIndex >= 0) - { - Projectile proj = Main.projectile[modifiers.DamageSource.SourceProjectileLocalIndex]; - if (proj != null && proj.active && (proj.minion || proj.sentry || proj.CountsAsClass(DamageClass.SummonMeleeSpeed))) - { - isSummon = true; - } - } - else if (modifiers.DamageSource.SourceProjectileType > 0) - { - int projType = modifiers.DamageSource.SourceProjectileType; - if (projType == ProjectileID.BlandWhip || projType == ProjectileID.FireWhip || - projType == ProjectileID.SwordWhip || projType == ProjectileID.MaceWhip || - projType == ProjectileID.ScytheWhip || projType == ProjectileID.ThornWhip || - projType == ProjectileID.BoneWhip || projType == ProjectileID.RainbowWhip || - projType == ProjectileID.CoolWhip) - { - isSummon = true; - } - } + bool isSummon = IsSummonOrWhipDamage(ref modifiers); + // Only apply multiplier if NOT summon/whip damage if (!isSummon) { // Always apply damage multiplier From 812d271631f75d7c535dc1d68a27a1ec4dfd8ff9 Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Mon, 3 Nov 2025 14:45:42 -0800 Subject: [PATCH 143/206] oh yeah --- AdventurePlayer.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/AdventurePlayer.cs b/AdventurePlayer.cs index a7a7d5f6..5bf6ef73 100644 --- a/AdventurePlayer.cs +++ b/AdventurePlayer.cs @@ -1559,7 +1559,6 @@ public override void PostHurt(Player.HurtInfo info) } } } - Player.AddBuff(ModContent.BuffType(), duration); } } From 5df4ea7cfad7a457a9a6222ffeca539b84da5575 Mon Sep 17 00:00:00 2001 From: resin Date: Mon, 3 Nov 2025 18:16:22 -0500 Subject: [PATCH 144/206] AdventureItem: Add per-team item drop pickups --- AdventureItem.cs | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/AdventureItem.cs b/AdventureItem.cs index aeb57c7c..3bd48747 100644 --- a/AdventureItem.cs +++ b/AdventureItem.cs @@ -1,7 +1,9 @@ using System.Collections.Generic; +using System.IO; using System.Linq; using Microsoft.Xna.Framework; using Terraria; +using Terraria.Enums; using Terraria.ID; using Terraria.Localization; using Terraria.ModLoader; @@ -12,6 +14,9 @@ namespace PvPAdventure; public class AdventureItem : GlobalItem { + public override bool InstancePerEntity => true; + public Team? _team; + public static readonly bool[] RecallItems = ItemID.Sets.Factory.CreateBoolSet(ItemID.MagicMirror, ItemID.CellPhone, ItemID.IceMirror, ItemID.Shellphone, ItemID.ShellphoneSpawn); @@ -172,6 +177,39 @@ public override void ModifyTooltips(Item item, List tooltips) } } + public override void NetSend(Item item, BinaryWriter writer) + { + var adventureItem = item.GetGlobalItem(); + var has = adventureItem._team != null; + + writer.Write(has); + + if (has) + writer.Write7BitEncodedInt((int)adventureItem._team); + } + + public override void NetReceive(Item item, BinaryReader reader) + { + var has = reader.ReadBoolean(); + var adventureItem = item.GetGlobalItem(); + + adventureItem._team = has ? (Team)reader.Read7BitEncodedInt() : null; + } + + public override bool CanPickup(Item item, Player player) + { + var team = item.GetGlobalItem()._team; + + return team == null || team == (Team)player.team; + } + + public override bool OnPickup(Item item, Player player) + { + item.GetGlobalItem()._team = null; + + return true; + } + public override bool? PrefixChance(Item item, int pre, UnifiedRandom rand) { // Prevent the item from spawning with a prefix, being placed into a reforge window, and loading with a prefix. From b971ef6300dacb9829036062cd7844809fadbad5 Mon Sep 17 00:00:00 2001 From: resin Date: Mon, 3 Nov 2025 18:17:47 -0500 Subject: [PATCH 145/206] AdventureDropDatabase: Make boss drops per-team instead of per-player --- AdventureDropDatabase.cs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/AdventureDropDatabase.cs b/AdventureDropDatabase.cs index e8d04cee..11655c39 100644 --- a/AdventureDropDatabase.cs +++ b/AdventureDropDatabase.cs @@ -1,5 +1,6 @@ using System.Linq; using Terraria; +using Terraria.Enums; using Terraria.GameContent.ItemDropRules; using Terraria.ID; using Terraria.ModLoader; @@ -30,10 +31,14 @@ public override void Load() { var number = Item.NewItem(npc.GetSource_Loot(), npc.Hitbox, id, stack, true, -1); - // FIXME: magic time unit - Main.timeItemSlotCannotBeReusedFor[number] = 54000; - NetMessage.SendData(MessageID.InstancedItem, remoteClient: npc.lastInteraction, number: number); - Main.item[number].active = false; + // FIXME: Not consistent with how the rest of the codebase determines the last hit. + if (npc.lastInteraction != 255) + { + var player = Main.player[npc.lastInteraction]; + Main.item[number].GetGlobalItem()._team = (Team)player.team; + } + + NetMessage.SendData(MessageID.SyncItem, number: number); } else { From c59bbf18f1bd120fac0b221724163ba0203529c2 Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Tue, 4 Nov 2025 20:20:55 -0800 Subject: [PATCH 146/206] firecracker now actually does 7.5 seconds firecracker reworked what a noob all whip debuffs go away upon the attacker's death --- AdventureItem.cs | 12 +- AdventurePlayer.cs | 287 +++++++++++++++++++++++++++++++++------ Localization/en-US.hjson | 96 ++++++++++--- 3 files changed, 332 insertions(+), 63 deletions(-) diff --git a/AdventureItem.cs b/AdventureItem.cs index c913cdbc..6ddf628d 100644 --- a/AdventureItem.cs +++ b/AdventureItem.cs @@ -324,7 +324,15 @@ public override void ModifyTooltips(Item item, List tooltips) TooltipLine setBonusLine = tooltips.FirstOrDefault(x => x.Name == "SetBonus" && x.Mod == "Terraria"); if (setBonusLine != null) { - setBonusLine.Text = "Set bonus:\nIncreases your max number of minions\nIncreases whip range by 20%\nIncreases whip debuff duration against players by 150%"; + setBonusLine.Text = "Set bonus:\nIncreases your max number of minions\nIncreases whip range by 20%\nIncreases whip debuff duration against players by 150%\nPrevents whip range penalty"; + } + } + if (item.type == ItemID.ObsidianHelm || item.type == ItemID.ObsidianShirt || item.type == ItemID.ObsidianPants) + { + TooltipLine setBonusLine = tooltips.FirstOrDefault(x => x.Name == "SetBonus" && x.Mod == "Terraria"); + if (setBonusLine != null) + { + setBonusLine.Text = "Set bonus:\n\tIncreases whip range by 30% and speed by 15%\nIncreases summon damage by 15%\nPrevents whip range penalty"; } } if (item.type == ItemID.BlandWhip || item.type == ItemID.ThornWhip || @@ -333,7 +341,7 @@ public override void ModifyTooltips(Item item, List tooltips) item.type == ItemID.ScytheWhip || item.type == ItemID.MaceWhip || item.type == ItemID.RainbowWhip) { - tooltips.Add(new TooltipLine(Mod, "WhipRangeWarning", "Range greatly reduced without Pygmy Necklace or Hercules Beetle") + tooltips.Add(new TooltipLine(Mod, "WhipRangeWarning", "Range greatly reduced without Pygmy Necklace, Hercules Beetle, or certain Set Bonuses") { OverrideColor = new Color(255, 100, 100) }); diff --git a/AdventurePlayer.cs b/AdventurePlayer.cs index 5bf6ef73..c74d26aa 100644 --- a/AdventurePlayer.cs +++ b/AdventurePlayer.cs @@ -1175,7 +1175,7 @@ public override void PostUpdateEquips() for (int i = 3; i < 8 + Player.GetAmountOfExtraAccessorySlotsToShow(); i++) { - if (Player.armor[i].type == ItemID.PygmyNecklace || Player.armor[i].type == ItemID.HerculesBeetle) + if (Player.armor[i].type == ItemID.PygmyNecklace || Player.armor[i].type == ItemID.HerculesBeetle || (Player.armor[0].type == ItemID.TikiMask && Player.armor[1].type == ItemID.TikiShirt &&Player.armor[2].type == ItemID.TikiPants) || (Player.armor[0].type == ItemID.ObsidianHelm && Player.armor[1].type == ItemID.ObsidianShirt && Player.armor[2].type == ItemID.ObsidianPants)) { largeWhipIncrease = true; break; @@ -1327,13 +1327,20 @@ public override void PostUpdateEquips() } } } +// Add this to each ModPlayer class that handles a debuff + +// For BitingEmbracePlayer: public class BitingEmbracePlayer : ModPlayer { + public int bitingEmbraceApplierIndex = -1; // Track who applied the debuff + public override void PostHurt(Player.HurtInfo info) { if (info.DamageSource.SourceProjectileType == ProjectileID.CoolWhip) { int duration = 300; + int applierIndex = -1; + if (info.DamageSource.SourcePlayerIndex >= 0 && info.DamageSource.SourcePlayerIndex < Main.maxPlayers) { Player attacker = Main.player[info.DamageSource.SourcePlayerIndex]; @@ -1344,15 +1351,35 @@ public override void PostHurt(Player.HurtInfo info) { duration = (int)(duration * 2.5f); } + applierIndex = info.DamageSource.SourcePlayerIndex; } } + + bitingEmbraceApplierIndex = applierIndex; Player.AddBuff(ModContent.BuffType(), duration); Player.AddBuff(BuffID.Frostburn2, duration); - } } + public override void PostUpdateBuffs() { + // Check if applier died - remove buff if so + if (Player.HasBuff() && bitingEmbraceApplierIndex >= 0 && bitingEmbraceApplierIndex < Main.maxPlayers) + { + Player applier = Main.player[bitingEmbraceApplierIndex]; + if (applier == null || !applier.active || applier.dead) + { + int buffIndex = Player.FindBuffIndex(ModContent.BuffType()); + if (buffIndex >= 0) + { + Player.buffTime[buffIndex] = 0; + } + Player.ClearBuff(BuffID.Frostburn2); + bitingEmbraceApplierIndex = -1; + return; + } + } + if (Player.HasBuff()) { float pulseTime = Main.GameUpdateCount % 60f / 60f; @@ -1394,6 +1421,10 @@ public override void PostUpdateBuffs() } } } + else + { + bitingEmbraceApplierIndex = -1; // Reset when buff expires + } } public override void ModifyHurt(ref Player.HurtModifiers modifiers) @@ -1431,13 +1462,17 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) } } +// For PressurePointsPlayer: public class PressurePointsPlayer : ModPlayer { + public int pressurePointsApplierIndex = -1; + public override void PostHurt(Player.HurtInfo info) { if (info.DamageSource.SourceProjectileType == ProjectileID.ThornWhip) { int duration = 300; + int applierIndex = -1; if (info.DamageSource.SourcePlayerIndex >= 0 && info.DamageSource.SourcePlayerIndex < Main.maxPlayers) { @@ -1449,16 +1484,33 @@ public override void PostHurt(Player.HurtInfo info) { duration = (int)(duration * 2.5f); } + applierIndex = info.DamageSource.SourcePlayerIndex; } } + pressurePointsApplierIndex = applierIndex; Player.AddBuff(ModContent.BuffType(), duration); - } } public override void PostUpdateBuffs() { + // Check if applier died - remove buff if so + if (Player.HasBuff() && pressurePointsApplierIndex >= 0 && pressurePointsApplierIndex < Main.maxPlayers) + { + Player applier = Main.player[pressurePointsApplierIndex]; + if (applier == null || !applier.active || applier.dead) + { + int buffIndex = Player.FindBuffIndex(ModContent.BuffType()); + if (buffIndex >= 0) + { + Player.buffTime[buffIndex] = 0; + } + pressurePointsApplierIndex = -1; + return; + } + } + if (Player.HasBuff()) { float pulseTime = Main.GameUpdateCount % 60f / 60f; @@ -1500,6 +1552,10 @@ public override void PostUpdateBuffs() } } } + else + { + pressurePointsApplierIndex = -1; + } } public override void ModifyHurt(ref Player.HurtModifiers modifiers) @@ -1539,13 +1595,17 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) } } +// For BrittleBonesPlayer: public class BrittleBonesPlayer : ModPlayer { + public int brittleBonesApplierIndex = -1; + public override void PostHurt(Player.HurtInfo info) { if (info.DamageSource.SourceProjectileType == ProjectileID.BoneWhip) { int duration = 300; + int applierIndex = -1; if (info.DamageSource.SourcePlayerIndex >= 0 && info.DamageSource.SourcePlayerIndex < Main.maxPlayers) { @@ -1557,13 +1617,33 @@ public override void PostHurt(Player.HurtInfo info) { duration = (int)(duration * 2.5f); } + applierIndex = info.DamageSource.SourcePlayerIndex; } } + + brittleBonesApplierIndex = applierIndex; Player.AddBuff(ModContent.BuffType(), duration); } } + public override void PostUpdateBuffs() { + // Check if applier died - remove buff if so + if (Player.HasBuff() && brittleBonesApplierIndex >= 0 && brittleBonesApplierIndex < Main.maxPlayers) + { + Player applier = Main.player[brittleBonesApplierIndex]; + if (applier == null || !applier.active || applier.dead) + { + int buffIndex = Player.FindBuffIndex(ModContent.BuffType()); + if (buffIndex >= 0) + { + Player.buffTime[buffIndex] = 0; + } + brittleBonesApplierIndex = -1; + return; + } + } + if (Player.HasBuff()) { float pulseTime = Main.GameUpdateCount % 60f / 60f; @@ -1605,7 +1685,12 @@ public override void PostUpdateBuffs() } } } + else + { + brittleBonesApplierIndex = -1; + } } + public override void ModifyHurt(ref Player.HurtModifiers modifiers) { if (Player.HasBuff()) @@ -1642,13 +1727,18 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) } } } + +// For MarkedPlayer: public class MarkedPlayer : ModPlayer { + public int markedApplierIndex = -1; + public override void PostHurt(Player.HurtInfo info) { if (info.DamageSource.SourceProjectileType == ProjectileID.SwordWhip) { int duration = 300; + int applierIndex = -1; if (info.DamageSource.SourcePlayerIndex >= 0 && info.DamageSource.SourcePlayerIndex < Main.maxPlayers) { @@ -1660,16 +1750,33 @@ public override void PostHurt(Player.HurtInfo info) { duration = (int)(duration * 2.5f); } + applierIndex = info.DamageSource.SourcePlayerIndex; } } + markedApplierIndex = applierIndex; Player.AddBuff(ModContent.BuffType(), duration); - } } public override void PostUpdateBuffs() { + // Check if applier died - remove buff if so + if (Player.HasBuff() && markedApplierIndex >= 0 && markedApplierIndex < Main.maxPlayers) + { + Player applier = Main.player[markedApplierIndex]; + if (applier == null || !applier.active || applier.dead) + { + int buffIndex = Player.FindBuffIndex(ModContent.BuffType()); + if (buffIndex >= 0) + { + Player.buffTime[buffIndex] = 0; + } + markedApplierIndex = -1; + return; + } + } + if (Player.HasBuff()) { float pulseTime = Main.GameUpdateCount % 60f / 60f; @@ -1711,6 +1818,10 @@ public override void PostUpdateBuffs() } } } + else + { + markedApplierIndex = -1; + } } public override void ModifyHurt(ref Player.HurtModifiers modifiers) @@ -1749,13 +1860,18 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) } } } + +// For AnathemaPlayer: public class AnathemaPlayer : ModPlayer -{ //ts is all temporary +{ + public int anathemaApplierIndex = -1; + public override void PostHurt(Player.HurtInfo info) { if (info.DamageSource.SourceProjectileType == ProjectileID.RainbowWhip) { int duration = 300; + int applierIndex = -1; if (info.DamageSource.SourcePlayerIndex >= 0 && info.DamageSource.SourcePlayerIndex < Main.maxPlayers) { @@ -1767,15 +1883,33 @@ public override void PostHurt(Player.HurtInfo info) { duration = (int)(duration * 2.5f); } + applierIndex = info.DamageSource.SourcePlayerIndex; } } + anathemaApplierIndex = applierIndex; Player.AddBuff(ModContent.BuffType(), duration); - } } + public override void PostUpdateBuffs() { + // Check if applier died - remove buff if so + if (Player.HasBuff() && anathemaApplierIndex >= 0 && anathemaApplierIndex < Main.maxPlayers) + { + Player applier = Main.player[anathemaApplierIndex]; + if (applier == null || !applier.active || applier.dead) + { + int buffIndex = Player.FindBuffIndex(ModContent.BuffType()); + if (buffIndex >= 0) + { + Player.buffTime[buffIndex] = 0; + } + anathemaApplierIndex = -1; + return; + } + } + if (Player.HasBuff()) { for (int i = 0; i < 3; i++) @@ -1798,13 +1932,11 @@ public override void PostUpdateBuffs() if (Main.rand.NextBool()) { - // Light particles dustType = DustID.PlatinumCoin; dustColor = Color.White; } else { - // Dark particles dustType = DustID.Smoke; dustColor = Color.Black; } @@ -1814,7 +1946,12 @@ public override void PostUpdateBuffs() dust.fadeIn = 0.8f; } } + else + { + anathemaApplierIndex = -1; + } } + public override void ModifyHurt(ref Player.HurtModifiers modifiers) { if (Player.HasBuff()) @@ -1848,19 +1985,22 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) info.Damage += 20; }; modifiers.FinalDamage *= 1.1f; - } } } } + +// For ShatteredArmorPlayer: public class ShatteredArmorPlayer : ModPlayer { + public int shatteredArmorApplierIndex = -1; + public override void PostHurt(Player.HurtInfo info) { - // Check if hit by MaceWhip projectile if (info.DamageSource.SourceProjectileType == ProjectileID.MaceWhip) { int duration = 300; + int applierIndex = -1; if (info.DamageSource.SourcePlayerIndex >= 0 && info.DamageSource.SourcePlayerIndex < Main.maxPlayers) { @@ -1872,15 +2012,33 @@ public override void PostHurt(Player.HurtInfo info) { duration = (int)(duration * 2.5f); } + applierIndex = info.DamageSource.SourcePlayerIndex; } } + shatteredArmorApplierIndex = applierIndex; Player.AddBuff(ModContent.BuffType(), duration); } } public override void PostUpdateBuffs() { + // Check if applier died - remove buff if so + if (Player.HasBuff() && shatteredArmorApplierIndex >= 0 && shatteredArmorApplierIndex < Main.maxPlayers) + { + Player applier = Main.player[shatteredArmorApplierIndex]; + if (applier == null || !applier.active || applier.dead) + { + int buffIndex = Player.FindBuffIndex(ModContent.BuffType()); + if (buffIndex >= 0) + { + Player.buffTime[buffIndex] = 0; + } + shatteredArmorApplierIndex = -1; + return; + } + } + if (Player.HasBuff()) { for (int i = 0; i < 1; i++) @@ -1894,6 +2052,10 @@ public override void PostUpdateBuffs() dust.fadeIn = 1.2f; } } + else + { + shatteredArmorApplierIndex = -1; + } } public override void ModifyHurt(ref Player.HurtModifiers modifiers) @@ -1929,12 +2091,10 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) info.Damage += 8; }; modifiers.FinalDamage *= 1.12f; - } } } } - public class HellhexPlayer : ModPlayer { public bool hellhexTriggered = false; @@ -2038,27 +2198,37 @@ public override bool PreKill(double damage, int hitDirection, bool pvp, ref bool { bool isSummon = IsSummonOrWhipDeath(damageSource); - if (!isSummon && Main.myPlayer == Player.whoAmI && damage >= 60) - { - float scale = (float)damage / 100f; // Scale based on damage - // Use stored applier index, fallback to -1 (no owner) if not set - int owner = hellhexApplierIndex >= 0 && hellhexApplierIndex < Main.maxPlayers ? hellhexApplierIndex : -1; - - int proj = Projectile.NewProjectile( - Player.GetSource_Death(), - Player.Center, - Vector2.Zero, - ProjectileID.FireWhipProj, - (int)damage, - 0f, - owner, - 0f, - scale - ); - - if (proj >= 0 && proj < Main.maxProjectiles) + if (!isSummon && damage >= 30) + { + // Only spawn on server or singleplayer + if (Main.netMode != NetmodeID.MultiplayerClient) { - Main.projectile[proj].scale = scale; + float scale = (float)damage / 100f; + int owner = hellhexApplierIndex >= 0 && hellhexApplierIndex < Main.maxPlayers ? hellhexApplierIndex : -1; + int explosionDamage = (int)(damage * 2.75f); + + int proj = Projectile.NewProjectile( + Player.GetSource_Death(), + Player.Center, + Vector2.Zero, + ProjectileID.FireWhipProj, + explosionDamage, + 0f, + owner, + 0f, + scale + ); + + if (proj >= 0 && proj < Main.maxProjectiles) + { + Main.projectile[proj].scale = scale; + + // Sync projectile to all clients + if (Main.netMode == NetmodeID.Server) + { + NetMessage.SendData(MessageID.SyncProjectile, -1, -1, null, proj); + } + } } } } @@ -2071,7 +2241,8 @@ public override void PostHurt(Player.HurtInfo info) // Apply Hellhex when hit by FireWhip if (info.DamageSource.SourceProjectileType == ProjectileID.FireWhip) { - int duration = 420; + int duration = 450; + int applierIndex = -1; if (info.DamageSource.SourcePlayerIndex >= 0 && info.DamageSource.SourcePlayerIndex < Main.maxPlayers) { @@ -2084,11 +2255,23 @@ public override void PostHurt(Player.HurtInfo info) duration = (int)(duration * 2.5f); } - hellhexApplierIndex = info.DamageSource.SourcePlayerIndex; + applierIndex = info.DamageSource.SourcePlayerIndex; } } + hellhexApplierIndex = applierIndex; Player.AddBuff(ModContent.BuffType(), duration); + + // Sync the applier index to all clients + if (Main.netMode == NetmodeID.Server) + { + ModPacket packet = Mod.GetPacket(); + packet.Write((byte)0); // Message type for Hellhex application + packet.Write((byte)Player.whoAmI); + packet.Write((byte)applierIndex); + packet.Send(); + } + return; } @@ -2097,8 +2280,8 @@ public override void PostHurt(Player.HurtInfo info) { bool isSummon = IsSummonOrWhipDamage(info); - // Only trigger if damage >= 60 and not summon/whip damage - if (!isSummon && info.Damage >= 60) + // Only trigger if damage >= 30 and not summon/whip damage + if (!isSummon && info.Damage >= 30) { int buffIndex = Player.FindBuffIndex(ModContent.BuffType()); if (buffIndex >= 0) @@ -2106,27 +2289,29 @@ public override void PostHurt(Player.HurtInfo info) Player.buffTime[buffIndex] = 0; } + // Only spawn on server or singleplayer if (Main.netMode != NetmodeID.MultiplayerClient) { Vector2 spawnPos = Player.Center; - float scale = info.Damage / 100f; // Scale based on damage - // Use stored applier index, fallback to -1 (no owner) if not set + float scale = info.Damage / 100f; int owner = hellhexApplierIndex >= 0 && hellhexApplierIndex < Main.maxPlayers ? hellhexApplierIndex : -1; + int explosionDamage = (int)(info.Damage * 2.75f); int proj = Projectile.NewProjectile( Player.GetSource_Buff(buffIndex), spawnPos, Vector2.Zero, ProjectileID.FireWhipProj, - info.Damage, + explosionDamage, 0f, - owner // Owned by the attacker who applied Hellhex + owner ); if (proj >= 0 && proj < Main.maxProjectiles) { Main.projectile[proj].scale = scale; + // Sync projectile to all clients if (Main.netMode == NetmodeID.Server) { NetMessage.SendData(MessageID.SyncProjectile, -1, -1, null, proj); @@ -2143,12 +2328,9 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) { bool isSummon = IsSummonOrWhipDamage(ref modifiers); - // Only apply multiplier if NOT summon/whip damage + // Track that Hellhex triggered for UI/effects purposes if (!isSummon) { - // Always apply damage multiplier - modifiers.FinalDamage *= 2.75f; - modifiers.ModifyHurtInfo += (ref Player.HurtInfo info) => { storedDamage = info.Damage; hellhexTriggered = true; @@ -2159,6 +2341,22 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) public override void PostUpdateBuffs() { + if (Player.HasBuff() && hellhexApplierIndex >= 0 && hellhexApplierIndex < Main.maxPlayers) + { + Player applier = Main.player[hellhexApplierIndex]; + if (applier == null || !applier.active || applier.dead) + { + int buffIndex = Player.FindBuffIndex(ModContent.BuffType()); + if (buffIndex >= 0) + { + Player.buffTime[buffIndex] = 0; + } + hellhexApplierIndex = -1; + hellhexTriggered = false; + return; + } + } + if (Player.HasBuff()) { for (int i = 0; i < 2; i++) @@ -2189,7 +2387,6 @@ public override void PostUpdateBuffs() } } } - public class PvPAdventurePlayer : ModPlayer { public bool hasReceivedStarterBag = false; diff --git a/Localization/en-US.hjson b/Localization/en-US.hjson index 1195f963..11771a76 100644 --- a/Localization/en-US.hjson +++ b/Localization/en-US.hjson @@ -246,9 +246,21 @@ Mods: { WorldProgressionState: { Tooltip: "" - Any.Label: Any - PreHardmode.Label: Pre Hardmode - Hardmode.Label: Hardmode + + Any: { + Label: Any + Tooltip: "" + } + + PreHardmode: { + Label: Pre Hardmode + Tooltip: "" + } + + Hardmode: { + Label: Hardmode + Tooltip: "" + } } ConfigItem: { @@ -591,23 +603,75 @@ Mods: { } Killsound: { - Part2.Label: Part2 - FatalCarCrash.Label: Fatal Car Crash - Shronker.Label: Shronker - Sharkron.Label: Sharkron - Ronaldoz.Label: Ronaldoz - Zacharry.Label: Zacharry + Part2: { + Label: Part2 + Tooltip: "" + } + + FatalCarCrash: { + Label: Fatal Car Crash + Tooltip: "" + } + + Shronker: { + Label: Shronker + Tooltip: "" + } + + Sharkron: { + Label: Sharkron + Tooltip: "" + } + + Ronaldoz: { + Label: Ronaldoz + Tooltip: "" + } + + Zacharry: { + Label: Zacharry + Tooltip: "" + } + Tooltip: "" } Hitsound: { - Part1.Label: Part1 - MarrowMurder.Label: Marrow Murder - Squelchy.Label: Squelchy - Crash.Label: Crash - Blip.Label: Blip - Buwee.Label: BuWEEEEE - OlBetsy.Label: Ol' Betsy + Part1: { + Label: Part1 + Tooltip: "" + } + + MarrowMurder: { + Label: Marrow Murder + Tooltip: "" + } + + Squelchy: { + Label: Squelchy + Tooltip: "" + } + + Crash: { + Label: Crash + Tooltip: "" + } + + Blip: { + Label: Blip + Tooltip: "" + } + + Buwee: { + Label: BuWEEEEE + Tooltip: "" + } + + OlBetsy: { + Label: Ol' Betsy + Tooltip: "" + } + Tooltip: "" } From c4427f43f73dc8806624156383c7dc88d1dc4c9e Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Tue, 4 Nov 2025 21:11:44 -0800 Subject: [PATCH 147/206] TNE now is vanilla crafting recipe --- System/RecipeManager.cs | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/System/RecipeManager.cs b/System/RecipeManager.cs index df2a633a..8eaa28e9 100644 --- a/System/RecipeManager.cs +++ b/System/RecipeManager.cs @@ -22,7 +22,6 @@ public override void AddRecipes() int[] itemsToRemove = new int[] { - ItemID.TrueNightsEdge, ItemID.MoonlordArrow, ItemID.ShroomiteBar, ItemID.WormFood, @@ -86,16 +85,16 @@ public override void AddRecipes() .AddTile(TileID.MythrilAnvil) .Register(); - //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(); + //temp sudo terrablade (no longer used) + //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(); } From c5bdebf130f725ab2384da6147ef8161c22e0d11 Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Thu, 6 Nov 2025 20:16:34 -0800 Subject: [PATCH 148/206] mobsy is a sneaky fibber --- AdventureDropDatabase.cs | 19 ++++++++++- AdventureNpc.cs | 32 +++++++++++++++++++ AdventurePlayer.cs | 69 +++++++++++++++++++++++++++++++--------- Dogshit.cs | 40 +++++++++++++---------- 4 files changed, 127 insertions(+), 33 deletions(-) diff --git a/AdventureDropDatabase.cs b/AdventureDropDatabase.cs index d28f8744..b0b3b4b1 100644 --- a/AdventureDropDatabase.cs +++ b/AdventureDropDatabase.cs @@ -96,13 +96,27 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) case NPCID.MossHornet: foreach (var drop in drops) + { ModifyDropRate(drop, ItemID.Stinger, 1, 1); + ModifyDropRate(drop, ItemID.TatteredBeeWing, 1, 33); + } break; - case NPCID.GiantTortoise: foreach (var drop in drops) ModifyDropRate(drop, ItemID.TurtleShell, 1, 3); break; + case NPCID.Psycho: + foreach (var drop in drops) + ModifyDropRate(drop, ItemID.PsychoKnife, 1, 4); + break; + case NPCID.Harpy: + foreach (var drop in drops) + ModifyDropRate(drop, ItemID.GiantHarpyFeather, 1, 75); + break; + case NPCID.IceGolem: + foreach (var drop in drops) + ModifyDropRate(drop, ItemID.IceFeather, 1, 1); + break; case NPCID.Necromancer: case NPCID.NecromancerArmored: @@ -156,7 +170,10 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) case NPCID.HellArmoredBonesMace: case NPCID.HellArmoredBonesSword: foreach (var drop in drops) + { ModifyDropRate(drop, ItemID.MaceWhip, 1, 10); + ModifyDropRate(drop, ItemID.BoneFeather, 1, 150); + } break; case NPCID.BlackRecluse: diff --git a/AdventureNpc.cs b/AdventureNpc.cs index 5aea5cc4..50b15104 100644 --- a/AdventureNpc.cs +++ b/AdventureNpc.cs @@ -754,4 +754,36 @@ public override void PostAI(NPC npc) } } } + public class DemonReplacement : GlobalNPC + { + public override void OnSpawn(NPC npc, IEntitySource source) + { + bool anyMechBossDefeated = NPC.downedMechBoss1 || NPC.downedMechBoss2 || NPC.downedMechBoss3; + + if (anyMechBossDefeated && npc.type == NPCID.Demon) + { + Vector2 position = npc.position; + Vector2 velocity = npc.velocity; + int target = npc.target; + int direction = npc.direction; + int spriteDirection = npc.spriteDirection; + float rotation = npc.rotation; + + npc.SetDefaults(NPCID.VoodooDemon); + + // Restore the state + npc.position = position; + npc.velocity = velocity; + npc.target = target; + npc.direction = direction; + npc.spriteDirection = spriteDirection; + npc.rotation = rotation; + + if (Main.netMode == NetmodeID.Server) + { + NetMessage.SendData(MessageID.SyncNPC, -1, -1, null, npc.whoAmI); + } + } + } + } } \ No newline at end of file diff --git a/AdventurePlayer.cs b/AdventurePlayer.cs index c74d26aa..1a796f97 100644 --- a/AdventurePlayer.cs +++ b/AdventurePlayer.cs @@ -2100,6 +2100,7 @@ public class HellhexPlayer : ModPlayer public bool hellhexTriggered = false; private int storedDamage = 0; public int hellhexApplierIndex = -1; // Track who applied the Hellhex debuff + private bool explosionSpawned = false; // Prevent duplicate explosions // Helper method to check if damage source is from summon/whip (for HurtInfo) private bool IsSummonOrWhipDamage(Player.HurtInfo info) @@ -2275,28 +2276,34 @@ public override void PostHurt(Player.HurtInfo info) return; } - // Only check for removal if player already has Hellhex - if (Player.HasBuff()) + // Only check for removal if player already has Hellhex and explosion hasn't spawned yet + if (Player.HasBuff() && !explosionSpawned) { bool isSummon = IsSummonOrWhipDamage(info); // Only trigger if damage >= 30 and not summon/whip damage if (!isSummon && info.Damage >= 30) { + explosionSpawned = true; // Mark that explosion is being spawned + + // Remove the buff immediately on all sides int buffIndex = Player.FindBuffIndex(ModContent.BuffType()); if (buffIndex >= 0) { Player.buffTime[buffIndex] = 0; } - // Only spawn on server or singleplayer - if (Main.netMode != NetmodeID.MultiplayerClient) - { - Vector2 spawnPos = Player.Center; - float scale = info.Damage / 100f; - int owner = hellhexApplierIndex >= 0 && hellhexApplierIndex < Main.maxPlayers ? hellhexApplierIndex : -1; - int explosionDamage = (int)(info.Damage * 2.75f); + // Calculate explosion parameters + Vector2 spawnPos = Player.Center; + float scale = info.Damage / 100f; + int owner = hellhexApplierIndex >= 0 && hellhexApplierIndex < Main.maxPlayers ? hellhexApplierIndex : -1; + int explosionDamage = (int)(info.Damage * 2.75f); + // On attacker's client or server: spawn the explosion immediately + if (Main.netMode == NetmodeID.SinglePlayer || + (info.DamageSource.SourcePlayerIndex >= 0 && Main.myPlayer == info.DamageSource.SourcePlayerIndex)) + { + // Attacker's client - spawn locally int proj = Projectile.NewProjectile( Player.GetSource_Buff(buffIndex), spawnPos, @@ -2310,14 +2317,43 @@ public override void PostHurt(Player.HurtInfo info) if (proj >= 0 && proj < Main.maxProjectiles) { Main.projectile[proj].scale = scale; + } - // Sync projectile to all clients - if (Main.netMode == NetmodeID.Server) - { - NetMessage.SendData(MessageID.SyncProjectile, -1, -1, null, proj); - } + // If this is multiplayer, send a packet to server to spawn for everyone else + if (Main.netMode == NetmodeID.MultiplayerClient) + { + ModPacket packet = Mod.GetPacket(); + packet.Write((byte)1); // Message type for Hellhex explosion + packet.Write((byte)Player.whoAmI); + packet.Write(spawnPos.X); + packet.Write(spawnPos.Y); + packet.Write(explosionDamage); + packet.Write(scale); + packet.Write((sbyte)owner); + packet.Send(); } } + // On server: spawn and sync to all clients + else if (Main.netMode == NetmodeID.Server) + { + int proj = Projectile.NewProjectile( + Player.GetSource_Buff(buffIndex), + spawnPos, + Vector2.Zero, + ProjectileID.FireWhipProj, + explosionDamage, + 0f, + owner + ); + + if (proj >= 0 && proj < Main.maxProjectiles) + { + Main.projectile[proj].scale = scale; + NetMessage.SendData(MessageID.SyncProjectile, -1, -1, null, proj); + } + } + // Victim's client (not attacker): don't spawn, wait for server sync + // This prevents double spawning } } } @@ -2341,6 +2377,7 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) public override void PostUpdateBuffs() { + // Check if applier died - remove buff if so if (Player.HasBuff() && hellhexApplierIndex >= 0 && hellhexApplierIndex < Main.maxPlayers) { Player applier = Main.player[hellhexApplierIndex]; @@ -2353,6 +2390,7 @@ public override void PostUpdateBuffs() } hellhexApplierIndex = -1; hellhexTriggered = false; + explosionSpawned = false; return; } } @@ -2383,7 +2421,8 @@ public override void PostUpdateBuffs() else { hellhexTriggered = false; - hellhexApplierIndex = -1; // Reset when buff expires + hellhexApplierIndex = -1; + explosionSpawned = false; } } } diff --git a/Dogshit.cs b/Dogshit.cs index d6882ab5..f7c7c875 100644 --- a/Dogshit.cs +++ b/Dogshit.cs @@ -16,39 +16,45 @@ using Terraria.WorldBuilding; namespace PvPAdventure { - public class RainSystem : ModSystem + public class IncreasedRainSystem : ModSystem { - private bool triggeredToday; + private int rainCheckTimer = 0; + private const int RainCheckInterval = 60; - public override void PreUpdateWorld() + public override void PostUpdateWorld() { - if (Main.netMode == NetmodeID.Server) return; + if (Main.netMode == NetmodeID.MultiplayerClient) + return; - if (Main.dayTime && Main.time == 0) - { - triggeredToday = false; - } + rainCheckTimer++; - if (Main.dayTime && - !triggeredToday && - Main.time >= 17524) + if (rainCheckTimer >= RainCheckInterval) { + rainCheckTimer = 0; - if (Main.rand.NextBool(3)) + if (!Main.raining && !Main.bloodMoon && !Main.eclipse) { - StartRain(); + if (Main.rand.NextBool(1200)) //this is just the chance each second that rain starts, so basically 1/20 every minute, so 1 rain every 20 mins + { + StartRain(); + } } - triggeredToday = true; } } private void StartRain() { - Main.rainTime = Main.rand.Next(3600, 18000); - Main.raining = true; + Main.StartRain(); - if (Main.netMode == NetmodeID.MultiplayerClient) + // Set a reasonable rain duration + Main.rainTime = Main.rand.Next(18000, 54000); // 5-15 minutes + Main.maxRaining = Main.rand.NextFloat(0.3f, 0.9f); + + // Sync to clients in multiplayer + if (Main.netMode == NetmodeID.Server) + { NetMessage.SendData(MessageID.WorldData); + } } } public class MechBossSpawnSystem : ModSystem From fdf4daa2a931a76e14bf6a686ed890b916f263b0 Mon Sep 17 00:00:00 2001 From: Erky Date: Sat, 8 Nov 2025 18:28:33 +0100 Subject: [PATCH 149/206] RTP Text cleanup --- AdventureConfig.cs | 13 +++ Content/Items/RTPMirror.cs | 82 ++++++++++++++++++ Content/Items/RTPMirror.png | Bin 0 -> 1362 bytes Core/Features/RTPFullscreenMap.cs | 134 ++++++++++++++++++++++++++++++ Core/Features/RTPMirrorPlayer.cs | 41 +++++++++ Localization/en-US.hjson | 108 ++++++++++++++++++++---- PvPAdventure.sln | 24 ++++++ 7 files changed, 386 insertions(+), 16 deletions(-) create mode 100644 Content/Items/RTPMirror.cs create mode 100644 Content/Items/RTPMirror.png create mode 100644 Core/Features/RTPFullscreenMap.cs create mode 100644 Core/Features/RTPMirrorPlayer.cs create mode 100644 PvPAdventure.sln diff --git a/AdventureConfig.cs b/AdventureConfig.cs index e067aa10..160367d9 100644 --- a/AdventureConfig.cs +++ b/AdventureConfig.cs @@ -1,3 +1,4 @@ +using PvPAdventure.Content.Items; using System; using System.Collections.Generic; using System.ComponentModel; @@ -65,6 +66,18 @@ public class InvasionSizeValue [DefaultValue(4 * 60)] public int RecallFrames { get; set; } + [Range(0, 60 * 60)] + [DefaultValue(4 * 60)] + public int RTPRecallFrames { get; set; } + + public override void OnChanged() + { + base.OnChanged(); + + // Update RTPMirror use time + //ModItem rtpMirrorItemType = ModContent.GetModItem(ModContent.GetInstance()); + } + [Range(0, 30 * 60)] [DefaultValue(1.5 * 60)] public int SpawnImmuneFrames { get; set; } diff --git a/Content/Items/RTPMirror.cs b/Content/Items/RTPMirror.cs new file mode 100644 index 00000000..b315bce3 --- /dev/null +++ b/Content/Items/RTPMirror.cs @@ -0,0 +1,82 @@ +using Discord; +using Microsoft.Xna.Framework; +using PvPAdventure.Core.Features; +using Terraria; +using Terraria.ID; +using Terraria.ModLoader; +using static PvPAdventure.Core.Features.TeleportMapSystem; + +namespace PvPAdventure.Content.Items; + +internal class RTPMirror : ModItem +{ + public override bool CanUseItem(Player player) + { + // Prevent item use if the player is moving + if (player.velocity.Length() > 0f) + { + return false; + } + + return base.CanUseItem(player); + } + + public override bool? UseItem(Player player) + { + for (int d = 0; d < 70; d++) + { + Dust.NewDust(player.position, player.width, player.height, DustID.MagicMirror, 0f, 0f, 150, default(Microsoft.Xna.Framework.Color), 1.5f); + } + + return true; + } + + public override void SetDefaults() + { + //Item.CloneDefaults(ItemID.MagicMirror); + + var config = ModContent.GetInstance(); + int recallFrames = config.RTPRecallFrames; + + Item.useTime = recallFrames; + Item.useAnimation = recallFrames; + Item.useStyle = ItemUseStyleID.HoldUp; + Item.UseSound = SoundID.Item6; + Item.rare = ItemRarityID.Blue; + Item.value = Item.buyPrice(gold: 5); + Item.noUseGraphic = false; + } + + public override void HoldItem(Player player) + { + if (player.itemAnimation == 1 && player.HeldItem.type == Item.type) + { + // This is the last frame of use animation + if (Main.myPlayer == player.whoAmI) + { + Main.mapFullscreen = true; + RTPSpawnSelectorSettings.IsEnabled = true; + } + } + } + + public override void UpdateInventory(Player player) + { + if (player.HeldItem.type == Item.type && player.itemAnimation > 0) + { + if (player.velocity.Length() > 0f) + { + // Cancel item use + player.itemAnimation = 0; + player.itemTime = 0; + //SoundEngine.PlaySound(SoundID.MenuClose, player.position); + } + } + } + + public override void PostUpdate() + { + base.PostUpdate(); + } + +} \ No newline at end of file diff --git a/Content/Items/RTPMirror.png b/Content/Items/RTPMirror.png new file mode 100644 index 0000000000000000000000000000000000000000..4f868ee0f25c20b5ad997971c1b06b3b35d3cbd7 GIT binary patch literal 1362 zcmZ{ieNfT|7{`CEtvq+lYi+fx+ng(Bc{W5rgw$l9`G#m*p{tfJ_*VIfnqtY@k9SF0 zDkAuXFJQu?ECDrNc7+JOotbE4ZnaL+N;@rQT4Vq0Zh!2L=lR@ypZnbN&zFnG1#fq7 zasU8ed&n_Nw2fc=Gxl3-dr~(gShLp$3RF@W(l+eGG-4!0J2aZJ>4Mf|Ozz-lg0J1KblOIXbWe4OgVG*d^E z@tRA4l{{j*MKFCWO!C0TMD?b2Wp_y;t1hF<>gb~#JPVK5W~P~x@v5@0atorL=1u9& z)>h#wiqWEax>?J=&yTr2M7!6LpePT&I_;~Y!}6~uG!!C=LhlxbbD6MoRbmwdkuQv` zHdc)31qKQEW&@+gD!eO>06}<~IURyQ*BkA%II5mXkO)JLvo zU?@^@OB3@p8y?qBmN7ATvfRdIrbdd(8D}a$Y<6{Somt$g097;6{x%Yi?Q{C6A1K3R z+-J&J*z}rQ*^szX2`V2;?`TLM$A|dLuc$gQ?M4!9f?31HrqyAcFfcqkGt<{M zHfH38yNamjT9@SH-Mdeo^zq5hKU9Xcb9%j0JMQP#-F3$W`RL(813PHT*4L{f=;p@8 zX3w{-Ue3;t(mrZ!?d)u6>F8)1WS9F9>0KU&BM|U-LY7!;v1qkxYs`<~C{NK4E;JN} z3kit;+uK)G1Ol_UwRLe(Dz#d>x;8fG^nSG4p+kocA3W&c;qLy!uL?zLYfFn-tyHQ& zy?%Y2we_=RjYc_-N=tv185Q=LlH-7ROBUMwy?U#ICib=K$ z9X!6YUn~0B5#ypEx`;yGy=#mPJMg)NxSvj=^#xX*Pf58*Jp9cbk%@F;Y)qqB&Jv5o zQi5AkQ&V%5Gc&U)6)ZjAb7%%UQi?q>JEV*ArOoSm;WE(LPlb0 rQo;WVu<|!1o8b2E2Xg8KQVu!pLgxQF@r=nYYz`2D#bMOwv-H0KT_ciJ literal 0 HcmV?d00001 diff --git a/Core/Features/RTPFullscreenMap.cs b/Core/Features/RTPFullscreenMap.cs new file mode 100644 index 00000000..2fd9da57 --- /dev/null +++ b/Core/Features/RTPFullscreenMap.cs @@ -0,0 +1,134 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using System; +using Terraria; +using Terraria.GameContent; +using Terraria.ID; +using Terraria.ModLoader; + +namespace PvPAdventure.Core.Features; + +public class TeleportMapSystem : ModSystem +{ + public static class RTPSpawnSelectorSettings + { + public static bool IsEnabled = false; + } + + public override void Load() + { + Main.OnPostFullscreenMapDraw += TP_Map; + } + + public override void Unload() + { + Main.OnPostFullscreenMapDraw -= TP_Map; + } + + public override void PostDrawFullscreenMap(ref string mouseText) + { + if (!RTPSpawnSelectorSettings.IsEnabled) + return; + + string teleportText = "PvP Adventure Teleport Options\n1. Click here to random teleport\n2. Click teammate to teleport"; + + // Load panel + Texture2D panelTexture = Main.Assets.Request("Images/UI/PanelBackground").Value; + int cornerSize = 12; + int barSize = 4; + Color panelColor = new Color(63, 82, 151) * 0.7f; + + // Panel bounds + Vector2 textSize = FontAssets.MouseText.Value.MeasureString(teleportText); + Vector2 textPosition = new(Main.screenWidth / 2 - textSize.X / 2, 20f); + Rectangle panelBounds = new((int)textPosition.X - 10, (int)textPosition.Y - 8, (int)textSize.X + 20, (int)textSize.Y + 12); + + // Check if mouse is hovering + bool isHovering = panelBounds.Contains(Main.mouseX, Main.mouseY); + Color textColor = isHovering ? Color.Yellow : Color.White; + + // Draw panel + DrawPanel(Main.spriteBatch, panelBounds, panelTexture, cornerSize, barSize, panelColor); + + // Draw text with hover color + Utils.DrawBorderString(Main.spriteBatch, teleportText, textPosition, textColor); + + // Optional: set mouseText to show tooltip + if (isHovering) + { + mouseText = "Click to teleport"; + } + } + + private static void RandomTeleport() + { + if (Main.netMode == NetmodeID.SinglePlayer) + Main.LocalPlayer.TeleportationPotion(); + else + NetMessage.SendData(MessageID.RequestTeleportationByServer); + } + + private void TP_Map(Vector2 arg1, float arg2) + { + if (!RTPSpawnSelectorSettings.IsEnabled) + return; + + string teleportText = "PvP Adventure Teleport Options\n1. Click here to random teleport\n2. Click teammate to teleport"; + Vector2 textSize = FontAssets.MouseText.Value.MeasureString(teleportText); + Vector2 textPosition = new(Main.screenWidth / 2 - textSize.X / 2, 20f); + Rectangle panelBounds = new((int)textPosition.X - 10, (int)textPosition.Y - 8, (int)textSize.X + 20, (int)textSize.Y + 12); + + // Check if mouse clicked inside panel bounds + if (Main.mouseLeft && Main.mouseLeftRelease && panelBounds.Contains(Main.mouseX, Main.mouseY)) + { + RandomTeleport(); // Trigger teleport + + // Close the map after teleporting + Main.mapFullscreen = false; + RTPSpawnSelectorSettings.IsEnabled = false; + } + } + + ///

+ /// Helper to draw a blue panel + /// + private void DrawPanel(SpriteBatch spriteBatch, Rectangle bounds, Texture2D texture, int cornerSize, int barSize, Color color) + { + Point point = bounds.Location; + Point point2 = new Point(bounds.Right - cornerSize, bounds.Bottom - cornerSize); + int width = bounds.Width - cornerSize * 2; + int height = bounds.Height - cornerSize * 2; + + // Corners + spriteBatch.Draw(texture, new Rectangle(point.X, point.Y, cornerSize, cornerSize), new Rectangle(0, 0, cornerSize, cornerSize), color); + spriteBatch.Draw(texture, new Rectangle(point2.X, point.Y, cornerSize, cornerSize), new Rectangle(cornerSize + barSize, 0, cornerSize, cornerSize), color); + spriteBatch.Draw(texture, new Rectangle(point.X, point2.Y, cornerSize, cornerSize), new Rectangle(0, cornerSize + barSize, cornerSize, cornerSize), color); + spriteBatch.Draw(texture, new Rectangle(point2.X, point2.Y, cornerSize, cornerSize), new Rectangle(cornerSize + barSize, cornerSize + barSize, cornerSize, cornerSize), color); + + // Edges + spriteBatch.Draw(texture, new Rectangle(point.X + cornerSize, point.Y, width, cornerSize), new Rectangle(cornerSize, 0, barSize, cornerSize), color); + spriteBatch.Draw(texture, new Rectangle(point.X + cornerSize, point2.Y, width, cornerSize), new Rectangle(cornerSize, cornerSize + barSize, barSize, cornerSize), color); + spriteBatch.Draw(texture, new Rectangle(point.X, point.Y + cornerSize, cornerSize, height), new Rectangle(0, cornerSize, cornerSize, barSize), color); + spriteBatch.Draw(texture, new Rectangle(point2.X, point.Y + cornerSize, cornerSize, height), new Rectangle(cornerSize + barSize, cornerSize, cornerSize, barSize), color); + + // Center + spriteBatch.Draw(texture, new Rectangle(point.X + cornerSize, point.Y + cornerSize, width, height), new Rectangle(cornerSize, cornerSize, barSize, barSize), color); + } + + [Obsolete("Used for teleporting to the mouse cursor position, not useful in this case")] + private void obsolete_TP_to_cursor() + { + Vector2 screenSize = new Vector2(Main.screenWidth, Main.screenHeight) * Main.UIScale; + Vector2 target = ((Main.MouseScreen - screenSize / 2) / 16 * (16 / Main.mapFullscreenScale) + Main.mapFullscreenPos) * 16; + + if (WorldGen.InWorld((int)target.X / 16, (int)target.Y / 16)) + { + Main.LocalPlayer.Center = target; + Main.LocalPlayer.fallStart = (int)Main.LocalPlayer.position.Y; + } + else + { + //Log.Info("Error: outside world bounds when trying to teleport"); + } + } +} \ No newline at end of file diff --git a/Core/Features/RTPMirrorPlayer.cs b/Core/Features/RTPMirrorPlayer.cs new file mode 100644 index 00000000..5663eff0 --- /dev/null +++ b/Core/Features/RTPMirrorPlayer.cs @@ -0,0 +1,41 @@ +using Microsoft.Xna.Framework; +using PvPAdventure.Content.Items; +using Terraria; +using Terraria.ModLoader; + +namespace PvPAdventure.Core.Features +{ + public class RTPMirrorPlayer : ModPlayer + { + public override void PostUpdate() + { + // Check if player is using RTPMirror + Item currentItem = Main.LocalPlayer.HeldItem; + int rtpMirrorItemType = ModContent.ItemType(); + + // Debug: item use time + //Main.NewText(Main.LocalPlayer.itemAnimation); + + if (currentItem != null && + currentItem.type == rtpMirrorItemType && + Main.LocalPlayer.itemAnimation > 0 && + Main.LocalPlayer.itemAnimation % 60 == 0) + { + int itemUseTimeLeft = Main.LocalPlayer.itemAnimation / 60 - 1; + string timeLeft = itemUseTimeLeft.ToString(); + + // Old combat text + //CombatText.NewText(Player.getRect(), Color.Cyan, itemUseTimeLeft); + + // Display text above the player every second + PopupText.NewText(new AdvancedPopupRequest + { + Color = Color.Crimson, + Text = timeLeft, + Velocity = new(0.0f, -4.0f), + DurationInFrames = 60 * 1 + }, Player.Top); + } + } + } +} \ No newline at end of file diff --git a/Localization/en-US.hjson b/Localization/en-US.hjson index 3ee3654d..9f139efb 100644 --- a/Localization/en-US.hjson +++ b/Localization/en-US.hjson @@ -128,6 +128,11 @@ Mods: { Tooltip: "" Label: Minimum Damage Received By Players From Player } + + RTPRecallFrames: { + Label: R T P Recall Frames + Tooltip: "" + } } PointsConfig: { @@ -238,9 +243,21 @@ Mods: { WorldProgressionState: { Tooltip: "" - Any.Label: Any - PreHardmode.Label: Pre Hardmode - Hardmode.Label: Hardmode + + Any: { + Label: Any + Tooltip: "" + } + + PreHardmode: { + Label: Pre Hardmode + Tooltip: "" + } + + Hardmode: { + Label: Hardmode + Tooltip: "" + } } ConfigItem: { @@ -562,23 +579,75 @@ Mods: { } Killsound: { - Part2.Label: Part2 - FatalCarCrash.Label: Fatal Car Crash - Shronker.Label: Shronker - Sharkron.Label: Sharkron - Ronaldoz.Label: Ronaldoz - Zacharry.Label: Zacharry + Part2: { + Label: Part2 + Tooltip: "" + } + + FatalCarCrash: { + Label: Fatal Car Crash + Tooltip: "" + } + + Shronker: { + Label: Shronker + Tooltip: "" + } + + Sharkron: { + Label: Sharkron + Tooltip: "" + } + + Ronaldoz: { + Label: Ronaldoz + Tooltip: "" + } + + Zacharry: { + Label: Zacharry + Tooltip: "" + } + Tooltip: "" } Hitsound: { - Part1.Label: Part1 - MarrowMurder.Label: Marrow Murder - Squelchy.Label: Squelchy - Crash.Label: Crash - Blip.Label: Blip - Buwee.Label: BuWEEEEE - OlBetsy.Label: Ol' Betsy + Part1: { + Label: Part1 + Tooltip: "" + } + + MarrowMurder: { + Label: Marrow Murder + Tooltip: "" + } + + Squelchy: { + Label: Squelchy + Tooltip: "" + } + + Crash: { + Label: Crash + Tooltip: "" + } + + Blip: { + Label: Blip + Tooltip: "" + } + + Buwee: { + Label: BuWEEEEE + Tooltip: "" + } + + OlBetsy: { + Label: Ol' Betsy + Tooltip: "" + } + Tooltip: "" } @@ -705,6 +774,13 @@ Mods: { True: "[c/FF0000:The game has been paused.]" False: "[c/00FF00:The game has been resumed.]" } + + Items: { + RTPMirror: { + Tooltip: "" + DisplayName: R T P Mirror + } + } } } diff --git a/PvPAdventure.sln b/PvPAdventure.sln new file mode 100644 index 00000000..1100145b --- /dev/null +++ b/PvPAdventure.sln @@ -0,0 +1,24 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.2.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PvPAdventure", "PvPAdventure.csproj", "{8C67A48A-1DD4-1910-9CCD-872426FDE8EF}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {8C67A48A-1DD4-1910-9CCD-872426FDE8EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8C67A48A-1DD4-1910-9CCD-872426FDE8EF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8C67A48A-1DD4-1910-9CCD-872426FDE8EF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8C67A48A-1DD4-1910-9CCD-872426FDE8EF}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {1B553FCD-BFE6-48FF-B3CA-665132715AC9} + EndGlobalSection +EndGlobal From ed20943492daa6db4669bb545cd176bcab7c0508 Mon Sep 17 00:00:00 2001 From: Erky Date: Sat, 8 Nov 2025 19:03:10 +0100 Subject: [PATCH 150/206] Added config option to toggle vanilla double tap dash --- AdventureClientConfig.cs | 3 + Core/Features/Dash/DetourVanillaDashSystem.cs | 44 ++++++++ Localization/en-US.hjson | 105 +++++++++++++++--- 3 files changed, 136 insertions(+), 16 deletions(-) create mode 100644 Core/Features/Dash/DetourVanillaDashSystem.cs diff --git a/AdventureClientConfig.cs b/AdventureClientConfig.cs index 6f35f225..9122fef1 100644 --- a/AdventureClientConfig.cs +++ b/AdventureClientConfig.cs @@ -12,6 +12,9 @@ public class AdventureClientConfig : ModConfig public PlayerOutlineConfig PlayerOutline { get; set; } = new(); public bool ShiftEnterOpensAllChat { get; set; } + + [DefaultValue(true)] + public bool IsVanillaDashEnabled { get; set; } [DefaultValue(true)] public bool ShowPauseMessage { get; set; } public class PlayerOutlineConfig diff --git a/Core/Features/Dash/DetourVanillaDashSystem.cs b/Core/Features/Dash/DetourVanillaDashSystem.cs new file mode 100644 index 00000000..39850040 --- /dev/null +++ b/Core/Features/Dash/DetourVanillaDashSystem.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Terraria; +using Terraria.ModLoader; + +namespace PvPAdventure.Core.Features.Dash +{ + internal class DetourVanillaDashSystem : ModSystem + { + public override void Load() + { + On_Player.DoCommonDashHandle += VanillaDashDetour; + } + public override void Unload() + { + On_Player.DoCommonDashHandle -= VanillaDashDetour; + } + + private static void VanillaDashDetour(On_Player.orig_DoCommonDashHandle orig, Player self, out int dir, out bool dashing, Player.DashStartAction dashStartAction) + { + // Get client config + var clientConfig = ModContent.GetInstance(); + + // Execute vanilla dash only if enabled in config + if (clientConfig.IsVanillaDashEnabled) + { + orig.Invoke(self, out dir, out dashing, dashStartAction); + return; + } + else + { + // Must set out parameters even if not dashing + dir = 0; + dashing = false; + } + + //if (self.whoAmI != Main.myPlayer) + //orig.Invoke(self, out dir, out dashing, dashStartAction); + } + } +} diff --git a/Localization/en-US.hjson b/Localization/en-US.hjson index 5434e9e7..f7a5fcb3 100644 --- a/Localization/en-US.hjson +++ b/Localization/en-US.hjson @@ -244,9 +244,21 @@ Mods: { WorldProgressionState: { Tooltip: "" - Any.Label: Any - PreHardmode.Label: Pre Hardmode - Hardmode.Label: Hardmode + + Any: { + Label: Any + Tooltip: "" + } + + PreHardmode: { + Label: Pre Hardmode + Tooltip: "" + } + + Hardmode: { + Label: Hardmode + Tooltip: "" + } } ConfigItem: { @@ -344,6 +356,15 @@ Mods: { Label: Sound Effect Tooltip: "" } + + IsVanillaDashEnabled: { + Label: Is Vanilla Dash Enabled + Tooltip: + ''' + On: Dash as usual with double tap + Off: Disables double tap dash. Use keybind instead + ''' + } } PlayerOutlineConfig: { @@ -568,23 +589,75 @@ Mods: { } Killsound: { - Part2.Label: Part2 - FatalCarCrash.Label: Fatal Car Crash - Shronker.Label: Shronker - Sharkron.Label: Sharkron - Ronaldoz.Label: Ronaldoz - Zacharry.Label: Zacharry + Part2: { + Label: Part2 + Tooltip: "" + } + + FatalCarCrash: { + Label: Fatal Car Crash + Tooltip: "" + } + + Shronker: { + Label: Shronker + Tooltip: "" + } + + Sharkron: { + Label: Sharkron + Tooltip: "" + } + + Ronaldoz: { + Label: Ronaldoz + Tooltip: "" + } + + Zacharry: { + Label: Zacharry + Tooltip: "" + } + Tooltip: "" } Hitsound: { - Part1.Label: Part1 - MarrowMurder.Label: Marrow Murder - Squelchy.Label: Squelchy - Crash.Label: Crash - Blip.Label: Blip - Buwee.Label: BuWEEEEE - OlBetsy.Label: Ol' Betsy + Part1: { + Label: Part1 + Tooltip: "" + } + + MarrowMurder: { + Label: Marrow Murder + Tooltip: "" + } + + Squelchy: { + Label: Squelchy + Tooltip: "" + } + + Crash: { + Label: Crash + Tooltip: "" + } + + Blip: { + Label: Blip + Tooltip: "" + } + + Buwee: { + Label: BuWEEEEE + Tooltip: "" + } + + OlBetsy: { + Label: Ol' Betsy + Tooltip: "" + } + Tooltip: "" } From 7d1dba17ad241e5e3e4ce8ecdf1667407bb2ada7 Mon Sep 17 00:00:00 2001 From: emyhrberg <121192176+emyhrberg@users.noreply.github.com> Date: Sat, 8 Nov 2025 20:31:53 +0100 Subject: [PATCH 151/206] Cleanup Adventure Mirror, fixed some of Unity Potion functionality --- AdventureConfig.cs | 8 ---- Content/Items/RTPMirror.png | Bin 1362 -> 505 bytes Core/Features/RTPFullscreenMap.cs | 26 +++++++--- Core/Features/RTPMirrorPlayer.cs | 7 ++- Core/Features/UnityPotionIL.cs | 76 ++++++++++++++++++++++++++++++ Localization/en-US.hjson | 4 +- 6 files changed, 104 insertions(+), 17 deletions(-) create mode 100644 Core/Features/UnityPotionIL.cs diff --git a/AdventureConfig.cs b/AdventureConfig.cs index 160367d9..a5e90ae3 100644 --- a/AdventureConfig.cs +++ b/AdventureConfig.cs @@ -70,14 +70,6 @@ public class InvasionSizeValue [DefaultValue(4 * 60)] public int RTPRecallFrames { get; set; } - public override void OnChanged() - { - base.OnChanged(); - - // Update RTPMirror use time - //ModItem rtpMirrorItemType = ModContent.GetModItem(ModContent.GetInstance()); - } - [Range(0, 30 * 60)] [DefaultValue(1.5 * 60)] public int SpawnImmuneFrames { get; set; } diff --git a/Content/Items/RTPMirror.png b/Content/Items/RTPMirror.png index 4f868ee0f25c20b5ad997971c1b06b3b35d3cbd7..fbff7c284f4a5011973f8338fbf549e0a1af1521 100644 GIT binary patch delta 490 zcmVL_t(Y ziDP6S5@;Ei{0GsR`np)<*DjpTh)tY{fyRK5kc(lUyrvRNTbY`G>E|zBg6Um{kAUgx zmo7u-ixB$Sg)@u;;{z?I%V*4*hT_7NlP-d3Nmf%7^)1WHAb;ZG;$XU>t^p-Z=;s41 zsLNqty=V76Fnwaj7clL{R|ckam;}J|m46?=^yTmSQG9|PCp7l~3%bDVhYuk>*m?_0 z2MJC9(>bhKVEXR=-ze(euxf(ony6D?x@DOSoqeDM4f~+jD6qiX{_S8|mBSxQd$Op4 z=>vbCLFivMP=5>%VUYmS&wpP>Nlh?7zc^5pmj}~4%u*1SK*M(XpW9&i&7T)oT@Dj} z{`)kTK6Y9XB}dcV2b$2*QBh77s{&7G96(|Qk(#Fbz6PexeOm;k!}IjPbZ1LDeaj*i z7z36A=dR8M)5)Pzv4;5+sLR*AF96dn-fCdl%@&gW*JCYShN6#tWl?Z^A~-*EG&P`< z_sM8J`2x)k$%URMsSiEuVSxUnsU|d4Y3k{sgzf!Dk5S4h^sq*E`M}r7!O%E?0a(t2 g0bDLd2Q>Eq0KI3Rw}XaFGynhq07*qoM6N<$g3{LI$^ZZW literal 1362 zcmZ{ieNfT|7{`CEtvq+lYi+fx+ng(Bc{W5rgw$l9`G#m*p{tfJ_*VIfnqtY@k9SF0 zDkAuXFJQu?ECDrNc7+JOotbE4ZnaL+N;@rQT4Vq0Zh!2L=lR@ypZnbN&zFnG1#fq7 zasU8ed&n_Nw2fc=Gxl3-dr~(gShLp$3RF@W(l+eGG-4!0J2aZJ>4Mf|Ozz-lg0J1KblOIXbWe4OgVG*d^E z@tRA4l{{j*MKFCWO!C0TMD?b2Wp_y;t1hF<>gb~#JPVK5W~P~x@v5@0atorL=1u9& z)>h#wiqWEax>?J=&yTr2M7!6LpePT&I_;~Y!}6~uG!!C=LhlxbbD6MoRbmwdkuQv` zHdc)31qKQEW&@+gD!eO>06}<~IURyQ*BkA%II5mXkO)JLvo zU?@^@OB3@p8y?qBmN7ATvfRdIrbdd(8D}a$Y<6{Somt$g097;6{x%Yi?Q{C6A1K3R z+-J&J*z}rQ*^szX2`V2;?`TLM$A|dLuc$gQ?M4!9f?31HrqyAcFfcqkGt<{M zHfH38yNamjT9@SH-Mdeo^zq5hKU9Xcb9%j0JMQP#-F3$W`RL(813PHT*4L{f=;p@8 zX3w{-Ue3;t(mrZ!?d)u6>F8)1WS9F9>0KU&BM|U-LY7!;v1qkxYs`<~C{NK4E;JN} z3kit;+uK)G1Ol_UwRLe(Dz#d>x;8fG^nSG4p+kocA3W&c;qLy!uL?zLYfFn-tyHQ& zy?%Y2we_=RjYc_-N=tv185Q=LlH-7ROBUMwy?U#ICib=K$ z9X!6YUn~0B5#ypEx`;yGy=#mPJMg)NxSvj=^#xX*Pf58*Jp9cbk%@F;Y)qqB&Jv5o zQi5AkQ&V%5Gc&U)6)ZjAb7%%UQi?q>JEV*ArOoSm;WE(LPlb0 rQo;WVu<|!1o8b2E2Xg8KQVu!pLgxQF@r=nYYz`2D#bMOwv-H0KT_ciJ diff --git a/Core/Features/RTPFullscreenMap.cs b/Core/Features/RTPFullscreenMap.cs index 2fd9da57..dde286c0 100644 --- a/Core/Features/RTPFullscreenMap.cs +++ b/Core/Features/RTPFullscreenMap.cs @@ -17,12 +17,18 @@ public static class RTPSpawnSelectorSettings public override void Load() { - Main.OnPostFullscreenMapDraw += TP_Map; + Main.QueueMainThreadAction(() => + { + Main.OnPostFullscreenMapDraw += TP_Map; + }); } public override void Unload() { - Main.OnPostFullscreenMapDraw -= TP_Map; + Main.QueueMainThreadAction(() => + { + Main.OnPostFullscreenMapDraw -= TP_Map; + }); } public override void PostDrawFullscreenMap(ref string mouseText) @@ -30,7 +36,11 @@ public override void PostDrawFullscreenMap(ref string mouseText) if (!RTPSpawnSelectorSettings.IsEnabled) return; - string teleportText = "PvP Adventure Teleport Options\n1. Click here to random teleport\n2. Click teammate to teleport"; + string teleportText = "" + + "PvP Adventure Teleport Options \n" + + "1. Click here to random teleport \n" + + "2. Click teammate to teleport \n" + + "(Upcoming) Click team bed to teleport"; // Load panel Texture2D panelTexture = Main.Assets.Request("Images/UI/PanelBackground").Value; @@ -53,7 +63,7 @@ public override void PostDrawFullscreenMap(ref string mouseText) // Draw text with hover color Utils.DrawBorderString(Main.spriteBatch, teleportText, textPosition, textColor); - // Optional: set mouseText to show tooltip + // set mouseText to show tooltip if (isHovering) { mouseText = "Click to teleport"; @@ -68,12 +78,16 @@ private static void RandomTeleport() NetMessage.SendData(MessageID.RequestTeleportationByServer); } + /// + /// Main functionality for teleporting. + /// Executed every frame. + /// private void TP_Map(Vector2 arg1, float arg2) { if (!RTPSpawnSelectorSettings.IsEnabled) return; - string teleportText = "PvP Adventure Teleport Options\n1. Click here to random teleport\n2. Click teammate to teleport"; + string teleportText = "PvP Adventure Teleport Options\n1. Click here to random teleport\n2. Click teammate to teleport\n3. (Future) Click team bed to teleport"; Vector2 textSize = FontAssets.MouseText.Value.MeasureString(teleportText); Vector2 textPosition = new(Main.screenWidth / 2 - textSize.X / 2, 20f); Rectangle panelBounds = new((int)textPosition.X - 10, (int)textPosition.Y - 8, (int)textSize.X + 20, (int)textSize.Y + 12); @@ -81,7 +95,7 @@ private void TP_Map(Vector2 arg1, float arg2) // Check if mouse clicked inside panel bounds if (Main.mouseLeft && Main.mouseLeftRelease && panelBounds.Contains(Main.mouseX, Main.mouseY)) { - RandomTeleport(); // Trigger teleport + RandomTeleport(); // Close the map after teleporting Main.mapFullscreen = false; diff --git a/Core/Features/RTPMirrorPlayer.cs b/Core/Features/RTPMirrorPlayer.cs index 5663eff0..8702760d 100644 --- a/Core/Features/RTPMirrorPlayer.cs +++ b/Core/Features/RTPMirrorPlayer.cs @@ -9,6 +9,11 @@ public class RTPMirrorPlayer : ModPlayer { public override void PostUpdate() { + if (Main.dedServ || Player.whoAmI != Main.myPlayer) + { + return; + } + // Check if player is using RTPMirror Item currentItem = Main.LocalPlayer.HeldItem; int rtpMirrorItemType = ModContent.ItemType(); @@ -21,7 +26,7 @@ public override void PostUpdate() Main.LocalPlayer.itemAnimation > 0 && Main.LocalPlayer.itemAnimation % 60 == 0) { - int itemUseTimeLeft = Main.LocalPlayer.itemAnimation / 60 - 1; + int itemUseTimeLeft = Main.LocalPlayer.itemAnimation / 60; string timeLeft = itemUseTimeLeft.ToString(); // Old combat text diff --git a/Core/Features/UnityPotionIL.cs b/Core/Features/UnityPotionIL.cs new file mode 100644 index 00000000..427d5945 --- /dev/null +++ b/Core/Features/UnityPotionIL.cs @@ -0,0 +1,76 @@ +using Microsoft.Xna.Framework; +using Mono.Cecil.Cil; +using MonoMod.Cil; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Terraria; +using Terraria.ModLoader; +using static PvPAdventure.Core.Features.TeleportMapSystem; + +namespace PvPAdventure.Core.Features; + +public class UnityPotionIL : ModSystem +{ + public override void Load() + { + Main.QueueMainThreadAction(() => + { + On_Player.HasUnityPotion += OverrideUnityPotionCheck; + On_Player.UnityTeleport += DisableRTPMenuAfterTeleport; + }); + } + + public override void Unload() + { + Main.QueueMainThreadAction(() => + { + On_Player.HasUnityPotion -= OverrideUnityPotionCheck; + On_Player.UnityTeleport -= DisableRTPMenuAfterTeleport; + }); + } + + private void DisableRTPMenuAfterTeleport(On_Player.orig_UnityTeleport orig, Player self, Vector2 telePos) + { + // this method does what it says + RTPSpawnSelectorSettings.IsEnabled = false; + orig(self, telePos); + } + + private static bool OverrideUnityPotionCheck(Terraria.On_Player.orig_HasUnityPotion orig, Player self) + { + // debug + var logger = ModContent.GetInstance().Logger; + //logger.Debug("has unity: " + Main.LocalPlayer.HasUnityPotion()); + //logger.Debug("is rtp menu enabled: " + "has unity: " + RTPSpawnSelectorSettings.IsEnabled()); + + if (RTPSpawnSelectorSettings.IsEnabled) + return true; + + return orig(self); + } +} + + //private void OverrideUnityPotionCheck(ILContext il) + //{ + // try + // { + // var c = new ILCursor(il); + + // if (c.TryGotoNext(i => i.MatchRet())) + // { + // c.Emit(OpCodes.Pop); + + // c.EmitDelegate>(() => + // { + // return RTPSpawnSelectorSettings.IsEnabled; + // }); + // } + // } + // catch (Exception e) + // { + // throw new ILPatchFailureException(Mod, il, e); + // } + //} diff --git a/Localization/en-US.hjson b/Localization/en-US.hjson index 9f139efb..6bbee2b9 100644 --- a/Localization/en-US.hjson +++ b/Localization/en-US.hjson @@ -130,7 +130,7 @@ Mods: { } RTPRecallFrames: { - Label: R T P Recall Frames + Label: RTP Recall Frames Tooltip: "" } } @@ -778,7 +778,7 @@ Mods: { Items: { RTPMirror: { Tooltip: "" - DisplayName: R T P Mirror + DisplayName: Adventure Mirror } } } From 99328e2b6f6d55ceda2ce6710b3ecf39b3a6946a Mon Sep 17 00:00:00 2001 From: emyhrberg <121192176+emyhrberg@users.noreply.github.com> Date: Mon, 10 Nov 2025 09:14:00 +0100 Subject: [PATCH 152/206] Adding some debug logs --- .../{RTPMirror.cs => AdventureMirror.cs} | 20 +++-- .../{RTPMirror.png => AdventureMirror.png} | Bin Core/Features/RTPFullscreenMap.cs | 17 ++-- Core/Features/RTPMirrorPlayer.cs | 8 +- Core/Features/RTPSpawnSelectorSettings.cs | 9 +++ Core/Features/UnityHooks.cs | 47 +++++++++++ Core/Features/UnityPotionIL.cs | 76 ------------------ Core/Helpers/Log.cs | 51 ++++++++++++ Localization/en-US.hjson | 5 ++ System/DiscordIdentification.cs | 2 +- 10 files changed, 132 insertions(+), 103 deletions(-) rename Content/Items/{RTPMirror.cs => AdventureMirror.cs} (81%) rename Content/Items/{RTPMirror.png => AdventureMirror.png} (100%) create mode 100644 Core/Features/RTPSpawnSelectorSettings.cs create mode 100644 Core/Features/UnityHooks.cs delete mode 100644 Core/Features/UnityPotionIL.cs create mode 100644 Core/Helpers/Log.cs diff --git a/Content/Items/RTPMirror.cs b/Content/Items/AdventureMirror.cs similarity index 81% rename from Content/Items/RTPMirror.cs rename to Content/Items/AdventureMirror.cs index b315bce3..dc9a6597 100644 --- a/Content/Items/RTPMirror.cs +++ b/Content/Items/AdventureMirror.cs @@ -1,6 +1,7 @@ using Discord; using Microsoft.Xna.Framework; using PvPAdventure.Core.Features; +using PvPAdventure.Core.Helpers; using Terraria; using Terraria.ID; using Terraria.ModLoader; @@ -8,7 +9,7 @@ namespace PvPAdventure.Content.Items; -internal class RTPMirror : ModItem +internal class AdventureMirror : ModItem { public override bool CanUseItem(Player player) { @@ -23,6 +24,9 @@ public override bool CanUseItem(Player player) public override bool? UseItem(Player player) { + Log.Debug("Adventure mirror used."); + Log.Debug("is rtp menu enabled: " + RTPSpawnSelectorSettings.GetIsEnabled()); + for (int d = 0; d < 70; d++) { Dust.NewDust(player.position, player.width, player.height, DustID.MagicMirror, 0f, 0f, 150, default(Microsoft.Xna.Framework.Color), 1.5f); @@ -51,11 +55,15 @@ public override void HoldItem(Player player) { if (player.itemAnimation == 1 && player.HeldItem.type == Item.type) { + Log.Debug("Adventure mirror time is up, opening map!"); + // This is the last frame of use animation if (Main.myPlayer == player.whoAmI) { Main.mapFullscreen = true; - RTPSpawnSelectorSettings.IsEnabled = true; + RTPSpawnSelectorSettings.SetIsEnabled(true); + + Log.Debug("Main.mapFullscreen set to: " + Main.mapFullscreen); } } } @@ -70,13 +78,9 @@ public override void UpdateInventory(Player player) player.itemAnimation = 0; player.itemTime = 0; //SoundEngine.PlaySound(SoundID.MenuClose, player.position); + + Log.Debug("cancelled RTP mirror"); } } } - - public override void PostUpdate() - { - base.PostUpdate(); - } - } \ No newline at end of file diff --git a/Content/Items/RTPMirror.png b/Content/Items/AdventureMirror.png similarity index 100% rename from Content/Items/RTPMirror.png rename to Content/Items/AdventureMirror.png diff --git a/Core/Features/RTPFullscreenMap.cs b/Core/Features/RTPFullscreenMap.cs index dde286c0..637b5259 100644 --- a/Core/Features/RTPFullscreenMap.cs +++ b/Core/Features/RTPFullscreenMap.cs @@ -10,16 +10,11 @@ namespace PvPAdventure.Core.Features; public class TeleportMapSystem : ModSystem { - public static class RTPSpawnSelectorSettings - { - public static bool IsEnabled = false; - } - public override void Load() { Main.QueueMainThreadAction(() => { - Main.OnPostFullscreenMapDraw += TP_Map; + Main.OnPostFullscreenMapDraw += InjectMapDraw; }); } @@ -27,13 +22,13 @@ public override void Unload() { Main.QueueMainThreadAction(() => { - Main.OnPostFullscreenMapDraw -= TP_Map; + Main.OnPostFullscreenMapDraw -= InjectMapDraw; }); } public override void PostDrawFullscreenMap(ref string mouseText) { - if (!RTPSpawnSelectorSettings.IsEnabled) + if (!RTPSpawnSelectorSettings.GetIsEnabled()) return; string teleportText = "" + @@ -82,9 +77,9 @@ private static void RandomTeleport() /// Main functionality for teleporting. /// Executed every frame. /// - private void TP_Map(Vector2 arg1, float arg2) + private void InjectMapDraw(Vector2 arg1, float arg2) { - if (!RTPSpawnSelectorSettings.IsEnabled) + if (!RTPSpawnSelectorSettings.GetIsEnabled()) return; string teleportText = "PvP Adventure Teleport Options\n1. Click here to random teleport\n2. Click teammate to teleport\n3. (Future) Click team bed to teleport"; @@ -99,7 +94,7 @@ private void TP_Map(Vector2 arg1, float arg2) // Close the map after teleporting Main.mapFullscreen = false; - RTPSpawnSelectorSettings.IsEnabled = false; + RTPSpawnSelectorSettings.SetIsEnabled(false); } } diff --git a/Core/Features/RTPMirrorPlayer.cs b/Core/Features/RTPMirrorPlayer.cs index 8702760d..ee82867c 100644 --- a/Core/Features/RTPMirrorPlayer.cs +++ b/Core/Features/RTPMirrorPlayer.cs @@ -16,10 +16,7 @@ public override void PostUpdate() // Check if player is using RTPMirror Item currentItem = Main.LocalPlayer.HeldItem; - int rtpMirrorItemType = ModContent.ItemType(); - - // Debug: item use time - //Main.NewText(Main.LocalPlayer.itemAnimation); + int rtpMirrorItemType = ModContent.ItemType(); if (currentItem != null && currentItem.type == rtpMirrorItemType && @@ -29,9 +26,6 @@ public override void PostUpdate() int itemUseTimeLeft = Main.LocalPlayer.itemAnimation / 60; string timeLeft = itemUseTimeLeft.ToString(); - // Old combat text - //CombatText.NewText(Player.getRect(), Color.Cyan, itemUseTimeLeft); - // Display text above the player every second PopupText.NewText(new AdvancedPopupRequest { diff --git a/Core/Features/RTPSpawnSelectorSettings.cs b/Core/Features/RTPSpawnSelectorSettings.cs new file mode 100644 index 00000000..f45f841c --- /dev/null +++ b/Core/Features/RTPSpawnSelectorSettings.cs @@ -0,0 +1,9 @@ +namespace PvPAdventure.Core.Features; + +public static class RTPSpawnSelectorSettings +{ + private static bool IsEnabled = false; + + public static bool GetIsEnabled() => IsEnabled; + public static void SetIsEnabled(bool value) => IsEnabled = value; +} diff --git a/Core/Features/UnityHooks.cs b/Core/Features/UnityHooks.cs new file mode 100644 index 00000000..a389aee6 --- /dev/null +++ b/Core/Features/UnityHooks.cs @@ -0,0 +1,47 @@ +using Microsoft.Xna.Framework; +using PvPAdventure.Core.Helpers; +using Terraria; +using Terraria.ModLoader; + +namespace PvPAdventure.Core.Features; + +public class UnityHooks : ModSystem +{ + public override void Load() + { + Main.QueueMainThreadAction(() => + { + On_Player.HasUnityPotion += OverrideUnityPotionCheck; + On_Player.UnityTeleport += DisableRTPMenuAfterTeleport; + }); + } + + public override void Unload() + { + Main.QueueMainThreadAction(() => + { + On_Player.HasUnityPotion -= OverrideUnityPotionCheck; + On_Player.UnityTeleport -= DisableRTPMenuAfterTeleport; + }); + } + + private void DisableRTPMenuAfterTeleport(On_Player.orig_UnityTeleport orig, Player self, Vector2 telePos) + { + // this method does what it says + RTPSpawnSelectorSettings.SetIsEnabled(false); + Log.Debug("Unity teleport detected, disabling RTP menu."); + orig(self, telePos); + } + + private static bool OverrideUnityPotionCheck(Terraria.On_Player.orig_HasUnityPotion orig, Player self) + { + // debug + Log.Debug("has unity: " + Main.LocalPlayer.HasUnityPotion()); + Log.Debug("is rtp menu enabled: " + RTPSpawnSelectorSettings.GetIsEnabled()); + + if (RTPSpawnSelectorSettings.GetIsEnabled()) + return true; + + return orig(self); + } +} diff --git a/Core/Features/UnityPotionIL.cs b/Core/Features/UnityPotionIL.cs deleted file mode 100644 index 427d5945..00000000 --- a/Core/Features/UnityPotionIL.cs +++ /dev/null @@ -1,76 +0,0 @@ -using Microsoft.Xna.Framework; -using Mono.Cecil.Cil; -using MonoMod.Cil; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Terraria; -using Terraria.ModLoader; -using static PvPAdventure.Core.Features.TeleportMapSystem; - -namespace PvPAdventure.Core.Features; - -public class UnityPotionIL : ModSystem -{ - public override void Load() - { - Main.QueueMainThreadAction(() => - { - On_Player.HasUnityPotion += OverrideUnityPotionCheck; - On_Player.UnityTeleport += DisableRTPMenuAfterTeleport; - }); - } - - public override void Unload() - { - Main.QueueMainThreadAction(() => - { - On_Player.HasUnityPotion -= OverrideUnityPotionCheck; - On_Player.UnityTeleport -= DisableRTPMenuAfterTeleport; - }); - } - - private void DisableRTPMenuAfterTeleport(On_Player.orig_UnityTeleport orig, Player self, Vector2 telePos) - { - // this method does what it says - RTPSpawnSelectorSettings.IsEnabled = false; - orig(self, telePos); - } - - private static bool OverrideUnityPotionCheck(Terraria.On_Player.orig_HasUnityPotion orig, Player self) - { - // debug - var logger = ModContent.GetInstance().Logger; - //logger.Debug("has unity: " + Main.LocalPlayer.HasUnityPotion()); - //logger.Debug("is rtp menu enabled: " + "has unity: " + RTPSpawnSelectorSettings.IsEnabled()); - - if (RTPSpawnSelectorSettings.IsEnabled) - return true; - - return orig(self); - } -} - - //private void OverrideUnityPotionCheck(ILContext il) - //{ - // try - // { - // var c = new ILCursor(il); - - // if (c.TryGotoNext(i => i.MatchRet())) - // { - // c.Emit(OpCodes.Pop); - - // c.EmitDelegate>(() => - // { - // return RTPSpawnSelectorSettings.IsEnabled; - // }); - // } - // } - // catch (Exception e) - // { - // throw new ILPatchFailureException(Mod, il, e); - // } - //} diff --git a/Core/Helpers/Log.cs b/Core/Helpers/Log.cs new file mode 100644 index 00000000..856a1ff0 --- /dev/null +++ b/Core/Helpers/Log.cs @@ -0,0 +1,51 @@ +using System.IO; +using System.Runtime.CompilerServices; +using log4net; +using Terraria.ModLoader; + +namespace PvPAdventure.Core.Helpers; + +/// +/// A static logging helper for PvPAdventure. +/// Example usage: Log.Info("This is an info message."); +/// Example usage: Log.Warn("This is a warning message."); +/// +public static class Log +{ + public static ILog Base + { + get + { + var m = ModContent.GetInstance(); + return (m != null && m.Logger != null) ? m.Logger : LogManager.GetLogger("PvPAdventure"); + } + } + + public static void Info(object message, [CallerFilePath] string file = "") + => Base.Info($"[{Class(file)}] {message}"); + + public static void Debug(object message, [CallerFilePath] string file = "") + => Base.Debug($"[{Class(file)}] {message}"); + + public static void Warn(object message, [CallerFilePath] string file = "") + => Base.Warn($"[{Class(file)}] {message}"); + + public static void Error(object message, [CallerFilePath] string file = "") + => Base.Error($"[{Class(file)}] {message}"); + + public static Prefixed For() => new(Base, typeof(T).Name); + public static Prefixed ForCaller([CallerFilePath] string file = "") => new(Base, Class(file)); + + private static string Class(string file) => Path.GetFileNameWithoutExtension(file); + + public readonly struct Prefixed + { + private readonly ILog _log; + private readonly string _p; + public Prefixed(ILog log, string prefix) { _log = log; _p = prefix; } + public void Info(object m) => _log.Info($"[{_p}] {m}"); + public void Debug(object m) => _log.Debug($"[{_p}] {m}"); + public void Warn(object m) => _log.Warn($"[{_p}] {m}"); + public void Error(object m) => _log.Error($"[{_p}] {m}"); + } +} diff --git a/Localization/en-US.hjson b/Localization/en-US.hjson index 6bbee2b9..3534565a 100644 --- a/Localization/en-US.hjson +++ b/Localization/en-US.hjson @@ -780,6 +780,11 @@ Mods: { Tooltip: "" DisplayName: Adventure Mirror } + + AdventureMirror: { + DisplayName: Adventure Mirror + Tooltip: "" + } } } } diff --git a/System/DiscordIdentification.cs b/System/DiscordIdentification.cs index 4be689a1..47bb501f 100644 --- a/System/DiscordIdentification.cs +++ b/System/DiscordIdentification.cs @@ -15,7 +15,7 @@ namespace PvPAdventure.System; [Autoload(Side = ModSide.Both)] public class DiscordIdentification : ModSystem { - private const bool Enabled = true; + private const bool Enabled = false; public delegate void PlayerJoinEventHandler(DiscordIdentification source, PlayerJoinArgs args); From bc57e3d4f7a2511bf27e6b35ba0fa3458c05dba9 Mon Sep 17 00:00:00 2001 From: emyhrberg <121192176+emyhrberg@users.noreply.github.com> Date: Mon, 10 Nov 2025 22:24:01 +0100 Subject: [PATCH 153/206] Possible fixes to map bugs --- Content/Items/AdventureMirror.cs | 74 ++++++++++++++++++++++++++----- Core/Features/RTPFullscreenMap.cs | 6 +++ 2 files changed, 69 insertions(+), 11 deletions(-) diff --git a/Content/Items/AdventureMirror.cs b/Content/Items/AdventureMirror.cs index dc9a6597..88ae6d42 100644 --- a/Content/Items/AdventureMirror.cs +++ b/Content/Items/AdventureMirror.cs @@ -2,6 +2,7 @@ using Microsoft.Xna.Framework; using PvPAdventure.Core.Features; using PvPAdventure.Core.Helpers; +using System; using Terraria; using Terraria.ID; using Terraria.ModLoader; @@ -27,10 +28,10 @@ public override bool CanUseItem(Player player) Log.Debug("Adventure mirror used."); Log.Debug("is rtp menu enabled: " + RTPSpawnSelectorSettings.GetIsEnabled()); - for (int d = 0; d < 70; d++) - { - Dust.NewDust(player.position, player.width, player.height, DustID.MagicMirror, 0f, 0f, 150, default(Microsoft.Xna.Framework.Color), 1.5f); - } + //for (int d = 0; d < 70; d++) + //{ + // Dust.NewDust(player.position, player.width, player.height, DustID.MagicMirror, 0f, 0f, 150, default(Microsoft.Xna.Framework.Color), 1.5f); + //} return true; } @@ -51,25 +52,76 @@ public override void SetDefaults() Item.noUseGraphic = false; } - public override void HoldItem(Player player) + // public override void HoldItem(Player player) + // { + // if (player.itemAnimation == 1 && player.HeldItem.type == Item.type) + // { + // Log.Debug("Adventure mirror time is up, opening map!"); + + // // This is the last frame of use animation + // if (Main.myPlayer == player.whoAmI) + // { + // Main.mapFullscreen = true; + // RTPSpawnSelectorSettings.SetIsEnabled(true); + + // Log.Debug("Main.mapFullscreen set to: " + Main.mapFullscreen); + // } + // } + // } + + // UseStyle is called each frame that the item is being actively used. + public override void UseStyle(Player player, Rectangle heldItemFrame) { - if (player.itemAnimation == 1 && player.HeldItem.type == Item.type) + if (Main.rand.NextBool()) { - Log.Debug("Adventure mirror time is up, opening map!"); + SpawnMirrorDust(player); + } + + // debug + Main.NewText(player.itemTime); - // This is the last frame of use animation - if (Main.myPlayer == player.whoAmI) + // This sets up the itemTime correctly. + if (player.itemTime == 0) + { + player.ApplyItemTime(Item); + } + else if (player.itemTime <= 10) + { + if (!Main.mapFullscreen) { + Main.NewText("Opened RTP spawn options at <10 frames"); Main.mapFullscreen = true; + Main.resetMapFull = true; RTPSpawnSelectorSettings.SetIsEnabled(true); - - Log.Debug("Main.mapFullscreen set to: " + Main.mapFullscreen); } + + // This code releases all grappling hooks and kills/despawns them. + player.RemoveAllGrapplingHooks(); } } + private static void SpawnMirrorDust(Player player) + { + Dust.NewDust( + player.position, + player.width, + player.height, + DustID.MagicMirror, + player.velocity.X * 0.5f, + player.velocity.Y * 0.5f, + Alpha: 150, + newColor: default, + Scale: 1.5f + ); + } + public override void UpdateInventory(Player player) { + if (!Main.mapFullscreen) + { + RTPSpawnSelectorSettings.SetIsEnabled(false); + } + if (player.HeldItem.type == Item.type && player.itemAnimation > 0) { if (player.velocity.Length() > 0f) diff --git a/Core/Features/RTPFullscreenMap.cs b/Core/Features/RTPFullscreenMap.cs index 637b5259..460fd3c0 100644 --- a/Core/Features/RTPFullscreenMap.cs +++ b/Core/Features/RTPFullscreenMap.cs @@ -87,9 +87,15 @@ private void InjectMapDraw(Vector2 arg1, float arg2) Vector2 textPosition = new(Main.screenWidth / 2 - textSize.X / 2, 20f); Rectangle panelBounds = new((int)textPosition.X - 10, (int)textPosition.Y - 8, (int)textSize.X + 20, (int)textSize.Y + 12); + if (panelBounds.Contains(Main.mouseX, Main.mouseY)) + { + Main.NewText("Hovering TPVPA Panel"); + } + // Check if mouse clicked inside panel bounds if (Main.mouseLeft && Main.mouseLeftRelease && panelBounds.Contains(Main.mouseX, Main.mouseY)) { + Main.NewText("Clicked TPVPA Panel"); RandomTeleport(); // Close the map after teleporting From b944d8dbc1683774284fe24cd54ec2295232a308 Mon Sep 17 00:00:00 2001 From: emyhrberg <121192176+emyhrberg@users.noreply.github.com> Date: Tue, 11 Nov 2025 21:54:27 +0100 Subject: [PATCH 154/206] DONT KEEP YOUR INVENTORY OPEN --- Content/Items/AdventureMirror.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Content/Items/AdventureMirror.cs b/Content/Items/AdventureMirror.cs index 88ae6d42..0710827d 100644 --- a/Content/Items/AdventureMirror.cs +++ b/Content/Items/AdventureMirror.cs @@ -87,13 +87,14 @@ public override void UseStyle(Player player, Rectangle heldItemFrame) } else if (player.itemTime <= 10) { + Main.playerInventory = false; if (!Main.mapFullscreen) { Main.NewText("Opened RTP spawn options at <10 frames"); Main.mapFullscreen = true; Main.resetMapFull = true; - RTPSpawnSelectorSettings.SetIsEnabled(true); } + RTPSpawnSelectorSettings.SetIsEnabled(true); // This code releases all grappling hooks and kills/despawns them. player.RemoveAllGrapplingHooks(); @@ -119,7 +120,10 @@ public override void UpdateInventory(Player player) { if (!Main.mapFullscreen) { - RTPSpawnSelectorSettings.SetIsEnabled(false); + if (!RTPSpawnSelectorSettings.GetIsEnabled()) + { + RTPSpawnSelectorSettings.SetIsEnabled(false); + } } if (player.HeldItem.type == Item.type && player.itemAnimation > 0) From 85011ee6dada74d4788e93017cf6ab9ac097d91e Mon Sep 17 00:00:00 2001 From: emyhrberg <121192176+emyhrberg@users.noreply.github.com> Date: Tue, 11 Nov 2025 23:25:55 +0100 Subject: [PATCH 155/206] New UI --- Content/Items/AdventureMirror.cs | 41 +--- .../AdventureMirrorCountdownPlayer.cs} | 4 +- .../AdventureTeleportState.cs | 230 ++++++++++++++++++ .../AdventureTeleportStateSettings.cs} | 4 +- .../AdventureTeleportSystem.cs | 86 +++++++ .../AdventureTeleport/PlayerHeadElement.cs | 39 +++ .../Features/AdventureTeleport/UnityChecks.cs | 42 ++++ Core/Features/RTPFullscreenMap.cs | 149 ------------ Core/Features/UnityHooks.cs | 47 ---- 9 files changed, 409 insertions(+), 233 deletions(-) rename Core/Features/{RTPMirrorPlayer.cs => AdventureTeleport/AdventureMirrorCountdownPlayer.cs} (91%) create mode 100644 Core/Features/AdventureTeleport/AdventureTeleportState.cs rename Core/Features/{RTPSpawnSelectorSettings.cs => AdventureTeleport/AdventureTeleportStateSettings.cs} (60%) create mode 100644 Core/Features/AdventureTeleport/AdventureTeleportSystem.cs create mode 100644 Core/Features/AdventureTeleport/PlayerHeadElement.cs create mode 100644 Core/Features/AdventureTeleport/UnityChecks.cs delete mode 100644 Core/Features/RTPFullscreenMap.cs delete mode 100644 Core/Features/UnityHooks.cs diff --git a/Content/Items/AdventureMirror.cs b/Content/Items/AdventureMirror.cs index 0710827d..334c6896 100644 --- a/Content/Items/AdventureMirror.cs +++ b/Content/Items/AdventureMirror.cs @@ -1,12 +1,8 @@ -using Discord; -using Microsoft.Xna.Framework; -using PvPAdventure.Core.Features; -using PvPAdventure.Core.Helpers; -using System; +using Microsoft.Xna.Framework; +using PvPAdventure.Core.Features.AdventureTeleport; using Terraria; using Terraria.ID; using Terraria.ModLoader; -using static PvPAdventure.Core.Features.TeleportMapSystem; namespace PvPAdventure.Content.Items; @@ -25,9 +21,6 @@ public override bool CanUseItem(Player player) public override bool? UseItem(Player player) { - Log.Debug("Adventure mirror used."); - Log.Debug("is rtp menu enabled: " + RTPSpawnSelectorSettings.GetIsEnabled()); - //for (int d = 0; d < 70; d++) //{ // Dust.NewDust(player.position, player.width, player.height, DustID.MagicMirror, 0f, 0f, 150, default(Microsoft.Xna.Framework.Color), 1.5f); @@ -46,29 +39,12 @@ public override void SetDefaults() Item.useTime = recallFrames; Item.useAnimation = recallFrames; Item.useStyle = ItemUseStyleID.HoldUp; - Item.UseSound = SoundID.Item6; + Item.UseSound = SoundID.Item6; // MAGIC MIRROR SOUND Item.rare = ItemRarityID.Blue; Item.value = Item.buyPrice(gold: 5); Item.noUseGraphic = false; } - // public override void HoldItem(Player player) - // { - // if (player.itemAnimation == 1 && player.HeldItem.type == Item.type) - // { - // Log.Debug("Adventure mirror time is up, opening map!"); - - // // This is the last frame of use animation - // if (Main.myPlayer == player.whoAmI) - // { - // Main.mapFullscreen = true; - // RTPSpawnSelectorSettings.SetIsEnabled(true); - - // Log.Debug("Main.mapFullscreen set to: " + Main.mapFullscreen); - // } - // } - // } - // UseStyle is called each frame that the item is being actively used. public override void UseStyle(Player player, Rectangle heldItemFrame) { @@ -78,7 +54,7 @@ public override void UseStyle(Player player, Rectangle heldItemFrame) } // debug - Main.NewText(player.itemTime); + //Main.NewText(player.itemTime); // This sets up the itemTime correctly. if (player.itemTime == 0) @@ -90,11 +66,10 @@ public override void UseStyle(Player player, Rectangle heldItemFrame) Main.playerInventory = false; if (!Main.mapFullscreen) { - Main.NewText("Opened RTP spawn options at <10 frames"); Main.mapFullscreen = true; Main.resetMapFull = true; } - RTPSpawnSelectorSettings.SetIsEnabled(true); + AdventureTeleportStateSettings.SetIsEnabled(true); // This code releases all grappling hooks and kills/despawns them. player.RemoveAllGrapplingHooks(); @@ -120,9 +95,9 @@ public override void UpdateInventory(Player player) { if (!Main.mapFullscreen) { - if (!RTPSpawnSelectorSettings.GetIsEnabled()) + if (!AdventureTeleportStateSettings.GetIsEnabled()) { - RTPSpawnSelectorSettings.SetIsEnabled(false); + AdventureTeleportStateSettings.SetIsEnabled(false); } } @@ -135,7 +110,7 @@ public override void UpdateInventory(Player player) player.itemTime = 0; //SoundEngine.PlaySound(SoundID.MenuClose, player.position); - Log.Debug("cancelled RTP mirror"); + //Log.Debug("cancelled RTP mirror"); } } } diff --git a/Core/Features/RTPMirrorPlayer.cs b/Core/Features/AdventureTeleport/AdventureMirrorCountdownPlayer.cs similarity index 91% rename from Core/Features/RTPMirrorPlayer.cs rename to Core/Features/AdventureTeleport/AdventureMirrorCountdownPlayer.cs index ee82867c..773087d6 100644 --- a/Core/Features/RTPMirrorPlayer.cs +++ b/Core/Features/AdventureTeleport/AdventureMirrorCountdownPlayer.cs @@ -3,9 +3,9 @@ using Terraria; using Terraria.ModLoader; -namespace PvPAdventure.Core.Features +namespace PvPAdventure.Core.Features.AdventureTeleport { - public class RTPMirrorPlayer : ModPlayer + public class AdventureMirrorCountdownPlayer : ModPlayer { public override void PostUpdate() { diff --git a/Core/Features/AdventureTeleport/AdventureTeleportState.cs b/Core/Features/AdventureTeleport/AdventureTeleportState.cs new file mode 100644 index 00000000..858ebea7 --- /dev/null +++ b/Core/Features/AdventureTeleport/AdventureTeleportState.cs @@ -0,0 +1,230 @@ +using Microsoft.Xna.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using Terraria; +using Terraria.Audio; +using Terraria.GameContent.UI.Elements; +using Terraria.ID; +using Terraria.UI; + +namespace PvPAdventure.Core.Features.AdventureTeleport; + +public class AdventureTeleportState : UIState +{ + private UIPanel _panel; + private UIText _title; + private UITextPanel _btnRandom; + private UITextPanel _btnTeammates; + private UITextPanel _btnBeds; + + public bool IsMouseOverUI { get; private set; } + + // Team menu + private UIList _teammateList; + private bool _teammatesOpen; + private int _selectedPlayerId = -1; + + private const float RowHeight = 28f; + private const float RowPadding = 4f; + private const float ListTop = 146f; + private const float PanelInnerPadding = 10f; // left/right padding inside _panel + + public override void OnInitialize() + { + _panel = new UIPanel(); + _panel.Width.Set(420f, 0f); + _panel.Height.Set(180f, 0f); + _panel.Top.Set(20f, 0f); + _panel.HAlign = 0.5f; + Append(_panel); + + _title = new UIText("PvP Adventure Teleport"); + _title.HAlign = 0.5f; + _title.Top.Set(8f, 0f); + _panel.Append(_title); + + _btnRandom = MakeButton("Random Teleport", 44f); + _btnRandom.OnLeftClick += (_, __) => RequestRandomTeleport(); + + _btnTeammates = MakeButton("Teleport to Teammate", 78f); + _btnTeammates.OnLeftClick += (_, __) => ToggleTeammatesMenu(); + + _btnBeds = MakeButton("Teleport to Bed", 112f); + _btnBeds.OnLeftClick += (_, __) => OpenBedsMenu(); + + _panel.Append(_btnRandom); + _panel.Append(_btnTeammates); + _panel.Append(_btnBeds); + } + + private UITextPanel MakeButton(string label, float top) + { + var b = new UITextPanel(label, 0.9f, large: false); + b.Width.Set(-20f, 1f); + b.Left.Set(10f, 0f); + b.Top.Set(top, 0f); + b.BackgroundColor = new Color(63, 82, 151) * 0.8f; + b.BorderColor = new Color(89, 116, 213) * 0.8f; + b.OnMouseOver += (evt, element) => b.BackgroundColor = new Color(73, 92, 161); + b.OnMouseOut += (evt, element) => b.BackgroundColor = new Color(63, 82, 151) * 0.8f; + return b; + } + + public override void Update(GameTime gameTime) + { + base.Update(gameTime); + + // Update mouse over state + IsMouseOverUI = _panel.IsMouseHovering + || _btnRandom.IsMouseHovering + || _btnTeammates.IsMouseHovering + || _btnBeds.IsMouseHovering + || (_teammateList?.IsMouseHovering ?? false); + } + + private void RequestRandomTeleport() + { + SoundEngine.PlaySound(SoundID.Item6); // MAGIC MIRROR SOUND + + if (Main.netMode == NetmodeID.MultiplayerClient) + { + NetMessage.SendData(MessageID.RequestTeleportationByServer); + } + else + { + Main.LocalPlayer.TeleportationPotion(); + } + + CloseAndExitMap(); + } + + private void ToggleTeammatesMenu() + { + _teammatesOpen = !_teammatesOpen; + + // Remove previous list if exists + _teammateList?.Remove(); + _teammateList = null; + + // If closing, restore compact panel height and reset Beds button + if (!_teammatesOpen) + { + _panel.Height.Set(180f, 0f); + _btnBeds.Top.Set(112f, 0f); + _btnBeds.Recalculate(); + SoundEngine.PlaySound(SoundID.MenuClose); + return; + } + SoundEngine.PlaySound(SoundID.MenuOpen); + + // Build a list + _teammateList = new UIList + { + ListPadding = RowPadding, + OverflowHidden = true + }; + _teammateList.Left.Set(PanelInnerPadding, 0f); + _teammateList.Top.Set(ListTop-RowHeight, 0f); + _teammateList.Width.Set(-PanelInnerPadding * 2f, 1f); // fill width minus padding + _panel.Append(_teammateList); + + // Gather teammates on same team (excluding self) + int myId = Main.myPlayer; + var me = Main.player[myId]; + int myTeam = me.team; + + var teammates = new List(); + if (myTeam != 0) + { + for (int i = 0; i < Main.maxPlayers; i++) + { + var p = Main.player[i]; + if (p != null && p.active && i != myId && p.team == myTeam) + teammates.Add(p); + } + } + + // If none, show yourself as a single entry instead + if (teammates.Count == 0) + { + _teammateList.Add(MakeTeammateRow(me, isSelf: true)); + } + else + { + foreach (var p in teammates) + _teammateList.Add(MakeTeammateRow(p, isSelf: false)); + } + + int rowCount = Math.Max(1, teammates.Count); + float listHeight = rowCount * RowHeight + (rowCount - 1) * RowPadding + 6f; + + _teammateList.Height.Set(listHeight, 0f); + _teammateList.Recalculate(); + + // Beds button just below list + float bedsTop = ListTop + listHeight + 8f; + _btnBeds.Top.Set(bedsTop, 0f); + _btnBeds.Recalculate(); + } + + private UIElement MakeTeammateRow(Player p, bool isSelf) + { + var row = new UIElement { OverflowHidden = true }; + row.OnMouseOver += (_, _) => { SoundEngine.PlaySound(SoundID.MenuTick); }; + row.Width.Set(0f, 1f); + row.Height.Set(RowHeight, 0f); + + var bg = new UIPanel(); + bg.Left.Set(0f, 0f); + bg.Top.Set(0f, 0f); + bg.Width.Set(0f, 1f); + bg.Height.Set(RowHeight, 0f); + bg.PaddingTop = bg.PaddingLeft = bg.PaddingRight = bg.PaddingBottom = 0; + bg.BackgroundColor = new Color(63, 82, 151) * 0.65f; + bg.BorderColor = new Color(89, 116, 213) * 0.90f; + + // 24x24 head at left + var head = new PlayerHeadElement(p, isSelf); + head.Left.Set(2f, 0f); + head.Top.Set(0f, 0f); // 2px padding inside 28px row + bg.Append(head); + + // Name text + var name = new UIText(isSelf ? $"You ({p?.name ?? "Player"})" : (p?.name ?? "Player"), 0.9f); + name.Left.Set(36, 0f); + name.Top.Set(5f, 0f); + name.TextColor = Color.White; + + row.OnMouseOver += (_, __) => { name.TextColor = Color.Yellow; }; + row.OnMouseOut += (_, __) => { name.TextColor = Color.White; }; + + row.OnLeftClick += (_, __) => + { + if (isSelf) + { + CloseAndExitMap(); + return; + } + if (p == null) return; + + Main.LocalPlayer.UnityTeleport(p.Center); + CloseAndExitMap(); + }; + + bg.Append(name); + row.Append(bg); + return row; + } + + private void OpenBedsMenu() + { + Main.NewText("Bed menu is still in construction (WIP)!"); + } + + private void CloseAndExitMap() + { + Main.mapFullscreen = false; + AdventureTeleportStateSettings.SetIsEnabled(false); + } +} diff --git a/Core/Features/RTPSpawnSelectorSettings.cs b/Core/Features/AdventureTeleport/AdventureTeleportStateSettings.cs similarity index 60% rename from Core/Features/RTPSpawnSelectorSettings.cs rename to Core/Features/AdventureTeleport/AdventureTeleportStateSettings.cs index f45f841c..325c5754 100644 --- a/Core/Features/RTPSpawnSelectorSettings.cs +++ b/Core/Features/AdventureTeleport/AdventureTeleportStateSettings.cs @@ -1,6 +1,6 @@ -namespace PvPAdventure.Core.Features; +namespace PvPAdventure.Core.Features.AdventureTeleport; -public static class RTPSpawnSelectorSettings +public static class AdventureTeleportStateSettings { private static bool IsEnabled = false; diff --git a/Core/Features/AdventureTeleport/AdventureTeleportSystem.cs b/Core/Features/AdventureTeleport/AdventureTeleportSystem.cs new file mode 100644 index 00000000..ea839904 --- /dev/null +++ b/Core/Features/AdventureTeleport/AdventureTeleportSystem.cs @@ -0,0 +1,86 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using Terraria; +using Terraria.ModLoader; +using Terraria.UI; + +namespace PvPAdventure.Core.Features.AdventureTeleport; + +[Autoload(Side = ModSide.Client)] +public class AdventureTeleportSystem : ModSystem +{ + private UserInterface ui; + internal AdventureTeleportState adventureTeleportState; + + public override void Load() + { + if (!Main.dedServ) + { + ui = new UserInterface(); + adventureTeleportState = new AdventureTeleportState(); + adventureTeleportState.Activate(); + + Main.OnPostFullscreenMapDraw += DrawOverFullscreenMap; + } + } + + public override void Unload() + { + if (!Main.dedServ) + Main.OnPostFullscreenMapDraw -= DrawOverFullscreenMap; + } + + public override void UpdateUI(GameTime gameTime) + { + if (ui == null) return; + + bool visible = AdventureTeleportStateSettings.GetIsEnabled() && Main.mapFullscreen; + + if (visible) + { + if (ui.CurrentState != adventureTeleportState) + ui.SetState(adventureTeleportState); + + ui.Update(gameTime); + + if (adventureTeleportState.IsMouseOverUI) + Main.LocalPlayer.mouseInterface = true; + } + else if (ui.CurrentState != null) + { + ui.SetState(null); + } + } + + // Draw AFTER the map, with our own Begin/End for UI + private void DrawOverFullscreenMap(Vector2 _mapPos, float _mapScale) + { + if (ui?.CurrentState == null) return; + + var sb = Main.spriteBatch; + bool began = false; + + try + { + sb.Begin( + SpriteSortMode.Deferred, + BlendState.AlphaBlend, + SamplerState.LinearClamp, + DepthStencilState.None, + RasterizerState.CullCounterClockwise, + effect: null, + transformMatrix: Main.UIScaleMatrix + ); + began = true; + + // draw our UI state over the fullscreen map + ui.Draw(sb, Main._drawInterfaceGameTime); + } + finally + { + if (began) + sb.End(); + } + } + +} diff --git a/Core/Features/AdventureTeleport/PlayerHeadElement.cs b/Core/Features/AdventureTeleport/PlayerHeadElement.cs new file mode 100644 index 00000000..c0db038d --- /dev/null +++ b/Core/Features/AdventureTeleport/PlayerHeadElement.cs @@ -0,0 +1,39 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Terraria; +using Terraria.UI; + +namespace PvPAdventure.Core.Features.AdventureTeleport; + +public class PlayerHeadElement : UIElement +{ + private readonly Player player; + private readonly bool isSelf; + + public PlayerHeadElement(Player player, bool isSelf) + { + this.player = player; + this.isSelf = isSelf; + Width.Set(24f, 0f); + Height.Set(24f, 0f); + } + + protected override void DrawSelf(SpriteBatch spriteBatch) + { + // Only draw if we have a player + if (player == null || !player.active) return; + + // Where to draw (top-left of this element) + var dims = GetDimensions(); + Vector2 pos = new Vector2(dims.X + dims.Width * 0.5f, dims.Y + dims.Height * 0.5f); // center on the element + float scale = 0.75f; + float alpha = 1f; + Main.MapPlayerRenderer.DrawPlayerHead( + Main.Camera, player, pos, alpha, scale, Color.White); + } +} diff --git a/Core/Features/AdventureTeleport/UnityChecks.cs b/Core/Features/AdventureTeleport/UnityChecks.cs new file mode 100644 index 00000000..439bc0b7 --- /dev/null +++ b/Core/Features/AdventureTeleport/UnityChecks.cs @@ -0,0 +1,42 @@ +using Microsoft.Xna.Framework; +using System; +using Terraria; +using Terraria.ModLoader; + +namespace PvPAdventure.Core.Features.AdventureTeleport; + +public class UnityChecks : ModSystem +{ + public override void Load() + { + Main.QueueMainThreadAction(() => + { + On_Player.HasUnityPotion += OverrideUnityPotionCheck; + //On_Player.UnityTeleport += DisableRTPMenuAfterTeleport; + }); + } + + public override void Unload() + { + Main.QueueMainThreadAction(() => + { + On_Player.HasUnityPotion -= OverrideUnityPotionCheck; + //On_Player.UnityTeleport -= DisableRTPMenuAfterTeleport; + }); + } + + [Obsolete("This method is redundant since we always set this variable to false whenever map is closed.")] + private void DisableRTPMenuAfterTeleport(On_Player.orig_UnityTeleport orig, Player self, Vector2 telePos) + { + AdventureTeleportStateSettings.SetIsEnabled(false); + orig(self, telePos); + } + + private static bool OverrideUnityPotionCheck(On_Player.orig_HasUnityPotion orig, Player self) + { + if (AdventureTeleportStateSettings.GetIsEnabled()) + return true; + + return orig(self); + } +} diff --git a/Core/Features/RTPFullscreenMap.cs b/Core/Features/RTPFullscreenMap.cs deleted file mode 100644 index 460fd3c0..00000000 --- a/Core/Features/RTPFullscreenMap.cs +++ /dev/null @@ -1,149 +0,0 @@ -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Graphics; -using System; -using Terraria; -using Terraria.GameContent; -using Terraria.ID; -using Terraria.ModLoader; - -namespace PvPAdventure.Core.Features; - -public class TeleportMapSystem : ModSystem -{ - public override void Load() - { - Main.QueueMainThreadAction(() => - { - Main.OnPostFullscreenMapDraw += InjectMapDraw; - }); - } - - public override void Unload() - { - Main.QueueMainThreadAction(() => - { - Main.OnPostFullscreenMapDraw -= InjectMapDraw; - }); - } - - public override void PostDrawFullscreenMap(ref string mouseText) - { - if (!RTPSpawnSelectorSettings.GetIsEnabled()) - return; - - string teleportText = "" + - "PvP Adventure Teleport Options \n" + - "1. Click here to random teleport \n" + - "2. Click teammate to teleport \n" + - "(Upcoming) Click team bed to teleport"; - - // Load panel - Texture2D panelTexture = Main.Assets.Request("Images/UI/PanelBackground").Value; - int cornerSize = 12; - int barSize = 4; - Color panelColor = new Color(63, 82, 151) * 0.7f; - - // Panel bounds - Vector2 textSize = FontAssets.MouseText.Value.MeasureString(teleportText); - Vector2 textPosition = new(Main.screenWidth / 2 - textSize.X / 2, 20f); - Rectangle panelBounds = new((int)textPosition.X - 10, (int)textPosition.Y - 8, (int)textSize.X + 20, (int)textSize.Y + 12); - - // Check if mouse is hovering - bool isHovering = panelBounds.Contains(Main.mouseX, Main.mouseY); - Color textColor = isHovering ? Color.Yellow : Color.White; - - // Draw panel - DrawPanel(Main.spriteBatch, panelBounds, panelTexture, cornerSize, barSize, panelColor); - - // Draw text with hover color - Utils.DrawBorderString(Main.spriteBatch, teleportText, textPosition, textColor); - - // set mouseText to show tooltip - if (isHovering) - { - mouseText = "Click to teleport"; - } - } - - private static void RandomTeleport() - { - if (Main.netMode == NetmodeID.SinglePlayer) - Main.LocalPlayer.TeleportationPotion(); - else - NetMessage.SendData(MessageID.RequestTeleportationByServer); - } - - /// - /// Main functionality for teleporting. - /// Executed every frame. - /// - private void InjectMapDraw(Vector2 arg1, float arg2) - { - if (!RTPSpawnSelectorSettings.GetIsEnabled()) - return; - - string teleportText = "PvP Adventure Teleport Options\n1. Click here to random teleport\n2. Click teammate to teleport\n3. (Future) Click team bed to teleport"; - Vector2 textSize = FontAssets.MouseText.Value.MeasureString(teleportText); - Vector2 textPosition = new(Main.screenWidth / 2 - textSize.X / 2, 20f); - Rectangle panelBounds = new((int)textPosition.X - 10, (int)textPosition.Y - 8, (int)textSize.X + 20, (int)textSize.Y + 12); - - if (panelBounds.Contains(Main.mouseX, Main.mouseY)) - { - Main.NewText("Hovering TPVPA Panel"); - } - - // Check if mouse clicked inside panel bounds - if (Main.mouseLeft && Main.mouseLeftRelease && panelBounds.Contains(Main.mouseX, Main.mouseY)) - { - Main.NewText("Clicked TPVPA Panel"); - RandomTeleport(); - - // Close the map after teleporting - Main.mapFullscreen = false; - RTPSpawnSelectorSettings.SetIsEnabled(false); - } - } - - /// - /// Helper to draw a blue panel - /// - private void DrawPanel(SpriteBatch spriteBatch, Rectangle bounds, Texture2D texture, int cornerSize, int barSize, Color color) - { - Point point = bounds.Location; - Point point2 = new Point(bounds.Right - cornerSize, bounds.Bottom - cornerSize); - int width = bounds.Width - cornerSize * 2; - int height = bounds.Height - cornerSize * 2; - - // Corners - spriteBatch.Draw(texture, new Rectangle(point.X, point.Y, cornerSize, cornerSize), new Rectangle(0, 0, cornerSize, cornerSize), color); - spriteBatch.Draw(texture, new Rectangle(point2.X, point.Y, cornerSize, cornerSize), new Rectangle(cornerSize + barSize, 0, cornerSize, cornerSize), color); - spriteBatch.Draw(texture, new Rectangle(point.X, point2.Y, cornerSize, cornerSize), new Rectangle(0, cornerSize + barSize, cornerSize, cornerSize), color); - spriteBatch.Draw(texture, new Rectangle(point2.X, point2.Y, cornerSize, cornerSize), new Rectangle(cornerSize + barSize, cornerSize + barSize, cornerSize, cornerSize), color); - - // Edges - spriteBatch.Draw(texture, new Rectangle(point.X + cornerSize, point.Y, width, cornerSize), new Rectangle(cornerSize, 0, barSize, cornerSize), color); - spriteBatch.Draw(texture, new Rectangle(point.X + cornerSize, point2.Y, width, cornerSize), new Rectangle(cornerSize, cornerSize + barSize, barSize, cornerSize), color); - spriteBatch.Draw(texture, new Rectangle(point.X, point.Y + cornerSize, cornerSize, height), new Rectangle(0, cornerSize, cornerSize, barSize), color); - spriteBatch.Draw(texture, new Rectangle(point2.X, point.Y + cornerSize, cornerSize, height), new Rectangle(cornerSize + barSize, cornerSize, cornerSize, barSize), color); - - // Center - spriteBatch.Draw(texture, new Rectangle(point.X + cornerSize, point.Y + cornerSize, width, height), new Rectangle(cornerSize, cornerSize, barSize, barSize), color); - } - - [Obsolete("Used for teleporting to the mouse cursor position, not useful in this case")] - private void obsolete_TP_to_cursor() - { - Vector2 screenSize = new Vector2(Main.screenWidth, Main.screenHeight) * Main.UIScale; - Vector2 target = ((Main.MouseScreen - screenSize / 2) / 16 * (16 / Main.mapFullscreenScale) + Main.mapFullscreenPos) * 16; - - if (WorldGen.InWorld((int)target.X / 16, (int)target.Y / 16)) - { - Main.LocalPlayer.Center = target; - Main.LocalPlayer.fallStart = (int)Main.LocalPlayer.position.Y; - } - else - { - //Log.Info("Error: outside world bounds when trying to teleport"); - } - } -} \ No newline at end of file diff --git a/Core/Features/UnityHooks.cs b/Core/Features/UnityHooks.cs deleted file mode 100644 index a389aee6..00000000 --- a/Core/Features/UnityHooks.cs +++ /dev/null @@ -1,47 +0,0 @@ -using Microsoft.Xna.Framework; -using PvPAdventure.Core.Helpers; -using Terraria; -using Terraria.ModLoader; - -namespace PvPAdventure.Core.Features; - -public class UnityHooks : ModSystem -{ - public override void Load() - { - Main.QueueMainThreadAction(() => - { - On_Player.HasUnityPotion += OverrideUnityPotionCheck; - On_Player.UnityTeleport += DisableRTPMenuAfterTeleport; - }); - } - - public override void Unload() - { - Main.QueueMainThreadAction(() => - { - On_Player.HasUnityPotion -= OverrideUnityPotionCheck; - On_Player.UnityTeleport -= DisableRTPMenuAfterTeleport; - }); - } - - private void DisableRTPMenuAfterTeleport(On_Player.orig_UnityTeleport orig, Player self, Vector2 telePos) - { - // this method does what it says - RTPSpawnSelectorSettings.SetIsEnabled(false); - Log.Debug("Unity teleport detected, disabling RTP menu."); - orig(self, telePos); - } - - private static bool OverrideUnityPotionCheck(Terraria.On_Player.orig_HasUnityPotion orig, Player self) - { - // debug - Log.Debug("has unity: " + Main.LocalPlayer.HasUnityPotion()); - Log.Debug("is rtp menu enabled: " + RTPSpawnSelectorSettings.GetIsEnabled()); - - if (RTPSpawnSelectorSettings.GetIsEnabled()) - return true; - - return orig(self); - } -} From ba3d466eb799b00e54c7c0dec4faeb7d1e6c67c4 Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Wed, 12 Nov 2025 16:32:56 -0800 Subject: [PATCH 156/206] Mech soul --- AdventureDropDatabase.cs | 23 ++-- AdventurePlayer.cs | 63 +++++++---- AdventureProjectile.cs | 235 +++++++++++++++++++++++++++++++++++++++ Localization/en-US.hjson | 10 +- 4 files changed, 297 insertions(+), 34 deletions(-) diff --git a/AdventureDropDatabase.cs b/AdventureDropDatabase.cs index b0b3b4b1..b33fe0dc 100644 --- a/AdventureDropDatabase.cs +++ b/AdventureDropDatabase.cs @@ -430,6 +430,10 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) (drop is CommonDrop commonDrop && commonDrop.itemId == ItemID.HallowedBar)); npcLoot.Add(ItemDropRule.Common(ItemID.HallowedBar, 1, 18, 30)); + // Remove existing soul drops + npcLoot.RemoveWhere(drop => + (drop is CommonDrop commonDrop && commonDrop.itemId == ItemID.SoulofMight)); + npcLoot.Add(ItemDropRule.Common(ItemID.SoulofMight, 1, 31, 31)); break; case NPCID.SkeletronPrime: @@ -437,17 +441,22 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) (drop is CommonDrop commonDrop && commonDrop.itemId == ItemID.HallowedBar)); npcLoot.Add(ItemDropRule.Common(ItemID.HallowedBar, 1, 18, 30)); + npcLoot.RemoveWhere(drop => + (drop is CommonDrop commonDrop && commonDrop.itemId == ItemID.SoulofFright)); + npcLoot.Add(ItemDropRule.Common(ItemID.SoulofFright, 1, 31, 31)); break; - case NPCID.Retinazer or NPCID.Spazmatism: - { - npcLoot.RemoveWhere(drop => (drop is CommonDrop commonDrop && commonDrop.itemId == ItemID.HallowedBar)); + case NPCID.Retinazer: + case NPCID.Spazmatism: + npcLoot.RemoveWhere(rule => true); - LeadingConditionRule noTwin = new(new Conditions.MissingTwin()); - npcLoot.Add(noTwin); + npcLoot.Add(ItemDropRule.ByCondition( + new Conditions.LegacyHack_IsBossAndNotExpert(), + ItemID.HallowedBar, 1, 18, 30)); - noTwin.OnSuccess(ItemDropRule.Common(ItemID.HallowedBar, 1, 3, 3)); - } + npcLoot.Add(ItemDropRule.ByCondition( + new Conditions.LegacyHack_IsBossAndNotExpert(), + ItemID.SoulofSight, 1, 31, 31)); break; case NPCID.Plantera: diff --git a/AdventurePlayer.cs b/AdventurePlayer.cs index 1a796f97..ffd0bdd2 100644 --- a/AdventurePlayer.cs +++ b/AdventurePlayer.cs @@ -1332,7 +1332,7 @@ public override void PostUpdateEquips() // For BitingEmbracePlayer: public class BitingEmbracePlayer : ModPlayer { - public int bitingEmbraceApplierIndex = -1; // Track who applied the debuff + public int bitingEmbraceApplierIndex = -1; public override void PostHurt(Player.HurtInfo info) { @@ -1363,7 +1363,6 @@ public override void PostHurt(Player.HurtInfo info) public override void PostUpdateBuffs() { - // Check if applier died - remove buff if so if (Player.HasBuff() && bitingEmbraceApplierIndex >= 0 && bitingEmbraceApplierIndex < Main.maxPlayers) { Player applier = Main.player[bitingEmbraceApplierIndex]; @@ -1423,7 +1422,7 @@ public override void PostUpdateBuffs() } else { - bitingEmbraceApplierIndex = -1; // Reset when buff expires + bitingEmbraceApplierIndex = -1; } } @@ -1431,6 +1430,9 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) { if (Player.HasBuff()) { + // Check if the current attacker is the same player who applied the debuff + bool isDebuffApplier = modifiers.DamageSource.SourcePlayerIndex == bitingEmbraceApplierIndex; + bool isSummon = false; if (modifiers.DamageSource.SourceProjectileLocalIndex >= 0) { @@ -1452,7 +1454,9 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) isSummon = true; } } - if (!isSummon) + + // Only apply bonus if NOT from summon/whip AND NOT from the debuff applier + if (!isSummon && !isDebuffApplier) { modifiers.ModifyHurtInfo += (ref Player.HurtInfo info) => { info.Damage += 6; @@ -1462,7 +1466,6 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) } } -// For PressurePointsPlayer: public class PressurePointsPlayer : ModPlayer { public int pressurePointsApplierIndex = -1; @@ -1495,7 +1498,6 @@ public override void PostHurt(Player.HurtInfo info) public override void PostUpdateBuffs() { - // Check if applier died - remove buff if so if (Player.HasBuff() && pressurePointsApplierIndex >= 0 && pressurePointsApplierIndex < Main.maxPlayers) { Player applier = Main.player[pressurePointsApplierIndex]; @@ -1562,6 +1564,9 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) { if (Player.HasBuff()) { + // Check if the current attacker is the same player who applied the debuff + bool isDebuffApplier = modifiers.DamageSource.SourcePlayerIndex == pressurePointsApplierIndex; + bool isSummon = false; if (modifiers.DamageSource.SourceProjectileLocalIndex >= 0) @@ -1585,7 +1590,8 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) } } - if (!isSummon) + // Only apply bonus if NOT from summon/whip AND NOT from the debuff applier + if (!isSummon && !isDebuffApplier) { modifiers.ModifyHurtInfo += (ref Player.HurtInfo info) => { info.Damage += 6; @@ -1595,7 +1601,6 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) } } -// For BrittleBonesPlayer: public class BrittleBonesPlayer : ModPlayer { public int brittleBonesApplierIndex = -1; @@ -1628,7 +1633,6 @@ public override void PostHurt(Player.HurtInfo info) public override void PostUpdateBuffs() { - // Check if applier died - remove buff if so if (Player.HasBuff() && brittleBonesApplierIndex >= 0 && brittleBonesApplierIndex < Main.maxPlayers) { Player applier = Main.player[brittleBonesApplierIndex]; @@ -1695,6 +1699,9 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) { if (Player.HasBuff()) { + // Check if the current attacker is the same player who applied the debuff + bool isDebuffApplier = modifiers.DamageSource.SourcePlayerIndex == brittleBonesApplierIndex; + bool isSummon = false; if (modifiers.DamageSource.SourceProjectileLocalIndex >= 0) @@ -1718,7 +1725,8 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) } } - if (!isSummon) + // Only apply bonus if NOT from summon/whip AND NOT from the debuff applier + if (!isSummon && !isDebuffApplier) { modifiers.ModifyHurtInfo += (ref Player.HurtInfo info) => { info.Damage += 7; @@ -1728,7 +1736,6 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) } } -// For MarkedPlayer: public class MarkedPlayer : ModPlayer { public int markedApplierIndex = -1; @@ -1761,7 +1768,6 @@ public override void PostHurt(Player.HurtInfo info) public override void PostUpdateBuffs() { - // Check if applier died - remove buff if so if (Player.HasBuff() && markedApplierIndex >= 0 && markedApplierIndex < Main.maxPlayers) { Player applier = Main.player[markedApplierIndex]; @@ -1828,6 +1834,9 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) { if (Player.HasBuff()) { + // Check if the current attacker is the same player who applied the debuff + bool isDebuffApplier = modifiers.DamageSource.SourcePlayerIndex == markedApplierIndex; + bool isSummon = false; if (modifiers.DamageSource.SourceProjectileLocalIndex >= 0) @@ -1851,7 +1860,8 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) } } - if (!isSummon) + // Only apply bonus if NOT from summon/whip AND NOT from the debuff applier + if (!isSummon && !isDebuffApplier) { modifiers.ModifyHurtInfo += (ref Player.HurtInfo info) => { info.Damage += 9; @@ -1861,7 +1871,6 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) } } -// For AnathemaPlayer: public class AnathemaPlayer : ModPlayer { public int anathemaApplierIndex = -1; @@ -1894,7 +1903,6 @@ public override void PostHurt(Player.HurtInfo info) public override void PostUpdateBuffs() { - // Check if applier died - remove buff if so if (Player.HasBuff() && anathemaApplierIndex >= 0 && anathemaApplierIndex < Main.maxPlayers) { Player applier = Main.player[anathemaApplierIndex]; @@ -1956,6 +1964,9 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) { if (Player.HasBuff()) { + // Check if the current attacker is the same player who applied the debuff + bool isDebuffApplier = modifiers.DamageSource.SourcePlayerIndex == anathemaApplierIndex; + bool isSummon = false; if (modifiers.DamageSource.SourceProjectileLocalIndex >= 0) @@ -1979,7 +1990,8 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) } } - if (!isSummon) + // Only apply bonus if NOT from summon/whip AND NOT from the debuff applier + if (!isSummon && !isDebuffApplier) { modifiers.ModifyHurtInfo += (ref Player.HurtInfo info) => { info.Damage += 20; @@ -1990,7 +2002,6 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) } } -// For ShatteredArmorPlayer: public class ShatteredArmorPlayer : ModPlayer { public int shatteredArmorApplierIndex = -1; @@ -2023,7 +2034,6 @@ public override void PostHurt(Player.HurtInfo info) public override void PostUpdateBuffs() { - // Check if applier died - remove buff if so if (Player.HasBuff() && shatteredArmorApplierIndex >= 0 && shatteredArmorApplierIndex < Main.maxPlayers) { Player applier = Main.player[shatteredArmorApplierIndex]; @@ -2062,6 +2072,9 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) { if (Player.HasBuff()) { + // Check if the current attacker is the same player who applied the debuff + bool isDebuffApplier = modifiers.DamageSource.SourcePlayerIndex == shatteredArmorApplierIndex; + bool isSummon = false; if (modifiers.DamageSource.SourceProjectileLocalIndex >= 0) @@ -2085,7 +2098,8 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) } } - if (!isSummon) + // Only apply bonus if NOT from summon/whip AND NOT from the debuff applier + if (!isSummon && !isDebuffApplier) { modifiers.ModifyHurtInfo += (ref Player.HurtInfo info) => { info.Damage += 8; @@ -2198,8 +2212,11 @@ public override bool PreKill(double damage, int hitDirection, bool pvp, ref bool if (Player.HasBuff()) { bool isSummon = IsSummonOrWhipDeath(damageSource); + // Check if killed by the debuff applier + bool isDebuffApplier = damageSource.SourcePlayerIndex == hellhexApplierIndex; - if (!isSummon && damage >= 30) + // Only spawn explosion if NOT from summon/whip AND NOT from the debuff applier + if (!isSummon && !isDebuffApplier && damage >= 30) { // Only spawn on server or singleplayer if (Main.netMode != NetmodeID.MultiplayerClient) @@ -2280,9 +2297,11 @@ public override void PostHurt(Player.HurtInfo info) if (Player.HasBuff() && !explosionSpawned) { bool isSummon = IsSummonOrWhipDamage(info); + // Check if hit by the debuff applier + bool isDebuffApplier = info.DamageSource.SourcePlayerIndex == hellhexApplierIndex; - // Only trigger if damage >= 30 and not summon/whip damage - if (!isSummon && info.Damage >= 30) + // Only trigger if damage >= 30 and NOT summon/whip AND NOT from the debuff applier + if (!isSummon && !isDebuffApplier && info.Damage >= 30) { explosionSpawned = true; // Mark that explosion is being spawned diff --git a/AdventureProjectile.cs b/AdventureProjectile.cs index e7525d9d..842155a4 100644 --- a/AdventureProjectile.cs +++ b/AdventureProjectile.cs @@ -1,3 +1,4 @@ +using System.IO; using Microsoft.Xna.Framework; using MonoMod.Cil; using PvPAdventure.System; @@ -6,6 +7,7 @@ using Terraria.Enums; using Terraria.ID; using Terraria.ModLoader; +using Terraria.ModLoader.IO; namespace PvPAdventure; @@ -786,5 +788,238 @@ public override void ModifyHitPlayer(Projectile projectile, Player target, ref P modifiers.SourceDamage *= 0.75f; } } + public class PiranhaGunPvPSystem : GlobalProjectile + { + public override bool InstancePerEntity => true; + + public int attachedPlayerIndex = -1; + private Vector2 attachOffset = Vector2.Zero; + + public override bool AppliesToEntity(Projectile entity, bool lateInstantiation) + { + return entity.type == ProjectileID.MechanicalPiranha; + } + + public override void SetDefaults(Projectile projectile) + { + // Enable player collision for PvP + projectile.friendly = true; + } + + public override void AI(Projectile projectile) + { + // Manual collision check with players if not attached + if (attachedPlayerIndex < 0) + { + Player owner = Main.player[projectile.owner]; + if (!owner.hostile) + return; + + // Check collision with hostile players + for (int i = 0; i < Main.maxPlayers; i++) + { + if (i == projectile.owner) + continue; + + Player target = Main.player[i]; + if (target.active && !target.dead && target.hostile && target.team != owner.team) + { + Rectangle projHitbox = new Rectangle((int)projectile.position.X, (int)projectile.position.Y, + projectile.width, projectile.height); + Rectangle playerHitbox = new Rectangle((int)target.position.X, (int)target.position.Y, + target.width, target.height); + + if (projHitbox.Intersects(playerHitbox)) + { + // Latch onto the player + attachedPlayerIndex = target.whoAmI; + attachOffset = projectile.Center - target.Center; + projectile.ai[0] = 1f; + projectile.ai[1] = target.whoAmI; + projectile.netUpdate = true; + + // Deal initial hit damage + if (Main.myPlayer == projectile.owner) + { + int hitDirection = (target.Center.X > owner.Center.X) ? 1 : -1; + target.Hurt(PlayerDeathReason.ByProjectile(owner.whoAmI, projectile.whoAmI), + projectile.damage, hitDirection, pvp: true); + } + break; + } + } + } + } + } + + public override void OnHitPlayer(Projectile projectile, Player target, Player.HurtInfo info) + { + // Latch onto player when hit in PvP + Player owner = Main.player[projectile.owner]; + if (owner.hostile && target.hostile && owner.team != target.team && attachedPlayerIndex < 0) + { + attachedPlayerIndex = target.whoAmI; + attachOffset = projectile.Center - target.Center; + projectile.ai[0] = 1f; // Set to "attached" state + projectile.ai[1] = target.whoAmI; + projectile.netUpdate = true; + } + } + + public override bool PreAI(Projectile projectile) + { + // Only apply custom AI when attached to a player + if (attachedPlayerIndex < 0) + return true; // Use vanilla AI for seeking/returning + + Player owner = Main.player[projectile.owner]; + Player target = Main.player[attachedPlayerIndex]; + + // Check if we should detach + bool shouldDetach = false; + + // Detach if target is invalid + if (!target.active || target.dead || !target.hostile || target.team == owner.team) + { + shouldDetach = true; + } + // Detach if owner isn't channeling the piranha gun + else if (!owner.channel || owner.HeldItem.type != ItemID.PiranhaGun) + { + shouldDetach = true; + } + // Detach if too far from owner + else if (Vector2.Distance(projectile.Center, owner.Center) > 2000f) + { + shouldDetach = true; + } + + if (shouldDetach) + { + attachedPlayerIndex = -1; + attachOffset = Vector2.Zero; + projectile.ai[0] = 0f; + projectile.ai[1] = 0f; + projectile.netUpdate = true; + return true; // Resume vanilla AI + } + + // Stick to the player with offset + projectile.Center = target.Center + attachOffset; + projectile.velocity = Vector2.Zero; + + // Make piranha face the target + Vector2 directionToTarget = target.Center - owner.Center; + projectile.rotation = directionToTarget.ToRotation() + MathHelper.PiOver2; + + // Keep the projectile visible and active + projectile.timeLeft = 300; + projectile.ai[0] = 1f; + + // Damage the player periodically + if (projectile.localAI[0] <= 0f) + { + projectile.localAI[0] = 15f; // Attack every 15 frames (4 times per second) + + if (Main.myPlayer == projectile.owner) + { + int damage = projectile.damage; + int hitDirection = (target.Center.X > owner.Center.X) ? 1 : -1; + + target.Hurt(PlayerDeathReason.ByProjectile(owner.whoAmI, projectile.whoAmI), + damage, hitDirection, pvp: true); + } + } + else + { + projectile.localAI[0]--; + } + + return false; // Don't run vanilla AI while attached + } + + public override bool CanHitPlayer(Projectile projectile, Player target) + { + // Prevent continuous collision damage when latched + if (attachedPlayerIndex == target.whoAmI) + return false; + + // Only allow hitting hostile players + Player owner = Main.player[projectile.owner]; + if (!owner.hostile || !target.hostile || owner.team == target.team) + return false; + + return base.CanHitPlayer(projectile, target); + } + + public override void SendExtraAI(Projectile projectile, BitWriter bitWriter, BinaryWriter binaryWriter) + { + binaryWriter.Write(attachedPlayerIndex); + binaryWriter.Write(attachOffset.X); + binaryWriter.Write(attachOffset.Y); + } + + public override void ReceiveExtraAI(Projectile projectile, BitReader bitReader, BinaryReader binaryReader) + { + attachedPlayerIndex = binaryReader.ReadInt32(); + attachOffset.X = binaryReader.ReadSingle(); + attachOffset.Y = binaryReader.ReadSingle(); + } + } + + // GlobalItem to keep the weapon channeling while piranhas are attached + public class PiranhaGunItemSystem : GlobalItem + { + public override bool AppliesToEntity(Item entity, bool lateInstantiation) + { + return entity.type == ItemID.PiranhaGun; + } + + public override void HoldItem(Item item, Player player) + { + // Check if any of the player's piranhas are attached to a player + bool hasAttachedPiranha = false; + for (int i = 0; i < Main.maxProjectiles; i++) + { + Projectile proj = Main.projectile[i]; + if (proj.active && proj.owner == player.whoAmI && proj.type == ProjectileID.MechanicalPiranha) + { + var modProj = proj.GetGlobalProjectile(); + if (modProj != null && modProj.attachedPlayerIndex >= 0) + { + hasAttachedPiranha = true; + break; + } + } + } + + // If piranhas are attached, keep the item in use state + if (hasAttachedPiranha && player.controlUseItem) + { + player.channel = true; + player.itemTime = 2; + player.itemAnimation = 2; + } + } + + public override bool CanUseItem(Item item, Player player) + { + // Check if any piranhas are attached - if so, prevent switching items + for (int i = 0; i < Main.maxProjectiles; i++) + { + Projectile proj = Main.projectile[i]; + if (proj.active && proj.owner == player.whoAmI && proj.type == ProjectileID.MechanicalPiranha) + { + var modProj = proj.GetGlobalProjectile(); + if (modProj != null && modProj.attachedPlayerIndex >= 0) + { + // Keep weapon locked in use + return true; + } + } + } + return base.CanUseItem(item, player); + } + } } diff --git a/Localization/en-US.hjson b/Localization/en-US.hjson index b79feae5..b8f0aa6c 100644 --- a/Localization/en-US.hjson +++ b/Localization/en-US.hjson @@ -382,11 +382,11 @@ Mods: { IsVanillaDashEnabled: { Label: Is Vanilla Dash Enabled - Tooltip: - ''' - On: Dash as usual with double tap - Off: Disables double tap dash. Use keybind instead - ''' + Tooltip: + ''' + On: Dash as usual with double tap + Off: Disables double tap dash. Use keybind instead + ''' } } From 52cfe04ca4614900ad45869b23adb921e3457700 Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Wed, 12 Nov 2025 23:09:25 -0800 Subject: [PATCH 157/206] the eye of cthulu (wrong) --- AdventureConfig.cs | 2 ++ AdventureProjectile.cs | 74 ++++++++++++++++++++++------------------ Localization/en-US.hjson | 10 ++++++ 3 files changed, 53 insertions(+), 33 deletions(-) diff --git a/AdventureConfig.cs b/AdventureConfig.cs index b09df1b4..1da4085a 100644 --- a/AdventureConfig.cs +++ b/AdventureConfig.cs @@ -176,6 +176,8 @@ public float CalculateMultiplier(float tileDistance) => [DefaultValue(null)] [NullAllowed] public Falloff DefaultFalloff { get; set; } } + [Description("Projectiles that deal no knockback in PvP")] + public List NoKnockbackProjectiles { get; set; } = new(); [Range(0, 5 * 60)] [DefaultValue(8)] public int MeleeInvincibilityFrames { get; set; } [Range(0, 60 * 2 * 60)] diff --git a/AdventureProjectile.cs b/AdventureProjectile.cs index 842155a4..183f138e 100644 --- a/AdventureProjectile.cs +++ b/AdventureProjectile.cs @@ -7,7 +7,9 @@ using Terraria.Enums; using Terraria.ID; using Terraria.ModLoader; +using Terraria.ModLoader.Config; using Terraria.ModLoader.IO; +using static PvPAdventure.AdventureConfig; namespace PvPAdventure; @@ -788,7 +790,7 @@ public override void ModifyHitPlayer(Projectile projectile, Player target, ref P modifiers.SourceDamage *= 0.75f; } } - public class PiranhaGunPvPSystem : GlobalProjectile + public class VanillaPirahinaGun : GlobalProjectile { public override bool InstancePerEntity => true; @@ -802,26 +804,27 @@ public override bool AppliesToEntity(Projectile entity, bool lateInstantiation) public override void SetDefaults(Projectile projectile) { - // Enable player collision for PvP projectile.friendly = true; } public override void AI(Projectile projectile) { - // Manual collision check with players if not attached if (attachedPlayerIndex < 0) { Player owner = Main.player[projectile.owner]; if (!owner.hostile) return; - // Check collision with hostile players for (int i = 0; i < Main.maxPlayers; i++) { if (i == projectile.owner) continue; Player target = Main.player[i]; + + if (target.HasBuff(ModContent.BuffType())) + continue; + if (target.active && !target.dead && target.hostile && target.team != owner.team) { Rectangle projHitbox = new Rectangle((int)projectile.position.X, (int)projectile.position.Y, @@ -831,14 +834,12 @@ public override void AI(Projectile projectile) if (projHitbox.Intersects(playerHitbox)) { - // Latch onto the player attachedPlayerIndex = target.whoAmI; attachOffset = projectile.Center - target.Center; projectile.ai[0] = 1f; projectile.ai[1] = target.whoAmI; projectile.netUpdate = true; - // Deal initial hit damage if (Main.myPlayer == projectile.owner) { int hitDirection = (target.Center.X > owner.Center.X) ? 1 : -1; @@ -852,9 +853,13 @@ public override void AI(Projectile projectile) } } + public override void ModifyHitPlayer(Projectile projectile, Player target, ref Player.HurtModifiers modifiers) + { + modifiers.Knockback *= 0f; + } + public override void OnHitPlayer(Projectile projectile, Player target, Player.HurtInfo info) { - // Latch onto player when hit in PvP Player owner = Main.player[projectile.owner]; if (owner.hostile && target.hostile && owner.team != target.team && attachedPlayerIndex < 0) { @@ -868,28 +873,24 @@ public override void OnHitPlayer(Projectile projectile, Player target, Player.Hu public override bool PreAI(Projectile projectile) { - // Only apply custom AI when attached to a player if (attachedPlayerIndex < 0) - return true; // Use vanilla AI for seeking/returning + return true; Player owner = Main.player[projectile.owner]; Player target = Main.player[attachedPlayerIndex]; - // Check if we should detach bool shouldDetach = false; - // Detach if target is invalid if (!target.active || target.dead || !target.hostile || target.team == owner.team) { shouldDetach = true; } - // Detach if owner isn't channeling the piranha gun + else if (!owner.channel || owner.HeldItem.type != ItemID.PiranhaGun) { shouldDetach = true; } - // Detach if too far from owner - else if (Vector2.Distance(projectile.Center, owner.Center) > 2000f) + else if (Vector2.Distance(projectile.Center, owner.Center) > 2000f) // this will detach the pirahinas if theyre too far away when attached to a player, we can change this { shouldDetach = true; } @@ -901,25 +902,21 @@ public override bool PreAI(Projectile projectile) projectile.ai[0] = 0f; projectile.ai[1] = 0f; projectile.netUpdate = true; - return true; // Resume vanilla AI + return true; } - // Stick to the player with offset projectile.Center = target.Center + attachOffset; projectile.velocity = Vector2.Zero; - // Make piranha face the target Vector2 directionToTarget = target.Center - owner.Center; projectile.rotation = directionToTarget.ToRotation() + MathHelper.PiOver2; - // Keep the projectile visible and active projectile.timeLeft = 300; projectile.ai[0] = 1f; - // Damage the player periodically if (projectile.localAI[0] <= 0f) { - projectile.localAI[0] = 15f; // Attack every 15 frames (4 times per second) + projectile.localAI[0] = 1f; // Attack every frame (temp), we can change ts if (Main.myPlayer == projectile.owner) { @@ -935,16 +932,14 @@ public override bool PreAI(Projectile projectile) projectile.localAI[0]--; } - return false; // Don't run vanilla AI while attached + return false; // Don't run vanilla AI } public override bool CanHitPlayer(Projectile projectile, Player target) { - // Prevent continuous collision damage when latched if (attachedPlayerIndex == target.whoAmI) return false; - // Only allow hitting hostile players Player owner = Main.player[projectile.owner]; if (!owner.hostile || !target.hostile || owner.team == target.team) return false; @@ -967,8 +962,8 @@ public override void ReceiveExtraAI(Projectile projectile, BitReader bitReader, } } - // GlobalItem to keep the weapon channeling while piranhas are attached - public class PiranhaGunItemSystem : GlobalItem + // GlobalItem even though in adventureprojectile because FUCK YOU + public class PiranhaGunItem : GlobalItem { public override bool AppliesToEntity(Item entity, bool lateInstantiation) { @@ -977,14 +972,13 @@ public override bool AppliesToEntity(Item entity, bool lateInstantiation) public override void HoldItem(Item item, Player player) { - // Check if any of the player's piranhas are attached to a player bool hasAttachedPiranha = false; for (int i = 0; i < Main.maxProjectiles; i++) { Projectile proj = Main.projectile[i]; if (proj.active && proj.owner == player.whoAmI && proj.type == ProjectileID.MechanicalPiranha) { - var modProj = proj.GetGlobalProjectile(); + var modProj = proj.GetGlobalProjectile(); if (modProj != null && modProj.attachedPlayerIndex >= 0) { hasAttachedPiranha = true; @@ -993,7 +987,6 @@ public override void HoldItem(Item item, Player player) } } - // If piranhas are attached, keep the item in use state if (hasAttachedPiranha && player.controlUseItem) { player.channel = true; @@ -1004,16 +997,14 @@ public override void HoldItem(Item item, Player player) public override bool CanUseItem(Item item, Player player) { - // Check if any piranhas are attached - if so, prevent switching items for (int i = 0; i < Main.maxProjectiles; i++) { Projectile proj = Main.projectile[i]; if (proj.active && proj.owner == player.whoAmI && proj.type == ProjectileID.MechanicalPiranha) { - var modProj = proj.GetGlobalProjectile(); + var modProj = proj.GetGlobalProjectile(); if (modProj != null && modProj.attachedPlayerIndex >= 0) { - // Keep weapon locked in use return true; } } @@ -1021,5 +1012,22 @@ public override bool CanUseItem(Item item, Player player) return base.CanUseItem(item, player); } } -} - + public class NoKnockbackProjectiles : GlobalProjectile + { + public override bool AppliesToEntity(Projectile entity, bool lateInstantiation) + { + int projType = entity.type; + + return projType == ProjectileID.Meteor1 || + projType == ProjectileID.Meteor2 || + projType == ProjectileID.Meteor3 || + projType == ProjectileID.HeatRay || + projType == ProjectileID.FlyingKnife || + projType == ProjectileID.LaserMachinegunLaser; + } + public override void ModifyHitPlayer(Projectile projectile, Player target, ref Player.HurtModifiers modifiers) + { + modifiers.Knockback *= 0f; + } + } +} \ No newline at end of file diff --git a/Localization/en-US.hjson b/Localization/en-US.hjson index b8f0aa6c..361c135f 100644 --- a/Localization/en-US.hjson +++ b/Localization/en-US.hjson @@ -355,6 +355,16 @@ Mods: { Label: No Line Of Sight Damage Reduction Tooltip: "" } + + NoKnockbackItems: { + Label: No Knockback Items + Tooltip: "" + } + + NoKnockbackProjectiles: { + Label: No Knockback Projectiles + Tooltip: "" + } } AdventureClientConfig: { From 36bb7e74ad2423b3c2708d30bfcc97b4974ee2a1 Mon Sep 17 00:00:00 2001 From: emyhrberg <121192176+emyhrberg@users.noreply.github.com> Date: Thu, 13 Nov 2025 16:01:47 +0100 Subject: [PATCH 158/206] Wip refactor --- Content/Items/AdventureMirror.cs | 2 +- .../AdventureMirrorCountdownPlayer.cs | 40 -------------- .../Hooks/UnityHooks.cs} | 9 ++-- .../Players/AdventureMirrorPlayer.cs | 51 ++++++++++++++++++ .../AdventureTeleportStateSettings.cs | 2 +- .../Systems}/AdventureTeleportState.cs | 5 +- .../Systems}/AdventureTeleportSystem.cs | 21 +++++++- .../UI/AdventureTeleportPanel.cs | 8 +++ .../UI}/PlayerHeadElement.cs | 8 +-- icon_small.png | Bin 0 -> 1227 bytes 10 files changed, 89 insertions(+), 57 deletions(-) delete mode 100644 Core/Features/AdventureTeleport/AdventureMirrorCountdownPlayer.cs rename Core/Features/{AdventureTeleport/UnityChecks.cs => SpawnSelector/Hooks/UnityHooks.cs} (80%) create mode 100644 Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs rename Core/Features/{AdventureTeleport => SpawnSelector/Structures}/AdventureTeleportStateSettings.cs (77%) rename Core/Features/{AdventureTeleport => SpawnSelector/Systems}/AdventureTeleportState.cs (97%) rename Core/Features/{AdventureTeleport => SpawnSelector/Systems}/AdventureTeleportSystem.cs (79%) create mode 100644 Core/Features/SpawnSelector/UI/AdventureTeleportPanel.cs rename Core/Features/{AdventureTeleport => SpawnSelector/UI}/PlayerHeadElement.cs (80%) create mode 100644 icon_small.png diff --git a/Content/Items/AdventureMirror.cs b/Content/Items/AdventureMirror.cs index 334c6896..c272d811 100644 --- a/Content/Items/AdventureMirror.cs +++ b/Content/Items/AdventureMirror.cs @@ -1,5 +1,5 @@ using Microsoft.Xna.Framework; -using PvPAdventure.Core.Features.AdventureTeleport; +using PvPAdventure.Core.Features.SpawnSelector.Structures; using Terraria; using Terraria.ID; using Terraria.ModLoader; diff --git a/Core/Features/AdventureTeleport/AdventureMirrorCountdownPlayer.cs b/Core/Features/AdventureTeleport/AdventureMirrorCountdownPlayer.cs deleted file mode 100644 index 773087d6..00000000 --- a/Core/Features/AdventureTeleport/AdventureMirrorCountdownPlayer.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Microsoft.Xna.Framework; -using PvPAdventure.Content.Items; -using Terraria; -using Terraria.ModLoader; - -namespace PvPAdventure.Core.Features.AdventureTeleport -{ - public class AdventureMirrorCountdownPlayer : ModPlayer - { - public override void PostUpdate() - { - if (Main.dedServ || Player.whoAmI != Main.myPlayer) - { - return; - } - - // Check if player is using RTPMirror - Item currentItem = Main.LocalPlayer.HeldItem; - int rtpMirrorItemType = ModContent.ItemType(); - - if (currentItem != null && - currentItem.type == rtpMirrorItemType && - Main.LocalPlayer.itemAnimation > 0 && - Main.LocalPlayer.itemAnimation % 60 == 0) - { - int itemUseTimeLeft = Main.LocalPlayer.itemAnimation / 60; - string timeLeft = itemUseTimeLeft.ToString(); - - // Display text above the player every second - PopupText.NewText(new AdvancedPopupRequest - { - Color = Color.Crimson, - Text = timeLeft, - Velocity = new(0.0f, -4.0f), - DurationInFrames = 60 * 1 - }, Player.Top); - } - } - } -} \ No newline at end of file diff --git a/Core/Features/AdventureTeleport/UnityChecks.cs b/Core/Features/SpawnSelector/Hooks/UnityHooks.cs similarity index 80% rename from Core/Features/AdventureTeleport/UnityChecks.cs rename to Core/Features/SpawnSelector/Hooks/UnityHooks.cs index 439bc0b7..2aed04da 100644 --- a/Core/Features/AdventureTeleport/UnityChecks.cs +++ b/Core/Features/SpawnSelector/Hooks/UnityHooks.cs @@ -1,11 +1,12 @@ using Microsoft.Xna.Framework; +using PvPAdventure.Core.Features.SpawnSelector.Structures; using System; using Terraria; using Terraria.ModLoader; -namespace PvPAdventure.Core.Features.AdventureTeleport; +namespace PvPAdventure.Core.Features.SpawnSelector.Hooks; -public class UnityChecks : ModSystem +public class UnityHooks : ModSystem { public override void Load() { @@ -26,13 +27,13 @@ public override void Unload() } [Obsolete("This method is redundant since we always set this variable to false whenever map is closed.")] - private void DisableRTPMenuAfterTeleport(On_Player.orig_UnityTeleport orig, Player self, Vector2 telePos) + private void DisableRTPMenuAfterTeleport(On_Player.orig_UnityTeleport orig, Terraria.Player self, Vector2 telePos) { AdventureTeleportStateSettings.SetIsEnabled(false); orig(self, telePos); } - private static bool OverrideUnityPotionCheck(On_Player.orig_HasUnityPotion orig, Player self) + private static bool OverrideUnityPotionCheck(On_Player.orig_HasUnityPotion orig, Terraria.Player self) { if (AdventureTeleportStateSettings.GetIsEnabled()) return true; diff --git a/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs b/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs new file mode 100644 index 00000000..ea19912b --- /dev/null +++ b/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs @@ -0,0 +1,51 @@ +using Microsoft.Xna.Framework; +using PvPAdventure.Content.Items; +using Terraria; +using Terraria.DataStructures; +using Terraria.ModLoader; + +namespace PvPAdventure.Core.Features.SpawnSelector.Players; + +public class AdventureMirrorPlayer : ModPlayer +{ + public override void PostUpdate() + { + if (Main.dedServ || Player.whoAmI != Main.myPlayer) + { + return; + } + + // Check if player is using RTPMirror + Item currentItem = Main.LocalPlayer.HeldItem; + int rtpMirrorItemType = ModContent.ItemType(); + + if (currentItem != null && + currentItem.type == rtpMirrorItemType && + Main.LocalPlayer.itemAnimation > 0 && + Main.LocalPlayer.itemAnimation % 60 == 0) + { + int itemUseTimeLeft = Main.LocalPlayer.itemAnimation / 60; + string timeLeft = itemUseTimeLeft.ToString(); + + // Display text above the player every second + PopupText.NewText(new AdvancedPopupRequest + { + Color = Color.Crimson, + Text = timeLeft, + Velocity = new(0.0f, -4.0f), + DurationInFrames = 60 * 1 + }, Player.Top); + } + } + + public override void UpdateDead() + { + //Main.NewText(Player.respawnTimer); + + // This code will keep the player from respawning. + //if (Player.respawnTimer <= 10) + //{ + //Player.respawnTimer = 10; + //} + } +} \ No newline at end of file diff --git a/Core/Features/AdventureTeleport/AdventureTeleportStateSettings.cs b/Core/Features/SpawnSelector/Structures/AdventureTeleportStateSettings.cs similarity index 77% rename from Core/Features/AdventureTeleport/AdventureTeleportStateSettings.cs rename to Core/Features/SpawnSelector/Structures/AdventureTeleportStateSettings.cs index 325c5754..6b41aed9 100644 --- a/Core/Features/AdventureTeleport/AdventureTeleportStateSettings.cs +++ b/Core/Features/SpawnSelector/Structures/AdventureTeleportStateSettings.cs @@ -1,4 +1,4 @@ -namespace PvPAdventure.Core.Features.AdventureTeleport; +namespace PvPAdventure.Core.Features.SpawnSelector.Structures; public static class AdventureTeleportStateSettings { diff --git a/Core/Features/AdventureTeleport/AdventureTeleportState.cs b/Core/Features/SpawnSelector/Systems/AdventureTeleportState.cs similarity index 97% rename from Core/Features/AdventureTeleport/AdventureTeleportState.cs rename to Core/Features/SpawnSelector/Systems/AdventureTeleportState.cs index 858ebea7..97109e27 100644 --- a/Core/Features/AdventureTeleport/AdventureTeleportState.cs +++ b/Core/Features/SpawnSelector/Systems/AdventureTeleportState.cs @@ -1,4 +1,5 @@ using Microsoft.Xna.Framework; +using PvPAdventure.Core.Features.SpawnSelector.Structures; using System; using System.Collections.Generic; using System.Linq; @@ -8,7 +9,7 @@ using Terraria.ID; using Terraria.UI; -namespace PvPAdventure.Core.Features.AdventureTeleport; +namespace PvPAdventure.Core.Features.SpawnSelector.Systems; public class AdventureTeleportState : UIState { @@ -191,7 +192,7 @@ private UIElement MakeTeammateRow(Player p, bool isSelf) bg.Append(head); // Name text - var name = new UIText(isSelf ? $"You ({p?.name ?? "Player"})" : (p?.name ?? "Player"), 0.9f); + var name = new UIText(isSelf ? $"You ({p?.name ?? "Player"})" : p?.name ?? "Player", 0.9f); name.Left.Set(36, 0f); name.Top.Set(5f, 0f); name.TextColor = Color.White; diff --git a/Core/Features/AdventureTeleport/AdventureTeleportSystem.cs b/Core/Features/SpawnSelector/Systems/AdventureTeleportSystem.cs similarity index 79% rename from Core/Features/AdventureTeleport/AdventureTeleportSystem.cs rename to Core/Features/SpawnSelector/Systems/AdventureTeleportSystem.cs index ea839904..33159432 100644 --- a/Core/Features/AdventureTeleport/AdventureTeleportSystem.cs +++ b/Core/Features/SpawnSelector/Systems/AdventureTeleportSystem.cs @@ -1,10 +1,12 @@ using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Graphics; +using Microsoft.Xna.Framework.Graphics; +using PvPAdventure.Core.Features.SpawnSelector.Structures; +using PvPAdventure.Core.Features.SpawnSelector.Systems; using Terraria; using Terraria.ModLoader; using Terraria.UI; -namespace PvPAdventure.Core.Features.AdventureTeleport; +namespace PvPAdventure.Core.Features.AdventureTeleport.System; [Autoload(Side = ModSide.Client)] public class AdventureTeleportSystem : ModSystem @@ -22,12 +24,25 @@ public override void Load() Main.OnPostFullscreenMapDraw += DrawOverFullscreenMap; } + + On_Main.TriggerPing += OverridePing; } public override void Unload() { if (!Main.dedServ) Main.OnPostFullscreenMapDraw -= DrawOverFullscreenMap; + + On_Main.TriggerPing -= OverridePing; + } + + private void OverridePing(On_Main.orig_TriggerPing orig, Vector2 position) + { + if (adventureTeleportState.IsMouseOverUI) + { + return; + } + orig(position); } public override void UpdateUI(GameTime gameTime) @@ -44,7 +59,9 @@ public override void UpdateUI(GameTime gameTime) ui.Update(gameTime); if (adventureTeleportState.IsMouseOverUI) + { Main.LocalPlayer.mouseInterface = true; + } } else if (ui.CurrentState != null) { diff --git a/Core/Features/SpawnSelector/UI/AdventureTeleportPanel.cs b/Core/Features/SpawnSelector/UI/AdventureTeleportPanel.cs new file mode 100644 index 00000000..18d9944e --- /dev/null +++ b/Core/Features/SpawnSelector/UI/AdventureTeleportPanel.cs @@ -0,0 +1,8 @@ + +using Terraria.GameContent.UI.Elements; + +namespace PvPAdventure.Core.Features.SpawnSelector.UI; +internal class AdventureTeleportPanel : UIPanel +{ + +} diff --git a/Core/Features/AdventureTeleport/PlayerHeadElement.cs b/Core/Features/SpawnSelector/UI/PlayerHeadElement.cs similarity index 80% rename from Core/Features/AdventureTeleport/PlayerHeadElement.cs rename to Core/Features/SpawnSelector/UI/PlayerHeadElement.cs index c0db038d..259657de 100644 --- a/Core/Features/AdventureTeleport/PlayerHeadElement.cs +++ b/Core/Features/SpawnSelector/UI/PlayerHeadElement.cs @@ -1,14 +1,9 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Terraria; using Terraria.UI; -namespace PvPAdventure.Core.Features.AdventureTeleport; +namespace PvPAdventure.Core.Features.SpawnSelector.UI; public class PlayerHeadElement : UIElement { @@ -28,7 +23,6 @@ protected override void DrawSelf(SpriteBatch spriteBatch) // Only draw if we have a player if (player == null || !player.active) return; - // Where to draw (top-left of this element) var dims = GetDimensions(); Vector2 pos = new Vector2(dims.X + dims.Width * 0.5f, dims.Y + dims.Height * 0.5f); // center on the element float scale = 0.75f; diff --git a/icon_small.png b/icon_small.png new file mode 100644 index 0000000000000000000000000000000000000000..c81d55a7a5b705df2dc964547e765a9089bcc7ff GIT binary patch literal 1227 zcmV;+1T_1JP)BeG3@UiMb zd_Xr2lLHNhiH;$dLX~}!zi?fTeb98=z${vR$ zn2iK10kt=zfbj!HY0L|&JoM%q?@TQ)w!5C*6TR4-=NDpvYr%X&#_U|CDNC2R!ZbDK z&)&!BKMvD(bcyNddB*o|IZR@y9Tg%llY$0wnUOiFsj-U)hMhaBHHr#?#rdPWcWoc) z-W3i`)^jrY4p=O;pY?{ez%J7m(3K`*Dn;e@8v8G=bNS}Oe7RLdj&C?7ikZ1}?#x;y zH6?bi>*n;vdZ5qRi|K#lYvu=X%%jh%XSXRR?>Q``|We#ki&zK7J-jNwS1 zPq$ObI{QwXYqC>V(cBK%m7(jzTq+5BE#7^uN=ZC+BBL|$E0a{}0Giz%PAav0gfa+YXl>G#N(q2l zW1X6-jWIiXea3b-=`VN~3aIif^r&H=UoddLhaL={**B8bGwW>K7R55_WG8(b$?We_ zFWuyxJGSsgC#X#xL+EXUC)o3R9rJj&&^Jz6>EmbfU@AQiBC|_8=0pC_q{rzKD-70G zsLm~+N@YrWe6F7@BhO2oJ_b)c+o8sep@_lBNbP*YJ4E32Haz*9;E98OF}ZM#)%qw4 zTC)Cifx{)kTc-s5_UoQ0S^Jj`qY)+uknC14U26Q}>;QL-8Q%S9lh>}?;Qj3@)UTI$ zd#c9dAPgTcoSD%(NUS1Ido&cYDV5u^iDW*X&-Af$t-|ZC!UKou%v67-;gu+jlqpmU z7rvK#{E5>Tw3$i=Of9HL&DE)ga&lKI8V#SXzR`U5t!-Ki^@felCdTtnn;xHj)}mUC z_q#QaE3t||H3B>A$EAl}No&OyXW+%-w{ziQla~39=?~!4D+MlH+HR9I%Txz|cJJF! z?6Ftk>axA3$-nD9%l`;2{^{}eVk?()`I_nkH12q0uf39e$>=VRiMxH)s(lO(wWm@y zrbIFeLvB0WLa$`cUp~=bVjPMEgYwgUt&`LiC}e3DLO4Rkz4c0V{4`slT9s4=G*aYh z8U==kj1;(-kY!NcU?G-qkG+yD$*;dD=C6XXpX8u!*;Hx=H5t&rT)p;6b|_yl`wQ$H zg<8#TuWKZ40!rLM$E-mddE^-r|EF=cPqF~_Ym-+X$>D4&g^XR6uGHZgiWq+xqlU7q pyZ1`Bl1izI9ngSv_>(Yf{tr!^Hy59zUbp}N002ovPDHLkV1gh1Re1ma literal 0 HcmV?d00001 From 946c719fefb602544e31fde12de0de5acad4e063 Mon Sep 17 00:00:00 2001 From: emyhrberg <121192176+emyhrberg@users.noreply.github.com> Date: Thu, 13 Nov 2025 20:29:02 +0100 Subject: [PATCH 159/206] UI pm done --- Content/Items/AdventureMirror.cs | 62 ++++- Content/Items/AdventureMirrorGlobalItem.cs | 20 ++ .../SpawnSelector/Hooks/ItemSlotHooks.cs | 76 ++++++ .../SpawnSelector/Hooks/UnityHooks.cs | 22 +- .../Players/AdventureMirrorPlayer.cs | 51 ---- .../Players/SpawnSelectorPlayer.cs | 67 +++++ .../AdventureTeleportStateSettings.cs | 9 - .../Systems/AdventureTeleportState.cs | 231 ------------------ .../Systems/AdventureTeleportSystem.cs | 103 -------- .../Systems/SpawnSelectorState.cs | 25 ++ .../Systems/SpawnSelectorSystem.cs | 93 +++++++ .../UI/AdventureTeleportPanel.cs | 8 - .../SpawnSelector/UI/PlayerHeadElement.cs | 33 --- .../UI/UISpawnSelectorCharacterListItem.cs | 177 ++++++++++++++ .../SpawnSelector/UI/UISpawnSelectorPanel.cs | 82 +++++++ Properties/launchSettings.json | 8 +- PvPAdventure.csproj | 8 +- PvPAdventure.csproj.user | 9 + 18 files changed, 624 insertions(+), 460 deletions(-) create mode 100644 Content/Items/AdventureMirrorGlobalItem.cs create mode 100644 Core/Features/SpawnSelector/Hooks/ItemSlotHooks.cs delete mode 100644 Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs create mode 100644 Core/Features/SpawnSelector/Players/SpawnSelectorPlayer.cs delete mode 100644 Core/Features/SpawnSelector/Structures/AdventureTeleportStateSettings.cs delete mode 100644 Core/Features/SpawnSelector/Systems/AdventureTeleportState.cs delete mode 100644 Core/Features/SpawnSelector/Systems/AdventureTeleportSystem.cs create mode 100644 Core/Features/SpawnSelector/Systems/SpawnSelectorState.cs create mode 100644 Core/Features/SpawnSelector/Systems/SpawnSelectorSystem.cs delete mode 100644 Core/Features/SpawnSelector/UI/AdventureTeleportPanel.cs delete mode 100644 Core/Features/SpawnSelector/UI/PlayerHeadElement.cs create mode 100644 Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs create mode 100644 Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs create mode 100644 PvPAdventure.csproj.user diff --git a/Content/Items/AdventureMirror.cs b/Content/Items/AdventureMirror.cs index c272d811..fd9766a0 100644 --- a/Content/Items/AdventureMirror.cs +++ b/Content/Items/AdventureMirror.cs @@ -1,6 +1,7 @@ using Microsoft.Xna.Framework; -using PvPAdventure.Core.Features.SpawnSelector.Structures; +using PvPAdventure.Core.Features.SpawnSelector.Systems; using Terraria; +using Terraria.Audio; using Terraria.ID; using Terraria.ModLoader; @@ -13,6 +14,14 @@ public override bool CanUseItem(Player player) // Prevent item use if the player is moving if (player.velocity.Length() > 0f) { + // Display text above the player every second + PopupText.NewText(new AdvancedPopupRequest + { + Color = Color.Crimson, + Text = "Cannot use while moving!", + Velocity = new(0.0f, -4.0f), + DurationInFrames = 60 * 1 + }, player.Top); return false; } @@ -66,10 +75,31 @@ public override void UseStyle(Player player, Rectangle heldItemFrame) Main.playerInventory = false; if (!Main.mapFullscreen) { - Main.mapFullscreen = true; - Main.resetMapFull = true; + SoundEngine.PlaySound(SoundID.MenuOpen); + Main.mapFullscreen = true; // open the fullscreen map + + //Main.resetMapFull = true; // reset the map view position to be zoomed out and centered on the player + + // center map + float worldCenterX = Main.maxTilesX / 2f; + float worldCenterY = Main.maxTilesY / 2f; + Main.mapFullscreenPos.X = worldCenterX; + Main.mapFullscreenPos.Y = worldCenterY; + + // zoom out + Main.mapFullscreenScale = 0.21f; + + // teleport to spawn + Vector2 spawnPos = new(Main.spawnTileX*16, Main.spawnTileY*16-100); + + Main.LocalPlayer.Teleport(spawnPos); + + if (Main.netMode == NetmodeID.MultiplayerClient) + { + // ? + } } - AdventureTeleportStateSettings.SetIsEnabled(true); + SpawnSelectorSystem.SetEnabled(true); // This code releases all grappling hooks and kills/despawns them. player.RemoveAllGrapplingHooks(); @@ -93,13 +123,13 @@ private static void SpawnMirrorDust(Player player) public override void UpdateInventory(Player player) { - if (!Main.mapFullscreen) - { - if (!AdventureTeleportStateSettings.GetIsEnabled()) - { - AdventureTeleportStateSettings.SetIsEnabled(false); - } - } + //if (!Main.mapFullscreen) + //{ + // if (!SpawnSelectorSettings.GetIsEnabled()) + // { + // SpawnSelectorSettings.SetIsEnabled(false); + // } + //} if (player.HeldItem.type == Item.type && player.itemAnimation > 0) { @@ -108,9 +138,15 @@ public override void UpdateInventory(Player player) // Cancel item use player.itemAnimation = 0; player.itemTime = 0; - //SoundEngine.PlaySound(SoundID.MenuClose, player.position); - //Log.Debug("cancelled RTP mirror"); + // Display text above the player every second + PopupText.NewText(new AdvancedPopupRequest + { + Color = Color.Crimson, + Text = "Cancelled!", + Velocity = new(0.0f, -4.0f), + DurationInFrames = 60 * 1 + }, player.Top); } } } diff --git a/Content/Items/AdventureMirrorGlobalItem.cs b/Content/Items/AdventureMirrorGlobalItem.cs new file mode 100644 index 00000000..71dedbcd --- /dev/null +++ b/Content/Items/AdventureMirrorGlobalItem.cs @@ -0,0 +1,20 @@ +using PvPAdventure.Content.Items; +using Terraria; +using Terraria.ModLoader; + +public class AdventureMirrorGlobalItem : GlobalItem +{ + public override bool InstancePerEntity => true; + + // Force the item to always be favorited + public override void UpdateInventory(Item item, Player player) + { + if (item.type == ModContent.ItemType()) + { + item.favorited = true; // Force on every tick + + + } + } + +} diff --git a/Core/Features/SpawnSelector/Hooks/ItemSlotHooks.cs b/Core/Features/SpawnSelector/Hooks/ItemSlotHooks.cs new file mode 100644 index 00000000..5bac1ca4 --- /dev/null +++ b/Core/Features/SpawnSelector/Hooks/ItemSlotHooks.cs @@ -0,0 +1,76 @@ +using Terraria; +using Terraria.ModLoader; +using Terraria.UI; +using Terraria.Audio; +using Terraria.ID; +using PvPAdventure.Content.Items; + +public class ItemSlotHooks : ModSystem +{ + public override void Load() + { + // 1) Handles Shift+trash / quick sell path + On_ItemSlot.LeftClick_SellOrTrash += Hook_LeftClick_SellOrTrash; + + // 2) Handles normal click on the trash slot + On_ItemSlot.LeftClick_ItemArray_int_int += Hook_LeftClick_ItemArray; + + // 3) Handles ALL selling (manual and quick) via Player.SellItem + On_Player.SellItem += Hook_SellItem; + } + + public override void Unload() + { + On_ItemSlot.LeftClick_SellOrTrash -= Hook_LeftClick_SellOrTrash; + On_ItemSlot.LeftClick_ItemArray_int_int -= Hook_LeftClick_ItemArray; + On_Player.SellItem -= Hook_SellItem; + } + + // ======== QUICK TRASH / QUICK SELL (Shift + click) ======== + private static bool Hook_LeftClick_SellOrTrash( + On_ItemSlot.orig_LeftClick_SellOrTrash orig, + Item[] inv, int context, int slot) + { + Item item = inv[slot]; + + if (!item.IsAir && item.type == ModContent.ItemType()) + { + SoundEngine.PlaySound(SoundID.MenuClose); + return false; // skip SellOrTrash completely + } + + return orig(inv, context, slot); + } + + // ======== DRAGGING ONTO THE TRASH SLOT ======== + private static void Hook_LeftClick_ItemArray( + On_ItemSlot.orig_LeftClick_ItemArray_int_int orig, + Item[] inv, int context, int slot) + { + if (context == ItemSlot.Context.TrashItem + && !Main.mouseItem.IsAir + && Main.mouseItem.type == ModContent.ItemType()) + { + SoundEngine.PlaySound(SoundID.MenuClose); + return; // do NOT process the trash slot + } + + orig(inv, context, slot); + } + + // ======== ANY SELL TO NPC SHOP (manual or quick) ======== + private static bool Hook_SellItem( + On_Player.orig_SellItem orig, + Player self, + Item item, + int stack) + { + if (!item.IsAir && item.type == ModContent.ItemType()) + { + SoundEngine.PlaySound(SoundID.MenuClose); + return false; // selling fails, nothing is removed + } + + return orig(self, item, stack); + } +} diff --git a/Core/Features/SpawnSelector/Hooks/UnityHooks.cs b/Core/Features/SpawnSelector/Hooks/UnityHooks.cs index 2aed04da..a6c1052c 100644 --- a/Core/Features/SpawnSelector/Hooks/UnityHooks.cs +++ b/Core/Features/SpawnSelector/Hooks/UnityHooks.cs @@ -1,19 +1,22 @@ using Microsoft.Xna.Framework; -using PvPAdventure.Core.Features.SpawnSelector.Structures; +using PvPAdventure.Core.Features.SpawnSelector.Systems; using System; using Terraria; using Terraria.ModLoader; namespace PvPAdventure.Core.Features.SpawnSelector.Hooks; +/// +/// This allows the player to click on teammates to teleport to them. +/// public class UnityHooks : ModSystem { public override void Load() { Main.QueueMainThreadAction(() => { - On_Player.HasUnityPotion += OverrideUnityPotionCheck; - //On_Player.UnityTeleport += DisableRTPMenuAfterTeleport; + On_Player.HasUnityPotion += OnHasUnityPotion; + On_Player.UnityTeleport += OnUnityTeleport; }); } @@ -21,21 +24,20 @@ public override void Unload() { Main.QueueMainThreadAction(() => { - On_Player.HasUnityPotion -= OverrideUnityPotionCheck; - //On_Player.UnityTeleport -= DisableRTPMenuAfterTeleport; + On_Player.HasUnityPotion -= OnHasUnityPotion; + On_Player.UnityTeleport -= OnUnityTeleport; }); } - [Obsolete("This method is redundant since we always set this variable to false whenever map is closed.")] - private void DisableRTPMenuAfterTeleport(On_Player.orig_UnityTeleport orig, Terraria.Player self, Vector2 telePos) + private void OnUnityTeleport(On_Player.orig_UnityTeleport orig, Player self, Vector2 telePos) { - AdventureTeleportStateSettings.SetIsEnabled(false); + SpawnSelectorSystem.SetEnabled(false); orig(self, telePos); } - private static bool OverrideUnityPotionCheck(On_Player.orig_HasUnityPotion orig, Terraria.Player self) + private static bool OnHasUnityPotion(On_Player.orig_HasUnityPotion orig, Player self) { - if (AdventureTeleportStateSettings.GetIsEnabled()) + if (SpawnSelectorSystem.GetEnabled()) return true; return orig(self); diff --git a/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs b/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs deleted file mode 100644 index ea19912b..00000000 --- a/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Microsoft.Xna.Framework; -using PvPAdventure.Content.Items; -using Terraria; -using Terraria.DataStructures; -using Terraria.ModLoader; - -namespace PvPAdventure.Core.Features.SpawnSelector.Players; - -public class AdventureMirrorPlayer : ModPlayer -{ - public override void PostUpdate() - { - if (Main.dedServ || Player.whoAmI != Main.myPlayer) - { - return; - } - - // Check if player is using RTPMirror - Item currentItem = Main.LocalPlayer.HeldItem; - int rtpMirrorItemType = ModContent.ItemType(); - - if (currentItem != null && - currentItem.type == rtpMirrorItemType && - Main.LocalPlayer.itemAnimation > 0 && - Main.LocalPlayer.itemAnimation % 60 == 0) - { - int itemUseTimeLeft = Main.LocalPlayer.itemAnimation / 60; - string timeLeft = itemUseTimeLeft.ToString(); - - // Display text above the player every second - PopupText.NewText(new AdvancedPopupRequest - { - Color = Color.Crimson, - Text = timeLeft, - Velocity = new(0.0f, -4.0f), - DurationInFrames = 60 * 1 - }, Player.Top); - } - } - - public override void UpdateDead() - { - //Main.NewText(Player.respawnTimer); - - // This code will keep the player from respawning. - //if (Player.respawnTimer <= 10) - //{ - //Player.respawnTimer = 10; - //} - } -} \ No newline at end of file diff --git a/Core/Features/SpawnSelector/Players/SpawnSelectorPlayer.cs b/Core/Features/SpawnSelector/Players/SpawnSelectorPlayer.cs new file mode 100644 index 00000000..5b9d627e --- /dev/null +++ b/Core/Features/SpawnSelector/Players/SpawnSelectorPlayer.cs @@ -0,0 +1,67 @@ +using Microsoft.Xna.Framework; +using PvPAdventure.Content.Items; +using PvPAdventure.Core.Features.SpawnSelector.Systems; +using PvPAdventure.System; +using Terraria; +using Terraria.ModLoader; +using static Terraria.ModLoader.BackupIO; + +namespace PvPAdventure.Core.Features.SpawnSelector.Players; + +public class SpawnSelectorPlayer : ModPlayer +{ + public override void PostUpdate() + { + if (Main.dedServ || Player.whoAmI != Main.myPlayer) + { + return; + } + + var regionManager = ModContent.GetInstance(); + Point tilePos = Player.Center.ToTileCoordinates(); + var region = regionManager.GetRegionContaining(tilePos); + bool inRegion = region != null; + + if (inRegion) + { + SpawnSelectorSystem.SetEnabled(true); + } + + // Unsure if this causes any bugs. + // It may be too forcing to always set it to false whenever map is closed. + if (!Main.mapFullscreen) + SpawnSelectorSystem.SetEnabled(false); + + // Check if player is using AdventureMirror + if (Player.HeldItem != null && + Player.HeldItem.type == ModContent.ItemType() && + Player.itemAnimation > 0 && + Player.itemAnimation % 60 == 0) + { + int itemUseTimeLeft = Main.LocalPlayer.itemAnimation / 60; + string timeLeft = itemUseTimeLeft.ToString(); + + // Display text above the player every second + PopupText.NewText(new AdvancedPopupRequest + { + Color = Color.Crimson, + Text = timeLeft, + Velocity = new(0.0f, -4.0f), + DurationInFrames = 60 * 1 + }, Player.Top); + } + } + + public bool hasSelectedSpawnPoint = false; + + public override void UpdateDead() + { + //Main.NewText(Player.respawnTimer); + + // Keeps the player from respawning until they have selected a spawn. + if (Player.respawnTimer <= 10 && !hasSelectedSpawnPoint) + { + Player.respawnTimer = 10; + } + } +} \ No newline at end of file diff --git a/Core/Features/SpawnSelector/Structures/AdventureTeleportStateSettings.cs b/Core/Features/SpawnSelector/Structures/AdventureTeleportStateSettings.cs deleted file mode 100644 index 6b41aed9..00000000 --- a/Core/Features/SpawnSelector/Structures/AdventureTeleportStateSettings.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace PvPAdventure.Core.Features.SpawnSelector.Structures; - -public static class AdventureTeleportStateSettings -{ - private static bool IsEnabled = false; - - public static bool GetIsEnabled() => IsEnabled; - public static void SetIsEnabled(bool value) => IsEnabled = value; -} diff --git a/Core/Features/SpawnSelector/Systems/AdventureTeleportState.cs b/Core/Features/SpawnSelector/Systems/AdventureTeleportState.cs deleted file mode 100644 index 97109e27..00000000 --- a/Core/Features/SpawnSelector/Systems/AdventureTeleportState.cs +++ /dev/null @@ -1,231 +0,0 @@ -using Microsoft.Xna.Framework; -using PvPAdventure.Core.Features.SpawnSelector.Structures; -using System; -using System.Collections.Generic; -using System.Linq; -using Terraria; -using Terraria.Audio; -using Terraria.GameContent.UI.Elements; -using Terraria.ID; -using Terraria.UI; - -namespace PvPAdventure.Core.Features.SpawnSelector.Systems; - -public class AdventureTeleportState : UIState -{ - private UIPanel _panel; - private UIText _title; - private UITextPanel _btnRandom; - private UITextPanel _btnTeammates; - private UITextPanel _btnBeds; - - public bool IsMouseOverUI { get; private set; } - - // Team menu - private UIList _teammateList; - private bool _teammatesOpen; - private int _selectedPlayerId = -1; - - private const float RowHeight = 28f; - private const float RowPadding = 4f; - private const float ListTop = 146f; - private const float PanelInnerPadding = 10f; // left/right padding inside _panel - - public override void OnInitialize() - { - _panel = new UIPanel(); - _panel.Width.Set(420f, 0f); - _panel.Height.Set(180f, 0f); - _panel.Top.Set(20f, 0f); - _panel.HAlign = 0.5f; - Append(_panel); - - _title = new UIText("PvP Adventure Teleport"); - _title.HAlign = 0.5f; - _title.Top.Set(8f, 0f); - _panel.Append(_title); - - _btnRandom = MakeButton("Random Teleport", 44f); - _btnRandom.OnLeftClick += (_, __) => RequestRandomTeleport(); - - _btnTeammates = MakeButton("Teleport to Teammate", 78f); - _btnTeammates.OnLeftClick += (_, __) => ToggleTeammatesMenu(); - - _btnBeds = MakeButton("Teleport to Bed", 112f); - _btnBeds.OnLeftClick += (_, __) => OpenBedsMenu(); - - _panel.Append(_btnRandom); - _panel.Append(_btnTeammates); - _panel.Append(_btnBeds); - } - - private UITextPanel MakeButton(string label, float top) - { - var b = new UITextPanel(label, 0.9f, large: false); - b.Width.Set(-20f, 1f); - b.Left.Set(10f, 0f); - b.Top.Set(top, 0f); - b.BackgroundColor = new Color(63, 82, 151) * 0.8f; - b.BorderColor = new Color(89, 116, 213) * 0.8f; - b.OnMouseOver += (evt, element) => b.BackgroundColor = new Color(73, 92, 161); - b.OnMouseOut += (evt, element) => b.BackgroundColor = new Color(63, 82, 151) * 0.8f; - return b; - } - - public override void Update(GameTime gameTime) - { - base.Update(gameTime); - - // Update mouse over state - IsMouseOverUI = _panel.IsMouseHovering - || _btnRandom.IsMouseHovering - || _btnTeammates.IsMouseHovering - || _btnBeds.IsMouseHovering - || (_teammateList?.IsMouseHovering ?? false); - } - - private void RequestRandomTeleport() - { - SoundEngine.PlaySound(SoundID.Item6); // MAGIC MIRROR SOUND - - if (Main.netMode == NetmodeID.MultiplayerClient) - { - NetMessage.SendData(MessageID.RequestTeleportationByServer); - } - else - { - Main.LocalPlayer.TeleportationPotion(); - } - - CloseAndExitMap(); - } - - private void ToggleTeammatesMenu() - { - _teammatesOpen = !_teammatesOpen; - - // Remove previous list if exists - _teammateList?.Remove(); - _teammateList = null; - - // If closing, restore compact panel height and reset Beds button - if (!_teammatesOpen) - { - _panel.Height.Set(180f, 0f); - _btnBeds.Top.Set(112f, 0f); - _btnBeds.Recalculate(); - SoundEngine.PlaySound(SoundID.MenuClose); - return; - } - SoundEngine.PlaySound(SoundID.MenuOpen); - - // Build a list - _teammateList = new UIList - { - ListPadding = RowPadding, - OverflowHidden = true - }; - _teammateList.Left.Set(PanelInnerPadding, 0f); - _teammateList.Top.Set(ListTop-RowHeight, 0f); - _teammateList.Width.Set(-PanelInnerPadding * 2f, 1f); // fill width minus padding - _panel.Append(_teammateList); - - // Gather teammates on same team (excluding self) - int myId = Main.myPlayer; - var me = Main.player[myId]; - int myTeam = me.team; - - var teammates = new List(); - if (myTeam != 0) - { - for (int i = 0; i < Main.maxPlayers; i++) - { - var p = Main.player[i]; - if (p != null && p.active && i != myId && p.team == myTeam) - teammates.Add(p); - } - } - - // If none, show yourself as a single entry instead - if (teammates.Count == 0) - { - _teammateList.Add(MakeTeammateRow(me, isSelf: true)); - } - else - { - foreach (var p in teammates) - _teammateList.Add(MakeTeammateRow(p, isSelf: false)); - } - - int rowCount = Math.Max(1, teammates.Count); - float listHeight = rowCount * RowHeight + (rowCount - 1) * RowPadding + 6f; - - _teammateList.Height.Set(listHeight, 0f); - _teammateList.Recalculate(); - - // Beds button just below list - float bedsTop = ListTop + listHeight + 8f; - _btnBeds.Top.Set(bedsTop, 0f); - _btnBeds.Recalculate(); - } - - private UIElement MakeTeammateRow(Player p, bool isSelf) - { - var row = new UIElement { OverflowHidden = true }; - row.OnMouseOver += (_, _) => { SoundEngine.PlaySound(SoundID.MenuTick); }; - row.Width.Set(0f, 1f); - row.Height.Set(RowHeight, 0f); - - var bg = new UIPanel(); - bg.Left.Set(0f, 0f); - bg.Top.Set(0f, 0f); - bg.Width.Set(0f, 1f); - bg.Height.Set(RowHeight, 0f); - bg.PaddingTop = bg.PaddingLeft = bg.PaddingRight = bg.PaddingBottom = 0; - bg.BackgroundColor = new Color(63, 82, 151) * 0.65f; - bg.BorderColor = new Color(89, 116, 213) * 0.90f; - - // 24x24 head at left - var head = new PlayerHeadElement(p, isSelf); - head.Left.Set(2f, 0f); - head.Top.Set(0f, 0f); // 2px padding inside 28px row - bg.Append(head); - - // Name text - var name = new UIText(isSelf ? $"You ({p?.name ?? "Player"})" : p?.name ?? "Player", 0.9f); - name.Left.Set(36, 0f); - name.Top.Set(5f, 0f); - name.TextColor = Color.White; - - row.OnMouseOver += (_, __) => { name.TextColor = Color.Yellow; }; - row.OnMouseOut += (_, __) => { name.TextColor = Color.White; }; - - row.OnLeftClick += (_, __) => - { - if (isSelf) - { - CloseAndExitMap(); - return; - } - if (p == null) return; - - Main.LocalPlayer.UnityTeleport(p.Center); - CloseAndExitMap(); - }; - - bg.Append(name); - row.Append(bg); - return row; - } - - private void OpenBedsMenu() - { - Main.NewText("Bed menu is still in construction (WIP)!"); - } - - private void CloseAndExitMap() - { - Main.mapFullscreen = false; - AdventureTeleportStateSettings.SetIsEnabled(false); - } -} diff --git a/Core/Features/SpawnSelector/Systems/AdventureTeleportSystem.cs b/Core/Features/SpawnSelector/Systems/AdventureTeleportSystem.cs deleted file mode 100644 index 33159432..00000000 --- a/Core/Features/SpawnSelector/Systems/AdventureTeleportSystem.cs +++ /dev/null @@ -1,103 +0,0 @@ -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Graphics; -using PvPAdventure.Core.Features.SpawnSelector.Structures; -using PvPAdventure.Core.Features.SpawnSelector.Systems; -using Terraria; -using Terraria.ModLoader; -using Terraria.UI; - -namespace PvPAdventure.Core.Features.AdventureTeleport.System; - -[Autoload(Side = ModSide.Client)] -public class AdventureTeleportSystem : ModSystem -{ - private UserInterface ui; - internal AdventureTeleportState adventureTeleportState; - - public override void Load() - { - if (!Main.dedServ) - { - ui = new UserInterface(); - adventureTeleportState = new AdventureTeleportState(); - adventureTeleportState.Activate(); - - Main.OnPostFullscreenMapDraw += DrawOverFullscreenMap; - } - - On_Main.TriggerPing += OverridePing; - } - - public override void Unload() - { - if (!Main.dedServ) - Main.OnPostFullscreenMapDraw -= DrawOverFullscreenMap; - - On_Main.TriggerPing -= OverridePing; - } - - private void OverridePing(On_Main.orig_TriggerPing orig, Vector2 position) - { - if (adventureTeleportState.IsMouseOverUI) - { - return; - } - orig(position); - } - - public override void UpdateUI(GameTime gameTime) - { - if (ui == null) return; - - bool visible = AdventureTeleportStateSettings.GetIsEnabled() && Main.mapFullscreen; - - if (visible) - { - if (ui.CurrentState != adventureTeleportState) - ui.SetState(adventureTeleportState); - - ui.Update(gameTime); - - if (adventureTeleportState.IsMouseOverUI) - { - Main.LocalPlayer.mouseInterface = true; - } - } - else if (ui.CurrentState != null) - { - ui.SetState(null); - } - } - - // Draw AFTER the map, with our own Begin/End for UI - private void DrawOverFullscreenMap(Vector2 _mapPos, float _mapScale) - { - if (ui?.CurrentState == null) return; - - var sb = Main.spriteBatch; - bool began = false; - - try - { - sb.Begin( - SpriteSortMode.Deferred, - BlendState.AlphaBlend, - SamplerState.LinearClamp, - DepthStencilState.None, - RasterizerState.CullCounterClockwise, - effect: null, - transformMatrix: Main.UIScaleMatrix - ); - began = true; - - // draw our UI state over the fullscreen map - ui.Draw(sb, Main._drawInterfaceGameTime); - } - finally - { - if (began) - sb.End(); - } - } - -} diff --git a/Core/Features/SpawnSelector/Systems/SpawnSelectorState.cs b/Core/Features/SpawnSelector/Systems/SpawnSelectorState.cs new file mode 100644 index 00000000..7680116a --- /dev/null +++ b/Core/Features/SpawnSelector/Systems/SpawnSelectorState.cs @@ -0,0 +1,25 @@ +using Microsoft.Xna.Framework; +using PvPAdventure.Core.Features.SpawnSelector.UI; +using Terraria.UI; +using Terraria.GameContent.UI.Elements; + +namespace PvPAdventure.Core.Features.SpawnSelector.Systems +{ + internal class SpawnSelectorState : UIState + { + public override void OnInitialize() + { + // Create the base panel with the teleport options + UISpawnSelectorPanel spawnSelectorPanel = new(); + Append(spawnSelectorPanel); + + // Create the title panel with a height of 32px, 10 px from the top, centered horizontally + UITextPanel chooseYourSpawnPanel = new("Choose Your Spawn", 0.8f, true); + chooseYourSpawnPanel.HAlign = 0.5f; + chooseYourSpawnPanel.VAlign = 0f; + chooseYourSpawnPanel.Top.Set(10, 0); + chooseYourSpawnPanel.BackgroundColor = new Color(73, 94, 171); + Append(chooseYourSpawnPanel); + } + } +} diff --git a/Core/Features/SpawnSelector/Systems/SpawnSelectorSystem.cs b/Core/Features/SpawnSelector/Systems/SpawnSelectorSystem.cs new file mode 100644 index 00000000..861f648d --- /dev/null +++ b/Core/Features/SpawnSelector/Systems/SpawnSelectorSystem.cs @@ -0,0 +1,93 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using PvPAdventure.Core.Features.SpawnSelector.UI; +using Terraria; +using Terraria.ModLoader; +using Terraria.UI; + +namespace PvPAdventure.Core.Features.SpawnSelector.Systems; + +[Autoload(Side = ModSide.Client)] +public class SpawnSelectorSystem : ModSystem +{ + private UserInterface ui; + private SpawnSelectorState state; + private UISpawnSelectorPanel teleportPanel; + + // Track whether the spawn selector is enabled + private static bool Enabled; // whether the spawn selector is currently showing in the fullscreen map + public static void SetEnabled(bool newValue) => Enabled = newValue; + public static bool GetEnabled() => Enabled; + + // Load and unload hooks + public override void Load() + { + if (!Main.dedServ) + { + ui = new(); + state = new(); + state.Activate(); + + Main.OnPostFullscreenMapDraw += DrawOverFullscreenMap; + } + + On_Main.TriggerPing += OnTriggerPing; + } + + public override void Unload() + { + if (!Main.dedServ) + Main.OnPostFullscreenMapDraw -= DrawOverFullscreenMap; + + On_Main.TriggerPing -= OnTriggerPing; + } + + private void OnTriggerPing(On_Main.orig_TriggerPing orig, Vector2 position) + { + // Skip ping execution if our panel is being hovered + if (teleportPanel != null && !teleportPanel.IsMouseHovering) + { + orig(position); + } + } + + public override void UpdateUI(GameTime gameTime) + { + if (ui == null) return; + + bool visible = GetEnabled() && Main.mapFullscreen; + + if (visible) + { + if (ui.CurrentState != state) + ui.SetState(state); + + ui.Update(gameTime); + } + else if (ui.CurrentState != null) + { + ui.SetState(null); + } + } + + // Draw AFTER the map, with our own Begin/End for UI + private void DrawOverFullscreenMap(Vector2 _mapPos, float _mapScale) + { + if (ui?.CurrentState == null) return; + + var sb = Main.spriteBatch; + bool began = false; + + try + { + sb.Begin(SpriteSortMode.Deferred,BlendState.AlphaBlend,SamplerState.LinearClamp,DepthStencilState.None,RasterizerState.CullCounterClockwise,null,Main.UIScaleMatrix); + began = true; + ui.Draw(sb, Main._drawInterfaceGameTime); + } + finally + { + if (began) + sb.End(); + } + } +} diff --git a/Core/Features/SpawnSelector/UI/AdventureTeleportPanel.cs b/Core/Features/SpawnSelector/UI/AdventureTeleportPanel.cs deleted file mode 100644 index 18d9944e..00000000 --- a/Core/Features/SpawnSelector/UI/AdventureTeleportPanel.cs +++ /dev/null @@ -1,8 +0,0 @@ - -using Terraria.GameContent.UI.Elements; - -namespace PvPAdventure.Core.Features.SpawnSelector.UI; -internal class AdventureTeleportPanel : UIPanel -{ - -} diff --git a/Core/Features/SpawnSelector/UI/PlayerHeadElement.cs b/Core/Features/SpawnSelector/UI/PlayerHeadElement.cs deleted file mode 100644 index 259657de..00000000 --- a/Core/Features/SpawnSelector/UI/PlayerHeadElement.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Graphics; -using Terraria; -using Terraria.UI; - -namespace PvPAdventure.Core.Features.SpawnSelector.UI; - -public class PlayerHeadElement : UIElement -{ - private readonly Player player; - private readonly bool isSelf; - - public PlayerHeadElement(Player player, bool isSelf) - { - this.player = player; - this.isSelf = isSelf; - Width.Set(24f, 0f); - Height.Set(24f, 0f); - } - - protected override void DrawSelf(SpriteBatch spriteBatch) - { - // Only draw if we have a player - if (player == null || !player.active) return; - - var dims = GetDimensions(); - Vector2 pos = new Vector2(dims.X + dims.Width * 0.5f, dims.Y + dims.Height * 0.5f); // center on the element - float scale = 0.75f; - float alpha = 1f; - Main.MapPlayerRenderer.DrawPlayerHead( - Main.Camera, player, pos, alpha, scale, Color.White); - } -} diff --git a/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs b/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs new file mode 100644 index 00000000..34ab074c --- /dev/null +++ b/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs @@ -0,0 +1,177 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using PvPAdventure.Core.Helpers; +using ReLogic.Content; +using System; +using Terraria; +using Terraria.GameContent; +using Terraria.GameContent.UI.Elements; +using Terraria.ID; +using Terraria.Localization; +using Terraria.UI; + +namespace PvPAdventure.Core.Features.SpawnSelector.UI +{ + /// + /// Vanilla-like character row: + /// + internal class UISpawnSelectorCharacterListItem : UIPanel + { + private readonly Asset _dividerTexture; + private readonly Asset _innerPanelTexture; + private readonly Asset _playerBGTexture; + + private readonly string _name; + private readonly string _hpText; + private readonly string _manaText; + + public UISpawnSelectorCharacterListItem() + { + _dividerTexture = Main.Assets.Request("Images/UI/Divider"); + _innerPanelTexture = Main.Assets.Request("Images/UI/InnerPanelBackground"); + _playerBGTexture = Main.Assets.Request("Images/UI/PlayerBackground"); + + _name = "Teammate"; + _hpText = "500 " + Language.GetTextValue("GameUI.PlayerLifeMax"); + _manaText = "200 " + Language.GetTextValue("GameUI.PlayerManaMax"); + } + + public override void OnInitialize() + { + //BorderColor = new Color(89, 116, 213) * 0.7f; + BorderColor = Color.Black; + BackgroundColor = new Color(63, 82, 151) * 0.7f; + Height.Set(72f, 0f); + Width.Set(-20f, 1f); + SetPadding(6f); + } + + private void DrawPanel(SpriteBatch spriteBatch, Vector2 position, float width) + { + spriteBatch.Draw(_innerPanelTexture.Value, position, + new Rectangle(0, 0, 8, _innerPanelTexture.Height()), Color.White); + + spriteBatch.Draw( + _innerPanelTexture.Value, + new Vector2(position.X + 8f, position.Y), + new Rectangle(8, 0, 8, _innerPanelTexture.Height()), + Color.White, + 0f, + Vector2.Zero, + new Vector2((width - 16f) / 8f, 1f), + SpriteEffects.None, + 0f + ); + + spriteBatch.Draw( + _innerPanelTexture.Value, + new Vector2(position.X + width - 8f, position.Y), + new Rectangle(16, 0, 8, _innerPanelTexture.Height()), + Color.White + ); + } + + protected override void DrawSelf(SpriteBatch sb) + { + base.DrawSelf(sb); + + CalculatedStyle inner = GetInnerDimensions(); + var dims = GetDimensions(); + + // Left "player" background + Vector2 pos = new(inner.X, inner.Y); + sb.Draw(_playerBGTexture.Value, pos, Color.White); + + // Right "bed" background + Vector2 bedPos = new(pos.X+dims.Width-73, pos.Y); + sb.Draw(_playerBGTexture.Value, bedPos, Color.White); + + // Draw bed (placeholder) + // Future: Draw section of map with the bed + bedPos += new Vector2(31, 31); + Item icon = new(ItemID.Bed); + ItemSlot.DrawItemIcon(icon, 31, sb, bedPos, 1.0f, 32f, Color.White); + + + // Draw player + sb.End(); + sb.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, DepthStencilState.Default, RasterizerState.CullNone, null, Main.UIScaleMatrix); + + try + { + // Draw player + pos += Main.screenPosition + new Vector2(16, 8); + + Player player = Main.LocalPlayer; + + // Celestial starboard (45) sucks + if (player.wings == 45) player.wings = 0; + + Main.PlayerRenderer.DrawPlayer(Main.Camera, player, pos, player.fullRotation, player.fullRotationOrigin, 0f, 0.9f); + } + catch (Exception e) + { + //Main.NewText("Failed to draw player", Color.Red); + Log.Error("Failed to draw player: " + e); + } + + float leftColumnWidth = _playerBGTexture.Width(); // keep aligned to texture + float startX = inner.X + leftColumnWidth; + + // Measure text width + Vector2 textSize = FontAssets.MouseText.Value.MeasureString(_name); + float centerX = inner.X + inner.Width * 0.5f; + + // Draw player name centered + Utils.DrawBorderString( + sb, + _name, + new Vector2(centerX - textSize.X * 0.5f, inner.Y - 2f), + Color.White + ); + + // Divider + sb.Draw( + _dividerTexture.Value, + new Vector2(startX+1, inner.Y + 21f), + null, + Color.White, + 0f, + Vector2.Zero, + new Vector2((dims.X + dims.Width - startX) / 8 - 10, 1f), + SpriteEffects.None, + 0f + ); + + // HP / MP panel + Vector2 panelPos = new(startX + 6f, inner.Y + 29f); + float panelWidth = 220f; + DrawPanel(sb, panelPos, panelWidth); + + Vector2 cursor = panelPos; + + // HP + sb.Draw(TextureAssets.Heart.Value, cursor + new Vector2(5f, 2f), Color.White); + cursor.X += 10f + TextureAssets.Heart.Width(); + Utils.DrawBorderString(sb, _hpText, cursor + new Vector2(0f, 3f), Color.White); + + // MP + cursor.X += 80f; + sb.Draw(TextureAssets.Mana.Value, cursor + new Vector2(5f, 2f), Color.White); + cursor.X += 10f + TextureAssets.Mana.Width(); + Utils.DrawBorderString(sb, _manaText, cursor + new Vector2(0f, 3f), Color.White); + } + + public override void MouseOut(UIMouseEvent evt) + { + base.MouseOut(evt); + BackgroundColor = new Color(63, 82, 151) * 0.8f; + } + + public override void MouseOver(UIMouseEvent evt) + { + base.MouseOver(evt); + BackgroundColor = new Color(73, 92, 161); + } + } +} diff --git a/Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs b/Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs new file mode 100644 index 00000000..226ff5c4 --- /dev/null +++ b/Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs @@ -0,0 +1,82 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using PvPAdventure.Core.Features.SpawnSelector.Systems; +using System; +using Terraria; +using Terraria.GameContent.UI.Elements; +using Terraria.ID; +using Terraria.ModLoader.UI; +using Terraria.UI; +using static System.Net.Mime.MediaTypeNames; + +namespace PvPAdventure.Core.Features.SpawnSelector.UI +{ + internal class UISpawnSelectorPanel : UIPanel + { + private UITextPanel randomButton; + + public override void OnInitialize() + { + Width.Set(400f, 0f); + Height.Set(300f, 0f); + HAlign = 0.5f; + VAlign = 0.0f; + Top.Set(10 + 32 - 10, 0); + BackgroundColor = new Color(33, 43, 79) * 0.8f; + SetPadding(6f); + + // --- Random teleport button --- + randomButton = new UITextPanel("Random"); + randomButton.Width.Set(-20f, 1f); + randomButton.Left.Set(10f, 0f); + randomButton.Top.Set(30f, 0f); + randomButton.BackgroundColor = new Color(63, 82, 151) * 0.8f; + randomButton.BorderColor = Color.Black; + randomButton.OnMouseOver += (_, _) => + { + randomButton.BackgroundColor = new Color(73, 92, 161); + }; + randomButton.OnMouseOut += (_, _) => + randomButton.BackgroundColor = new Color(63, 82, 151) * 0.8f; + randomButton.OnLeftClick += (_, _) => PerformRandomTeleport(); + Append(randomButton); + + var item1 = new UISpawnSelectorCharacterListItem(); + item1.Width.Set(-20f, 1f); + item1.Left.Set(10, 0f); + item1.Top.Set(74, 0f); + Append(item1); + + var item2 = new UISpawnSelectorCharacterListItem(); + item2.Width.Set(-20f, 1f); + item2.Left.Set(10, 0f); + item2.Top.Set(74 + 72 + 4, 0f); + Append(item2); + } + + private void PerformRandomTeleport() + { + if (Main.netMode == NetmodeID.MultiplayerClient) + NetMessage.SendData(MessageID.RequestTeleportationByServer); + else + Main.LocalPlayer.TeleportationPotion(); + + CloseAndExitMap(); + } + + private void CloseAndExitMap() + { + Main.mapFullscreen = false; + SpawnSelectorSystem.SetEnabled(false); + } + + + public override void Draw(SpriteBatch spriteBatch) + { + //RemoveAllChildren(); + //OnInitialize(); + + base.Draw(spriteBatch); + } + } +} diff --git a/Properties/launchSettings.json b/Properties/launchSettings.json index 07e2f8d0..280b6ecf 100644 --- a/Properties/launchSettings.json +++ b/Properties/launchSettings.json @@ -11,6 +11,12 @@ "executablePath": "dotnet", "commandLineArgs": "$(tMLServerPath)", "workingDirectory": "$(tMLSteamPath)" - } + }, + "TerrariaSkipSelect": { + "commandName": "Executable", + "executablePath": "dotnet", + "commandLineArgs": "$(tMLPath) -skipselect", + "workingDirectory": "$(tMLSteamPath)" + }, } } \ No newline at end of file diff --git a/PvPAdventure.csproj b/PvPAdventure.csproj index cc33f564..da9cae18 100644 --- a/PvPAdventure.csproj +++ b/PvPAdventure.csproj @@ -1,4 +1,4 @@ - + PvPAdventure @@ -22,4 +22,10 @@ lib\System.Linq.Async.dll

4+e$0sZG_WLBVKfYpIx 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 E17mSI+yDRo literal 0 HcmV?d00001 diff --git a/Assets/Buff/ShatteredArmor.png b/Assets/Buff/ShatteredArmor.png new file mode 100644 index 0000000000000000000000000000000000000000..b221cf92f52a7602a96e8935acb6f8d6b75902e7 GIT binary patch literal 441 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vO2U$sR$z3=CCj3=9n|3=F@3LJcn% z7)lKo7+xhXFj&oCU=S~uvn$XBC?OHx6XFV_fxt}H!p+`QfLk&-K1o4P>;M1%Ti6qq z10@(sg8YIR9G=}s196hP-Cfwl5<6Z4IqW5#zOL*qx!4$$nYXCDt_BL_db&7E_x8s2o8uSoR1!aE_-TD;)z zUv^uTxcn$Twv9lGRZCnWN>UO_QmvAUQh^kMk%5t^uAzahfmw)wp_Q?zm4UIgfq|8Q z!K1LXXHhid=BH$)RpQn#nOn3Fs6hj6LrG?CYH>+oZUJsRN90V_0rfC=y85}Sb4q9e E0J}wlH2?qr literal 0 HcmV?d00001 diff --git a/Localization/en-US.hjson b/Localization/en-US.hjson index defb6769..97756bf7 100644 --- a/Localization/en-US.hjson +++ b/Localization/en-US.hjson @@ -741,6 +741,21 @@ Mods: { DisplayName: BRO IS A CHOJ Description: You are too much of a CHOJ to dash effectively } + + ShatteredArmor: { + Description: Mods.PvPAdventure.Buffs.ShatteredArmor.Description + DisplayName: Shattered Armor + } + + Anathema: { + Description: Mods.PvPAdventure.Buffs.Anathema.Description + DisplayName: Anathema + } + + Hellhex: { + Description: Mods.PvPAdventure.Buffs.Hellhex.Description + DisplayName: Hellhex + } } } } From 5d25656de5d46f59736dd5dfe193a3476e41f50d Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Fri, 10 Oct 2025 20:03:30 -0700 Subject: [PATCH 123/206] CHAGNED SOME DROP RATES --- AdventureDropDatabase.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/AdventureDropDatabase.cs b/AdventureDropDatabase.cs index 22900114..36d4cdd1 100644 --- a/AdventureDropDatabase.cs +++ b/AdventureDropDatabase.cs @@ -96,7 +96,7 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) case NPCID.GiantTortoise: foreach (var drop in drops) - ModifyDropRate(drop, ItemID.TurtleShell, 1, 4); + ModifyDropRate(drop, ItemID.TurtleShell, 1, 3); break; case NPCID.Necromancer: @@ -216,6 +216,13 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) ModifyDropRate(drop, ItemID.Binoculars, 1, 1); break; + case NPCID.DungeonSpirit: + npcLoot.RemoveWhere(drop => + (drop is CommonDrop commonDrop && commonDrop.itemId == ItemID.Ectoplasm) || + drop is LeadingConditionRule); + npcLoot.Add(ItemDropRule.Common(ItemID.Ectoplasm, 1, 3, 5)); + break; + case NPCID.KingSlime: foreach (var drop in drops) ModifyDropRate(drop, ItemID.SlimySaddle, 1, 1); From 47de89ef6257d32b141ceb3bc3ae7604a9dc40d8 Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Sat, 11 Oct 2025 10:15:57 -0700 Subject: [PATCH 124/206] updates --- AdventurePlayer.cs | 349 ++++++++++++++++++++++++++++++++- Assets/Buff/BitingEmbrace.png | Bin 0 -> 579 bytes Assets/Buff/BrittleBones.png | Bin 0 -> 494 bytes Assets/Buff/Hellhex.png | Bin 97759 -> 872 bytes Assets/Buff/Marked.png | Bin 0 -> 589 bytes Assets/Buff/PressurePoints.png | Bin 0 -> 474 bytes Localization/en-US.hjson | 72 ++++--- 7 files changed, 387 insertions(+), 34 deletions(-) create mode 100644 Assets/Buff/BitingEmbrace.png create mode 100644 Assets/Buff/BrittleBones.png create mode 100644 Assets/Buff/Marked.png create mode 100644 Assets/Buff/PressurePoints.png diff --git a/AdventurePlayer.cs b/AdventurePlayer.cs index fbb039c4..5f2b7f2f 100644 --- a/AdventurePlayer.cs +++ b/AdventurePlayer.cs @@ -1263,17 +1263,304 @@ public override void PostUpdateEquips() } } } -public class CoolWhipBuff : ModPlayer +public class BitingEmbracePlayer : ModPlayer { public override void PostHurt(Player.HurtInfo info) { if (info.DamageSource.SourceProjectileType == ProjectileID.CoolWhip) { - Player.AddBuff(BuffID.ScytheWhipPlayerBuff, 1); + + int duration = 300; + + if (info.DamageSource.SourcePlayerIndex >= 0 && info.DamageSource.SourcePlayerIndex < Main.maxPlayers) + { + Player attacker = Main.player[info.DamageSource.SourcePlayerIndex]; + if (attacker != null && attacker.active) + { + TikiArmorPlayer tikiPlayer = attacker.GetModPlayer(); + if (tikiPlayer.hasTikiSet) + { + duration = (int)(duration * 1.5f); + } + } + } + + Player.AddBuff(ModContent.BuffType(), duration); + Player.AddBuff(BuffID.Frozen, duration / 75); + } + } + public override void ModifyHurt(ref Player.HurtModifiers modifiers) + { + if (Player.HasBuff()) + { + bool isSummon = false; + + if (modifiers.DamageSource.SourceProjectileLocalIndex >= 0) + { + Projectile proj = Main.projectile[modifiers.DamageSource.SourceProjectileLocalIndex]; + if (proj != null && proj.active && (proj.minion || proj.sentry || proj.CountsAsClass(DamageClass.SummonMeleeSpeed))) + { + isSummon = true; + } + } + else if (modifiers.DamageSource.SourceProjectileType > 0) + { + int projType = modifiers.DamageSource.SourceProjectileType; + if (projType == ProjectileID.BlandWhip || projType == ProjectileID.FireWhip || + projType == ProjectileID.SwordWhip || projType == ProjectileID.MaceWhip || + projType == ProjectileID.ScytheWhip || projType == ProjectileID.ThornWhip || + projType == ProjectileID.BoneWhip || projType == ProjectileID.RainbowWhip || + projType == ProjectileID.CoolWhip) + { + isSummon = true; + } + } + + if (!isSummon) + { + modifiers.FinalDamage += 6; + } + } + } +} + +public class PressurePointsPlayer : ModPlayer +{ + public override void PostHurt(Player.HurtInfo info) + { + if (info.DamageSource.SourceProjectileType == ProjectileID.ThornWhip) + { + int duration = 300; + + if (info.DamageSource.SourcePlayerIndex >= 0 && info.DamageSource.SourcePlayerIndex < Main.maxPlayers) + { + Player attacker = Main.player[info.DamageSource.SourcePlayerIndex]; + if (attacker != null && attacker.active) + { + TikiArmorPlayer tikiPlayer = attacker.GetModPlayer(); + if (tikiPlayer.hasTikiSet) + { + duration = (int)(duration * 1.5f); + } + } + } + + Player.AddBuff(ModContent.BuffType(), duration); + + } + } + public override void ModifyHurt(ref Player.HurtModifiers modifiers) + { + if (Player.HasBuff()) + { + bool isSummon = false; + + if (modifiers.DamageSource.SourceProjectileLocalIndex >= 0) + { + Projectile proj = Main.projectile[modifiers.DamageSource.SourceProjectileLocalIndex]; + if (proj != null && proj.active && (proj.minion || proj.sentry || proj.CountsAsClass(DamageClass.SummonMeleeSpeed))) + { + isSummon = true; + } + } + else if (modifiers.DamageSource.SourceProjectileType > 0) + { + int projType = modifiers.DamageSource.SourceProjectileType; + if (projType == ProjectileID.BlandWhip || projType == ProjectileID.FireWhip || + projType == ProjectileID.SwordWhip || projType == ProjectileID.MaceWhip || + projType == ProjectileID.ScytheWhip || projType == ProjectileID.ThornWhip || + projType == ProjectileID.BoneWhip || projType == ProjectileID.RainbowWhip || + projType == ProjectileID.CoolWhip) + { + isSummon = true; + } + } + + if (!isSummon) + { + modifiers.FinalDamage += 6; + } + } + } +} + +public class BrittleBonesPlayer : ModPlayer +{ + public override void PostHurt(Player.HurtInfo info) + { + if (info.DamageSource.SourceProjectileType == ProjectileID.BoneWhip) + { + int duration = 300; + + if (info.DamageSource.SourcePlayerIndex >= 0 && info.DamageSource.SourcePlayerIndex < Main.maxPlayers) + { + Player attacker = Main.player[info.DamageSource.SourcePlayerIndex]; + if (attacker != null && attacker.active) + { + TikiArmorPlayer tikiPlayer = attacker.GetModPlayer(); + if (tikiPlayer.hasTikiSet) + { + duration = (int)(duration * 1.5f); + } + } + } + + Player.AddBuff(ModContent.BuffType(), duration); + + } + } + public override void ModifyHurt(ref Player.HurtModifiers modifiers) + { + if (Player.HasBuff()) + { + bool isSummon = false; + + if (modifiers.DamageSource.SourceProjectileLocalIndex >= 0) + { + Projectile proj = Main.projectile[modifiers.DamageSource.SourceProjectileLocalIndex]; + if (proj != null && proj.active && (proj.minion || proj.sentry || proj.CountsAsClass(DamageClass.SummonMeleeSpeed))) + { + isSummon = true; + } + } + else if (modifiers.DamageSource.SourceProjectileType > 0) + { + int projType = modifiers.DamageSource.SourceProjectileType; + if (projType == ProjectileID.BlandWhip || projType == ProjectileID.FireWhip || + projType == ProjectileID.SwordWhip || projType == ProjectileID.MaceWhip || + projType == ProjectileID.ScytheWhip || projType == ProjectileID.ThornWhip || + projType == ProjectileID.BoneWhip || projType == ProjectileID.RainbowWhip || + projType == ProjectileID.CoolWhip) + { + isSummon = true; + } + } + + if (!isSummon) + { + modifiers.FinalDamage += 7; + } + } + } +} +public class MarkedPlayer : ModPlayer +{ + public override void PostHurt(Player.HurtInfo info) + { + if (info.DamageSource.SourceProjectileType == ProjectileID.SwordWhip) + { + int duration = 300; + + if (info.DamageSource.SourcePlayerIndex >= 0 && info.DamageSource.SourcePlayerIndex < Main.maxPlayers) + { + Player attacker = Main.player[info.DamageSource.SourcePlayerIndex]; + if (attacker != null && attacker.active) + { + TikiArmorPlayer tikiPlayer = attacker.GetModPlayer(); + if (tikiPlayer.hasTikiSet) + { + duration = (int)(duration * 1.5f); + } + } + } + + Player.AddBuff(ModContent.BuffType(), duration); + + } + } + public override void ModifyHurt(ref Player.HurtModifiers modifiers) + { + if (Player.HasBuff()) + { + bool isSummon = false; + + if (modifiers.DamageSource.SourceProjectileLocalIndex >= 0) + { + Projectile proj = Main.projectile[modifiers.DamageSource.SourceProjectileLocalIndex]; + if (proj != null && proj.active && (proj.minion || proj.sentry || proj.CountsAsClass(DamageClass.SummonMeleeSpeed))) + { + isSummon = true; + } + } + else if (modifiers.DamageSource.SourceProjectileType > 0) + { + int projType = modifiers.DamageSource.SourceProjectileType; + if (projType == ProjectileID.BlandWhip || projType == ProjectileID.FireWhip || + projType == ProjectileID.SwordWhip || projType == ProjectileID.MaceWhip || + projType == ProjectileID.ScytheWhip || projType == ProjectileID.ThornWhip || + projType == ProjectileID.BoneWhip || projType == ProjectileID.RainbowWhip || + projType == ProjectileID.CoolWhip) + { + isSummon = true; + } + } + + if (!isSummon) + { + modifiers.FinalDamage += 9; + } + } + } +} +public class AnathemaPlayer : ModPlayer +{ //ts is all temporary + public override void PostHurt(Player.HurtInfo info) + { + if (info.DamageSource.SourceProjectileType == ProjectileID.RainbowWhip) + { + int duration = 300; + + if (info.DamageSource.SourcePlayerIndex >= 0 && info.DamageSource.SourcePlayerIndex < Main.maxPlayers) + { + Player attacker = Main.player[info.DamageSource.SourcePlayerIndex]; + if (attacker != null && attacker.active) + { + TikiArmorPlayer tikiPlayer = attacker.GetModPlayer(); + if (tikiPlayer.hasTikiSet) + { + duration = (int)(duration * 1.5f); + } + } + } + + Player.AddBuff(ModContent.BuffType(), duration); + } } + public override void ModifyHurt(ref Player.HurtModifiers modifiers) + { + if (Player.HasBuff()) + { + bool isSummon = false; + if (modifiers.DamageSource.SourceProjectileLocalIndex >= 0) + { + Projectile proj = Main.projectile[modifiers.DamageSource.SourceProjectileLocalIndex]; + if (proj != null && proj.active && (proj.minion || proj.sentry || proj.CountsAsClass(DamageClass.SummonMeleeSpeed))) + { + isSummon = true; + } + } + else if (modifiers.DamageSource.SourceProjectileType > 0) + { + int projType = modifiers.DamageSource.SourceProjectileType; + if (projType == ProjectileID.BlandWhip || projType == ProjectileID.FireWhip || + projType == ProjectileID.SwordWhip || projType == ProjectileID.MaceWhip || + projType == ProjectileID.ScytheWhip || projType == ProjectileID.ThornWhip || + projType == ProjectileID.BoneWhip || projType == ProjectileID.RainbowWhip || + projType == ProjectileID.CoolWhip) + { + isSummon = true; + } + } + if (!isSummon) + { + modifiers.FinalDamage += 8; + modifiers.FinalDamage *= 1.1f; + } + } + } } public class ShatteredArmorPlayer : ModPlayer { @@ -1282,9 +1569,8 @@ public override void PostHurt(Player.HurtInfo info) // Check if hit by MaceWhip projectile if (info.DamageSource.SourceProjectileType == ProjectileID.MaceWhip) { - int duration = 420; // 7 seconds base + int duration = 300; - // Check if attacker has Tiki set bonus if (info.DamageSource.SourcePlayerIndex >= 0 && info.DamageSource.SourcePlayerIndex < Main.maxPlayers) { Player attacker = Main.player[info.DamageSource.SourcePlayerIndex]; @@ -1293,7 +1579,7 @@ public override void PostHurt(Player.HurtInfo info) TikiArmorPlayer tikiPlayer = attacker.GetModPlayer(); if (tikiPlayer.hasTikiSet) { - duration = (int)(duration * 1.5f); // 50% longer = 10.5 seconds + duration = (int)(duration * 1.5f); } } } @@ -1306,8 +1592,6 @@ public override void PostUpdateBuffs() { if (Player.HasBuff()) { - Player.statDefense -= 16; - for (int i = 0; i < 1; i++) { int dustType = DustID.BatScepter ; @@ -1350,6 +1634,7 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) if (!isSummon) { + modifiers.FinalDamage += 8; modifiers.FinalDamage *= 1.12f; } } @@ -1474,7 +1759,7 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) // Only apply double damage for non-summon damage if (!isSummon) { - modifiers.FinalDamage *= 2f; // Double damage + modifiers.FinalDamage *= 2.75f; // Double damage modifiers.ModifyHurtInfo += (ref Player.HurtInfo info) => { storedDamage = info.Damage; }; @@ -1692,4 +1977,52 @@ public override void Update(Player player, ref int buffIndex) { // Visual effects and buff management handled in ModPlayer } +} +public class PressurePoints : ModBuff +{ + public override string Texture => $"PvPAdventure/Assets/Buff/PressurePoints"; + + public override void SetStaticDefaults() + { + Main.debuff[Type] = true; + Main.buffNoSave[Type] = false; + Main.buffNoTimeDisplay[Type] = false; + Main.persistentBuff[Type] = true; + } +} +public class BrittleBones : ModBuff +{ + public override string Texture => $"PvPAdventure/Assets/Buff/BrittleBones"; + + public override void SetStaticDefaults() + { + Main.debuff[Type] = true; + Main.buffNoSave[Type] = false; + Main.buffNoTimeDisplay[Type] = false; + Main.persistentBuff[Type] = true; + } +} +public class BitingEmbrace : ModBuff +{ + public override string Texture => $"PvPAdventure/Assets/Buff/BitingEmbrace"; + + public override void SetStaticDefaults() + { + Main.debuff[Type] = true; + Main.buffNoSave[Type] = false; + Main.buffNoTimeDisplay[Type] = false; + Main.persistentBuff[Type] = true; + } +} +public class Marked : ModBuff +{ + public override string Texture => $"PvPAdventure/Assets/Buff/Marked"; + + public override void SetStaticDefaults() + { + Main.debuff[Type] = true; + Main.buffNoSave[Type] = false; + Main.buffNoTimeDisplay[Type] = false; + Main.persistentBuff[Type] = true; + } } \ No newline at end of file diff --git a/Assets/Buff/BitingEmbrace.png b/Assets/Buff/BitingEmbrace.png new file mode 100644 index 0000000000000000000000000000000000000000..e15e827c171455dbe5a28530af273b8dbd8a2df9 GIT binary patch literal 579 zcmV-J0=)f+P)%boWA|J+40;wd%yGcp6`9mInUWAAyI@#5|BtpQV1ok29=~F z&5%SoFIP|lEj|6fSBLw+vW#}%26Y{uJ&GN-9{Bdao-ZW1E4|WL(WDz&8Kb*&p0@%5-yM;=qQp%Xl zKjRkMJ8@C5&GA6Reo`9#b<3Foh=#gK;OAH2%~g6`cqAy=;ZR47=yMjh_E9Bx+XJ!C zEDcie`OQ5Q=d{YHcx!hDSTi;*n$Lni1=wBdmcs(`FBDDIv?xxtP%)R4Eg;<_;2Y9NdJifvDV)D z_(sL@ib7z2QKM*nBJiUCp6|7lS<$sm7N`&^6HzoE!DL^ z-Y%w7Cxrd~|NjW@oY_D{j3q&S!3+-1Zlr-YN#5=*-166t8~}3IOFVsD*h7`c-fr&|B1zx77N`_kcRUXfE# zzqPOZ61@G#;Eun`j$Fk%?@P_Q*KmbDim8?e?Y+=sA$fP^gd`yytCM%VY(!@U91fbm z^n}e0m@6vnqB)DV*>uk; zoheYi{XZi|!jyx1GaJ7HU8q{(8c~vxSdwa$T$Bo=7>o>zOmz(nbPWwd49%=eO|1+} zv<(cb3=BfkdnHgbzopr0CCKoa{vGU literal 0 HcmV?d00001 diff --git a/Assets/Buff/Hellhex.png b/Assets/Buff/Hellhex.png index e0bc55b94f4e2ebf7c76508e69586a9bfdb53f5e..c392c1b2343ee91cd28ccf2cb9db15fc0c127bf8 100644 GIT binary patch literal 872 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

+ + + + + + \ No newline at end of file diff --git a/PvPAdventure.csproj.user b/PvPAdventure.csproj.user new file mode 100644 index 00000000..62b33ede --- /dev/null +++ b/PvPAdventure.csproj.user @@ -0,0 +1,9 @@ + + + + ProjectDebugger + + + TerrariaSkipSelect + + \ No newline at end of file From d71020d6140a8fb293b2a005ff942d482a99700a Mon Sep 17 00:00:00 2001 From: emyhrberg <121192176+emyhrberg@users.noreply.github.com> Date: Thu, 13 Nov 2025 21:35:12 +0100 Subject: [PATCH 160/206] Maybe working --- Content/Items/AdventureMirror.cs | 4 + Content/Items/AdventureMirrorGlobalItem.cs | 26 +- .../Players/SpawnSelectorPlayer.cs | 11 +- .../Systems/SpawnSelectorState.cs | 24 +- .../UI/UISpawnSelectorCharacterListItem.cs | 284 ++++++++++++++---- .../SpawnSelector/UI/UISpawnSelectorPanel.cs | 57 ++-- 6 files changed, 304 insertions(+), 102 deletions(-) diff --git a/Content/Items/AdventureMirror.cs b/Content/Items/AdventureMirror.cs index fd9766a0..d2426eff 100644 --- a/Content/Items/AdventureMirror.cs +++ b/Content/Items/AdventureMirror.cs @@ -57,6 +57,10 @@ public override void SetDefaults() // UseStyle is called each frame that the item is being actively used. public override void UseStyle(Player player, Rectangle heldItemFrame) { + // Only run for the client who is actually using the item. + if (player.whoAmI != Main.myPlayer) + return; + if (Main.rand.NextBool()) { SpawnMirrorDust(player); diff --git a/Content/Items/AdventureMirrorGlobalItem.cs b/Content/Items/AdventureMirrorGlobalItem.cs index 71dedbcd..02f3ad88 100644 --- a/Content/Items/AdventureMirrorGlobalItem.cs +++ b/Content/Items/AdventureMirrorGlobalItem.cs @@ -1,20 +1,20 @@ -using PvPAdventure.Content.Items; -using Terraria; +using Terraria; using Terraria.ModLoader; -public class AdventureMirrorGlobalItem : GlobalItem +namespace PvPAdventure.Content.Items { - public override bool InstancePerEntity => true; - - // Force the item to always be favorited - public override void UpdateInventory(Item item, Player player) + public class AdventureMirrorGlobalItem : GlobalItem { - if (item.type == ModContent.ItemType()) - { - item.favorited = true; // Force on every tick + public override bool InstancePerEntity => true; - + // Force the item to always be favorited + public override void UpdateInventory(Item item, Player player) + { + if (item.type == ModContent.ItemType()) + { + item.favorited = true; // Force on every tick + } } - } -} + } +} \ No newline at end of file diff --git a/Core/Features/SpawnSelector/Players/SpawnSelectorPlayer.cs b/Core/Features/SpawnSelector/Players/SpawnSelectorPlayer.cs index 5b9d627e..8c8e7c32 100644 --- a/Core/Features/SpawnSelector/Players/SpawnSelectorPlayer.cs +++ b/Core/Features/SpawnSelector/Players/SpawnSelectorPlayer.cs @@ -17,15 +17,13 @@ public override void PostUpdate() return; } + // Force SSS to be enabled when player is within the spawn region. var regionManager = ModContent.GetInstance(); Point tilePos = Player.Center.ToTileCoordinates(); var region = regionManager.GetRegionContaining(tilePos); bool inRegion = region != null; - if (inRegion) - { SpawnSelectorSystem.SetEnabled(true); - } // Unsure if this causes any bugs. // It may be too forcing to always set it to false whenever map is closed. @@ -61,7 +59,12 @@ public override void UpdateDead() // Keeps the player from respawning until they have selected a spawn. if (Player.respawnTimer <= 10 && !hasSelectedSpawnPoint) { - Player.respawnTimer = 10; + //Player.respawnTimer = 10; + if (!Main.mapFullscreen) + { + Main.mapFullscreen = true; + SpawnSelectorSystem.SetEnabled(true); + } } } } \ No newline at end of file diff --git a/Core/Features/SpawnSelector/Systems/SpawnSelectorState.cs b/Core/Features/SpawnSelector/Systems/SpawnSelectorState.cs index 7680116a..9a69d306 100644 --- a/Core/Features/SpawnSelector/Systems/SpawnSelectorState.cs +++ b/Core/Features/SpawnSelector/Systems/SpawnSelectorState.cs @@ -1,7 +1,10 @@ using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using PvPAdventure.Core.Features.SpawnSelector.Systems; using PvPAdventure.Core.Features.SpawnSelector.UI; -using Terraria.UI; +using PvPAdventure.Core.Helpers; using Terraria.GameContent.UI.Elements; +using Terraria.UI; namespace PvPAdventure.Core.Features.SpawnSelector.Systems { @@ -9,11 +12,9 @@ internal class SpawnSelectorState : UIState { public override void OnInitialize() { - // Create the base panel with the teleport options UISpawnSelectorPanel spawnSelectorPanel = new(); Append(spawnSelectorPanel); - // Create the title panel with a height of 32px, 10 px from the top, centered horizontally UITextPanel chooseYourSpawnPanel = new("Choose Your Spawn", 0.8f, true); chooseYourSpawnPanel.HAlign = 0.5f; chooseYourSpawnPanel.VAlign = 0f; @@ -21,5 +22,22 @@ public override void OnInitialize() chooseYourSpawnPanel.BackgroundColor = new Color(73, 94, 171); Append(chooseYourSpawnPanel); } + + public override void OnActivate() + { + base.OnActivate(); + UISpawnSelectorPanel panel = null; + foreach (var element in Elements) + { + panel = element as UISpawnSelectorPanel; + if (panel != null) + break; + } + if (panel != null) + { + panel.Rebuild(); + Log.Info("SpawnSelectorState: Rebuilt panel on activate"); + } + } } } diff --git a/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs b/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs index 34ab074c..c5a51031 100644 --- a/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs +++ b/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs @@ -1,9 +1,11 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; +using PvPAdventure.Core.Features.SpawnSelector.Systems; using PvPAdventure.Core.Helpers; using ReLogic.Content; using System; using Terraria; +using Terraria.Audio; using Terraria.GameContent; using Terraria.GameContent.UI.Elements; using Terraria.ID; @@ -13,7 +15,7 @@ namespace PvPAdventure.Core.Features.SpawnSelector.UI { /// - /// Vanilla-like character row: + /// Vanilla-like character row. /// internal class UISpawnSelectorCharacterListItem : UIPanel { @@ -21,24 +23,20 @@ internal class UISpawnSelectorCharacterListItem : UIPanel private readonly Asset _innerPanelTexture; private readonly Asset _playerBGTexture; - private readonly string _name; - private readonly string _hpText; - private readonly string _manaText; + private readonly int _playerIndex; + private Rectangle _bedHitbox; - public UISpawnSelectorCharacterListItem() + public UISpawnSelectorCharacterListItem(Terraria.Player player, bool isSelf) { _dividerTexture = Main.Assets.Request("Images/UI/Divider"); _innerPanelTexture = Main.Assets.Request("Images/UI/InnerPanelBackground"); _playerBGTexture = Main.Assets.Request("Images/UI/PlayerBackground"); - _name = "Teammate"; - _hpText = "500 " + Language.GetTextValue("GameUI.PlayerLifeMax"); - _manaText = "200 " + Language.GetTextValue("GameUI.PlayerManaMax"); + _playerIndex = isSelf ? Main.myPlayer : player.whoAmI; } public override void OnInitialize() { - //BorderColor = new Color(89, 116, 213) * 0.7f; BorderColor = Color.Black; BackgroundColor = new Color(63, 82, 151) * 0.7f; Height.Set(72f, 0f); @@ -46,94 +44,102 @@ public override void OnInitialize() SetPadding(6f); } - private void DrawPanel(SpriteBatch spriteBatch, Vector2 position, float width) - { - spriteBatch.Draw(_innerPanelTexture.Value, position, - new Rectangle(0, 0, 8, _innerPanelTexture.Height()), Color.White); - - spriteBatch.Draw( - _innerPanelTexture.Value, - new Vector2(position.X + 8f, position.Y), - new Rectangle(8, 0, 8, _innerPanelTexture.Height()), - Color.White, - 0f, - Vector2.Zero, - new Vector2((width - 16f) / 8f, 1f), - SpriteEffects.None, - 0f - ); - - spriteBatch.Draw( - _innerPanelTexture.Value, - new Vector2(position.X + width - 8f, position.Y), - new Rectangle(16, 0, 8, _innerPanelTexture.Height()), - Color.White - ); - } - protected override void DrawSelf(SpriteBatch sb) { base.DrawSelf(sb); CalculatedStyle inner = GetInnerDimensions(); var dims = GetDimensions(); + var rect = dims.ToRectangle(); + + Player player = Main.player[_playerIndex]; + if (player == null || !player.active) + { + Utils.DrawBorderString(sb, "Unable to find player :(", rect.Location.ToVector2() + new Vector2(50, 0), Color.White); + return; + } + + DrawMapFullscreenBackground(sb, rect, player); // Left "player" background Vector2 pos = new(inner.X, inner.Y); sb.Draw(_playerBGTexture.Value, pos, Color.White); // Right "bed" background - Vector2 bedPos = new(pos.X+dims.Width-73, pos.Y); - sb.Draw(_playerBGTexture.Value, bedPos, Color.White); + Vector2 bedBGPos = new(pos.X + dims.Width - 73, pos.Y); + sb.Draw(_playerBGTexture.Value, bedBGPos, Color.White); - // Draw bed (placeholder) - // Future: Draw section of map with the bed - bedPos += new Vector2(31, 31); + // Bed icon position (same as before) + Vector2 bedIconPos = bedBGPos + new Vector2(31, 31); Item icon = new(ItemID.Bed); - ItemSlot.DrawItemIcon(icon, 31, sb, bedPos, 1.0f, 32f, Color.White); + ItemSlot.DrawItemIcon(icon, 31, sb, bedIconPos, 1.0f, 32f, Color.White); + // Update clickable bed hitbox (approx 32x32 centered on icon pos) + _bedHitbox = new Rectangle( + (int)(bedIconPos.X - 16), + (int)(bedIconPos.Y - 16), + 32, + 32 + ); - // Draw player + // Draw player sprite (switch to point-clamp batch) sb.End(); - sb.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, DepthStencilState.Default, RasterizerState.CullNone, null, Main.UIScaleMatrix); + sb.Begin(SpriteSortMode.Deferred, + BlendState.AlphaBlend, + SamplerState.PointClamp, + DepthStencilState.Default, + RasterizerState.CullNone, + null, + Main.UIScaleMatrix); try { - // Draw player - pos += Main.screenPosition + new Vector2(16, 8); - - Player player = Main.LocalPlayer; - - // Celestial starboard (45) sucks - if (player.wings == 45) player.wings = 0; + Vector2 playerDrawPos = pos + Main.screenPosition + new Vector2(16, 8); - Main.PlayerRenderer.DrawPlayer(Main.Camera, player, pos, player.fullRotation, player.fullRotationOrigin, 0f, 0.9f); + Main.PlayerRenderer.DrawPlayer( + Main.Camera, + player, + playerDrawPos, + player.fullRotation, + player.fullRotationOrigin, + 0f, + 0.9f + ); } catch (Exception e) { - //Main.NewText("Failed to draw player", Color.Red); Log.Error("Failed to draw player: " + e); } - float leftColumnWidth = _playerBGTexture.Width(); // keep aligned to texture + // Switch back to "normal" UI batch + sb.End(); + sb.Begin(SpriteSortMode.Deferred, + BlendState.AlphaBlend, + SamplerState.LinearClamp, + DepthStencilState.None, + RasterizerState.CullCounterClockwise, + null, + Main.UIScaleMatrix); + + float leftColumnWidth = _playerBGTexture.Width(); float startX = inner.X + leftColumnWidth; - // Measure text width - Vector2 textSize = FontAssets.MouseText.Value.MeasureString(_name); + // Name centered + string name = string.IsNullOrEmpty(player.name) ? "Teammate" : player.name; + Vector2 nameSize = FontAssets.MouseText.Value.MeasureString(name); float centerX = inner.X + inner.Width * 0.5f; - // Draw player name centered Utils.DrawBorderString( sb, - _name, - new Vector2(centerX - textSize.X * 0.5f, inner.Y - 2f), + name, + new Vector2(centerX - nameSize.X * 0.5f, inner.Y - 2f), Color.White ); // Divider sb.Draw( _dividerTexture.Value, - new Vector2(startX+1, inner.Y + 21f), + new Vector2(startX + 1, inner.Y + 21f), null, Color.White, 0f, @@ -153,13 +159,21 @@ protected override void DrawSelf(SpriteBatch sb) // HP sb.Draw(TextureAssets.Heart.Value, cursor + new Vector2(5f, 2f), Color.White); cursor.X += 10f + TextureAssets.Heart.Width(); - Utils.DrawBorderString(sb, _hpText, cursor + new Vector2(0f, 3f), Color.White); + string hpText = $"{player.statLife}/{player.statLifeMax}"; + Utils.DrawBorderString(sb, hpText, cursor + new Vector2(0f, 3f), Color.White); // MP cursor.X += 80f; sb.Draw(TextureAssets.Mana.Value, cursor + new Vector2(5f, 2f), Color.White); cursor.X += 10f + TextureAssets.Mana.Width(); - Utils.DrawBorderString(sb, _manaText, cursor + new Vector2(0f, 3f), Color.White); + string manaText = $"{player.statMana}/{player.statManaMax}"; + Utils.DrawBorderString(sb, manaText, cursor + new Vector2(0f, 3f), Color.White); + } + + public override void MouseOver(UIMouseEvent evt) + { + base.MouseOver(evt); + BackgroundColor = new Color(73, 92, 161); } public override void MouseOut(UIMouseEvent evt) @@ -168,10 +182,154 @@ public override void MouseOut(UIMouseEvent evt) BackgroundColor = new Color(63, 82, 151) * 0.8f; } - public override void MouseOver(UIMouseEvent evt) + public override void LeftClick(UIMouseEvent evt) { - base.MouseOver(evt); - BackgroundColor = new Color(73, 92, 161); + base.LeftClick(evt); + + // Only react if the BED area was clicked, not the whole row + if (!_bedHitbox.Contains(evt.MousePosition.ToPoint())) + return; + + Terraria.Player player = Main.player[_playerIndex]; + TeleportToPlayerBed(player); + } + + private static void TeleportToPlayerBed(Terraria.Player target) + { + if (target == null || !target.active) + return; + + Terraria.Player local = Main.LocalPlayer; + if (local == null || !local.active) + return; + + // Figure out target spawn (bed) tile + int spawnX = target.SpawnX; + int spawnY = target.SpawnY; + + // Fallback: world spawn if no personal spawn + if (spawnX <= 0 || spawnY <= 0) + { + spawnX = Main.spawnTileX; + spawnY = Main.spawnTileY; + } + + // Convert tile coords to world coords (put feet on the ground) + Vector2 dest = new Vector2( + spawnX * 16 + local.width / 2f, + spawnY * 16 - local.height + ); + + if (Main.netMode == NetmodeID.SinglePlayer) + { + local.Teleport(dest); + SoundEngine.PlaySound(SoundID.Item6, dest); // magic mirror sound + } + else + { + // Multiplayer: you'd normally send a custom packet to your mod's server-side logic + // to perform a server-authoritative teleport. + // Example (pseudo): + // ModContent.GetInstance().SendBedTeleportPacket(target.whoAmI); + } + + // Close fullscreen map + spawn selector + Main.mapFullscreen = false; + SpawnSelectorSystem.SetEnabled(false); + } + + private void DrawPanel(SpriteBatch spriteBatch, Vector2 position, float width) + { + spriteBatch.Draw(_innerPanelTexture.Value, position, + new Rectangle(0, 0, 8, _innerPanelTexture.Height()), Color.White); + + spriteBatch.Draw( + _innerPanelTexture.Value, + new Vector2(position.X + 8f, position.Y), + new Rectangle(8, 0, 8, _innerPanelTexture.Height()), + Color.White, + 0f, + Vector2.Zero, + new Vector2((width - 16f) / 8f, 1f), + SpriteEffects.None, + 0f + ); + + spriteBatch.Draw( + _innerPanelTexture.Value, + new Vector2(position.X + width - 8f, position.Y), + new Rectangle(16, 0, 8, _innerPanelTexture.Height()), + Color.White + ); + } + + public static void DrawMapFullscreenBackground(SpriteBatch sb, Rectangle rect, Player player) + { + if (player == null || !player.active) + return; + + var screenPos = Main.screenPosition; + var tile = Main.tile[(int)(player.Center.X / 16f), (int)(player.Center.Y / 16f)]; + if (tile == null) return; + + int wall = tile.wall; + int bgIndex = -1; + Color color = Color.White; + + if (screenPos.Y > (Main.maxTilesY - 232) * 16) + bgIndex = 2; + else if (player.ZoneDungeon) + bgIndex = 4; + else if (wall == 87) + bgIndex = 13; + else if (screenPos.Y > Main.worldSurface * 16.0) + { + bgIndex = wall switch + { + 86 or 108 => 15, + 180 or 184 => 16, + 178 or 183 => 17, + 62 or 263 => 18, + _ => player.ZoneGlowshroom ? 20 : + player.ZoneCorrupt ? player.ZoneDesert ? 39 : player.ZoneSnow ? 33 : 22 : + player.ZoneCrimson ? player.ZoneDesert ? 40 : player.ZoneSnow ? 34 : 23 : + player.ZoneHallow ? player.ZoneDesert ? 41 : player.ZoneSnow ? 35 : 21 : + player.ZoneSnow ? 3 : + player.ZoneJungle ? 12 : + player.ZoneDesert ? 14 : + player.ZoneRockLayerHeight ? 31 : 1 + }; + } + else if (player.ZoneGlowshroom) + bgIndex = 19; + else + { + color = Main.ColorOfTheSkies; + int midTileX = (int)((screenPos.X + Main.screenWidth / 2f) / 16f); + + if (player.ZoneSkyHeight) bgIndex = 32; + else if (player.ZoneCorrupt) bgIndex = player.ZoneDesert ? 36 : 5; + else if (player.ZoneCrimson) bgIndex = player.ZoneDesert ? 37 : 6; + else if (player.ZoneHallow) bgIndex = player.ZoneDesert ? 38 : 7; + else if (screenPos.Y / 16f < Main.worldSurface + 10.0 && (midTileX < 380 || midTileX > Main.maxTilesX - 380)) + bgIndex = 10; + else if (player.ZoneSnow) bgIndex = 11; + else if (player.ZoneJungle) bgIndex = 8; + else if (player.ZoneDesert) bgIndex = 9; + else if (Main.bloodMoon) { bgIndex = 25; color *= 2f; } + else if (player.ZoneGraveyard) bgIndex = 26; + } + + var asset = bgIndex >= 0 && bgIndex < TextureAssets.MapBGs.Length + ? TextureAssets.MapBGs[bgIndex] + : TextureAssets.MapBGs[0]; + + rect.X += 10; + rect.Y += 10; + rect.Width -= 20; + rect.Height -= 20; + + sb.Draw(asset.Value, rect, color); } } } diff --git a/Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs b/Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs index 226ff5c4..376538ac 100644 --- a/Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs +++ b/Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs @@ -1,13 +1,11 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using PvPAdventure.Core.Features.SpawnSelector.Systems; -using System; +using PvPAdventure.Core.Helpers; +using System.Collections.Generic; using Terraria; using Terraria.GameContent.UI.Elements; using Terraria.ID; -using Terraria.ModLoader.UI; -using Terraria.UI; -using static System.Net.Mime.MediaTypeNames; namespace PvPAdventure.Core.Features.SpawnSelector.UI { @@ -25,7 +23,6 @@ public override void OnInitialize() BackgroundColor = new Color(33, 43, 79) * 0.8f; SetPadding(6f); - // --- Random teleport button --- randomButton = new UITextPanel("Random"); randomButton.Width.Set(-20f, 1f); randomButton.Left.Set(10f, 0f); @@ -41,17 +38,43 @@ public override void OnInitialize() randomButton.OnLeftClick += (_, _) => PerformRandomTeleport(); Append(randomButton); - var item1 = new UISpawnSelectorCharacterListItem(); - item1.Width.Set(-20f, 1f); - item1.Left.Set(10, 0f); - item1.Top.Set(74, 0f); - Append(item1); + var p1 = new UISpawnSelectorCharacterListItem(Main.LocalPlayer, isSelf: true); + p1.Width.Set(-20f, 1f); + p1.Left.Set(10, 0f); + p1.Top.Set(74, 0f); + Append(p1); - var item2 = new UISpawnSelectorCharacterListItem(); - item2.Width.Set(-20f, 1f); - item2.Left.Set(10, 0f); - item2.Top.Set(74 + 72 + 4, 0f); - Append(item2); + var players = new List(); + if (Main.LocalPlayer.team != 0) + { + for (int i = 0; i < Main.maxPlayers; i++) + { + Player p = Main.player[i]; + if (p != null && p.active && p.whoAmI != Main.LocalPlayer.whoAmI && p.team == Main.LocalPlayer.team) + { + Main.NewText("Adding teammate: " + p.name); + players.Add(p); + } + } + } + + for (int i = 0; i < players.Count; i++) + { + var row = new UISpawnSelectorCharacterListItem(players[i], isSelf: false); + row.Width.Set(-20f, 1f); + row.Left.Set(10, 0f); + row.Top.Set(74 + i * 70, 0f); + Append(row); + } + + Log.Info($"UISpawnSelectorPanel.OnInitialize: team={Main.LocalPlayer.team}, teammates={players.Count}"); + } + + public void Rebuild() + { + RemoveAllChildren(); + OnInitialize(); + Log.Info("UISpawnSelectorPanel.Rebuild: UI rebuilt"); } private void PerformRandomTeleport() @@ -70,12 +93,8 @@ private void CloseAndExitMap() SpawnSelectorSystem.SetEnabled(false); } - public override void Draw(SpriteBatch spriteBatch) { - //RemoveAllChildren(); - //OnInitialize(); - base.Draw(spriteBatch); } } From 4fb3de37646b3172b7231a14609d79ba0fb54153 Mon Sep 17 00:00:00 2001 From: emyhrberg <121192176+emyhrberg@users.noreply.github.com> Date: Thu, 13 Nov 2025 22:07:18 +0100 Subject: [PATCH 161/206] Team teleport maybe working --- Content/Items/AdventureMirror.cs | 2 +- .../UI/UISpawnSelectorCharacterListItem.cs | 51 +++++++++---------- .../SpawnSelector/UI/UISpawnSelectorPanel.cs | 20 ++++---- 3 files changed, 35 insertions(+), 38 deletions(-) diff --git a/Content/Items/AdventureMirror.cs b/Content/Items/AdventureMirror.cs index d2426eff..5abe0e0e 100644 --- a/Content/Items/AdventureMirror.cs +++ b/Content/Items/AdventureMirror.cs @@ -100,7 +100,7 @@ public override void UseStyle(Player player, Rectangle heldItemFrame) if (Main.netMode == NetmodeID.MultiplayerClient) { - // ? + // TODO? } } SpawnSelectorSystem.SetEnabled(true); diff --git a/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs b/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs index c5a51031..26059c19 100644 --- a/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs +++ b/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs @@ -9,7 +9,6 @@ using Terraria.GameContent; using Terraria.GameContent.UI.Elements; using Terraria.ID; -using Terraria.Localization; using Terraria.UI; namespace PvPAdventure.Core.Features.SpawnSelector.UI @@ -26,13 +25,13 @@ internal class UISpawnSelectorCharacterListItem : UIPanel private readonly int _playerIndex; private Rectangle _bedHitbox; - public UISpawnSelectorCharacterListItem(Terraria.Player player, bool isSelf) + public UISpawnSelectorCharacterListItem(Player player) { _dividerTexture = Main.Assets.Request("Images/UI/Divider"); _innerPanelTexture = Main.Assets.Request("Images/UI/InnerPanelBackground"); _playerBGTexture = Main.Assets.Request("Images/UI/PlayerBackground"); - _playerIndex = isSelf ? Main.myPlayer : player.whoAmI; + _playerIndex = player.whoAmI; } public override void OnInitialize() @@ -66,21 +65,21 @@ protected override void DrawSelf(SpriteBatch sb) sb.Draw(_playerBGTexture.Value, pos, Color.White); // Right "bed" background - Vector2 bedBGPos = new(pos.X + dims.Width - 73, pos.Y); - sb.Draw(_playerBGTexture.Value, bedBGPos, Color.White); + //Vector2 bedBGPos = new(pos.X + dims.Width - 73, pos.Y); + //sb.Draw(_playerBGTexture.Value, bedBGPos, Color.White); - // Bed icon position (same as before) - Vector2 bedIconPos = bedBGPos + new Vector2(31, 31); - Item icon = new(ItemID.Bed); - ItemSlot.DrawItemIcon(icon, 31, sb, bedIconPos, 1.0f, 32f, Color.White); + // Bed icon + //Vector2 bedIconPos = bedBGPos + new Vector2(31, 31); + //Item icon = new(ItemID.Bed); + //ItemSlot.DrawItemIcon(icon, 31, sb, bedIconPos, 1.0f, 32f, Color.White); // Update clickable bed hitbox (approx 32x32 centered on icon pos) - _bedHitbox = new Rectangle( - (int)(bedIconPos.X - 16), - (int)(bedIconPos.Y - 16), - 32, - 32 - ); + //_bedHitbox = new Rectangle( + // (int)(bedIconPos.X - 16), + // (int)(bedIconPos.Y - 16), + // 32, + // 32 + //); // Draw player sprite (switch to point-clamp batch) sb.End(); @@ -187,11 +186,14 @@ public override void LeftClick(UIMouseEvent evt) base.LeftClick(evt); // Only react if the BED area was clicked, not the whole row - if (!_bedHitbox.Contains(evt.MousePosition.ToPoint())) - return; + //if (!_bedHitbox.Contains(evt.MousePosition.ToPoint())) + //return; Terraria.Player player = Main.player[_playerIndex]; - TeleportToPlayerBed(player); + + Main.LocalPlayer.UnityTeleport(player.position); + + //TeleportToPlayerBed(player); } private static void TeleportToPlayerBed(Terraria.Player target) @@ -207,14 +209,14 @@ private static void TeleportToPlayerBed(Terraria.Player target) int spawnX = target.SpawnX; int spawnY = target.SpawnY; - // Fallback: world spawn if no personal spawn + // Fallback: player position if no personal spawn if (spawnX <= 0 || spawnY <= 0) { - spawnX = Main.spawnTileX; - spawnY = Main.spawnTileY; + spawnX = (int) target.position.X; + spawnY = (int)target.position.Y; } - // Convert tile coords to world coords (put feet on the ground) + // Convert tile coords to world coords Vector2 dest = new Vector2( spawnX * 16 + local.width / 2f, spawnY * 16 - local.height @@ -223,13 +225,10 @@ private static void TeleportToPlayerBed(Terraria.Player target) if (Main.netMode == NetmodeID.SinglePlayer) { local.Teleport(dest); - SoundEngine.PlaySound(SoundID.Item6, dest); // magic mirror sound } else { - // Multiplayer: you'd normally send a custom packet to your mod's server-side logic - // to perform a server-authoritative teleport. - // Example (pseudo): + // TODO Multiplayer: send teleport request to server // ModContent.GetInstance().SendBedTeleportPacket(target.whoAmI); } diff --git a/Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs b/Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs index 376538ac..0b8b3741 100644 --- a/Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs +++ b/Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs @@ -38,12 +38,14 @@ public override void OnInitialize() randomButton.OnLeftClick += (_, _) => PerformRandomTeleport(); Append(randomButton); - var p1 = new UISpawnSelectorCharacterListItem(Main.LocalPlayer, isSelf: true); - p1.Width.Set(-20f, 1f); - p1.Left.Set(10, 0f); - p1.Top.Set(74, 0f); - Append(p1); + // Debug: add test entry + //var p1 = new UISpawnSelectorCharacterListItem(Main.LocalPlayer); + //p1.Width.Set(-20f, 1f); + //p1.Left.Set(10, 0f); + //p1.Top.Set(74, 0f); + //Append(p1); + // Add teammates var players = new List(); if (Main.LocalPlayer.team != 0) { @@ -58,9 +60,10 @@ public override void OnInitialize() } } + // Add UI elements for each teammate for (int i = 0; i < players.Count; i++) { - var row = new UISpawnSelectorCharacterListItem(players[i], isSelf: false); + var row = new UISpawnSelectorCharacterListItem(players[i]); row.Width.Set(-20f, 1f); row.Left.Set(10, 0f); row.Top.Set(74 + i * 70, 0f); @@ -84,11 +87,6 @@ private void PerformRandomTeleport() else Main.LocalPlayer.TeleportationPotion(); - CloseAndExitMap(); - } - - private void CloseAndExitMap() - { Main.mapFullscreen = false; SpawnSelectorSystem.SetEnabled(false); } From fbfce8211d43bb6aed3e2298b67f17365374d992 Mon Sep 17 00:00:00 2001 From: emyhrberg <121192176+emyhrberg@users.noreply.github.com> Date: Fri, 14 Nov 2025 03:56:24 +0100 Subject: [PATCH 162/206] New UI! --- AdventureConfig.cs | 2 +- Assets/SpawnSelector/Question_Mark.png | Bin 0 -> 321 bytes Assets/SpawnSelector/Question_Mark_Blue.png | Bin 0 -> 316 bytes Content/Items/AdventureMirror.cs | 155 +++---------- .../SpawnSelector/Hooks/ItemSlotHooks.cs | 8 +- .../Players/AdventureMirrorPlayer.cs | 203 ++++++++++++++++++ .../Players/ModifyPlayerDrawInfo.cs | 47 ++++ .../Players/SpawnSelectorPlayer.cs | 70 ------ .../Systems/SpawnSelectorState.cs | 58 ++--- .../Systems/SpawnSelectorSystem.cs | 2 +- .../UI/UISpawnSelectorCharacterListItem.cs | 127 ++++------- .../SpawnSelector/UI/UISpawnSelectorPanel.cs | 138 +++++++----- .../UI/UISpawnSelectorRandomPanel.cs | 78 +++++++ Core/Helpers/AssetLoader.cs | 41 ++++ Localization/en-US.hjson | 6 + PvPAdventure.csproj | 46 ++-- System/Client/Keybinds.cs | 2 + icon_small.png | Bin 1227 -> 942 bytes 18 files changed, 587 insertions(+), 396 deletions(-) create mode 100644 Assets/SpawnSelector/Question_Mark.png create mode 100644 Assets/SpawnSelector/Question_Mark_Blue.png create mode 100644 Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs create mode 100644 Core/Features/SpawnSelector/Players/ModifyPlayerDrawInfo.cs delete mode 100644 Core/Features/SpawnSelector/Players/SpawnSelectorPlayer.cs create mode 100644 Core/Features/SpawnSelector/UI/UISpawnSelectorRandomPanel.cs create mode 100644 Core/Helpers/AssetLoader.cs diff --git a/AdventureConfig.cs b/AdventureConfig.cs index a5e90ae3..ede84da1 100644 --- a/AdventureConfig.cs +++ b/AdventureConfig.cs @@ -68,7 +68,7 @@ public class InvasionSizeValue [Range(0, 60 * 60)] [DefaultValue(4 * 60)] - public int RTPRecallFrames { get; set; } + public int AdventureMirrorRecallFrames { get; set; } [Range(0, 30 * 60)] [DefaultValue(1.5 * 60)] diff --git a/Assets/SpawnSelector/Question_Mark.png b/Assets/SpawnSelector/Question_Mark.png new file mode 100644 index 0000000000000000000000000000000000000000..fe979b345e61870b274c2150170700bb96661325 GIT binary patch literal 321 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?3oVGw3ym^DWNDEQga z#W5tJHTlo~|MrI+n3geaott=tk%vczCG^Aw#}^+I436H|E|kCMXS~QcjOMh=TzpNo*oUm^q3C&3m2~b z{r`V{VaIYtje;~EED&cvVd9ZvAx6-aRTT&dU0;I&Hq+H+@fmV&3{LA7>Y zoEs)OthMNIdhn)l&7l`N8J7QAvGAT!lES9Yo{MZUT5FSzUEHU5*rS|*L9Hg@+4t5T RNkH#2c)I$ztaD0e0swgwf7k#3 literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/Question_Mark_Blue.png b/Assets/SpawnSelector/Question_Mark_Blue.png new file mode 100644 index 0000000000000000000000000000000000000000..f504f5e26097266571686dde0c5de204e00ad616 GIT binary patch literal 316 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?3oVGw3ym^DWNDEQ9P z#W5tJHTlo~|MrI+n3geaott=tk%vczCG^Aw#}^+I436H|E|kCMXS~Qcjyd6db(b>Z=!|Cjhg<{P?&|2e*_Paq*lLQBzLamP%J(hYYEYMdU}N5w2=j<_?K zdxk`tm(+o$pL_Q0*C>n^J?j&4g7>aKg3D*is&@+4o;#bf6g({ts 0f) - { - // Display text above the player every second - PopupText.NewText(new AdvancedPopupRequest - { - Color = Color.Crimson, - Text = "Cannot use while moving!", - Velocity = new(0.0f, -4.0f), - DurationInFrames = 60 * 1 - }, player.Top); - return false; - } - - return base.CanUseItem(player); - } - - public override bool? UseItem(Player player) - { - //for (int d = 0; d < 70; d++) - //{ - // Dust.NewDust(player.position, player.width, player.height, DustID.MagicMirror, 0f, 0f, 150, default(Microsoft.Xna.Framework.Color), 1.5f); - //} - - return true; - } - public override void SetDefaults() { - //Item.CloneDefaults(ItemID.MagicMirror); - var config = ModContent.GetInstance(); - int recallFrames = config.RTPRecallFrames; + int recallFrames = config.AdventureMirrorRecallFrames; // 5 seconds = 60 * 5 - Item.useTime = recallFrames; - Item.useAnimation = recallFrames; + Item.useTime = 10; + Item.useAnimation = 10; Item.useStyle = ItemUseStyleID.HoldUp; - Item.UseSound = SoundID.Item6; // MAGIC MIRROR SOUND + Item.UseSound = SoundID.Item6; Item.rare = ItemRarityID.Blue; Item.value = Item.buyPrice(gold: 5); Item.noUseGraphic = false; } - // UseStyle is called each frame that the item is being actively used. - public override void UseStyle(Player player, Rectangle heldItemFrame) + public override bool CanUseItem(Player player) { - // Only run for the client who is actually using the item. - if (player.whoAmI != Main.myPlayer) - return; - - if (Main.rand.NextBool()) - { - SpawnMirrorDust(player); - } - - // debug - //Main.NewText(player.itemTime); - - // This sets up the itemTime correctly. - if (player.itemTime == 0) - { - player.ApplyItemTime(Item); - } - else if (player.itemTime <= 10) + if (player.velocity.Length() > 0f) { - Main.playerInventory = false; - if (!Main.mapFullscreen) + PopupText.NewText(new AdvancedPopupRequest { - SoundEngine.PlaySound(SoundID.MenuOpen); - Main.mapFullscreen = true; // open the fullscreen map - - //Main.resetMapFull = true; // reset the map view position to be zoomed out and centered on the player - - // center map - float worldCenterX = Main.maxTilesX / 2f; - float worldCenterY = Main.maxTilesY / 2f; - Main.mapFullscreenPos.X = worldCenterX; - Main.mapFullscreenPos.Y = worldCenterY; - - // zoom out - Main.mapFullscreenScale = 0.21f; - - // teleport to spawn - Vector2 spawnPos = new(Main.spawnTileX*16, Main.spawnTileY*16-100); - - Main.LocalPlayer.Teleport(spawnPos); - - if (Main.netMode == NetmodeID.MultiplayerClient) - { - // TODO? - } - } - SpawnSelectorSystem.SetEnabled(true); - - // This code releases all grappling hooks and kills/despawns them. - player.RemoveAllGrapplingHooks(); + Color = Color.Crimson, + Text = "Cannot use while moving!", + Velocity = new(0f, -4f), + DurationInFrames = 60 + }, player.Top); + return false; } - } - private static void SpawnMirrorDust(Player player) - { - Dust.NewDust( - player.position, - player.width, - player.height, - DustID.MagicMirror, - player.velocity.X * 0.5f, - player.velocity.Y * 0.5f, - Alpha: 150, - newColor: default, - Scale: 1.5f - ); + // Don’t allow starting a second mirror while one is active + var mp = player.GetModPlayer(); + if (mp.MirrorActive) + return false; + + return true; } - public override void UpdateInventory(Player player) + public override bool? UseItem(Player player) { - //if (!Main.mapFullscreen) - //{ - // if (!SpawnSelectorSettings.GetIsEnabled()) - // { - // SpawnSelectorSettings.SetIsEnabled(false); - // } - //} + var config = ModContent.GetInstance(); + int recallFrames = config.AdventureMirrorRecallFrames; - if (player.HeldItem.type == Item.type && player.itemAnimation > 0) - { - if (player.velocity.Length() > 0f) - { - // Cancel item use - player.itemAnimation = 0; - player.itemTime = 0; + player.GetModPlayer() + .StartMirrorUse(recallFrames); - // Display text above the player every second - PopupText.NewText(new AdvancedPopupRequest - { - Color = Color.Crimson, - Text = "Cancelled!", - Velocity = new(0.0f, -4.0f), - DurationInFrames = 60 * 1 - }, player.Top); - } - } + return true; } -} \ No newline at end of file +} diff --git a/Core/Features/SpawnSelector/Hooks/ItemSlotHooks.cs b/Core/Features/SpawnSelector/Hooks/ItemSlotHooks.cs index 5bac1ca4..d6b28c3e 100644 --- a/Core/Features/SpawnSelector/Hooks/ItemSlotHooks.cs +++ b/Core/Features/SpawnSelector/Hooks/ItemSlotHooks.cs @@ -1,8 +1,6 @@ using Terraria; using Terraria.ModLoader; using Terraria.UI; -using Terraria.Audio; -using Terraria.ID; using PvPAdventure.Content.Items; public class ItemSlotHooks : ModSystem @@ -35,7 +33,7 @@ private static bool Hook_LeftClick_SellOrTrash( if (!item.IsAir && item.type == ModContent.ItemType()) { - SoundEngine.PlaySound(SoundID.MenuClose); + //SoundEngine.PlaySound(SoundID.MenuClose); return false; // skip SellOrTrash completely } @@ -51,7 +49,7 @@ private static void Hook_LeftClick_ItemArray( && !Main.mouseItem.IsAir && Main.mouseItem.type == ModContent.ItemType()) { - SoundEngine.PlaySound(SoundID.MenuClose); + //SoundEngine.PlaySound(SoundID.MenuClose); return; // do NOT process the trash slot } @@ -67,7 +65,7 @@ private static bool Hook_SellItem( { if (!item.IsAir && item.type == ModContent.ItemType()) { - SoundEngine.PlaySound(SoundID.MenuClose); + //SoundEngine.PlaySound(SoundID.MenuClose); return false; // selling fails, nothing is removed } diff --git a/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs b/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs new file mode 100644 index 00000000..e05bc252 --- /dev/null +++ b/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs @@ -0,0 +1,203 @@ +using Microsoft.Xna.Framework; +using PvPAdventure.Content.Items; +using PvPAdventure.Core.Features.SpawnSelector.Systems; +using PvPAdventure.System; +using PvPAdventure.System.Client; +using System.Linq; +using Terraria; +using Terraria.Audio; +using Terraria.GameInput; +using Terraria.ID; +using Terraria.ModLoader; +using static Terraria.GameContent.Animations.IL_Actions.Sprites; + +namespace PvPAdventure.Core.Features.SpawnSelector.Players; + +public class AdventureMirrorPlayer : ModPlayer +{ + public int MirrorTimer; // frames left + public bool MirrorActive; + private int _mirrorDuration; // for countdown + + public void StartMirrorUse(int durationFrames) + { + if (MirrorActive) + return; + + MirrorActive = true; + MirrorTimer = durationFrames; + } + + private void UpdateSpawnSelectorEnabledState() + { + // Force SSS to be enabled when player is within the spawn region. + var regionManager = ModContent.GetInstance(); + Point tilePos = Player.Center.ToTileCoordinates(); + var region = regionManager.GetRegionContaining(tilePos); + bool inRegion = region != null; + if (inRegion) + SpawnSelectorSystem.SetEnabled(true); + + // Unsure if this causes any bugs. + // It may be too forcing to always set it to false whenever map is closed. + if (!Main.mapFullscreen) + SpawnSelectorSystem.SetEnabled(false); + } + + public override void PostUpdate() + { + UpdateSpawnSelectorEnabledState(); + + if (!MirrorActive) + return; + + if (Main.dedServ || Player.whoAmI != Main.myPlayer) + return; + + + + // cancel if player moves + if (Player.velocity.Length() > 0f) + { + MirrorActive = false; + PopupText.NewText(new AdvancedPopupRequest + { + Color = Color.Crimson, + Text = "Cancelled!", + Velocity = new(0f, -4f), + DurationInFrames = 60 + }, Player.Top); + return; + } + + // dust while channeling + if (Main.rand.NextBool()) + { + Dust.NewDust( + Player.position, + Player.width, + Player.height, + DustID.MagicMirror, + Player.velocity.X * 0.5f, + Player.velocity.Y * 0.5f, + 150, + default, + 1.5f + ); + } + + // countdown tick + MirrorTimer--; + + // Show countdown every full second + if (MirrorTimer > 0 && MirrorTimer % 60 == 0) + { + int secondsLeft = MirrorTimer / 60; + PopupText.NewText(new AdvancedPopupRequest + { + Color = Color.Crimson, + Text = secondsLeft.ToString(), + Velocity = new(0f, -4f), + DurationInFrames = 60 + }, Player.Top); + } + + // End of channel, teleport once + if (MirrorTimer <= 0) + { + Main.playerInventory = false; + + if (!Main.mapFullscreen) + { + SoundEngine.PlaySound(SoundID.MenuOpen); + Main.mapFullscreen = true; + + float worldCenterX = Main.maxTilesX / 2f; + float worldCenterY = Main.maxTilesY / 2f; + Main.mapFullscreenPos.X = worldCenterX; + Main.mapFullscreenPos.Y = worldCenterY; + + Main.mapFullscreenScale = 0.21f; + + Vector2 spawnPos = new(Main.spawnTileX * 16, Main.spawnTileY * 16 - 100); + Main.LocalPlayer.Teleport(spawnPos); + + if (Main.netMode == NetmodeID.MultiplayerClient) + { + // TODO: sync needed? + } + } + + SpawnSelectorSystem.SetEnabled(true); + Player.RemoveAllGrapplingHooks(); + + MirrorActive = false; + } + } + + public override void UpdateDead() + { + // debug + //Main.NewText(Player.respawnTimer); + + // Keeps the player from respawning until they have selected a spawn. + if (Player.respawnTimer <= 10) + { + //Player.respawnTimer = 10; + if (!Main.mapFullscreen) + { + Main.mapFullscreen = true; + SpawnSelectorSystem.SetEnabled(true); + } + } + } + + public override void ProcessTriggers(TriggersSet triggersSet) + { + var keybinds = ModContent.GetInstance(); + + if (keybinds.AdventureMirrorKeybind.JustPressed) + { + TryUseAdventureMirror(); + } + } + + private void TryUseAdventureMirror() + { + // Find a mirror in the player's inventory + int mirrorIndex = -1; + + for (int i = 0; i < Player.inventory.Length; i++) + { + if (Player.inventory[i].type == ModContent.ItemType()) + { + mirrorIndex = i; + break; + } + } + + if (mirrorIndex == -1) + { + Main.NewText("You don't have an Adventure Mirror!", Color.Red); + return; + } + + // Cancel if the player is moving + if (Player.velocity.Length() > 0f) + { + PopupText.NewText(new AdvancedPopupRequest + { + Color = Color.Crimson, + Text = "Cannot use while moving!", + Velocity = new(0, -4), + DurationInFrames = 60 + }, Player.Top); + return; + } + + // Force the player to use the item + Player.selectedItem = mirrorIndex; + Player.controlUseItem = true; + Player.ItemCheck(); + } +} diff --git a/Core/Features/SpawnSelector/Players/ModifyPlayerDrawInfo.cs b/Core/Features/SpawnSelector/Players/ModifyPlayerDrawInfo.cs new file mode 100644 index 00000000..67dd894b --- /dev/null +++ b/Core/Features/SpawnSelector/Players/ModifyPlayerDrawInfo.cs @@ -0,0 +1,47 @@ +using Microsoft.Xna.Framework; +using Terraria; +using Terraria.DataStructures; +using Terraria.GameContent; +using Terraria.ModLoader; + +namespace PvPAdventure.Core.Features.SpawnSelector.Players; + +public class ModifyPlayerDrawInfo : ModPlayer +{ + public static bool ForceFullBrightOnce; + public override void ModifyDrawInfo(ref PlayerDrawSet drawInfo) + { + if (!ForceFullBrightOnce) + return; + + drawInfo.shadow = 0f; + drawInfo.stealth = 1f; + + var p = drawInfo.drawPlayer; + p.socialIgnoreLight = true; + + drawInfo.colorEyeWhites = Color.White; + drawInfo.colorEyes = p.eyeColor; + drawInfo.colorHair = p.GetHairColor(useLighting: false); + drawInfo.colorHead = p.skinColor; + drawInfo.colorBodySkin = p.skinColor; + drawInfo.colorLegs = p.skinColor; + + drawInfo.colorShirt = p.shirtColor; + drawInfo.colorUnderShirt = p.underShirtColor; + drawInfo.colorPants = p.pantsColor; + drawInfo.colorShoes = p.shoeColor; + + drawInfo.colorArmorHead = Color.White; + drawInfo.colorArmorBody = Color.White; + drawInfo.colorArmorLegs = Color.White; + drawInfo.colorMount = Color.White; + + drawInfo.colorDisplayDollSkin = PlayerDrawHelper.DISPLAY_DOLL_DEFAULT_SKIN_COLOR; + + drawInfo.headGlowColor = new Color(drawInfo.headGlowColor.R, drawInfo.headGlowColor.G, drawInfo.headGlowColor.B, 0); + drawInfo.bodyGlowColor = new Color(drawInfo.bodyGlowColor.R, drawInfo.bodyGlowColor.G, drawInfo.bodyGlowColor.B, 0); + drawInfo.armGlowColor = new Color(drawInfo.armGlowColor.R, drawInfo.armGlowColor.G, drawInfo.armGlowColor.B, 0); + drawInfo.legsGlowColor = new Color(drawInfo.legsGlowColor.R, drawInfo.legsGlowColor.G, drawInfo.legsGlowColor.B, 0); + } +} \ No newline at end of file diff --git a/Core/Features/SpawnSelector/Players/SpawnSelectorPlayer.cs b/Core/Features/SpawnSelector/Players/SpawnSelectorPlayer.cs deleted file mode 100644 index 8c8e7c32..00000000 --- a/Core/Features/SpawnSelector/Players/SpawnSelectorPlayer.cs +++ /dev/null @@ -1,70 +0,0 @@ -using Microsoft.Xna.Framework; -using PvPAdventure.Content.Items; -using PvPAdventure.Core.Features.SpawnSelector.Systems; -using PvPAdventure.System; -using Terraria; -using Terraria.ModLoader; -using static Terraria.ModLoader.BackupIO; - -namespace PvPAdventure.Core.Features.SpawnSelector.Players; - -public class SpawnSelectorPlayer : ModPlayer -{ - public override void PostUpdate() - { - if (Main.dedServ || Player.whoAmI != Main.myPlayer) - { - return; - } - - // Force SSS to be enabled when player is within the spawn region. - var regionManager = ModContent.GetInstance(); - Point tilePos = Player.Center.ToTileCoordinates(); - var region = regionManager.GetRegionContaining(tilePos); - bool inRegion = region != null; - if (inRegion) - SpawnSelectorSystem.SetEnabled(true); - - // Unsure if this causes any bugs. - // It may be too forcing to always set it to false whenever map is closed. - if (!Main.mapFullscreen) - SpawnSelectorSystem.SetEnabled(false); - - // Check if player is using AdventureMirror - if (Player.HeldItem != null && - Player.HeldItem.type == ModContent.ItemType() && - Player.itemAnimation > 0 && - Player.itemAnimation % 60 == 0) - { - int itemUseTimeLeft = Main.LocalPlayer.itemAnimation / 60; - string timeLeft = itemUseTimeLeft.ToString(); - - // Display text above the player every second - PopupText.NewText(new AdvancedPopupRequest - { - Color = Color.Crimson, - Text = timeLeft, - Velocity = new(0.0f, -4.0f), - DurationInFrames = 60 * 1 - }, Player.Top); - } - } - - public bool hasSelectedSpawnPoint = false; - - public override void UpdateDead() - { - //Main.NewText(Player.respawnTimer); - - // Keeps the player from respawning until they have selected a spawn. - if (Player.respawnTimer <= 10 && !hasSelectedSpawnPoint) - { - //Player.respawnTimer = 10; - if (!Main.mapFullscreen) - { - Main.mapFullscreen = true; - SpawnSelectorSystem.SetEnabled(true); - } - } - } -} \ No newline at end of file diff --git a/Core/Features/SpawnSelector/Systems/SpawnSelectorState.cs b/Core/Features/SpawnSelector/Systems/SpawnSelectorState.cs index 9a69d306..c1d7ae6b 100644 --- a/Core/Features/SpawnSelector/Systems/SpawnSelectorState.cs +++ b/Core/Features/SpawnSelector/Systems/SpawnSelectorState.cs @@ -1,43 +1,47 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; -using PvPAdventure.Core.Features.SpawnSelector.Systems; using PvPAdventure.Core.Features.SpawnSelector.UI; using PvPAdventure.Core.Helpers; using Terraria.GameContent.UI.Elements; using Terraria.UI; -namespace PvPAdventure.Core.Features.SpawnSelector.Systems +namespace PvPAdventure.Core.Features.SpawnSelector.Systems; + +public class SpawnSelectorState : UIState { - internal class SpawnSelectorState : UIState + public UISpawnSelectorPanel spawnSelectorPanel; + public override void OnInitialize() { - public override void OnInitialize() - { - UISpawnSelectorPanel spawnSelectorPanel = new(); - Append(spawnSelectorPanel); + spawnSelectorPanel = new(); + Append(spawnSelectorPanel); - UITextPanel chooseYourSpawnPanel = new("Choose Your Spawn", 0.8f, true); - chooseYourSpawnPanel.HAlign = 0.5f; - chooseYourSpawnPanel.VAlign = 0f; - chooseYourSpawnPanel.Top.Set(10, 0); - chooseYourSpawnPanel.BackgroundColor = new Color(73, 94, 171); - Append(chooseYourSpawnPanel); - } + UITextPanel chooseYourSpawnPanel = new("Choose Your Spawn", 0.8f, true); + chooseYourSpawnPanel.HAlign = 0.5f; + chooseYourSpawnPanel.VAlign = 0f; + chooseYourSpawnPanel.Top.Set(10, 0); + chooseYourSpawnPanel.BackgroundColor = new Color(73, 94, 171); + Append(chooseYourSpawnPanel); + } - public override void OnActivate() + public override void OnActivate() + { + base.OnActivate(); + UISpawnSelectorPanel panel = null; + foreach (var element in Elements) { - base.OnActivate(); - UISpawnSelectorPanel panel = null; - foreach (var element in Elements) - { - panel = element as UISpawnSelectorPanel; - if (panel != null) - break; - } + panel = element as UISpawnSelectorPanel; if (panel != null) - { - panel.Rebuild(); - Log.Info("SpawnSelectorState: Rebuilt panel on activate"); - } + break; } + if (panel != null) + { + panel.Rebuild(); + Log.Info("SpawnSelectorState: Rebuilt panel on activate"); + } + } + + public override void Draw(SpriteBatch spriteBatch) + { + base.Draw(spriteBatch); } } diff --git a/Core/Features/SpawnSelector/Systems/SpawnSelectorSystem.cs b/Core/Features/SpawnSelector/Systems/SpawnSelectorSystem.cs index 861f648d..a75209dd 100644 --- a/Core/Features/SpawnSelector/Systems/SpawnSelectorSystem.cs +++ b/Core/Features/SpawnSelector/Systems/SpawnSelectorSystem.cs @@ -11,7 +11,7 @@ namespace PvPAdventure.Core.Features.SpawnSelector.Systems; public class SpawnSelectorSystem : ModSystem { private UserInterface ui; - private SpawnSelectorState state; + public SpawnSelectorState state; private UISpawnSelectorPanel teleportPanel; // Track whether the spawn selector is enabled diff --git a/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs b/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs index 26059c19..5daefa83 100644 --- a/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs +++ b/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs @@ -1,14 +1,13 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; +using PvPAdventure.Core.Features.SpawnSelector.Players; using PvPAdventure.Core.Features.SpawnSelector.Systems; using PvPAdventure.Core.Helpers; using ReLogic.Content; using System; using Terraria; -using Terraria.Audio; using Terraria.GameContent; using Terraria.GameContent.UI.Elements; -using Terraria.ID; using Terraria.UI; namespace PvPAdventure.Core.Features.SpawnSelector.UI @@ -18,12 +17,14 @@ namespace PvPAdventure.Core.Features.SpawnSelector.UI /// internal class UISpawnSelectorCharacterListItem : UIPanel { + internal const float ItemWidth = 260f; + internal const float ItemHeight = 72f; + private readonly Asset _dividerTexture; private readonly Asset _innerPanelTexture; private readonly Asset _playerBGTexture; private readonly int _playerIndex; - private Rectangle _bedHitbox; public UISpawnSelectorCharacterListItem(Player player) { @@ -38,8 +39,10 @@ public override void OnInitialize() { BorderColor = Color.Black; BackgroundColor = new Color(63, 82, 151) * 0.7f; - Height.Set(72f, 0f); - Width.Set(-20f, 1f); + + Height.Set(ItemHeight, 0f); + Width.Set(ItemWidth, 0f); + SetPadding(6f); } @@ -48,40 +51,26 @@ protected override void DrawSelf(SpriteBatch sb) base.DrawSelf(sb); CalculatedStyle inner = GetInnerDimensions(); - var dims = GetDimensions(); - var rect = dims.ToRectangle(); Player player = Main.player[_playerIndex]; + var dims = GetDimensions(); + if (player == null || !player.active) { - Utils.DrawBorderString(sb, "Unable to find player :(", rect.Location.ToVector2() + new Vector2(50, 0), Color.White); + var rect2 = dims.ToRectangle(); + + Utils.DrawBorderString(sb, "Unable to find player :(", rect2.Location.ToVector2() + new Vector2(50, 0), Color.White); return; } - DrawMapFullscreenBackground(sb, rect, player); - - // Left "player" background + // Left player background Vector2 pos = new(inner.X, inner.Y); sb.Draw(_playerBGTexture.Value, pos, Color.White); - // Right "bed" background - //Vector2 bedBGPos = new(pos.X + dims.Width - 73, pos.Y); - //sb.Draw(_playerBGTexture.Value, bedBGPos, Color.White); - - // Bed icon - //Vector2 bedIconPos = bedBGPos + new Vector2(31, 31); - //Item icon = new(ItemID.Bed); - //ItemSlot.DrawItemIcon(icon, 31, sb, bedIconPos, 1.0f, 32f, Color.White); + Rectangle rect = new((int)pos.X-5, (int)pos.Y-5, 68,68); - // Update clickable bed hitbox (approx 32x32 centered on icon pos) - //_bedHitbox = new Rectangle( - // (int)(bedIconPos.X - 16), - // (int)(bedIconPos.Y - 16), - // 32, - // 32 - //); + DrawMapFullscreenBackground(sb, rect, player); - // Draw player sprite (switch to point-clamp batch) sb.End(); sb.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, @@ -91,6 +80,7 @@ protected override void DrawSelf(SpriteBatch sb) null, Main.UIScaleMatrix); + ModifyPlayerDrawInfo.ForceFullBrightOnce = true; try { Vector2 playerDrawPos = pos + Main.screenPosition + new Vector2(16, 8); @@ -109,6 +99,10 @@ protected override void DrawSelf(SpriteBatch sb) { Log.Error("Failed to draw player: " + e); } + finally + { + ModifyPlayerDrawInfo.ForceFullBrightOnce = false; + } // Switch back to "normal" UI batch sb.End(); @@ -124,15 +118,16 @@ protected override void DrawSelf(SpriteBatch sb) float startX = inner.X + leftColumnWidth; // Name centered - string name = string.IsNullOrEmpty(player.name) ? "Teammate" : player.name; + string name = string.IsNullOrEmpty(player.name) ? "Unknown player" : player.name; Vector2 nameSize = FontAssets.MouseText.Value.MeasureString(name); float centerX = inner.X + inner.Width * 0.5f; Utils.DrawBorderString( sb, name, - new Vector2(centerX - nameSize.X * 0.5f, inner.Y - 2f), - Color.White + new Vector2(centerX, inner.Y), + Color.White, + scale: 1.1f ); // Divider @@ -143,35 +138,42 @@ protected override void DrawSelf(SpriteBatch sb) Color.White, 0f, Vector2.Zero, - new Vector2((dims.X + dims.Width - startX) / 8 - 10, 1f), + new Vector2((dims.X + dims.Width - startX) / 8-0.5f, 1f), SpriteEffects.None, 0f ); // HP / MP panel - Vector2 panelPos = new(startX + 6f, inner.Y + 29f); - float panelWidth = 220f; + Vector2 panelPos = new(startX + 0f, inner.Y + 29f); + float panelWidth = 190f; DrawPanel(sb, panelPos, panelWidth); Vector2 cursor = panelPos; // HP - sb.Draw(TextureAssets.Heart.Value, cursor + new Vector2(5f, 2f), Color.White); - cursor.X += 10f + TextureAssets.Heart.Width(); - string hpText = $"{player.statLife}/{player.statLifeMax}"; + sb.Draw(TextureAssets.Heart.Value, cursor + new Vector2(4f, 2f), Color.White); + cursor.X += 6f + TextureAssets.Heart.Width(); + string hpText = $"{player.statLife} HP"; Utils.DrawBorderString(sb, hpText, cursor + new Vector2(0f, 3f), Color.White); // MP cursor.X += 80f; - sb.Draw(TextureAssets.Mana.Value, cursor + new Vector2(5f, 2f), Color.White); - cursor.X += 10f + TextureAssets.Mana.Width(); - string manaText = $"{player.statMana}/{player.statManaMax}"; + sb.Draw(TextureAssets.Mana.Value, cursor + new Vector2(-15f, 0f), Color.White); + cursor.X += -11f + TextureAssets.Mana.Width(); + string manaText = $"{player.statMana} MP"; Utils.DrawBorderString(sb, manaText, cursor + new Vector2(0f, 3f), Color.White); + + // Set hover teleport tooltip + if (IsMouseHovering) + { + Main.instance.MouseText("Teleport to " + name); + } } public override void MouseOver(UIMouseEvent evt) { base.MouseOver(evt); + BackgroundColor = new Color(73, 92, 161); } @@ -185,54 +187,11 @@ public override void LeftClick(UIMouseEvent evt) { base.LeftClick(evt); - // Only react if the BED area was clicked, not the whole row - //if (!_bedHitbox.Contains(evt.MousePosition.ToPoint())) - //return; - - Terraria.Player player = Main.player[_playerIndex]; + Player player = Main.player[_playerIndex]; Main.LocalPlayer.UnityTeleport(player.position); - //TeleportToPlayerBed(player); - } - - private static void TeleportToPlayerBed(Terraria.Player target) - { - if (target == null || !target.active) - return; - - Terraria.Player local = Main.LocalPlayer; - if (local == null || !local.active) - return; - - // Figure out target spawn (bed) tile - int spawnX = target.SpawnX; - int spawnY = target.SpawnY; - - // Fallback: player position if no personal spawn - if (spawnX <= 0 || spawnY <= 0) - { - spawnX = (int) target.position.X; - spawnY = (int)target.position.Y; - } - - // Convert tile coords to world coords - Vector2 dest = new Vector2( - spawnX * 16 + local.width / 2f, - spawnY * 16 - local.height - ); - - if (Main.netMode == NetmodeID.SinglePlayer) - { - local.Teleport(dest); - } - else - { - // TODO Multiplayer: send teleport request to server - // ModContent.GetInstance().SendBedTeleportPacket(target.whoAmI); - } - - // Close fullscreen map + spawn selector + // close map and SSS Main.mapFullscreen = false; SpawnSelectorSystem.SetEnabled(false); } diff --git a/Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs b/Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs index 0b8b3741..ac873ce2 100644 --- a/Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs +++ b/Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs @@ -1,94 +1,116 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; -using PvPAdventure.Core.Features.SpawnSelector.Systems; using PvPAdventure.Core.Helpers; using System.Collections.Generic; using Terraria; using Terraria.GameContent.UI.Elements; -using Terraria.ID; namespace PvPAdventure.Core.Features.SpawnSelector.UI { - internal class UISpawnSelectorPanel : UIPanel + public class UISpawnSelectorPanel : UIPanel { - private UITextPanel randomButton; + private UIPanel _randomPanel; + private readonly List _playerItems = new(); + + private const float Spacing = 8f; + private const float HorizontalPadding = 16f; + private const float VerticalPadding = 12f; public override void OnInitialize() { - Width.Set(400f, 0f); - Height.Set(300f, 0f); HAlign = 0.5f; VAlign = 0.0f; - Top.Set(10 + 32 - 10, 0); + Top.Set(52, 0); + BackgroundColor = new Color(33, 43, 79) * 0.8f; - SetPadding(6f); - - randomButton = new UITextPanel("Random"); - randomButton.Width.Set(-20f, 1f); - randomButton.Left.Set(10f, 0f); - randomButton.Top.Set(30f, 0f); - randomButton.BackgroundColor = new Color(63, 82, 151) * 0.8f; - randomButton.BorderColor = Color.Black; - randomButton.OnMouseOver += (_, _) => - { - randomButton.BackgroundColor = new Color(73, 92, 161); - }; - randomButton.OnMouseOut += (_, _) => - randomButton.BackgroundColor = new Color(63, 82, 151) * 0.8f; - randomButton.OnLeftClick += (_, _) => PerformRandomTeleport(); - Append(randomButton); - - // Debug: add test entry - //var p1 = new UISpawnSelectorCharacterListItem(Main.LocalPlayer); - //p1.Width.Set(-20f, 1f); - //p1.Left.Set(10, 0f); - //p1.Top.Set(74, 0f); - //Append(p1); - - // Add teammates + SetPadding(0f); + + BuildLayout(); + + Log.Info("UISpawnSelectorPanel.OnInitialize: layout built"); + } + + private void BuildLayout() + { + RemoveAllChildren(); + _playerItems.Clear(); + + // === ADD TEAMMATES var players = new List(); - if (Main.LocalPlayer.team != 0) + var local = Main.LocalPlayer; + + if (local.team != 0) { for (int i = 0; i < Main.maxPlayers; i++) { Player p = Main.player[i]; - if (p != null && p.active && p.whoAmI != Main.LocalPlayer.whoAmI && p.team == Main.LocalPlayer.team) - { - Main.NewText("Adding teammate: " + p.name); - players.Add(p); - } + if (p == null || !p.active || p.whoAmI == local.whoAmI || p.team != local.team) + continue; + + players.Add(p); } } - // Add UI elements for each teammate - for (int i = 0; i < players.Count; i++) + // === TEST DATA: add 3 self player copies for singleplayer testing + if (players.Count == 0) { + for (int i = 0; i < 3; i++) + { + players.Add(local); + } + } + + int playerCount = players.Count; + + float itemWidth = UISpawnSelectorCharacterListItem.ItemWidth; + float itemHeight = UISpawnSelectorCharacterListItem.ItemHeight; + float randomWidth = itemHeight; // square random panel + + float contentWidth = playerCount * itemWidth + + playerCount * Spacing + + randomWidth; + + float panelWidth = contentWidth + HorizontalPadding * 2f; + float panelHeight = itemHeight + VerticalPadding * 2f; + + Width.Set(panelWidth, 0f); + Height.Set(panelHeight, 0f); + + float startX = HorizontalPadding; + float y = VerticalPadding; + + // Players in a row + for (int i = 0; i < playerCount; i++) + { + float x = startX + i * (itemWidth + Spacing); + var row = new UISpawnSelectorCharacterListItem(players[i]); - row.Width.Set(-20f, 1f); - row.Left.Set(10, 0f); - row.Top.Set(74 + i * 70, 0f); + row.Left.Set(x, 0f); + row.Top.Set(y, 0f); + Append(row); + _playerItems.Add(row); } - Log.Info($"UISpawnSelectorPanel.OnInitialize: team={Main.LocalPlayer.team}, teammates={players.Count}"); - } + // Square random panel to the right of the last player, + // with exactly one Spacing after the last player. + _randomPanel = new UISpawnSelectorRandomPanel( + startX, + itemHeight, + playerCount, + itemWidth, + Spacing, + y + ); + Append(_randomPanel); - public void Rebuild() - { - RemoveAllChildren(); - OnInitialize(); - Log.Info("UISpawnSelectorPanel.Rebuild: UI rebuilt"); + Log.Debug($"UISpawnSelectorPanel.BuildLayout: players={playerCount}, panelWidth={panelWidth}"); } - private void PerformRandomTeleport() + public void Rebuild() { - if (Main.netMode == NetmodeID.MultiplayerClient) - NetMessage.SendData(MessageID.RequestTeleportationByServer); - else - Main.LocalPlayer.TeleportationPotion(); - - Main.mapFullscreen = false; - SpawnSelectorSystem.SetEnabled(false); + BuildLayout(); + Log.Debug("UISpawnSelectorPanel.Rebuild: UI rebuilt"); } public override void Draw(SpriteBatch spriteBatch) diff --git a/Core/Features/SpawnSelector/UI/UISpawnSelectorRandomPanel.cs b/Core/Features/SpawnSelector/UI/UISpawnSelectorRandomPanel.cs new file mode 100644 index 00000000..8b4f5405 --- /dev/null +++ b/Core/Features/SpawnSelector/UI/UISpawnSelectorRandomPanel.cs @@ -0,0 +1,78 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using PvPAdventure.Core.Features.SpawnSelector.Systems; +using PvPAdventure.Core.Helpers; +using Terraria; +using Terraria.GameContent.UI.Elements; +using Terraria.ID; +using Terraria.ModLoader; +using Terraria.UI; + +namespace PvPAdventure.Core.Features.SpawnSelector.UI +{ + internal class UISpawnSelectorRandomPanel : UIPanel + { + public UISpawnSelectorRandomPanel(float startX, float itemHeight, int playerCount, float itemWidth, float Spacing, float y) + { + Width.Set(itemHeight, 0f); + Height.Set(itemHeight, 0f); + Top.Set(y, 0f); + + float randomX = startX + playerCount * (itemWidth + Spacing); + Left.Set(randomX, 0f); + + BackgroundColor = new Color(63, 82, 151) * 0.8f; + BorderColor = Color.Black; + } + + public override void LeftClick(UIMouseEvent evt) + { + base.LeftClick(evt); + + if (Main.netMode == NetmodeID.MultiplayerClient) + { + NetMessage.SendData(MessageID.RequestTeleportationByServer); + } + else + { + Main.LocalPlayer.TeleportationPotion(); + } + + Main.mapFullscreen = false; + SpawnSelectorSystem.SetEnabled(false); + } + + public override void MouseOver(UIMouseEvent evt) + { + base.MouseOver(evt); + BackgroundColor = new Color(73, 92, 161); + + } + + public override void MouseOut(UIMouseEvent evt) + { + base.MouseOut(evt); + BackgroundColor = new Color(63, 82, 151) * 0.8f; + } + + public override void Draw(SpriteBatch spriteBatch) + { + base.Draw(spriteBatch); + + if (IsMouseHovering) + { + Main.instance.MouseText("Random"); + } + + // Draw question mark + var dims = GetDimensions(); + var rect = dims.ToRectangle(); + spriteBatch.Draw(Ass.Question_Mark.Value, rect, Color.White); + } + + public override void Update(GameTime gameTime) + { + base.Update(gameTime); + } + } +} diff --git a/Core/Helpers/AssetLoader.cs b/Core/Helpers/AssetLoader.cs new file mode 100644 index 00000000..fc7575ec --- /dev/null +++ b/Core/Helpers/AssetLoader.cs @@ -0,0 +1,41 @@ +using System.Reflection; +using Microsoft.Xna.Framework.Graphics; +using ReLogic.Content; +using Terraria.ModLoader; + +namespace PvPAdventure.Core.Helpers; + +/// +/// Static class to hold all assets used in the mod. +/// +public static class Ass +{ + // Add assets here + public static Asset Question_Mark; + + // This bool automatically initializes all specified assets + public static bool Initialized { get; set; } + + static Ass() + { + foreach (FieldInfo field in typeof(Ass).GetFields()) + { + if (field.FieldType == typeof(Asset)) + { + var asset = ModContent.Request($"PvPAdventure/Assets/SpawnSelector/{field.Name}", AssetRequestMode.AsyncLoad); + field.SetValue(null, asset); + } + } + } +} + +/// +/// System that automatically initializes assets +/// +public class LoadAssets : ModSystem +{ + public override void Load() + { + _ = Ass.Initialized; + } +} \ No newline at end of file diff --git a/Localization/en-US.hjson b/Localization/en-US.hjson index 3534565a..50141ec8 100644 --- a/Localization/en-US.hjson +++ b/Localization/en-US.hjson @@ -13,6 +13,7 @@ Mods: { Scoreboard.DisplayName: Scoreboard BountyShop.DisplayName: Bounty Shop AllChat.DisplayName: All Chat + AdventureMirror.DisplayName: Adventure Mirror } Configs: { @@ -133,6 +134,11 @@ Mods: { Label: RTP Recall Frames Tooltip: "" } + + AdventureMirrorRecallFrames: { + Label: Adventure Mirror Recall Frames + Tooltip: "" + } } PointsConfig: { diff --git a/PvPAdventure.csproj b/PvPAdventure.csproj index da9cae18..05bbc501 100644 --- a/PvPAdventure.csproj +++ b/PvPAdventure.csproj @@ -1,27 +1,27 @@  - - - PvPAdventure - latest - - - - - - - - - - - lib\Discord.Net.Core.dll - - - lib\Discord.Net.Rest.dll - - - lib\System.Linq.Async.dll - - + + + PvPAdventure + latest + + + + + + + + + + + lib\Discord.Net.Core.dll + + + lib\Discord.Net.Rest.dll + + + lib\System.Linq.Async.dll + + diff --git a/System/Client/Keybinds.cs b/System/Client/Keybinds.cs index d72d756f..8d7699b5 100644 --- a/System/Client/Keybinds.cs +++ b/System/Client/Keybinds.cs @@ -9,11 +9,13 @@ public class Keybinds : ModSystem public ModKeybind Scoreboard { get; private set; } public ModKeybind BountyShop { get; private set; } public ModKeybind AllChat { get; private set; } + public ModKeybind AdventureMirrorKeybind { get; private set; } public override void Load() { Scoreboard = KeybindLoader.RegisterKeybind(Mod, "Scoreboard", Keys.OemTilde); BountyShop = KeybindLoader.RegisterKeybind(Mod, "BountyShop", Keys.P); AllChat = KeybindLoader.RegisterKeybind(Mod, "AllChat", Keys.U); + AdventureMirrorKeybind = KeybindLoader.RegisterKeybind(Mod, "AdventureMirror", Keys.M); } } \ No newline at end of file diff --git a/icon_small.png b/icon_small.png index c81d55a7a5b705df2dc964547e765a9089bcc7ff..e06b69194deb74c1c306133c9d1b382ca427a528 100644 GIT binary patch delta 899 zcmV-}1AP3;39bi_IDZ3RNkl+p!AD|CXu@ALjK@ds}B$PJVNKMmP zqh^z|yW8EF`fV z^5}os&R$^n?0*8zEpErxH~c_X&V9bpXz;PCmu8NvPEG0jQUue>ek>MhJC4eWGs)`! z3fj;x%OwO9VThY)@8Ofn-P z&CM5MHlThedP|QWnIYwpPRUhZ-?JzY&eRVDaJU;H`_zDQ{+Eo1Sg zIXF#zG=GI{%ztB|e9Gbez0t?^jQCt|s-9pLi@+260(dy_GeSRR^q=_<=Cs23%%Z+4 zpycSGjmm0T>y9n;JjcI&pOwu$-KM;AJSYceA#XXqAiv^LZ9MZ`lCiMg2Jlo>FKon&+P8jN|Xx@)D_GM{P2!DW6qxYlRW)dHoYa1H~Q$&9z^^OI2yB|BZ<41kv!Hu{iU1#lu3Rs*;93YKyv zT6|jEdlR3M9B=epojx>bsXKc8;xh>Ctn~{|U9MK})$9*G=5h*FP{XJUw&r?(k9|A2 z%$eB|9lKH^we%?E^#ziDmu((7Ia%b%>`h+#tK>r6;__rt%TJq#Y`E17h5&p)@^i02 Z{sDgRvp--8={o=b002ovPDHLkV1i;>%yIw# delta 1187 zcmV;U1YG;B2g?bNIDZ6vNklXaibd-ajT$91(#X4C?XVbQ4y_3)FL&sA~vz4X(MSgGkMHp=H7FT zoclcY&P?bm4)@%-kMDfn|2yCPk9h3(hc|#Bj0OzhQG-#z+2lLHNhiH;$dLX~}!zi?fTeb98=z z${vR$n2iK10kt=zfbj!HY0L|&JoM%q?@TQ)w!5C*6TR4-=NDpvYr%X&#_U|CDNC2R z!ZbDK&)&!BKYtF>cXWyA>3PQYZ#hh2sT~y}Fq47?bD5Djs;RMy2!@?It2K%Wg2nlx zymxIM>fRL&PS$fW`VLquwV(Bdw!kja7|@j_V=6`E_Zs^zuXFk4!+g0_MviYdCW@K4 zb?(esCN(8?uqXnzh2XM~J%_3gBU+!~sqq0ej4 zFAXwMDBWJE!Qy99)~T8@@8C9xaz+t&=!!s%^dYeJFlmjQdUj{6F%=$F+z#25q3gt4DhYcn-hHl0Nj!EUqciaulW?#WL$; zCw&~r?C(=A-Q=D-w(v(Ms7)S2=xu~2*zEmbfU@AQiBC|_8=0pC_ zq{rzKD-70GsLm~+N@YrWe6F7@BhO2oJ_b)c+o8sep@_lBNbP*YJ4E32Haz*9;E98O zF}ZM#)%qw4TC)Cifx{)kTc-s5_UoQ0S^Jj`qY)+uknC14U26Q}>;QL-8Q%S9lh>}? z;D7z?E7Y%-d3&nHdaJs zrs0(+jg%==3>UtaeEf;i7_^y62TU!fNX^x$hjMaPD;f=-ufEZI_pNPO4E2VM&nCw6 zP@5i~e%7K|jrY4XkSno@Ks5q8?8l{tUVlkz#TRGb#pAbg;bN1P`H$%j;M6MxE?wGg zlQqj!2Y`0(+fnSXSK{ijy{E~)>psi>2rmBV@%LgYmvs4>>I5|Icx11=l6}eOE{}=3 zeb%ad3=g%ZQa7eVG7Cd)JKaLBWY1qd(O_a6iUou6(|)a!)D|dYX%|8`LdL!IN`H3z zG+Uxtl~e{aQsinH1%`->6u6j>Wl-N>A(nBEy^<}-ufHkguY$6lVnu_>(Yf{tr!^Hy59zUbp}N002ovPDHLkV1ivw BRAT@D From d13ec226bf4e1046c52e731a2181c10de15b67ea Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Thu, 13 Nov 2025 22:31:33 -0800 Subject: [PATCH 163/206] makes pirahina gun only attack every 40 frames instead of 8 (five times slower hits with only one pirahina) --- AdventureConfig.cs | 2 -- AdventureProjectile.cs | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/AdventureConfig.cs b/AdventureConfig.cs index 1da4085a..b09df1b4 100644 --- a/AdventureConfig.cs +++ b/AdventureConfig.cs @@ -176,8 +176,6 @@ public float CalculateMultiplier(float tileDistance) => [DefaultValue(null)] [NullAllowed] public Falloff DefaultFalloff { get; set; } } - [Description("Projectiles that deal no knockback in PvP")] - public List NoKnockbackProjectiles { get; set; } = new(); [Range(0, 5 * 60)] [DefaultValue(8)] public int MeleeInvincibilityFrames { get; set; } [Range(0, 60 * 2 * 60)] diff --git a/AdventureProjectile.cs b/AdventureProjectile.cs index 183f138e..b3f3cdb6 100644 --- a/AdventureProjectile.cs +++ b/AdventureProjectile.cs @@ -916,7 +916,7 @@ public override bool PreAI(Projectile projectile) if (projectile.localAI[0] <= 0f) { - projectile.localAI[0] = 1f; // Attack every frame (temp), we can change ts + projectile.localAI[0] = 40f; // Attack every frame (temp), we can change ts if (Main.myPlayer == projectile.owner) { From 934338bf08b64b39cfdd18605ea37656c0bdd4db Mon Sep 17 00:00:00 2001 From: emyhrberg <121192176+emyhrberg@users.noreply.github.com> Date: Sat, 15 Nov 2025 00:41:00 +0100 Subject: [PATCH 164/206] Fixing some stuff, adding right click functionality --- Assets/SpawnSelector/Question_Mark.png | Bin 321 -> 1710 bytes Assets/SpawnSelector/Teleportation_Potion.png | Bin 0 -> 1776 bytes Content/Items/AdventureMirror.cs | 47 +++-- Content/Items/AdventureMirrorGlobalItem.cs | 13 +- .../SpawnSelector/Hooks/ItemSlotHooks.cs | 15 +- .../Players/AdventureMirrorPlayer.cs | 168 ++++++++++++------ .../UI/UISpawnSelectorCharacterListItem.cs | 93 +++++++--- .../UI/UISpawnSelectorRandomPanel.cs | 27 ++- Localization/en-US.hjson | 11 +- 9 files changed, 256 insertions(+), 118 deletions(-) create mode 100644 Assets/SpawnSelector/Teleportation_Potion.png diff --git a/Assets/SpawnSelector/Question_Mark.png b/Assets/SpawnSelector/Question_Mark.png index fe979b345e61870b274c2150170700bb96661325..c0519347d76ab5b694077230cbfb9611bde1fd54 100644 GIT binary patch literal 1710 zcmbVNZEVzJ9Ph}o7j%rL;?pAl#r?kD@ z?ULnCm+2P87^A>A;S)rVsL2w^!ic&U{IHFf_+b(zO3aoRh7-3Ld;_1}8=xqWChha~ zdw&1-e@8m}&sMD8xE{l>iq;ly0F8~-TULU;CzZXI&`_?mbQ>7 z4t6B{K`GfMaWc`c4X;n|h#(3~5l=)Ts=+4&BE!q0xwTCbcm`tj2}F}65byGJ;2x+0 zoTFG$Vi-H_;wY|;V??*>Dcr``oHS#nnL3i?c-F?F^V~xqak?Dh1KwwH!q7?}dQDT~ zX*wQ{Q*k>5^)StH97i)Y+GZmWf;0wHQ%sPmu{qD+1%{+6nyEk)w;0797&8R|shYJR zsugHeBj+dNF*+e?G)pm-O&Opp6>wTik7R_)5)C3C3RKfTShj%GdZ7u8UidH6h2uK} zAm93Y1sQkMB^oV=FwEwDWJb;*cSRe)0S(XrV8ECzf#!as=4Q(pjrZt4G@%}ZFp`f{ zM_y&z=Asz9rc+U67&o@ub^&-r69|MAHIijX))8b_-ciT1_F6Pym@L!>WhFH552%gd zolc&0-vLEABa5bZPp~ZUA*e@1WUvwy!+_S*Fo74`$a`P}>PRrs&Ysc2=i^&d!xU8s zw0Z>s*-R;l%*%GUPO{mZB*VxqQkETd(j5YBQglkJT@1NdM~^dq-wUOf71{iK`G4MT z*A-M+V&uMgtb(&rf^Sg_6s&<RdW% zQI&&5Wf)czYV|e+6X~lLNq;e0eePQ7sH3L1^gDMN8!vx#ZOB=(f8W%;sn;7%T`qa# zMQudD)-|_`9vQ7We0pXyoKm;_Y<@oZZvXMO+P1i>7Kb>|e=svpuT-6HU%dGK^o3Az zez;`gg8Fu7>&I}Vs=wjQ#L_Z`aMPEE{IdtvmY1%ttbX&_ncYWs4oo;a=$_+04)3u4YAI?sEdg<5BAtWQs9GJTKV8x!= w`Q4?7UA6V^AlR|*Q!n3g#irlZRbG9FTj+j*IDLG(^+#!K_Ip2g`uUgs0@q|!-~a#s delta 309 zcmV-50m}Za4Z#8-iBL{Q4GJ0x0000DNk~Le0000W0000W2nGNE0CReJ^pPPKe*p7I zL_t(og=75x|3AY(0;U1Aonh1g3=Av;RmiYG=q23~5AhK1A(FPnUtzyQ}z9GX%cK`q;d|2l9h4^9s3jhEBNkvXX Hu0mjf1;l_c diff --git a/Assets/SpawnSelector/Teleportation_Potion.png b/Assets/SpawnSelector/Teleportation_Potion.png new file mode 100644 index 0000000000000000000000000000000000000000..d7ca8ed271d00841d66db6a8adc95fb551937f60 GIT binary patch literal 1776 zcmbVNUyKt)7~hMUz;PrX7Zr`VE^;}L?e6y4Zg-&I(caN2dp2#8J5ZGA>}tT+Au*vMq z?EJp(`+a}r+r8(7BtA2NvB%-}jyVVjG?K^w!(}omVo$apuUm zmG$~Fe@oK(OcoZFPaa}^o%;B~hh2ZYarA@w)SnlBsMns~f9mkl1{LV=GDBJB(M#ub zx>;-|x48_nWQ9LEm^Y8!!!UPD8@Um0MBNGyF#}K|c^s&kHbpbchD}u)qEYOzd0a58 z828KcCmd^NF>W}limDyQMI$-x;OzKN4vmi@MdLPYWH(d+RbXNdvQ@KWxu6>38hQa; z`=14lZ9u%y7}xI`WJlCA8z&BCm4L(}QS4)7C7?tU5k}>8Y)}k_1+h;MBfO*lDG2C! z^WmsDN7F$jG1xRlcQLN$c{UJ)N~IF0^aY4h5F|xW1TiQCgFHp>Zq4#wmABkgEe#3m zBFC^jgIKJu5#~wRi*c0dtPiH$R%^Mm1m#~Q~ z&!t$YjkSx!BW{sgM|J!78Ur-8s@k?OFBj8nn{d5>G3rJ$AoHT#T+PNp2D_x}AUrTe zX|D3Uu|eFy&?8QckWwpC=@w-+C$4QJjUUL^Jf-ywETRD%U`1&1lerHw0@4=)^H0b=WXr0SmTO;MjH;L7bF`Lk;`v z8Z1;5q%7Bi7Q(4SjH5mW3_}AbtRr2Qbv~kD#7A*R;-M}}d=yHdkgP;xF{-!Z69kq0 z%(mn;Dj$uaK1o54m%6Z2Q7tSvUkThJH ztXlI%Wbt#&Rmor*RRAFJt2@RaKdo5fnxBn%B5-pa%&M&vF;%)ix@Tc7(Y*?EaDRbD z>xShdT#vj9#}=l3bIDtP`rPun73$5fq9U{knD$D6^PLg=rZSrp;s5z+oXu%KEjaCJ z{<7Uq>89P0u|-uowBNqUoLxeD_2E>aKi7M3-@z~Me3|XKUEaC<*wy;GV;9yQ*uVTr zCVhEx&$>!#*|Re*PF~tI*tP!de(); int recallFrames = config.AdventureMirrorRecallFrames; // 5 seconds = 60 * 5 - Item.useTime = 10; - Item.useAnimation = 10; + Item.useTime = recallFrames; + Item.useAnimation = recallFrames; Item.useStyle = ItemUseStyleID.HoldUp; Item.UseSound = SoundID.Item6; Item.rare = ItemRarityID.Blue; @@ -25,33 +24,43 @@ public override void SetDefaults() public override bool CanUseItem(Player player) { - if (player.velocity.Length() > 0f) - { - PopupText.NewText(new AdvancedPopupRequest - { - Color = Color.Crimson, - Text = "Cannot use while moving!", - Velocity = new(0f, -4f), - DurationInFrames = 60 - }, player.Top); + var adventureMirrorPlayer = player.GetModPlayer(); + + if (adventureMirrorPlayer.CancelIfPlayerMoves()) return false; - } - // Don’t allow starting a second mirror while one is active - var mp = player.GetModPlayer(); - if (mp.MirrorActive) + if (adventureMirrorPlayer.MirrorActive) return false; return true; } + public override bool CanRightClick() => true; + public override bool ConsumeItem(Player player) => false; + + public override void RightClick(Player player) + { + var adventureMirrorPlayer = player.GetModPlayer(); + + if (adventureMirrorPlayer.CancelIfPlayerMoves()) + return; + + if (adventureMirrorPlayer.MirrorActive) + return; + + var config = ModContent.GetInstance(); + int recallFrames = config.AdventureMirrorRecallFrames + 1; + + adventureMirrorPlayer.StartMirrorUse(recallFrames); + } + public override bool? UseItem(Player player) { var config = ModContent.GetInstance(); - int recallFrames = config.AdventureMirrorRecallFrames; + int recallFrames = config.AdventureMirrorRecallFrames + 1; - player.GetModPlayer() - .StartMirrorUse(recallFrames); + var mp = player.GetModPlayer(); + mp.StartMirrorUse(recallFrames); return true; } diff --git a/Content/Items/AdventureMirrorGlobalItem.cs b/Content/Items/AdventureMirrorGlobalItem.cs index 02f3ad88..12d66652 100644 --- a/Content/Items/AdventureMirrorGlobalItem.cs +++ b/Content/Items/AdventureMirrorGlobalItem.cs @@ -1,4 +1,5 @@ -using Terraria; +using PvPAdventure.Core.Features.SpawnSelector.Players; +using Terraria; using Terraria.ModLoader; namespace PvPAdventure.Content.Items @@ -16,5 +17,15 @@ public override void UpdateInventory(Item item, Player player) } } + public override bool CanPickup(Item item, Player player) + { + // Disallow item pickup while timer is on + if (player.GetModPlayer().MirrorTimer > 0) + { + return false; + } + + return base.CanPickup(item, player); + } } } \ No newline at end of file diff --git a/Core/Features/SpawnSelector/Hooks/ItemSlotHooks.cs b/Core/Features/SpawnSelector/Hooks/ItemSlotHooks.cs index d6b28c3e..a94c310a 100644 --- a/Core/Features/SpawnSelector/Hooks/ItemSlotHooks.cs +++ b/Core/Features/SpawnSelector/Hooks/ItemSlotHooks.cs @@ -7,13 +7,8 @@ public class ItemSlotHooks : ModSystem { public override void Load() { - // 1) Handles Shift+trash / quick sell path On_ItemSlot.LeftClick_SellOrTrash += Hook_LeftClick_SellOrTrash; - - // 2) Handles normal click on the trash slot On_ItemSlot.LeftClick_ItemArray_int_int += Hook_LeftClick_ItemArray; - - // 3) Handles ALL selling (manual and quick) via Player.SellItem On_Player.SellItem += Hook_SellItem; } @@ -24,7 +19,7 @@ public override void Unload() On_Player.SellItem -= Hook_SellItem; } - // ======== QUICK TRASH / QUICK SELL (Shift + click) ======== + // QUICK TRASH / QUICK SELL (Shift + click) private static bool Hook_LeftClick_SellOrTrash( On_ItemSlot.orig_LeftClick_SellOrTrash orig, Item[] inv, int context, int slot) @@ -40,7 +35,7 @@ private static bool Hook_LeftClick_SellOrTrash( return orig(inv, context, slot); } - // ======== DRAGGING ONTO THE TRASH SLOT ======== + // DRAGGING ONTO THE TRASH SLOT private static void Hook_LeftClick_ItemArray( On_ItemSlot.orig_LeftClick_ItemArray_int_int orig, Item[] inv, int context, int slot) @@ -50,13 +45,13 @@ private static void Hook_LeftClick_ItemArray( && Main.mouseItem.type == ModContent.ItemType()) { //SoundEngine.PlaySound(SoundID.MenuClose); - return; // do NOT process the trash slot + return; } orig(inv, context, slot); } - // ======== ANY SELL TO NPC SHOP (manual or quick) ======== + // SELLING TO NPCS private static bool Hook_SellItem( On_Player.orig_SellItem orig, Player self, @@ -66,7 +61,7 @@ private static bool Hook_SellItem( if (!item.IsAir && item.type == ModContent.ItemType()) { //SoundEngine.PlaySound(SoundID.MenuClose); - return false; // selling fails, nothing is removed + return false; } return orig(self, item, stack); diff --git a/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs b/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs index e05bc252..680c50f5 100644 --- a/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs +++ b/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs @@ -3,13 +3,12 @@ using PvPAdventure.Core.Features.SpawnSelector.Systems; using PvPAdventure.System; using PvPAdventure.System.Client; -using System.Linq; using Terraria; using Terraria.Audio; +using Terraria.GameContent; using Terraria.GameInput; using Terraria.ID; using Terraria.ModLoader; -using static Terraria.GameContent.Animations.IL_Actions.Sprites; namespace PvPAdventure.Core.Features.SpawnSelector.Players; @@ -17,7 +16,6 @@ public class AdventureMirrorPlayer : ModPlayer { public int MirrorTimer; // frames left public bool MirrorActive; - private int _mirrorDuration; // for countdown public void StartMirrorUse(int durationFrames) { @@ -38,11 +36,42 @@ private void UpdateSpawnSelectorEnabledState() if (inRegion) SpawnSelectorSystem.SetEnabled(true); - // Unsure if this causes any bugs. - // It may be too forcing to always set it to false whenever map is closed. + // Force closes SSS whenever map is closed. if (!Main.mapFullscreen) SpawnSelectorSystem.SetEnabled(false); } + public bool CancelIfPlayerMoves() + { + if (Player.velocity.LengthSquared() <= 0f) + return false; + + // stop the mirror channel + if (MirrorActive) + { + MirrorActive = false; + MirrorTimer = 0; + } + + // stop the actual item use / animation too + if (Player.itemAnimation > 0 && Player.HeldItem.type == ModContent.ItemType()) + { + Player.controlUseItem = false; + Player.channel = false; + Player.itemAnimation = 0; + Player.itemTime = 0; + Player.reuseDelay = 0; + } + + PopupText.NewText(new AdvancedPopupRequest + { + Color = Color.Crimson, + Text = "Cannot use while moving!", + Velocity = new(0f, -4f), + DurationInFrames = 60 + }, Player.Top); + + return true; + } public override void PostUpdate() { @@ -54,40 +83,16 @@ public override void PostUpdate() if (Main.dedServ || Player.whoAmI != Main.myPlayer) return; - - - // cancel if player moves - if (Player.velocity.Length() > 0f) - { - MirrorActive = false; - PopupText.NewText(new AdvancedPopupRequest - { - Color = Color.Crimson, - Text = "Cancelled!", - Velocity = new(0f, -4f), - DurationInFrames = 60 - }, Player.Top); + if (CancelIfPlayerMoves()) return; - } - // dust while channeling + // spawn dust if (Main.rand.NextBool()) - { - Dust.NewDust( - Player.position, - Player.width, - Player.height, - DustID.MagicMirror, - Player.velocity.X * 0.5f, - Player.velocity.Y * 0.5f, - 150, - default, - 1.5f - ); - } + Dust.NewDust(Player.position, Player.width, Player.height,DustID.MagicMirror, Player.velocity.X * 0.5f,Player.velocity.Y * 0.5f,150,default,1.5f); // countdown tick MirrorTimer--; + //Main.NewText(MirrorTimer); // Show countdown every full second if (MirrorTimer > 0 && MirrorTimer % 60 == 0) @@ -105,6 +110,7 @@ public override void PostUpdate() // End of channel, teleport once if (MirrorTimer <= 0) { + // Close player inventory Main.playerInventory = false; if (!Main.mapFullscreen) @@ -119,13 +125,9 @@ public override void PostUpdate() Main.mapFullscreenScale = 0.21f; - Vector2 spawnPos = new(Main.spawnTileX * 16, Main.spawnTileY * 16 - 100); - Main.LocalPlayer.Teleport(spawnPos); - - if (Main.netMode == NetmodeID.MultiplayerClient) - { - // TODO: sync needed? - } + Vector2 spawnPos = new(Main.spawnTileX * 16, Main.spawnTileY * 16 - 48); + //Main.LocalPlayer.Teleport(spawnPos, 0); + CustomTeleportWithoutSound(spawnPos); } SpawnSelectorSystem.SetEnabled(true); @@ -135,6 +137,77 @@ public override void PostUpdate() } } + private void CustomTeleportWithoutSound(Vector2 newPos) + { + try + { + Player._funkytownAchievementCheckCooldown = 100; + Player.environmentBuffImmunityTimer = 4; + Player.RemoveAllGrapplingHooks(); + Player.StopVanityActions(); + if (Player.shimmering || Player.shimmerWet) + { + Player.shimmering = false; + Player.shimmerWet = false; + Player.wet = false; + Player.ClearBuff(353); + } + int extraInfo2 = 0; + + float num = MathHelper.Clamp(1f - Player.teleportTime * 0.99f, 0.01f, 1f); + Vector2 otherPosition = Player.position; + //Main.TeleportEffect(Player.getRect(), 0, extraInfo2, num, TeleportationSide.Entry, newPos); + float num2 = Vector2.Distance(Player.position, newPos); + PressurePlateHelper.UpdatePlayerPosition(Player); + Player.position = newPos; + Player.fallStart = (int)(Player.position.Y / 16f); + if (Player.whoAmI == Main.myPlayer) + { + bool flag = false; + if (num2 < new Vector2(Main.screenWidth, Main.screenHeight).Length() / 2f + 100f) + { + int time = 0; + Main.SetCameraLerp(0.1f, time); + flag = true; + } + else + { + NPC.ResetNetOffsets(); + Main.BlackFadeIn = 255; + Lighting.Clear(); + Main.screenLastPosition = Main.screenPosition; + Main.screenPosition.X = Player.position.X + (float)(Player.width / 2) - (float)(Main.screenWidth / 2); + Main.screenPosition.Y = Player.position.Y + (float)(Player.height / 2) - (float)(Main.screenHeight / 2); + Main.instantBGTransitionCounter = 10; + Player.ForceUpdateBiomes(); + } + //if (num > 0.1f || !flag || Style != 0) + //{ + // if (Main.mapTime < 5) + // { + // Main.mapTime = 5; + // } + // Main.maxQ = true; + // Main.renderNow = true; + //} + } + + PressurePlateHelper.UpdatePlayerPosition(Player); + Player.ResetAdvancedShadows(); + for (int i = 0; i < 3; i++) + { + Player.UpdateSocialShadow(); + } + Player.oldPosition = Player.position + Player.BlehOldPositionFixer; + //Main.TeleportEffect(Player.getRect(), 0, extraInfo2, num, TeleportationSide.Exit, otherPosition); + Player.teleportTime = 1f; + Player.teleportStyle = 0; + } + catch + { + } + } + public override void UpdateDead() { // debug @@ -162,7 +235,7 @@ public override void ProcessTriggers(TriggersSet triggersSet) } } - private void TryUseAdventureMirror() + public void TryUseAdventureMirror() { // Find a mirror in the player's inventory int mirrorIndex = -1; @@ -182,18 +255,7 @@ private void TryUseAdventureMirror() return; } - // Cancel if the player is moving - if (Player.velocity.Length() > 0f) - { - PopupText.NewText(new AdvancedPopupRequest - { - Color = Color.Crimson, - Text = "Cannot use while moving!", - Velocity = new(0, -4), - DurationInFrames = 60 - }, Player.Top); - return; - } + CancelIfPlayerMoves(); // Force the player to use the item Player.selectedItem = mirrorIndex; diff --git a/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs b/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs index 5daefa83..9a07da12 100644 --- a/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs +++ b/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs @@ -46,6 +46,30 @@ public override void OnInitialize() SetPadding(6f); } + private void DrawHeadOnMap(Player p) + { + float scale = Main.mapFullscreenScale; + + Vector2 headPos = new( + ((p.position.X + p.width / 2f) / 16f - Main.mapFullscreenPos.X) * scale + + Main.screenWidth / 2f - 14f * scale+48, + + ((p.position.Y + p.gfxOffY + p.height / 2f) / 16f - Main.mapFullscreenPos.Y) * scale + + Main.screenHeight / 2f - 14f * scale+58 + ); + + Color color = Main.teamColor[p.team]; + + //Main.PlayerRenderer.DrawPlayerHead( + // Main.Camera, + // p, + // headPos, + // scale: 1.3f, + // borderColor: color + //); + Utils.DrawBorderString(Main.spriteBatch, p.name, headPos, Color.White); + } + protected override void DrawSelf(SpriteBatch sb) { base.DrawSelf(sb); @@ -65,9 +89,9 @@ protected override void DrawSelf(SpriteBatch sb) // Left player background Vector2 pos = new(inner.X, inner.Y); - sb.Draw(_playerBGTexture.Value, pos, Color.White); + //sb.Draw(_playerBGTexture.Value, pos, Color.White); - Rectangle rect = new((int)pos.X-5, (int)pos.Y-5, 68,68); + Rectangle rect = new((int)pos.X-5, (int)pos.Y-5, 106,72); DrawMapFullscreenBackground(sb, rect, player); @@ -83,17 +107,13 @@ protected override void DrawSelf(SpriteBatch sb) ModifyPlayerDrawInfo.ForceFullBrightOnce = true; try { - Vector2 playerDrawPos = pos + Main.screenPosition + new Vector2(16, 8); - - Main.PlayerRenderer.DrawPlayer( - Main.Camera, - player, - playerDrawPos, - player.fullRotation, - player.fullRotationOrigin, - 0f, - 0.9f - ); + Vector2 playerDrawPos = pos + Main.screenPosition + new Vector2(32, 8); + + //Main.PlayerRenderer.DrawPlayer(Main.Camera,player,playerDrawPos,player.fullRotation,player.fullRotationOrigin,0f,0.9f); + + Color myTeamColor = Main.teamColor[Main.LocalPlayer.team]; + + Main.PlayerRenderer.DrawPlayerHead(Main.Camera, player, pos+ new Vector2(40,37), scale: 1.3f, borderColor: myTeamColor); } catch (Exception e) { @@ -120,7 +140,7 @@ protected override void DrawSelf(SpriteBatch sb) // Name centered string name = string.IsNullOrEmpty(player.name) ? "Unknown player" : player.name; Vector2 nameSize = FontAssets.MouseText.Value.MeasureString(name); - float centerX = inner.X + inner.Width * 0.5f; + float centerX = inner.X + inner.Width * 0.5f+20; Utils.DrawBorderString( sb, @@ -133,19 +153,19 @@ protected override void DrawSelf(SpriteBatch sb) // Divider sb.Draw( _dividerTexture.Value, - new Vector2(startX + 1, inner.Y + 21f), + new Vector2(startX + 44, inner.Y + 21f), null, Color.White, 0f, Vector2.Zero, - new Vector2((dims.X + dims.Width - startX) / 8-0.5f, 1f), + new Vector2((dims.X + dims.Width - startX) / 8-7, 1f), SpriteEffects.None, 0f ); // HP / MP panel - Vector2 panelPos = new(startX + 0f, inner.Y + 29f); - float panelWidth = 190f; + Vector2 panelPos = new(startX + 60f, inner.Y + 29f); + float panelWidth = 90f; DrawPanel(sb, panelPos, panelWidth); Vector2 cursor = panelPos; @@ -157,17 +177,44 @@ protected override void DrawSelf(SpriteBatch sb) Utils.DrawBorderString(sb, hpText, cursor + new Vector2(0f, 3f), Color.White); // MP - cursor.X += 80f; - sb.Draw(TextureAssets.Mana.Value, cursor + new Vector2(-15f, 0f), Color.White); - cursor.X += -11f + TextureAssets.Mana.Width(); - string manaText = $"{player.statMana} MP"; - Utils.DrawBorderString(sb, manaText, cursor + new Vector2(0f, 3f), Color.White); + //cursor.X += 80f; + //sb.Draw(TextureAssets.Mana.Value, cursor + new Vector2(-15f, 0f), Color.White); + //cursor.X += -11f + TextureAssets.Mana.Width(); + //string manaText = $"{player.statMana} MP"; + //Utils.DrawBorderString(sb, manaText, cursor + new Vector2(0f, 3f), Color.White); // Set hover teleport tooltip if (IsMouseHovering) { Main.instance.MouseText("Teleport to " + name); + var old = Main.UIScaleMatrix; + + Main.spriteBatch.End(); + Main.spriteBatch.Begin( + SpriteSortMode.Immediate, + BlendState.AlphaBlend, + SamplerState.PointClamp, + DepthStencilState.None, + RasterizerState.CullCounterClockwise, + null, + Matrix.Identity + ); + + DrawHeadOnMap(player); + + Main.spriteBatch.End(); + Main.spriteBatch.Begin( + SpriteSortMode.Deferred, + BlendState.AlphaBlend, + SamplerState.PointClamp, + DepthStencilState.None, + RasterizerState.CullCounterClockwise, + null, + old + ); } + //Main.NewText(Main.mouseY); // 482,435 is spawn + } public override void MouseOver(UIMouseEvent evt) diff --git a/Core/Features/SpawnSelector/UI/UISpawnSelectorRandomPanel.cs b/Core/Features/SpawnSelector/UI/UISpawnSelectorRandomPanel.cs index 8b4f5405..7b0a7b96 100644 --- a/Core/Features/SpawnSelector/UI/UISpawnSelectorRandomPanel.cs +++ b/Core/Features/SpawnSelector/UI/UISpawnSelectorRandomPanel.cs @@ -3,6 +3,7 @@ using PvPAdventure.Core.Features.SpawnSelector.Systems; using PvPAdventure.Core.Helpers; using Terraria; +using Terraria.GameContent; using Terraria.GameContent.UI.Elements; using Terraria.ID; using Terraria.ModLoader; @@ -55,19 +56,33 @@ public override void MouseOut(UIMouseEvent evt) BackgroundColor = new Color(63, 82, 151) * 0.8f; } - public override void Draw(SpriteBatch spriteBatch) + public override void Draw(SpriteBatch sb) { - base.Draw(spriteBatch); + base.Draw(sb); if (IsMouseHovering) { - Main.instance.MouseText("Random"); + Main.instance.MouseText("Random Teleport"); } // Draw question mark - var dims = GetDimensions(); - var rect = dims.ToRectangle(); - spriteBatch.Draw(Ass.Question_Mark.Value, rect, Color.White); + var d = GetDimensions(); + var tex = Ass.Question_Mark.Value; + var rect = new Rectangle( + (int)(d.X + (d.Width - tex.Width) * 0.5f), + (int)(d.Y + (d.Height - tex.Height) * 0.5f), + tex.Width, + tex.Height + ); + sb.Draw(tex, rect, Color.White); + + // debug + //sb.Draw(TextureAssets.MagicPixel.Value, rect, Color.Red * 0.45f); + + // Draw teleportation potion + Item icon = new(ItemID.TeleportationPotion); + Vector2 pos = new(rect.X + 37, rect.Y + 36); + //ItemSlot.DrawItemIcon(icon, 31, sb, pos, 1.0f, 32f, Color.White); } public override void Update(GameTime gameTime) diff --git a/Localization/en-US.hjson b/Localization/en-US.hjson index 50141ec8..57f2b368 100644 --- a/Localization/en-US.hjson +++ b/Localization/en-US.hjson @@ -782,14 +782,13 @@ Mods: { } Items: { - RTPMirror: { - Tooltip: "" - DisplayName: Adventure Mirror - } - AdventureMirror: { DisplayName: Adventure Mirror - Tooltip: "" + Tooltip: + ''' + Gaze in the mirror to go on adventures + Right click to use + ''' } } } From 513a6b0269da549c46ed9456bc0998f20bdf5bee Mon Sep 17 00:00:00 2001 From: emyhrberg <121192176+emyhrberg@users.noreply.github.com> Date: Sat, 15 Nov 2025 19:07:09 +0100 Subject: [PATCH 165/206] Fix crunchy text, added smooth map BGs, UI improvements --- Assets/SpawnSelector/CornerMask4px.png | Bin 0 -> 268 bytes Assets/SpawnSelector/FadeHorizontal.png | Bin 0 -> 80 bytes Assets/SpawnSelector/MapBG1.png | Bin 0 -> 4406 bytes Assets/SpawnSelector/MapBG10.png | Bin 0 -> 2262 bytes Assets/SpawnSelector/MapBG11.png | Bin 0 -> 2836 bytes Assets/SpawnSelector/MapBG12.png | Bin 0 -> 3447 bytes Assets/SpawnSelector/MapBG13.png | Bin 0 -> 10442 bytes Assets/SpawnSelector/MapBG14.png | Bin 0 -> 6003 bytes Assets/SpawnSelector/MapBG15.png | Bin 0 -> 5034 bytes Assets/SpawnSelector/MapBG16.png | Bin 0 -> 10951 bytes Assets/SpawnSelector/MapBG17.png | Bin 0 -> 5892 bytes Assets/SpawnSelector/MapBG18.png | Bin 0 -> 7861 bytes Assets/SpawnSelector/MapBG19.png | Bin 0 -> 10791 bytes Assets/SpawnSelector/MapBG2.png | Bin 0 -> 3466 bytes Assets/SpawnSelector/MapBG20.png | Bin 0 -> 3376 bytes Assets/SpawnSelector/MapBG21.png | Bin 0 -> 4971 bytes Assets/SpawnSelector/MapBG22.png | Bin 0 -> 14635 bytes Assets/SpawnSelector/MapBG23.png | Bin 0 -> 4431 bytes Assets/SpawnSelector/MapBG24.png | Bin 0 -> 4523 bytes Assets/SpawnSelector/MapBG25.png | Bin 0 -> 291 bytes Assets/SpawnSelector/MapBG26.png | Bin 0 -> 3331 bytes Assets/SpawnSelector/MapBG27.png | Bin 0 -> 4784 bytes Assets/SpawnSelector/MapBG28.png | Bin 0 -> 7876 bytes Assets/SpawnSelector/MapBG29.png | Bin 0 -> 9729 bytes Assets/SpawnSelector/MapBG3.png | Bin 0 -> 4762 bytes Assets/SpawnSelector/MapBG30.png | Bin 0 -> 10879 bytes Assets/SpawnSelector/MapBG31.png | Bin 0 -> 9307 bytes Assets/SpawnSelector/MapBG32.png | Bin 0 -> 4568 bytes Assets/SpawnSelector/MapBG33.png | Bin 0 -> 1879 bytes Assets/SpawnSelector/MapBG34.png | Bin 0 -> 5236 bytes Assets/SpawnSelector/MapBG35.png | Bin 0 -> 6505 bytes Assets/SpawnSelector/MapBG36.png | Bin 0 -> 7611 bytes Assets/SpawnSelector/MapBG37.png | Bin 0 -> 2454 bytes Assets/SpawnSelector/MapBG38.png | Bin 0 -> 2580 bytes Assets/SpawnSelector/MapBG39.png | Bin 0 -> 2804 bytes Assets/SpawnSelector/MapBG4.png | Bin 0 -> 5575 bytes Assets/SpawnSelector/MapBG40.png | Bin 0 -> 5072 bytes Assets/SpawnSelector/MapBG41.png | Bin 0 -> 5990 bytes Assets/SpawnSelector/MapBG42.png | Bin 0 -> 4794 bytes Assets/SpawnSelector/MapBG5.png | Bin 0 -> 4478 bytes Assets/SpawnSelector/MapBG6.png | Bin 0 -> 5718 bytes Assets/SpawnSelector/MapBG7.png | Bin 0 -> 5501 bytes Assets/SpawnSelector/MapBG8.png | Bin 0 -> 7262 bytes Assets/SpawnSelector/MapBG9.png | Bin 0 -> 7093 bytes Content/Items/AdventureMirror.cs | 17 +- Core/Debug/DebugKeybinds.cs | 66 +++++++ .../SpawnSelector/Hooks/ItemSlotHooks.cs | 1 + .../Players/AdventureMirrorPlayer.cs | 36 ++-- .../Systems/SpawnSelectorSystem.cs | 5 +- .../UI/UISpawnSelectorCharacterListItem.cs | 162 +++++++++++------- .../SpawnSelector/UI/UISpawnSelectorPanel.cs | 63 +++++-- .../UI/UISpawnSelectorRandomPanel.cs | 2 - Core/Helpers/AssetLoader.cs | 36 ++-- Localization/en-US.hjson | 15 +- 54 files changed, 283 insertions(+), 120 deletions(-) create mode 100644 Assets/SpawnSelector/CornerMask4px.png create mode 100644 Assets/SpawnSelector/FadeHorizontal.png create mode 100644 Assets/SpawnSelector/MapBG1.png create mode 100644 Assets/SpawnSelector/MapBG10.png create mode 100644 Assets/SpawnSelector/MapBG11.png create mode 100644 Assets/SpawnSelector/MapBG12.png create mode 100644 Assets/SpawnSelector/MapBG13.png create mode 100644 Assets/SpawnSelector/MapBG14.png create mode 100644 Assets/SpawnSelector/MapBG15.png create mode 100644 Assets/SpawnSelector/MapBG16.png create mode 100644 Assets/SpawnSelector/MapBG17.png create mode 100644 Assets/SpawnSelector/MapBG18.png create mode 100644 Assets/SpawnSelector/MapBG19.png create mode 100644 Assets/SpawnSelector/MapBG2.png create mode 100644 Assets/SpawnSelector/MapBG20.png create mode 100644 Assets/SpawnSelector/MapBG21.png create mode 100644 Assets/SpawnSelector/MapBG22.png create mode 100644 Assets/SpawnSelector/MapBG23.png create mode 100644 Assets/SpawnSelector/MapBG24.png create mode 100644 Assets/SpawnSelector/MapBG25.png create mode 100644 Assets/SpawnSelector/MapBG26.png create mode 100644 Assets/SpawnSelector/MapBG27.png create mode 100644 Assets/SpawnSelector/MapBG28.png create mode 100644 Assets/SpawnSelector/MapBG29.png create mode 100644 Assets/SpawnSelector/MapBG3.png create mode 100644 Assets/SpawnSelector/MapBG30.png create mode 100644 Assets/SpawnSelector/MapBG31.png create mode 100644 Assets/SpawnSelector/MapBG32.png create mode 100644 Assets/SpawnSelector/MapBG33.png create mode 100644 Assets/SpawnSelector/MapBG34.png create mode 100644 Assets/SpawnSelector/MapBG35.png create mode 100644 Assets/SpawnSelector/MapBG36.png create mode 100644 Assets/SpawnSelector/MapBG37.png create mode 100644 Assets/SpawnSelector/MapBG38.png create mode 100644 Assets/SpawnSelector/MapBG39.png create mode 100644 Assets/SpawnSelector/MapBG4.png create mode 100644 Assets/SpawnSelector/MapBG40.png create mode 100644 Assets/SpawnSelector/MapBG41.png create mode 100644 Assets/SpawnSelector/MapBG42.png create mode 100644 Assets/SpawnSelector/MapBG5.png create mode 100644 Assets/SpawnSelector/MapBG6.png create mode 100644 Assets/SpawnSelector/MapBG7.png create mode 100644 Assets/SpawnSelector/MapBG8.png create mode 100644 Assets/SpawnSelector/MapBG9.png create mode 100644 Core/Debug/DebugKeybinds.cs diff --git a/Assets/SpawnSelector/CornerMask4px.png b/Assets/SpawnSelector/CornerMask4px.png new file mode 100644 index 0000000000000000000000000000000000000000..8f03f4353fab813910a3a823b9e04bef34e0e43c GIT binary patch literal 268 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=mpxq^Ln`LHy=};MSV4p(@ZbLb zb3H{lZ)&8@W3iUKarBMIyO`v|bBf=+^Ixzk%l7-{*2%~FKi<2(UvA#1U7O3Nn}4_) z{raKXuV){VbL^V7Ph^O4m`oRZzCJU5@$riP0X5vAp?l?)oZ0{L-P^lQU#_vX7hI@P Tt+JF6FS$$$R;|6k9>*7jZH eLAl2peun<-g8yqaZ{Y?iVeoYIb6Mw<&;$Vdrx$+! literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG1.png b/Assets/SpawnSelector/MapBG1.png new file mode 100644 index 0000000000000000000000000000000000000000..b981a57d181cb2d141f0111f55f8f900749a0fbf GIT binary patch literal 4406 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 literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG11.png b/Assets/SpawnSelector/MapBG11.png new file mode 100644 index 0000000000000000000000000000000000000000..596da6219c45e4154b793f48f5328d7044f824e1 GIT binary patch literal 2836 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 Z`#;INucwpDS}Xtn002ovPDHLkV1j3tr<(u( literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG13.png b/Assets/SpawnSelector/MapBG13.png new file mode 100644 index 0000000000000000000000000000000000000000..0faf8c72b57e5894cf98f4174dba7df52ebfb493 GIT binary patch literal 10442 zcmV;*C^grKP)RCt`7eOr&@NOs;K^TuQ{uT@?5>dSP`O!rJ{wWHO}VAiuU zs}(E@0=#;#uz(~Re)WrgfZy7`z;Avu><7ayh5=t>z=92HcOly{tQ~u2G`H@a>8|R! zSLKy?A(8m7meADwf3L8Q)5hv_|&b0TuCZmIp5cTRR(Pp_5p$@dKXUMBv- zLnRX97%w3kF3$UL0aDIk->F$tF=O6v4CzlMY2^S&hyV$Rh9%nGx9Mg_JwwG3G&fqzB;?XeWJOJHoRme$zacAnCFWpfJ z=!H9CKp|)pQirF#?zKA2`}``AdahfFq2}%_JHCCl!feZHDR_bGk4Q_^Z@5a(x&f%` z^{H$EPynpX0mN&+ch_PTV$%UdC87)f;`r{vJwAW4Q%yn91?TiK{rIv!x(;@0@mtVV zqE2tF*BJ;AuoFN7tgHZ7uoMD7!A<~rd$YaNEoJLdG@Y_1&{4UV0y0 zwdw{>SU0E=Ew0Ox9)NFL@Bhv&6;O~>U_(Tm0$81$?e%gBR&O*Us~oRnCm)Z7Y5xfU zP^eGY^m__02{_k`p{(G%fRE#XKQSIXIXR}aa+|z~K^Maztu-1H%;!`tm3TwhXgW>H z^_xM8#&S!siX|FMr!?q?REj6$4(DW5ECvw!*e}r8g-d(;RT}rg6iEASm1f;JgIDbo z(_^meuKHcitkBF4s8K0!+0jr{bT|*mG|lw5Sye_>f9$8_43c)7m9kN!;b=@&xlE2x zqp9zaJDbs7r%7HAb7Kdv1{JAVF{xUqFrarf*6DJj*acwcp+Tnum%O<_z445^AfolA zMFpe8Dwau8tS#y?FjHXs`JC$#^)7-kUF3VXrczYb^+qFBvjq19Ef92vT7{_%)gS=v zuC4K2H*kc(*u2PCVkI87S*`L0wZw))-KV(|@E+_OCaOh%^kO4rqNrJ2V9^3dQIQY; z4d6t=o&JYY}=g{dH#gf8#S8w z$x8$#&C4??Q6*(A#4MI53Ik>(t^qTxQi+ZK8g|T9! z&O{u`=f|H6>FoKGE4nuxQyj&-fq6LZ1~G$DC>GLl*eX*)^_$5x{EQlNahzpot6ihs z`H+pF=B7!86{dZsJN5ZJ)+~p*eV4XdO)49zCEDc*krC2h;<1*hR&2U-XLNV7!>j~r zq@DmyoM@MUQl@J~ow*R4YKs@&{eL8&Q3X>WhPiJKBxXH z;;zVhfUN=~DF^cOMr@%2MZPI2EYoa*wB&Bl7N7y6E7xmY*l$PINOPTiM@TtV(V286o~xlXUcrf z%I3QA@6cDm`9DAGG02AoD;KRSUWMBh|ggJ3|mifx+l2+mQu8 zrpNUP-Pzh$GFkvA$RNi$h*DR&;i-cr_tAqhx<#xTKqi2~7EJr}Q` z*YYom&%}P95z}Vf;bW0z)JczpodT$A@W%vL_ARX93MZK|%~w7XXSaTei90S^@@ufT55)Rtj6C41zMKS_xd};XP;? zsZ?080$vasyftdgr3w~6We*oc7%m`XVy#PpGP#dlri&hcFy+Aj;Qg&F-j~dnHtIDR zPZpM=_)1`BHt?-WHUQ2q>=S)?d`!pgfLC966` zM2+SFdM(fnW&*(Oc*GmniEXc8lT(OU)yjipM<}!)J&WFw(a%C)P*kiMnR8lVBY*#$ zWds4JjBdy#l2@jO=r-3|X`h-kmH?ET%M+csVhDBiYSeu(zE*K~FAzWi0}%ZfQ6SXm zZmXTL4}GoFhwN9WSV)$U;-chTD`MitU}N2GP^VUB5FzcF!+SgwR3xsGhk#mzx;=7L zkRE%zTo;^^!1!!o05UtlN&t)F?vbjrs#D4B3q_H0Crs3Ve15jD1K^qfP^owfWJu#*#ZFP3d0^#*0!6sbd}C*i?riSTS^^%V zKX$1%cKNtuHCUzKCG-&m2$%-&cAW)?SvC7>+c%fS6wx;VJb;LPQ&evE;|0>I*eB<7 zK;^oLJ4^dg9auS*y@d0!Zb{ay5kpAi>n|^^bq(U4=wRxVjkqiTUDYp&DuwYVqfugH z>E8jk!c-Yc&KgA=&Rc6V9*rhLipb8Q)OeELNDyd{JvM-P_Qj0uz1yO4 zF{05?NRDOE*o(E+y}#_6m&{5zCqqowukG8+Pz+MP`C*$% z6s77N#?s3q%UA(&k|{?SEMw_Qg_$@OzclZ&2$+lS{>Oj*1%Dn)#$>g84%;Dw#{<%^ zEli^AxK?D4;@MP_I8v#&W*B1ios)*q6!+ zosMIFHs=jePJ-`JCTx|@LA+4CV5V(VC>n=UjSVtAB6k>2tx{vwRm&AB7(~(BqqgHv zLG@SJWg16+yb3ckCd96lik$^&NDvH_YniQyfW_#8 zN3$89mvblw(5Co_x3>1lj}7)I(c<8il#GZ~Z%6AB(3iqE+H2NQpA-y*pzlPVDgEZt z(fN|KE5UP#_#nvs<lp{D1VCaC{eS$MBWh?NIE3)FYE8EE4=)B>SLl8u z0wxuGsd)igE?X$%C6(F(KW7!z7lE|7ELD<76Lb>jnnrJx>ws+G+B>sW%Wopg7 zUSDH&PLcouf(g>U;RPV~clTK3iU{-c-~!S-bav{#rU(KGA_Aap3G2tNl6&8?={p~F zXsv0|yT5;fKX1Ke@G;7>mM%6}x_Q1R2GM1Z00ONw8V`~_Gv@d+x};jI$ytVAB>>5i z1cDeX7^(vyduaf9?uS0)C04K=-{n5@gEt>M!iTRJ;hZ|Ek8&dp>20HtYt}sF$caoHMheFZ{OhosT-SdAmvvK3Jz}qfFCbK)c^*vg40N zgkiPgUyit}>JYtnJfc|heWectIyeTnb8kj6Kmu#FWSV3c5l#Gxz3wek!1!_8Fi&v~y42#Kkr3_N2 zT9rpIpEv4ts#_KMrguS|T9ce|nLBuhX}c8qNP2Q;%|QUbpo{($odz!b`o=c7Q+pt7|2?m6!UT_bdt$AkkL>Krj;^PDcs=v~VyC6%H`J4UpgYsKadR z+_qCzf{p!?0$KH#PX8*V{z1gYQU<~Op#i{9v3db6EMLdAXfl|QV-nqNHyAvyQ2-P$ zp=JRD*eXmz`be=*qPkt-_lM;=o5$>jVgtzSZG&d+vR^4FCAx6RPF1OY0Z(V73|upq zpIjZ%FP}fBf>EFXVzQkZ^p}TEX}?itP;2Efos1?_st0t{9a9_zWS2`cbR(K3ZVd$L zqq1J0X2GV&31~hma=&?eHe%PM^HBY`+YMROLd^;zaSXN&x*>xIl?ZkC>=R`?2s>A? z^z8YR8l578xWq;=_vn(Pj z(k(KmmN@WGuMRE7I|rGZsI2H=IUEk7L%KM3 zskX7mr_rTxugWZK-mz(3j8jG;?+5DdS+a-!8kQHq0SL-Q{_Gk%&yo%OA>?8>=6m?D zPxZJ)gPtnOlOO%@J{v~HB;>xdS}AgPvAJ$?cY%B*Z0oIN60QpqmPO=-B|5ouITWco z`e2?2*eC!1Ffht51yrFT=UGAhipuN{W~nO#HLJTta*Z&wycJV0j>y!<%r!v+s#epM?96cA>Km z)+UCVz$hu>0ECmIh`4=rF{E6|UM7dhKsT&naYa^%evO_LICWp1o2v_)f4B-0Z}~ei zXGgBdW*5MP(I+Sgb9J{v&#M&?HX2(q8lR~KQ$&FH7oUHYj-3DK{(UMJBI>y=16r#& z^z`hC+E$s)`eW|M!?;8<&!d)Yk{_!e!eH!D*@OyGKL(XMuLsoY4pWr{^#ee=gw+4l z6(bcJf90gW@ffP6VkMZ64Jv&25BJk+B<(}L=kOOH$BaKYIY`f;p`bD0dc8qmIBu+NwcjeU1-ApU=ZVgpBJ6KXvcz#DIk{&C-k6zP=B%rkb|8!>NRGwh@OF$6=7%kqS_#E%GjiV>3{)PurmuJ zV$bdb7!Ft515zed>V(ue#foA{_(DX#G zSB+z$pG1OOmW_FRCeDMA!phoaiOk0*Dv7HZuk*O&=O-upu-GmxkJ<1+htFSty8@%f zE)jiqi~i(y*QshR&vL@|;NnO=5&v*qjfrN}qo`dmjIilta;*R+DmMLo0%%rxN!q5K zE(zl&n^-LZASDwI-_ebuhd)$Vb)0$8Qt!}rUEadEOB;^GM9{MbpaSy-mj%!VyBpWe zNz_QxtAy}SuB%+RKfudMQ7Reg7F*q1CwDgDkQIUiERz{0E{(kz)hagiB&Fe9tnLuyr;tit7Y1Q5wk*l%imgQns{c+fimO~93XR@MIMXI(Pq zT|S0dhRW@2Uoks{A`gup=5~G=g!rJkYw)Y|@xK zIzI5I-Ka1dUo{Cit4?)*0H7YDT_qd}%zz1onlO4`$pXl#HhD&j9&8u}L;h^7V$t{C zDbSDKwTXW35BNH$;DS-4w;Jsfd>BGdw_COXFmJ}xq9PR&vDYUGK~SN3=7P8>5M9NJ z>tklX{rSH-WR{Jh5yweo&LyO7)|Z&BYXSTYm?|kPB4Px#9EUeZw>RS%-?%qeB#hGg zM#-5Kbtx&Ba*d>^3V<)0+6Ohf_x2*Fpo41sv%MCJOyltJo``_!tnSQX=Q7|+R_t82i_>6|!M7U#wPVn*)TT+#YIPXz2N z8}q<}U|Ktpv2@X|tCbhs0)Ulg$(s*4c{)u;PW04M$&bQdK1ALPYEX4l~z zkpH8rUI7@uN{`+92hz{uKi~OkpqJhNPhaj_G2S!gl&Fc%lI)1S^j zJ0gsPh{469U9VBST%?K-l0Of~3w)}V3-q)*q_H1xp#AwpkNlZOwRldGh-ex_ zO7#585m}az4vmRmoD$M1EH^mhLCN4f!h4dvi2GI7=bYaIMj@<+DU$r1N`-2b zB3~n+ID`TbWY=?p5Vn(KEqq_{fts$oXIEnmKx6L7Yd>sL zd&j1LO!{1#5F`c%7MuVJ#b|*F73)-t9st@SmDeND8|;x|1i4$^;A1fHZhMoS_Rg4% z=hGqYU-Ykd9fmOl{8=1#VJB4X^U(#}{$6#7l?X#(Z1&+@iyBdzeM{Y{<>QE`RBbK! znR<8*MwZN?lXZhcUN#vhyWSFv9-WQ42s8PA0J-JZJT(FGd+v> zrN`;&ApjBcZGN;LINnoKc|BQE7>(6n_Bk5h7cg}JCePTmAsH0%G&nzAiMaM z09X%D6yDn1eS|CnFYx$>8kI#m8%|u6CmS1_6I3uws#PlF`D(iN!`&Uav({$zBG+f_ zhC#v1pplP3Zld17l=~Ez_ZUKg5mYZ*bTAt5@YQC$$?EZ_dqua`HaPpeQC9i4*vlp$ z%I9N$K;(xMOp?49D$x0O$bDpgKBZbIiI0{lY7%hOQ4@kak8^O)_nf+8suoL}=7GTj zUVx$$smcjVnoJcy4bxWrBBrim=&z*mWrvHQ-&Bu524xGecC26Lm?c!Y;Th5 zXn^z$0O|)meR*<1R@vhIqOxXE%dAoqdg<~|EhKumAqCAMweD2t*{3e&$_(9r`kqH4 z-=iI;$$)OwS_}%NFKm>Z^jLt*GEqRpF+lHBYV^g~B?AKx0m?ci3@5&;Hpa2F9K-5LlCq!nGq5s65o%@`A69$l|SM;Ii z2O-#tIp6b?ezxyRG`aEz{6+>yO~wd&SK|6rdgPKlm8 z9#E@kQ8Bh@V2qiG*hHY7VdkIuUD|7?<6G+;YF3r`4=WsdY%-BY1ePsWDeeJsbdU`I zKmcM8`f5&$g`_N{;-OB#C`=R*8G3$_eSnEU$-02!DNivdm@%tY+!G9h;Il5#W<--= z#6W>{qB&y@O2Wc`k{0K2qcD);wb=pVfM{TTjbks>M@5rgPXhUwJ4R?VSt zXeL2-lY;4h?rv@qW{zcBEwU1dmSV!t>@kal&5*C3O_w4(64cfOp)~}^{kVYDSkjP| zFetkOs6?<{zkMgY$Kz+;kc252z^l>HEo0-_8I>jT6PR4QJY zU#Otg>w{X<#{vb!fA**UZfVK1fAY6~%76-(I{3VvUE=FuYPtw2U$6MdxW{T#R@_8L zQX)Qh*Tca$1royR9%*X|<^c&gxEwK%0+0Z)3ZOh$b&kQr!G2vm)U%6Yo{E4;wgQMO zynsx-3-8&ro5&!v8<|vei_B(x4}pdYqeruTnN4^MvmFmzp6-_?0;mMtIgDqjg$QMc zNR}l_D=bl8euM?7v~>nXL$;LRhw5`Zbe~Um^o2Dt`&-sT5+M0KO$DSI73f#bjydJC zRjH=g1_CCY*X>W2?gbf zx`piT%k$%$?oVdHkm0kuefB$f>@3PuG!dv<0rO_V<{&$yS*z2WB2K@&QMpZzC(pUO zj9I?|X3|GurAq&6jJ}&RpsoroBqI}l@16JPSH~xWAr6`H22ej6f6hQIDtn;s&SBAm!Wz^cA3HvLq^=;V+I< zIMXRRyhdPqtwgkR8;#uEip04jcK zcBQebF_smH6U+6OJ6da5OKMQqiM|t&Em40^voa7aK#0oB6VW(23-eM(R$zF`PF2T)jI`97;C(! zz6PYuqC64i>62%rOfT1g#=WqKdR}5CfRxT2CO78ozqz%;!Gt`4dVX#H79STWncbCS zY>Rw(a7bS|U#SO4n29L}=>sQyCcx8|!2a{EK3A2U8R5^fcvs1GO9dMw$naZlJmj&% zFOH6Qgoc4^7isWfkoMF1ccrh>nGH)6VkNIB3D4*&kzy%UH&?bd;bVQ@X_pxQd{0s` zA!78rY#PG15#x8>ej`RguMQ+u)B5oK8}vKxen3y2E9>>%t=qXb!1*_CE(V=NLZd+c z;{W^?`tZh^te&yKDu(*JS9^{3eBat@OS6lG4KRlIFCgTI4x)h8%~+{y|IFE5Le^qC@Jh~J?xoGyJYe*3kKzi1Gbf+c6>>@TUaGH+OdE zH}Ad0>;s4bXjZ;BJ!Z>JU#to0MK`B)9lt6CQAW~bao)To+g=9bPu~CF+I9c(Pyh20 zGi4k!PmN|ptZL~~#dv~YgtX07Ny)3!sE9C9XXeWQUiF>4GKleq@BL;B>-B=VyqpWN z+wX4fvDyP;Bux^zuNbHm5dd{_Ui_$q<@N1F#`2(!FgzudEDY5_L|-TXLG)u09l-3l zJi!t=uM#xWth?|s6}hU?|0W`=m;2=%8^6B46AMVl|HQm}u`u-t%=6D)Cg^iyI^8M} z;~>k}bOGX~v2+i_PV@T1RX~cY0)7?XoVC!O(O^7J`@)y8M8n_rT~HU{H~bzFx@09288SQR_xZ0X z>=jgF6lR0Pe;r1mPb}G`G!SvzQ>i7Zn58pA*0L9oT%Ny<3SM=bEtB8W%NfipSUR{; zDOtetBzs;rAhO@n`zlnR{!rlgDxH*Ws!d+*cZ7l&!) z9PazF3g2nB>5c6j{!2l+$XrZmlxQ5QSh?z0tt*Ra-ny0{op5PH0sg_tgf6PgDh zH4tTSXFLEcBk~qicoZJPO<)5u(`G@yWu;b`Y*KqOAUg3TWSSA(xYZ`RU8Paz(NDko zKE1WOPljpI#c;sSjpvCXlPl)-<|b`-)@bfyb(Jcu)$2s2!IO}A>GDZPrQ)J%2*Qw8 z&4TJz?v;`L`3gMS8MHx^|LCoUT#icrxBvTpa=H8|5Rto^ zw>VMz?DB$F#FAh>vJ`n~11 zAj(o+bR~!ssq-N@n;m{OjE4eHEOD0o%Lf1o>)G*hC4Y=fD*W}Go%9?_yTkVoQ1bxQ z%d!Aw%aYHAoG&g1wLk!dO-riRsL0IN^9{`0Y&}H)6d{4Mow-%PWgcEhq{}7DyojOop zubdaa8R*P;`BRFGZI!C?ZCR=_RX|P789HnKKmGn$%x61{Hvj+t07*qoM6N<$f*Y*+ A&j0`b literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG14.png b/Assets/SpawnSelector/MapBG14.png new file mode 100644 index 0000000000000000000000000000000000000000..4faf6041dc378e69e8e371f677587b097e583962 GIT binary patch literal 6003 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 literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG15.png b/Assets/SpawnSelector/MapBG15.png new file mode 100644 index 0000000000000000000000000000000000000000..9a9a161874bee64b8d50adece645f80ff22526e3 GIT binary patch literal 5034 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 A-2eap literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG16.png b/Assets/SpawnSelector/MapBG16.png new file mode 100644 index 0000000000000000000000000000000000000000..3af0977db3e2648901ad5bba7a3e61f353b38f9c GIT binary patch literal 10951 zcmV;&Dmc}NP))l4T-i%iIOFeTxz)-a!Kv% z?C#uGPfy=fU3X?xWv21H$jFYasqUE}0r>&dkr^3z#TW047unW{sWeErR465Y2nO{A zws~w1l~W}ttN8)y-ISE1i43sg<3L)dWU$)sr7cOfH?L!EkCHx5Q!bl9&-0~xYc<3> z7HpiI%j4>LclTZ5R;FZJx$zVBnld-(c%*FEo-AINj;cwPbs%X4!Tsb6dOJjY@k_vJbSb3Y*W zBMl;Hw6jOS(fdcHchAu@RdBK087BM7Tdib!9Jm|+Bo2aS4?lc8ea-!d_tN(qZO6_{ zI>kg}1WX>gw%!#GYwbR!ifI9BX+Ez2u1;cYr=|dk-)-E$czdO_=UBb73uYxhK*RH7 zTfpKVo2#h(NbRpTeAId#CbC(JeZ)HJ9rMXcMJ7n3=0M$$_2#yw{Wy{Px9cgKs16bk z``rf8dG$b#>Uegx2A0<~xlmt^+{6xjQb08=R438%R%Cmpmy=GdWP50MIjO7WdP&=I zQI+!(XU(N%SQ1QgAk;fb0(hP;^$maTKxxF>d1k@J)%AvKFU6dw zxlDsdaLJu=-EPVXqg^l`izDU5MgTWC^RF*e_dU<#z-Ja`aryqnBkyI3zp~v!GgKYD zABg)AJ9@$Zhv1pSW0exnXhFa{I-}aoSJDYEYmI)gzuxGh)q#Lo>kJcdYMEf_dly}4 z!~Myki<`07w_;#M!7S$on5$$GFiB@-W3B{nWvw9qlL#h3jE`9qv(bJ!@linTr!Tc$ z(j9MdiV5ndn0;KX9oO#YOb_=qa|t*aunVUHT)g3oy_N|u!ECm7xv-_TM@6KijtOVQ z9IcPlyStpodJUk-q2x|0=Fa8_XOd=VRVt`bgGeF= zlKWtQ7jGtFbq|mhu+tf0vf%Ei8`ZUq&JasSW^wV#{e8hS0X=Pq*lX(z;ZSn329=2H zP+wXtgkcHRY&9id7PPF0siXPVIHm!86quSjwK$}{T$q_k+OSji>u9|_P88nUQaVKs z5)&Mfc};WQEJ=D>gQ)=^h!m&Xog<)41t|BIH*>;y`rgTQ4BAdtfte1rlXLQAWfZl% zoRqiLy9vmfhKMzdF9J!@y?=eJA)v|oWU^x25*i+7y?`B-6lWF+F_`>%miEm zOV>ryT)r?C%yGKQg2EL3tpE(F$nV5J94_XjwX8lbs3z_IB*s_8!R=woKKh_)Y~m{kS~w+RCG%^&Lt zd?p@X=C&r*`TgDc2it*c^Lm|rAR?B>yUZU zmeN?;9%2|Okon7{L-5TDSr<`YA?LctrChXqFR_%RGzVBN3x621s1_Sclyo;shx_NBp|V?0lv zPck{ofXOmYZvksVpqR7J=|wnps(>&4g#wDCftajhu)X6eov6iX%zed7 zR=AT??|C>mTM^^v)NJKoFg2hQpA@OQsp0xP1SUo7$6mKUrvF&`_P8szg}1Z=p^x5(C`qMQC^yCbE&* z_bhDn?1URyv_LJuVUQsMoSq6q{7wv2`)d@n7VuO#!ej}kw}Gj$dWJu_>EOa#fNH#d zzh@y^&f}HW6`1ZtnQl>3KLlR}pY&9G#f0h(0B-4}qyK%2IPA zfzm`!HD^9MS;ShmgAE!7QGjC3#kuKp60!NnT!7iw@I5|lwuPl~gj+2I^z(-z z-1jVWdl6P@j$A7-fbs)WV~aK%)sHcE-lT;a0fm@LsZUuZV45K6Q96^ckWYt+#Y!={ z=~I}J|&Bll@Q${9wYY}saC@XGz6jY3)( zI7cVcyXy9i2C|@z>p`Hn-bOVaN;#1arS3s}w@*58jCFC|#-X`9me;xow{rj9T35J} zK$1hn7y?A^E>yA#%yHbv8_mTWIiD|}F=!<*S`FeelSR1^L7dGi3-yg!8{fB>!P#nv zk3JRR{PRlejw5!o?qrigO>QJzdd(A&N|DWTOpr~$X5XC`P&Jq)kQB>&r!A|9^KK7c zT#f`t8ffG~0!a}4ft?r^1f~~8C^;6qC=wtwVEl1VlRGD}5JQJ`H4NhE??a(9CWH?|vzxc%{?0ggRW6)w{q zY;xErnOvwv?6~8jAZoxeF}Jh4MZbYYQNzMUJQ-v9bmYwCIeH8#;ALIroQ`|<%9U+jFN=Ev9VOCAk)!ReqYb}1Qxi|vU9RQ`YGP~z;778gP z1}do%s)d0}(QuB9*XK+|t&>U|S8{79RYIe$xHqy}_=TlZBFgAnQpCQzlS_gEq!&IA zU^99Ng_SRi1=$2|oR~E^`_5J<1`X+O%1Jm~b8A8taC>!9FRX!;RCZ;10p9o*fv1niHWPvKAA9N7v0-IYKNJ{R^8;8}M+UfU zIdJGtTakcJV*l6_$H)NizGtaWYNZFpF& z2gv0{vJK*r1|UJm=3MmRZE_j`b>foJXD|Q`SCoM_TvygBFY@-QLww?WHvY-)^aQXU zcux-B{}BhZ`vauy6l^OM8$%)9xa0|!r*kf@UtUEypG9r6fnz6U&~EiHHKF={a&i*& zT1`D5yU`r4WV-o0T)=$B`3{aEiQ>M+mJiy6ww9mD>Xjfi^AE{dA^jb|$ejd{ zb<}^a-12enw0AXlatcN~Znm)9ur+CzyX~$(b3k(NpoBczv$uhJZ zl&kSA+GcMX48}o-ltZ(H| zjV;&0gaR@Q<6uIlK&3>~Mvzr>t*BgZ@$TuOfH;!}@-8q@%m}a<{{1p z8VBMQO?y8;&5J~IdcC2DNR}E*?(-@dOt$NLLn*ZzMm_0_xFURa4XF5$83m$%X)8&V zj!Sc&07s4^`~Tpl)A9`8dLzPH*9OQr7BXpNJ!fM#ydQVR(PL@&VNQ7oJH9YTzMR48 zS_2&qc-Qj_33w%1w%f|G<-U7tGKC=xfS9fMK;?o0l5?+|`CuJy%#+B4C#SPmZ2+qq zq0Bn)XkPClm5Y!nyLx_lB~cO4;(`zUEe4Pr!84CK`swq-+`SLxROlABLzDY((*N z20@`KlFz%s2${4ECkPYqt99m)Ne7efaB$^Yo}5!GM98FEl*Jx#@$vU~xU-cU9eHV(T5d;B4#_Qg9QAa|Gggm{$F$O z?NuAS;Sj}iBtMGu9nZ$?CeY|xXn7%qLnXFI!x$Wv8c2PNz)4$*%3+8w-e&uB+Lq%w zYQuiv@g(|V1A{)%4Mnb5ybq-ouMvc>gHXUCklBI@CqDjzKb6Jx*8+rt6dwTjTo$>k zGIV&Kn`>ziw{l-MgyxRh zgPShH{#z|{+>bn5$R)l-?A=X!i*jSG6hgU+} z*@&=tFT@KcQyA_590T{;f#}DTu7z%3$>ex7Wuf3&a1bHqax!>VbP^N|EIE*+wo1*( zU5Zn-4dWl%R3!qYCZ?xymQ23u0J`?S`J*M8PT9hdHi3(QB$vuQw=Lksb1wW^gnSj) zTv0Aj+6D5ZjJPC$AK<0u+Bh-W$7-jPfT^EV#C@rNFz}Htq|ojRgi8r%#|x0nx;U~p z2e*)Ok+GSxqY!`VUIQ0SRg_YVe=WMrANz4MfB!S69-c+;*1cqUhDHy&?d4mx080aj z{dlGt!e0%sF*AYL_<^W1`I~}rOLQIgNvzxW+7MIf~&#QZS)|hX6g1siP1xEma)vtE8^kg{oY?ExHe7 zrOzzRq8VGRlKEF~F&l$Ri}uphI$VhkWgG-ig!#z|ZZ+FD6P5+Ah50-*?^;=3)?gTM5m0_1oq!e{F09>4N@3V1$+|8m1gT$pbVTPhEPbu#fYX`qpwUaG=vc8Bs%cLok7(!g46C_r*VZSD+F ztN=qBxb~Shu~Vzz>YWx^gA}>}aC+WHIu#+EwuGB^IuT}P3W%aC9&B_3h}VZXG_L?l z&!}m#*}L^*O6uEJcCfHe#LDds5C;UL4JWcwszghTQBHUtt3amJ{<3A^Qx|(UJL}+Q z-^I!AlthIX;`^!70siCxU79TZ*N+7F)z=27=2UjuH)GD#{X$R(s40dg1ex)GXrk3D zlfdLe{=^N5+fzJ~`+Yim>Rt|KaIS~wHI;$X*bEU=Jd`-0EaF(@L=6xB5WM$)0olLU z!TI7c{<3vs&wYzAi2UhiGs$H=xvHA6u-fS$leX~o{SZ$r(t=bzmTd#|dJQXUU92`! zNM#0aVlhn4JeQ5&lp?vwi6bh%6KCCc4pVhhe$i1A#~;jyZsf7^q9=V|@!`z(vqnjg zOU{o&3AmeG6fH3~s2oVhW$QMHy z{NDFW$Uy?yI{m*<)wvIP5h{5H|KckO z@GrdG!_U9q;?v*m;}>3ZQR}6!)*K+8ve5QI6#=4af=DD1t=Q3tWm>hl*t*qLEkl9Y zWudH-HyVcG-iYy&w#8-P@fVg{w09!hy&vq!KyY39!x1JYLsXX>gyl1804$tE=FK-rZDghs8F%w_7Vc5b`m%AW0@;05UCU0Dwi!Ic-wW?V7%`Mh6wOD+18(G@6* zwMD}-WQfbcVGgV)!Y7t&+}TvIRGG569pXY9rzM$*SR}eBoaIOj;@q6&NW>-Sc&sBe zy|WY#>8|&Z&wk=_%jLS`x~$;&9!y`fhZIFZ!>(tT^+Rzu3dkYP^;)KF;=%-;=dO zZ`OJdCUcw=Q&jJ%fVn2!d0Ny)^eJt_C1U?@0a2_^B_o4=;b6D(we89>?Ay5d?LL|{ z;OTz^T>jU8fT=TQ5dGLsAo`zg$~B9Vn`ms!>;bl1ofLgZX}GnmxKs?FOc;o$;f-c0 zDKz>K{?C;relSkZy`h8N3?nVrc;~S!j^^7qwwO{QDRSf(H!m({P(cTOv>ah!p#a|n z)(dGdbO_qnd0V*d`46fNzw>7bc##ezj*tlFR0bu^KBL4hty&sM1pbXRTU?c2`-qx_ z`N@x_arE=RFMY9xU;o4uK6FlT>F<6ei+}zV55IUJC&0@zl402FM|_96c1_|yyY4`J zoIg73p+8Jq1ie+2bU|2|q@ z-b92Mv}oi63P?dA?q}LBIwq?Jt)z`G+kn$x^1}H6n!Ob6w%eG=Mv^_iuI92a{W9;G z59H)x*22^CAx`S>AWm(<Z4v_@c!3@F`^=W{PR)+l`eL zQfXlNXf>H7(cp19%(P~cK)X2MsiJ@-=_6^1O|JJ-S;TZTxEM%$${5VIx70Kfx9`+| z5AO`I-W(>WBHF+iofR>&>fXDM#(NjkvG&H^L}_xa&LSX@bIFy*ryT**TuJ>O|A&vW zCkuH0i9rISCUPd}$DRRRI+e%oUG9hld~Q06Z!If_pTmPsEu%e7#G)I*ea3q^`@t-C z9rYoxa~UMyelPY0Xh@Ok7-Sbafqo~|s398lw#@y;17^tc84)U^(QEhRy4!1AOdcws z)9T~))jE!xQGjZ_Dal;*UA@V&!5knaVlh#R30wTA17DDe8`du_)z_AP!^Dc#MxNLHk&=>V5i$y3=LuF}{W#6nrMOP32vz-EW~ZlSgGX zuPob;%l`8+m&xEh+cVoh4-Rb|6G*Y9c~Oq^^M|vt?0l+_mIEyFdBrh@rUp`%2?9yo z=XNv5$&^ewm&R{hYT#(qg74EZPSVN7#$6ToyL z73)m{M%QaS=!}496AWFhhSIK2i_2w}{9xohX#HYjnf}t;^qqC_*Z<>?Ux=iUZ z)}d~!GesoFb^JMVHd^;0Jo`)*S8gcxKqo@$7%@d{+XL?3u4Dd~N~w> z4FF9*IjBm7G+d@ypxiXKXp{8gx z0n?}y&srK0VW#76a#GBdI-iQ$qLvC_0w7a91SFjg z#q(os`rZ#ac;mW?2TQ(`4$}d6<*VzGBS=8kR=b#<%j=o8B+@R%BreCJKT6|=K$0%r&&YB?JsAG;jWT}lIrW^s{bx-<Dc&{U(Ddzt3%X=z?l;f{`^%}5}wU_wA(gjrqkHi>SJ~)jgw1N ztgm$wF@EOk;vV2w-oCdXnGf9l*3~+`|H3H+CSQhtR%SEIL}GoXYyKB?YW$6zN$L4J?mQ#Et^3+dhigBkqm42#Iw4K_5qk zOo~={w&nsUEqzR}XRZlhri0!VkaVt)DS{0!_3s16RK#a%2+XD-fadZRzI1VjiBg=J z3E=dp8Qi??VRO5ImtH!Y7&xozU0lE0!1c1_lw6borwzu!W& zoY@7FbAsj)cdiwo7$e7OPSjwUA6sI{FK1EL{@hDt2@a5${;#>j?BIiZ%5lJr^I7#E z&?0`^;-vOQAjg^Yr%R3C9(glns^j`)<+jKnQ@0sEE`^Zoc-l(`+;yl<77QItNqO;` z0p5L7-6*wS<2OIuQ{lh(+GkJA;Qk6zZ-66l#-avvWnBTbcvww$v2M%IpF3?8xOlMH z+69vfP&Cm3q!{9~6LV3?i6&Q?+vGwTLL|NTRRgMtB36@L6GCG~r&@BYW@Dm&>8LH8 zPEkAx;CDioUh@R#QNMQ-z|Q9G04vTpN!^`gm126_90;)@OvJMd+`q5d>7Q+a8Q<^0 zn?u})C#S#Xtc^c=L;18^0X7wXb!>U1g{PLPd%pL>$qj<_4vJbz2?IzC=60)(av`n2 z)Ig5=xRajMCz)cHUlZY1v&IocGnWfcoG~i1->NQ6W}4;ba=a%MxtCs3{>JDs1(6WO z{MSQ)J+s2#%7^w%jx~WD0r;VFEMR?kfV=CvtFX7@xmdSQK`s7R#XGn_D84NLXW zF^!{#X9dXQgA|4it+j_JGt+_J0it-__sf+d{ZBy0eTmDYY|M$?Aiy(IJ&B(lq}$A6 zk0Xj7hl=}v-X<5ufSPSar@q*36i{hz07~wC2vD)?_j0QFp{F}*DlpUQMdgtuX#zEvGka_Gbu(mQXd%0p=0XqT^{1-vnmG5KVSPsfUXyz!=>=? z_W=8zkCU<5fgxsTMF%(}n?K0BVv3SA%NOK^)4^-jmSTIDoN-%-oU3;81M{$*xfj^;b(Klrf{h z9yV3I$+>zVaKly;7&R_y_bb@kY9W)&2%rRWlr!(Hck%An&rE z0f~0CfDXTg$t=8<0wx-b!3TyGZ9~~r?_XC)qj?%dUKpqFC2|QgUv&|kcYXlVz0(8&$ z^fPxRk^n)DpK&9g@z=n#&eX)OU20CfvhLx`Y*tNdc)*J^kYW(I?44hro`@$#=$Pc0`8f0_kWDIb37dh1nJ$vh=%++=JEMLNXhyit1l)`q=`bC} zd?HN~k7vUj*!46~Kr75CFh>D=9G64`IJ#caG>rE9 z4+?W!t@@Z`>uH6U=<*!Isl|N&7QMxk!qIl)jG!@KoAsK*_WPXoD43(1NpSVCp_rM$8afWDi8waEYjN9bI(KeJ6qwPllO`<^5>q?h(P$`c*#GlTbSS@b}28SsQh(FO0Vjh!^ZNri_EsucZ2T4+er@e)8S~-u!Py zrnpT+>|=1L86_g|SyRLIlk3b!ao9L82-cH=^qo?A47gk{s|_cOmr1&_g^;$`aczWa#{l;zQTn8!mf)D;mSh@1dT?qmljBb!QlDf-<#Fjd9RQ|PUEfCv>?e-L z_NU3dGT9sdYsNDDCG0 zeYZ3bCv}Y@`LBO|{Lqm~r0zS#vF%OKJL>0-jEnInj*zxo#|1jZiQ0}ISfYy!F!iy& zGJ0IA`EkRB<7gbGn*T|V+wuQL+du4Ra1}dTcT3fkza z8JHxjG79Fn^ZrT!HTCY}x<8NW^3=z0IP2JH2Z?BsB(0HCN77DMGVDgu85W~P(&+!= pd>l#>ENA4u2E=4ovwN=k{{X#(7VQ14;iv!r002ovPDHLkV1ir9MKJ&X literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG17.png b/Assets/SpawnSelector/MapBG17.png new file mode 100644 index 0000000000000000000000000000000000000000..8d8592098518f261ed9f4d1b1c294ce2c38d0043 GIT binary patch literal 5892 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
  • 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 TjRc4l00000NkvXXu0mjfT}fgv diff --git a/Assets/SpawnSelector/MapBG19.png b/Assets/SpawnSelector/MapBG19.png deleted file mode 100644 index e09d63beca3e9c4df18b0f9cc353e702410e045e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10791 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 diff --git a/Assets/SpawnSelector/MapBG2.png b/Assets/SpawnSelector/MapBG2.png deleted file mode 100644 index 29e70dfc4ce50a1c4c5a039f112251fb76f66858..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3466 zcmV;54R!K~P)Wy}8@ixK{74H281-e!BYPj``x}KbyAg&bnPZa9Y=m49Xq}j%+58 z>vwf1xP7iqgRi4E{y5(uQzfzmG(bDV5vjj%z3WIPx%!#ib9;TB%Y`((_R96@qisD) zrd5C#V5%J|8UpE?2>4gv`(75J?ktetn$s56yT9M9_4`%%yN#bwK-^c+(}GN zik9ngv@;n{w`ennVF`~icp$K}1)&cf`TC*Kd&ZM$H}s)$pjzzm*sgTq-Yo;D2d82k zp)8$>xK<66Ls_CrLnI_BNQpYX{pHWC+TbKS?r|y@>hdv*EDov|r-vy!kT-<-HAdQQtu@Q>nsbsbYb>{O_a=Ftmf)(gI5Q7eNe`g<^ z@06<@i+1ALD%^ll>2oT&;z}_z5X0YFhLbgbT7KrGZt`dZTEw4oA-??Y;KRd^C3nN5d=2N^CznZ>#tdXcmt*F+n!68Dfe(eoRFXnhXHoK$9Onm}c~nt}(9KG?Ey zxgK>>a7_j_h}7s(bqeB~m74X_<{Zbk6OCxeWOAxO0#?P2+-eyw1Ls#1VVY8QB`(ea z(n2bky41v@CBCc5)mSIHDts+e5zK7GRb>oZCDdKvXF$KPRq9*}7hdc^rSqs7N&?{g z;@T>>k(zO!>y0jGFa-+<7-Trq+>H7V<>7z=pw50qBnwQo&Z$_DxiMCf8>%@gnY1Y~ z)4a9*cW7K3*tkNOuH05&eFU&moR<(das@Iex;n2awHNtODF<14e8l&vV9^MSUj>m< zf&TA3e`Rhx?oFyL35(-_E%Q1fvUQzGXJ*l|6}oRA;blYJ43{j%IZZC=2Hv>uw){-Z zwQ*{brLdY=hQ`6KghAz2=3P>hn?LVKBGtKs>)4O{UrVC;)4JBnKBz{Bwz3j#%vbq7 zAXPQuPSAi!tWLaDaKr}<){FqR{FJ3Dx>zpblOTmt;A|8OfR?&VBS6mT3Pd7Q7HaBQ z!Woo^co<%uV%4jedl>Z(m$Od{s*xm};2RQZtKh*zFjS5?BFjYuIL{_a z!F21ASBa{$yR;I_e*uk-WjV%ru4Us4lc^H9HJKaf(3qqfaZH+Xn4QZKnnv5sD;_(EaAq|G3)`#nN!ltB)S7{IuGC3kCHR{`BORPf%=2ir$Qw|C&kBpp z`;g7nu#-GC!c>BHjG%!jDU;k`$>dA|AS;wzmJtMztUfh++`(DGXM>po`=V!bWvZ4x z-8o+7g4J)cBG>aL4Am_%H92=Gpjw@wQjID(HJ0VtUS;5%q0432{26U`s+RL+8P5Gf z|HHPZNM~0v5AB|4!z+;=w`YS5DBfOhF8<~rp=m2zk4mI#e`^5ql-42+M7u2@B?E|4 z=+iwCk}9aA@q=(99hq+LN0x%2zyJKNtCiBx$Wun7+X%(T)Nm_MlP-bn>>&}q6C>mP zt^6KsxWmZiRrkl|ABc6^TP>LySYRW^rJiuTZsi2vICoF`RW#UMerDjGXD#^QG$ktvCCUjXanhu5D0O+09!OdF_TE^pc-*ghXQY+P@DR5dyMx-lqN`%PGvoI#6 zY$<0R{_QH<;HxIkd&87bB`} zL37;5Tp6TPQ#p8GMI9QFtn>lE&)dpk1dcRW2vUSmq9VN`sV+lLGRYizek>afJU242 ztO0|emX{@BuR>(eJYF=e+w zH`5SXD<_RU<^_!^7su6|yPL&PbIlYBRR@r>0FOE@6aJk(GRv~;(WifEuDn3Jvqyn8aT@63 z!hTCgC&=cUBlw1`r7hk>n@Op@2FDppNDBj$H& zLup05IwDUN*LHSgse!_TWGc3`%%xE4mFw-`JbW_FIW3ooM921CR-B#7?yC%9mf)7(nQ5+CpgoyCv-uC# z=|iYG>5XD0MB&twX2P{zd72?3a`criEja%ZubN2-Ecop8IkQ1%W~FNEH6yPTugnsm z93CeYs3Ln2eh>R*HMEQ?ZAbLo>d6X>)Bh@2BOT>dcVQn$;a;<_D1-;*Dh|Li+o zD<$_hQeDOFburocT=o{QeM!1o95`8S@RWNG376dtWcy+dk~gabW~$3|)Yo6Vwle~! z4@-<_|Jv`-F?8?;JH%gAvm*KQnYp%Ndg1_`nyvda7R^!k>X&yW$B9cv91 zcaO8?EA>>T7L9+Stg@Qzsn*sKjyA@@ZQk7nr^Ofk^Yo!p$#8mUN2+^+PSq;E`Ov{!he!MyOydo65m&3zH#ePx}N>= scRT+-b6k7RCt{2T}^WwR~3CDjbx7^OUg*Lk&!Lp0%9O3V~T`Dk_C%U zuz>}YUjV;^KfoV=JsUPGU{As(upm`X7y>dD#)=(T9*+}^EkzmX^vr4BzH{G4e@GU# zPF2_Ie*OA=+;i`J_r30sTEpSco#5HP)YI<337SJ|?##D&o|)+M!i$9htKEhCd~2tl zr3d}{6BVs}Y297Cu;Tu6d)wXm_f7Y#V_L}RE8qOF+j(%;%|7@byWU&8>bi^P^82`V z@5Z}@=a*l4D=(w(%X|7h@5#J_{{0rx_PD(1Ye^(X(u8WrGS34JghGG#=U?Zf0uVIv zAb0@6?~Vy40Z4V8tb_HiY=B7e*MemZEsc{zuCJ}Qo42;z`+wP(xCculkg zVj*}E3*Z_ugaz|j62&|~Duh%V%R5HN1m1l8ihJ+<>$z3po@I$3+iK)_$Fy+C+7Ln> z4@830RGB7OCV++|nG&J7^aQRTQ_BcQD&$y4hMY4efQr#L-6%VOe5pkz1Xc&9ucqK7 zlaO#tlcXqqg~;Hj*@rNzl0 zK}UPX9jk&!xs+=frkgFJMG!d4b8fYWuj3L)B-UkIzsX$^xzIlD2t~7pLZ;;+E#FQe zWd~8N$$5bN!2v78qFRy%Qn8ReI3gE|G0P(bQl2D^3NIDE?ikuJ|6Z0DZI#yimI@4R z%h<;Rd8q5d8}-&@sjx`PV}tQ^s2?1+RQ#rwCDA#vtZzr>LN22WkxmHd?gzhdqfM@( zk6fpX-5a8?XB{AvL|O)7#R68_DN38{W_>_ebm)HjTDF~sYs_u)m)_1&c`f%RtKujl z)@k9Xk-u zDYKMmr}}qVXp^tFfLaPmE2}uS8dNknh3NjtKI2-xQ3@f|${6&WyZXbzyHMoS-T_M0z&aZOWj33+ zWRcpws@#7QpoL>x@>7t1jb9)G-AmU-FO+xuJ5kmb8!3=eRSJT0X4!dw+MEgs2*SAE zKIi5y+26~=P{oR?E|2v1?l!1Ea@wJ5F0-;QmnJ&wF0*l<=PTci2?cch_rJ)=1CbyX zZl%n;S7rTL2NZbKx!LFGd@ub|(WsmCL28>XK;f2L*~m9@uZR5I(b_mtmb*A9f(`|E zl&PF=b)99ECHUPeEmB&h^^!P*&?_;Gl>JV$-+rMp@!VlTe_c^_`iaezl5h~nqb%BG zEwZfXm(e!s9*JvrI&NkDOn$z22DS(-HcR*7hnh!k)TQs}wm_=te^^4t)% zv@&^rsx#+4AM9qS#Ho&Rj~{$GQO`_wIX^!b4BT|5lcfOaf#8v{4XZEchhE^bFB$fV z?V^pXkG9>Z#TT;n*&Z<4nalgBzc1F?c})dyZApaIB-v=lN_`fg$&v&y<$xg&f<#b2 zyk1KN@Z>B2(0721MA03rKA@GP%2Sqp;KI;G&2E?;t68=LtXjjfH% zEKfs{yr=GIMF9qbzvZ8!$of#vu8Oj=0~Rt{BUGs zhUOIO-5agRM~uc`Y3ay!X{sVbB2nda7rmYJ)gnPT`lc93qzn%8RL>c*;Si34CFzZJ zVs7fZ^FiJVm8*i3`uM>c6+%bO+QX#~%d{P{Ol_5AH-GC0X7}?u<~ebDXS2|!3*DCs z&xh)^&Sy@YcKeSXxt`l}i=FlCTmt!W>0-4Z^H849>q|~$Az3oEU@8ff!Q;fdDx; z-TLb3%oA`N@*KGN*RwX*7FlX~N%Va^8?GhA9tC81rTM5YD&$>zYKTbEa^lJ|oj65HpTc z%aj&M9;O&@Sb;~KS2d}Y=Y4+hnp;?U^0#oRqT?YVmQQ6Y<3&QyKN#}CA}p4c`U_oE zqOUqZ2+;4{&5k=D+=e(D1_g7t!Vl3Dnivk(@|gsFEkbQ9}lv8nF3Y&R`#cS zWg_{u?}6A`6CZpH={ZQIzVb~HQWdOErm^~@)#@)7e7`EM;=wd;ZJ$MIH!F$NKa`0D z38A?Nur#0f{(+3j>+Ag*#PQi!yD@|mQCcRKfQy&kOzxwUvsQp$03@}@=NhbzGYVxI z5{{+$JS;)-@LktMsIT(AF9kx1UH2Pgy~L98uNBQ&ks1g@6p9qWmDZQte{|iwy0Yya zY`hm0oJ3us1`P%*(gWyJPaVFGprxmaDM(CCBsC9!d_G%#d2PMI(F4!~E-Wm$e!rJr zudj^U44&8Y_*`rgF0_+42iH}aly)db%Fhb2d}#>zra=lqu2#CokS1M!crhD9|MZoN zXmpS%uzYrPf=HRx#bCS>1rMQjr4D1cVZ|SE&ID4449OLJpQ`(5#PvV@wjgW}qrp6+ z_wI~d@S^d1A8%#kAthkNAp%j}hvmRMfMjv2kg0FmQ9oOUZ2gl(`Nuqb7U)ZT#Pr3-E0Vg->gg*Q2r>lPFz|=l6tC_<*tA8GbSQ8v#f;cBX{f zX9lY70BP{Yx!PDP3rz8La*AtX5D)@W-7w+%dEaP_^rRt@XAz2yqMcit|M2d+$~jhQ zVu+|zA_0z71AVd}3Dm)jwRdX~u8GrDDr1XK(8D|_7uo(4g@BYUGqzEztrH!QB*=5t zPmRMhI)H1G;Q`2VpG(2>vd=P&fdiL>g2b4`q2Cl36i1SWYg(ER*);6h}hIm+I z=_7>vdxt%y`@q ziIWPDG8alu!a7JE#$vgC2@SPl!G2W*3$Zg1g0e##~*(8OZUbPe&X$mmao2t{zye^ zTNWkfJ!=k>gLAGp2o8j)Tz^hJ`vex*sRU@t?+ay<^>GX`--4wSqq>XF$|<4WA6X9D z9$D)~6dAItkn8fb6(cm{QWp}e z?>IsCSFZvzd_hp_mGAuwu5cJ4pbo5h%IwJ!R$r>r^EA<Zv1yV>CC7}v*2%wIe0Fg1FBjdjgZ}~Ft*Pt+XmKI{0000v=jvUU$)zp?e2ap z{ay2%Z=Ts_-tRp#-?!bxNctqRGjnF<%*=Vt`*Ys&&bMvjVc*C_Kdl0_2*e~SD5wDmT+OD*bF=O9Bz1? z$v)qL6kxSu!R=B*`j6*X-VS-c8r9i~I9#dn`8A zy#5Vg&-TY7p<~-04-3{m8q3jm%NFm8gdRS#B3`qie{U|K`o7%8b1RYdU9S9my)%70 zaweSE`?m%{Es-hM_E(%88X0e=B$@*a`>co(Nh0~sSnCUDLv!0}d|Q?}M;C$;XVE3) zdOlSuu=|B)B9TyOK;P(-Q5ry`2fnL)Paac}wUZZ!bR-u<&i~@Ag=e5tS|~5zfeX=5 zc7g7DL}I@?_!8B-==P+fp@AteShJzHujjQw9AF8zK+hlC@lL)^La}h0YIbSo-dsBE zyUdz-uwGwA5DB%m^@IK8+6K~iXfTAn@KUJ4RqJldwWeo3OTAgW02S#&^0?X%!Zv1# z2wtZ|vL3Z}yxvNv64#wwhfbu|C_ol^J*0uEjpZt(D#0Msdnb^nlIBUQZ5IW#Ayhm` z<+FIOK8i{vmnfNF+uFobB_4s4(ok!B2<@#_>acH#96a`?!nw`ZMJ2T+b!kTdcD;Tq z61C&xO<~4+&xZ?F-yO^I?Ij`KSHNC+&!U}gGQL8c&}*W~UwP+uBcV{Wgy+%Xnv`_H zn~gffct(YNR$wnyb*m)fr6D2qC6!pKYQ1$Cs?O~)4NWJA1jcvEY!ini+$KQkt8cwo zxR-r)V(q}%f^95w4Cw%&UFWR%awM}=ctY18cUK!6}#e7K+iE^A{rLIin zHcKSW)peJ-PSr0K>_ft8Z#_{Ms(@S&2@*lx_P)Fk+8&Z9idAH3H>7iyM$JWmdMU{+wkh?lO9|kro3cFr^ zK3Avuerg7)o~@a2rUi+!BML%oJA(TpD*Q~?!B;*>xT!$paN9fgg@0&wW$+0ERWwdxi7DMGnTRg#Ko zsO?m!>Y6Gd%Lpy&bQ%dNBQ8bG;PJ%`0RyO9mZ`I-?c_=AC1-hJ$z&o zNx2Pq0@0Mgi_L~5AXlOG6zAgE)(q4oGt8@-g9Aeo=PM5dGRd+U;W&db^jgC?c)&7J zy~dkLRch<4B|1Zy<3qq^BB0>eU6s^-?P*lqL_G#O6viZQLK}JAs=lmb!q)9WG*H?( z4pTBBm1Ibvl2H?9F zSUrBrgHPqo%fP&e;RSJFWFqd{Fign^RkF*5jqW(pg7cbcTzGd5}UH8cWr7f*wcogi5HUv zRNbonuOhK*_G7xdSB1{RGy@ylRt-}INF--ZRJB4PvCs?EdvJz^gt8+spie-}YDDO& z7268|1Z?9P4YaqnnkA42)hCe>FU=4oSp*=I^QUE?X4H-W=%j$E=NQf_bAaqvO&uWn(vZ$(Q#q!C)Gjjyw9{fK?>aR! zNsWV3wjShwG)NL{8iA=Tk_`K)^QS7EURX~FRbp+YDTMRNUZ||MdMeh-5~z|2Hh8m3 z3S;J3tL|GSA$F3S`<(JBgC$fa#YrR_FfJ-(s{LX%LKdUd4uDRfp}iOZ@+zQFZ6;xh z*HP7`8YBhlELEj`=yfS#Yl#@GSFb0TaU7k9$1<|8K2Hw30P%AcVD%5k=?A}7^rA1llq|ROH zd5}cJUca{S$wDd!C!ayC%`-}66sT{as`XHRJ&SNK%OV8O5n^oCyI4uJnF5}z1d-ZE zmx5F#o+5RRS_R1|X{DM)CPGhh++@`SD!E(-NU0RO+IYh27;dn%lm~u)5gpL@(7Jm+dpxBozMyU zx#c-@JZILVDv8J2AzkCh z%&&&iBXw1}s_#TNe*AP?A~|apg%e|^L-&Q@(9 zVPXY2n)KzkQ-1 z@5Y9zQUPf=4KWUR{koXTn!?%a-lJzm^Rk}Ko`PiI92{TR-JD>_8XlG?ZPOK`WksgyRC!|iid0U+sU$T3|oc$DvKY! zve8m0A#H|80%bfFRc)AfUnLSqO+u7;_;%h`Z6t~?p~=GE(1vk`w6 zhC}j2+p@)Bf=q8(i$p5CIIWg>-d-zE`vrKPq=zu^5l=JGrk>88ND>Gf4Rs<@HkRk= zn&()vL)bC3c6?mJvEjZQ@8nS)N~l$}JkIexLwy4Sb<@K!CL|FAk9~AJCo-APg|&w0 z4(xue!I`P!=E9!Z7y#<4%wAd8&H%NFdt2Dxy6tprhA>Yu0g}dRK(D9*cBZ|H)!D52_?1+9+C7Id5q>)7mIWam*~)=qWpyN8wD;79A+mvm?t; zu_FMNOz(5|$*54OOOV8cq*`M2*sd2|%t=(>oKuO9fw1opIquj?Th8mWOo_F=1oz8) z2x^SzeV(lQ4w}FW*pGfJ!Fn%}ymi~VVcBA+*NL&Toq>toY#E6jys%b^^pvViIVc1r zRweh;=xYVZWW%9xM~wu+@!)lOFKqLC`z$KSx=*h+l^f+v#N+;UnAP6-b=S%92=+dH zR&KmW?gE+i2C!GEVw)km%ud?Iv)e>U^@2=7iPVN2?^vGOW7I){)r-~pYMCXI@a!ny z1q_tTl*gL-wudtz`g1X!s!yT8n=K5Q7u_BS<%BZUDMER@bt-HlD@k610+dK@dtf8R z>!gl_*>!jx-oI{ZLum&hVR0;azF4NxY2UYOhRA-pr{1g9bLFa!GxbRoTL0;qyiEP_87VB$e=n8>4s*sXs*|h?vupR`<5vGSAin zhap%mcfPBvCpFg-!88D%86bd~K}#%An$fN#64<`uN52o-p8k3A8aOd5&;{O%N|U_V2gCt@l3=_U?Q;#t%O}ygNqZSAY8lVeI{(P&@UX{GzkNXTlBN zc{uF<=U>Cd&5y)2fX4j7EjQ=WM+3M2Fw~A64|C?ujdj+Jei(Q!l(8Jwue$rbF!bT^ z(01`;oy7LyY(MVv?#sU@ltIPe{7AsXlW|7pRPDWR?(CsBOEYU`cU-W|eV&W@L86v% ziD;i+Fd0B+M}3AOZ-;C~i8Dg6p=WmI(_USle9|!ckvDu-XZUdctZ?r1k#P3#%VEaY z`*9)Yp$?DC&I!adAQ8`iAB<5McuqJ+ECbZGsibN->xt6p%)BTV z{j!lLjlrf;ax}t2hey*c0ZOG+t=RW+YuoPs+4e%r%uA*4W;a0kOTT$GmZh#~1|TVq zY-HO|;piOL$JmqGIQHT%zZuUh3*~j2FS>Qu;*C?aKDFaEAg@q0XMaTnl1bPGS7)fq z_NIPk0?;83C#&HJH;}1lhNM=B^vFvcw`EvkPL$dK9SI!^c5>t9M{*nOIXs>>YJWh= z!n@AG2HiPBVzUVpc0B2Uksl>eNknvsGbluo%*jYwv*a{`vin0ind`%e<3WikrJNlN zB$rqM1Y_YC(jxWSMDe~Axks%K$TAX{|0K+9AXc zxWaSF3Tk#LrDLj)(f}UWy)CM1K%bS@Q&oFJ5@p8}B#~q46rq4k(z3tLUKME1$(#xz z%P`&b6ICkRLo*#h%dM2#ItV?Fjv70Fl~nr!7Wy9)Qkj!>sP(D+UlZEJD&U-|gs`f5 z7Kq(!26}EYL~^at={a>8>B>7xHWzI7841#SVNWW(UrggUt~bk@d5t=iDpc>uk9v0R ze8cson?bLUs;VJQtFU3ts%NOuMtly`YbA}6Tc%<)F&k*Oljng>cUmPoj(zb~8+|a7 zeq48{YTbLUDkAk6%E03)othj#l}sX+-F9=sw3j8a@C#jvR(tJa>{MAjlj$J6nN){R zeg9^jaVj)Wvz>|ef+T_z?7#i&ukzy{4TNG%LUGQ4P$%=c2Of^n-H}b-P5NI)O{Lnk zT0yDouxd-2$q^X8r8F+-vWclTP*Z2R6 pHW1o&`Cl%6c5wM$E{4wz{tGzDljq2~>W2UT002ovPDHLkV1kCxkDmYl diff --git a/Assets/SpawnSelector/MapBG22.png b/Assets/SpawnSelector/MapBG22.png deleted file mode 100644 index 31894cc715fccc23807cde0fd83770c535300b4a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14635 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 diff --git a/Assets/SpawnSelector/MapBG24.png b/Assets/SpawnSelector/MapBG24.png deleted file mode 100644 index bfdde406dbd4ed6f6626a58dc541f4cf5c9fa891..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4523 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 JPDHLkV1ipLy4?T( diff --git a/Assets/SpawnSelector/MapBG25.png b/Assets/SpawnSelector/MapBG25.png deleted file mode 100644 index 55894c3432d1665d13a58fb7626f2425f5fcc2b6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 291 zcmeAS@N?(olHy`uVBq!ia0vp^#X#)H!3HEBeVpw8q&N#aB7uV3!XV7ZFl&wkQ1Gg! zi(^Q|oVRxkxtJUUTo2~HuTMXkkZ{ygxI`}Wrq7iRd>@`yl<)uX*#7MC_6gCmR?l#H zmwnE#_0D~pWG>0V-(MMP`e!I6wRK1;rFGDskyNO$&0-6O)J>*nmfkgAberUESG@er Za4wg#av{@;n?MgTc)I$ztaD0e0szuAYOw$S diff --git a/Assets/SpawnSelector/MapBG26.png b/Assets/SpawnSelector/MapBG26.png deleted file mode 100644 index 9e0ca8525a3041e233990b08a0f493defc327be6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3331 zcmV+e4gB(nP)>Q>cn@n6Z%lAvlZRjkgd8u< zW59$w<}v@3W5{zL1oD!+BXOAE>e5?~CU{j$ z53Z6`{-n{Iuu4^U7F((%!oyya+>3-oLa<5*&wpHRQoA26%R0eLWNu#-kQ?v5tG}Pa ziWr~_5<-aUvgyuI5yO1#K{oH+q4(Z@e+sBrA4oj1}7)<$)Ep3?aw|lz9WNTkUUo6P(kxGyID+v*xkzS>h%2&ezp*x zc2SV%;fFQgX2(s2Fa76H2w9XkBsG+MHzi)Qs~*A zCgJO(YUOg0BWA0~GDLQ*IG4vt0A;`&@+9a*sSr$hO+g;^E`iEZ2!=XowK42!#hO}@ zh&cVr3DUA#US?uP=_W<72s+1>KF zyip+U(aK_X%T|eW=T%MsHPD5(aWZL4Uc}Y z*_xWTFgU)?vt1EtX0F&|2TWMy?s=b};>X(9w5fP(7;H1)uJ203efed}W4NP8b3P0z=c$rWH-Upq^= z2E0bHW;_q$&uA;dfFV((Y7n@M}rYrosb?~45{%}JktZvYn2CSvQCDqdtWCbg>W#S zhi*iB?H)OCKcUuIiu9A5N{i_19;n>1*k&dZtZ28yM z2qWJX$FLg+%Vak@>JG+{V37bT3vT$~VDf{YoUSfJ!MKw0`bvG4mCmeTbGtTkI=!f; zJ-9AK1#o$j;5CuuNDX!WgO}KqACF0A#Dg_zG)gt5nlfLsJFS zg)`nuOJ~-wxm}~34}K}avgzyxXXElao+S8#Vgx(^GoWt%!-xu-&D`x%sy$Uvy8W?xn4>-mb6EqGa_Q z3bq~cj?4ct05G}1Q4bj=6eeF-OcNZPd8ADl zK!*os!U{)cffx_N=RM(C0U47c9015$dvM9z5mXnO1#(`MS*COr$w0F#bfxA@%ni~2 z>&8%sX&B@ajlZr7_e$aft9a;I9O-3(YJQ1Y|1&X6WF%;&*LX{Zkjb(Zfl zSRF`JSs;rF^+VlEh9R##`P|L}QkL&l1jxM7RW1#3Q8CmT%2;N)Mt$?v8SfPVnO4Rk zR;i1pYezN)ZcpuKetRqap9TBRI#US+gCTu+d`|b*%5Q`haUFT}_s)?Bf7H4$zLy0! zOKIg{7b}A_y`MJuVda6HW~I@6FN>P7)VDp%34X{diT(+`O<2U-39nV&m zAK0S9raCs!v1$JH>MHqe@;jeoFBW4ai?^msyZbL%E7I1PN&MV2yO!TGi8lu1V;Pb+ z8Y(gfEI&k5e48Gf^~E)&=jSafN9r`Vh%3sIAKsl=+la5RK)@~#uI1gJw1VVO*6xXH z8KK5X#xugc`Lj|Hx0+YW0?M+!vAP+l6~Sy)oyiXE>coZt#?60z{S`g;J@Fh9CVUFR z7ZmY+yPFGW5zTXAA*(D%U3r!bP*z3W3uOU9!>KTHPDYQkinks{@SPY@WgdgHS9@7-*ZGlZPJ{ z4FmB7Wv?B7X`z-+Po5lU|1(CK704Yc%eBtBE!Hq>X6VXM29W1Z$LR<28B0y&sT3_J z&t_qn!O*9Tb&vduinxF1#_kp_Rs}iFF-dNayyb6Xq;L9QP}V~LoDS$BEmw@0c{70( zvSsqd0VYMA-ibJeyTzw4sB_jG7ewdEUl%!sFFP+H&q|R(1W~+ZlU?mUo;)Tm`OVN8 z!D_uRNX}TEMZRv09ln4GkM0)?xL0Vi66;JEmnk*BO08v+ zSF@;}{DVK7L-IAwJLmCOc-jqUFIi_I?l|G3TZGbXU$0Z_Ggq4B^m0ym`UdL+JQL`N z`-XRP>5k(mak4zbyfwB=hQ}cb*Wn-%2S8%O080~W8t_K@M!!xcb^MY&eixw=|EOJb zfTr|kelp}mtFLLyMKo}kG|Mh^(!}Xm-}~0haftwAB4hm1q68$yONPliK&-Ei;va9d zt@E*k0&HrfGA{$1Ta?54T1Ab~YD*(oSJ2W-z7od|um2HGHi&Gn1 zmyhlp*&1YJHGt@}B|Ly^S+jJ8EXn2JxrnJ#Le~AQErbzI^JVGQZ?(oH&{>pLs73Vh zd8p`+v1D1?L{>kT{Kw$zZpArS<0Xo)f~1!$3Y<2Li8$%j6wV<(T?gX4(&{e{KT8BG zGO8#yCR%~r2p7JrOHnJOHipi1%4JBu7inCQm71R^Pc<(!pFD8V+DNtRIRPIhFfr12 zzWCG;ExA`2^UAY~;D!l@hRp&)$}A N002ovPDHLkV1g_MTpa)a diff --git a/Assets/SpawnSelector/MapBG27.png b/Assets/SpawnSelector/MapBG27.png deleted file mode 100644 index 9e1777bf7462fc822391c62ffdfe64780570244d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4784 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 KMNUMnLSTXk6kMzT diff --git a/Assets/SpawnSelector/MapBG28.png b/Assets/SpawnSelector/MapBG28.png deleted file mode 100644 index cd98391369e763e2ebb7189d856cc685bda3b3bf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7876 zcmV;#9y{TQP)_G7$#E2c+vJ}~tj0B0avJTj?B}>}b-MN-? zki$7RLk@>zH_0aZsJnvSueyrW)h9VKl0Hu1RlTZu*Y|$MJE}*>h~w~ZesGQg$AQDw z0tElwm5n8QuaQ;~P4DgN<)@k#*PZ_f5Cs8(K%wY|qA0rY^v5B%)f{R)$AQg<&4*JB zZKrylo^*he5`WVA91sLR4qiy2=(6~I3Tni|Vj?qy2ZhHSKhLdGB}ohrCyO#+a@|))l9WGmL9>Ky;U3%Oem4*w*-m(_cJ_| zRwtn?B=)WKn{Cr&5=pI!0(Tga!gxeMI+j9Gi6IqDA{9+=n2skg(?5Z8qw|>QA4gUl zhHY8gjN8k**xOc-dXIp`jk~zEwut+=HSDQH6tyynS_vhsj1rToAtpy*TCNJFKT2bI za2Q`-Kax;6wKg+glc=9iZ*8U1Pj(-}t=;>F&h;o#Nf04oB0Y?|dus=gp678y_|hl{ zkVu6}3Svr>iOWg`GVwGru`V3%AIFE!z7NyR40`%StS)cDxNjn7ui%|q%K&U#-CV;B zdmYi02)ZL(_`&1}ypnu3ocC7ng?GM=2iuQOQ1_u!icD%!ib6Fth?dEAm2B-FTz#GE z*$U0tJ?sGC`x%}GS!WK8XiA0ZpI9Z5B~po@E0(}q_XJQ8(Vx!Z)#rW$A3XPdV0#a+ zZ7f~AkGc5?+`P8T{b+V#2>M0U*SCd%}0M8pZv?u;(qQSWRQK9xO0+SH7p&b z(M?Oo17E) zM4pItuy@en@)(ue|sozH$4l zYKJ`V%1zVowasD1p-mm2Rz1T5Nl7PoTI#r&88{3C-|2CslGJOGiA*D#=*Ewpco`p> ze=l;kSMhLjyNkW@;D%28LvM$;JY9l~qx`Uvh`z6;ARYlv(FB9flDcKbfg&(1Pw zXXFtk@{}~}5()>)rHfd#cQ7IKVa43UePa`k)eXG8cLf6*J?KyMARVV+P@IQEQ7Pij zDmC&4nrXyZG6mAzl7Dy&Mdwd~PD$^`n-yt(v^qB$I68$dmF&GLNRam$Pa&J`!Oy+x zr+`8kYPpEP{_dLhg3=fy`JJVEc=OhEyt#CXWDp;F`8`bJg1P2Pq3 zuu(B9SXVdkwViL`C(gVFJ+U;>u_QZTimdSL6PpvEbB)NYFoqGn=ok7pfj%M2AzhPG zMAyORzE|OhKpwY*QPB;(YYIDge;lJs=7ccHQ*o1#aU`QLOh+g1zPXoivU?KHv>LKJ z5EIl(=cISzHb|yymKc|Z*~1To*SnA&p^I-o-Ix0(R2E2m0Oz zR5ZYHYDf!`Nar5W?B+NQ=8sRpbWEH*KE*^{US5LXn9yt$0~w`iJ6)$}C^p0IZfYwW z55YmnDB*f(5g$15ZrCvsW6Cg!ks>CJJ5q&}rc7+0_ z;^Qa?d*~B-{qR{5N#Q28+CDcd4k9n+F(M8jFK+wS6s~rV4@u^_u#RzY1Y1%b-$$SKl(DwDKmCPz}>F#I^krX~_ z$-Iz0-S)Y>kjIcP;D@=u^;nblUe28JiR5@;6dS@OCgf2RB6}EDMsR-iBn-8Lx#?kF z@|xL5iYGg1+a}J;OyS(jG)&v%0fY$?mvi^Akbj8xo|%W?7`}}hj?MD>q+$s>#$%|C z$txxWYac7>DyGK9Fcj%WSuSBh8pUIA1LML7)f^M7q%(0#-j!k&L#$8Q`k`Ny0+5YlfcfKJD#_p*&06omH&f8CXI+%o}C^!+J5-^qsXr?LA6?cMnJs*S9~@4bw1r zC~)$)+rt}y2qtw(Ymrx%?l6hpzV!}1`NjW@`C}7U$UVf!Xb&{U;O8|*XM!H?<mcR!C6VVMQV6U7}5ZnLPFQH;fHj1?|rwzX>pRJ zGZ>EaW;tyCzJOE0N$#*G#Th2_m^jX}F0@K9KQo3fh)|k~CGu|GS@9+A%AI8n|L~2! zz-KOg9lE1qswWGBb{RMZzIx*l4_DUqwmEJipGTJ%MM`joDk-@aNhyQ1N`ce#gvHwc z=3Q^c*SXxMh4~KZ2Z(fX-MPgPo5B{4+k)Zmu6>$AB2Vs3A#+mTkdD<8i+t_9|E$A@ zSi_V!Q4=mNZ*X|J&HJZ>6S(0lVqTcTqO*)?9K!==6=F0cdine}huy7>q*y;zpZkmm>9uex{lrYzE`v^ZR{j6^gUw!EZ{6u~$_dg&g3Z#^RwMPXEXA{Vo4jjWq zpDc2`tr@UO8pLE2qYJ!EvnhtVvsmBF<4N%1@#cBFb!Vylk{7L#&~jHShOSf!y_qh& zboMNMnIE#mpv8GL7P0ToBXKmLhV@z=Mm;qB!`{K>{e9GCiV zx_1PL{s?ZZtw6O^wwq)xlbIM#+imV_BUjpkNq(zip=ehy-Zxr9WRSox&gEa|XwkZ+ zTX^<}h}^OT2oV7ryDG$yG`1=h2F4N)A|f_ZGS*>39E!7qiqQy5>9Ypy(K$H8n(OwU zH6}XTr6#suwvBS7jJ12)Og51iw3TF6FU-y2jisCXd{j{I+pqs$-m`Nx_W-Zzv@Oxr>%Df4iJ2#m*Mf6RFpA_>>BZ+Emcrp^JPzmE_66WF?m^?Vt& zX+hjQ7=H~U6}}#Zh|Se9&?Cbt>MW_P2<>F((YCNP&RMOq)=n#U;KeCwRMUcK+1M%U zW9?oZS8v~`dFSHd4W6!hgF_3?9iL%4IX^XtOLrGB)7y`c(LQt!B~hVWc$UV*-P?8d zH*FSo@%GJSZ0{D>3#J(&MUjy0?ZZ*9(0{4zGjg!P-Z=A@SAG+6BFg6^i3BStV|~XZ zRf>qNWEwWsZx=A!mvkFS*YR-b9gN>Qi)Vq(B(MocB8BR1bK0cr*f32C`{g3iy(wJU zSi$M+5MG=+$ z8EozskV+`fZLq`^)H372fJe!p3PuAS7PZTl}mQklTa^R3VYM3n(L#4Q{p5`WTUXvdoQNX zaQGa~Fqx;FldvocQ`RIj&4kl$V=Oa_OIr_F&0bu*i3_uH?(TG+P#z36v`zqUHER62T?aM5;$YkvAmSh!!glB#9;TJ%#s!(xr?j z{PC%G;frg3>V7NM7^9A1nV@-E-Q&9*zkUcz{(*isN_~2zzpabCz(h(b`xsDydOSVX-H&HDud(9;CU;2EcaSnoS*vA@?(EvIIGuOg{70#YhT=V zf|z6y>3D?ikbzNoX+o6U#v}=}AMGDx{Aiz5EgeRo!p{w+6&{CfN)iOa zJ~EMYg$r$0;ZNt99If!iTLDj%ErvTRVKOxfnyO><{wDs;i$98E-J@8x*0E%+<8tl} z%61tgyNql)hNazAmcp)71SukZ_W@575d6>gEW3tOIufx2A3@R@dE$qeHvLTBr|RNr z-=;P(O+c1m?v)V9#92BiFZo%7@}Q!yEfL9K+#f`8i#0N@6o2!|L^*f|CDE zm_TxVl4REpv2WJ#zMr({uwWP_w2FaBQAKWj7thD%kclQ?!@zB04JEtCN5S0Z34vrn z!s=cQ6|2HTCI?e>QsoiqH*0{@`g*&nHB4kD#D)pwH!cY0_<|OCiAax7mOMpB@+ zD5PHLoDL$7$Dy)>oN4oWPDI4NUHQ)lrb}TvX$(tY_#VAKDULCLlOhee1>RaARIkJN zH4hzJz&V!Av-WA2rioeOI7?^mb{0Q0`y9@7%_0?v!4WJxur~3~+QiD<2I6rM>-%}O zo8+x_4QA@d@Q4i)>cJy4D5X!TcD?$EbaKhL#t|FX!q-mx4io7~9g!y{Vl0&;twb=9 zO9wqegp!RV2Z*2>GJa*`Un7|AFZKOW#|3L8t+a=S2wWA`{ctqi&*6nYeyzjj@V0#w z&*LmES=VsJI)y9R0;VccSST$*d62~4|ACKSD%pcxB@IWQZ6F#RTY0P(^K2_g)pif{ z)HQfmnwm*yGMVyKZ&(E%)^?I~di4|jEbI~BS0%SSb2Nz zP>tX%hbcWGtg--Eks!xJM3OS1DH**pY5bRqzlJ~0e-lO1tPU|uR?*WTr>2ny8YDL8 z5H&)O^s;)i&-s5X|ErC^9sA1jzmH5h$%L`WrGr3|2~{GyXl}G@A{$GyWcDR9u$-7* zaFWiW5GhAwCel+~QnfP?DE{xQf81T0tR8ZdzN|bv+)qMiuGWTQIE_HlnCw@wU&josuJCbP?E|1$sibF4Q5MUip4Q0b^Z zVM1FG87$~wD*yS1pY4dqR!&*i2_wX!w5_DE8gJ+L9F@dQq_h$0$c!dyGd8O4Tg4I+ zN$|*A+Ah@;HaPncEJ&yBcDNyq(g>e__}PZ>jU=%hnM9;}ZXcP*PSMV!1ksGt8ZwoL z$;()@;LO-Dd1;FX&5lK|d21KxWCUZ`o*FgVtZ?B%c*eY)?Kx^scB=XP>7zeB6p4-0 zY%7VZfA8s(KZs_6(TY%?%pFVPX*+K4$sr$>s`*v9(`r`0)IAxNkkG~`5Rp=`p=m6%AHG$@iMyHmknPaNfnj{TAWJ#DgN0-8@G?bxGD zUMTI+tO86;Y+K1rE8A}NB&fQa25QW^_DJ)H4PHM9kw+Sovp)pOGJK)V)Ao8(hN#L|r=15UdwJJhHfsBxaJXPctzJwagW zNV7%^BiON;Rp_XVWw#j)1>?fyc$yvSSxBx2*$Hje5vGdNNzLK)zFrjzeqDcdUcOaQ8$># zjhzZ&eM!Wk3e?;_uiT?I4R&?|9fdxBYgyoiaYygPg5G)K`KvRicc$7kWH|lrhKC-8 zm#1tS^`dAw^qmDDMrz%7PtB5wRV0~-R5CGmX>?^=7g?<|U-R?QZUoAY(hBE$6j*|r z&Y?Sm6zD`96r(PEsk2V@BxtmQf#PIQbcK`l#PCmiIrMq9`%rZ!h!6T$Cl;aKnv3zz zRMU)6P@=-W#^|Nz{n)Q}pMHlj81I1=h)ISUbubURs*3JdtmBH?4LV0K?rC+NP7yY1 zPbE$2P!b>;=E0Pg*Mz1Z^S2SEK`Z~&$eij|nuw$o`sjWIm7XY|x*y>p=0031yVpWA zQvKq$N}^tUt^uMEFC!PU6_TKf4ivkV^onIc5#6#-$MdA!3h8P~w@@@Rq#SoT(tCzF zk=t>&l!5c+2zNer&$;`n4`Br3zndL}exDOU^uTmFn&}%-B9iV=TqGi~R7N8r643~B zGax-x61``Wi7GL=iLz8pO*h>wlG!AjeCZ%R`bEdCIJCX`c~t5QVpN6^xJTN7e&3vq znvP(b&>h!)(GT2{8SumE2Rny>*I76{+wDA_X7R4QPTJ@{0`LfJrDZxbKdlhdFtSHL zF!T#VAJu3kOJyt(g=&!Am9bZ>@Lrw1z8)-A|No67ZSIOm^znbS1>7)UnGn)3IMoml z`fnQG#_g*R(s7i^lyAg+#~ZH_ndvB;eeK|06X+sfq?3s6x}C%nME-`7f4wz8dLzjX zLgKqUfFiD?S=G|7bi`wEJlxnuWg>%wWx3=B8z@>O zS+x#ALQH~F2y8nEbs`}X^`8x)385I9Yb_&~>Kh(HJ7jz)RyH~wbCd#3Jw zH4pm#O6tlMl_6B;v#C?kwNkO5$0ZJ*HiWr}3y1q%7%F^NN@xY8D+UryhH3(_Dv5j@ zRLKDwLhz6X$S8nTy^dBp5nTt*gPkh?A<+1&B|_Sx zAwrsm;c28m9H&jD$-D2@T}H{f44JDMc~g%n&6Ni$DOnVX^61as424| zHP;?t?GWe`LqjKO^Po>kQ(s!8htO%bfOmtN3;qW1PRLI91(O$M66m%>nd&HZY56M_3R z>iIy}1mWbY|8p@;ofI~ZK)*tsT?``}A0pUm&>&&qJUG6QRC>;tR~F4gidJYsDAKFJ z=R$eZb;1C`9jjAv!)bW%(&As}k_DDdPnwfSsYbFJfu*^PU8f=u!NSQiKU{OaMl*SK z&N~mniw~j^i2>C0ey=b=lEMwy#7@;|(3o7;nBj&FHgY=>YSeWouU1mr4B;VQ_@199 zeLNJ9@^-4((M*4I%4CKL`^3L`=rkZwh{-6@SJ*9_h$bfPNGKkm!Rw^Cm4vo)h8o~$ i)URfItR4_a*Z&`sSpvlvkTRYC0000mZ*1 diff --git a/Assets/SpawnSelector/MapBG29.png b/Assets/SpawnSelector/MapBG29.png deleted file mode 100644 index 398b4026506be17dc52a781e222846b10510d6e3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9729 zcmV+cCjQxpP)&hC(X9 z3xJ5yNWqH)dZB_J0)C{>izo%Bfm8@3;7LFN2$Vt~flvwbD3uDn0&GWMY(&C#0oxXM zeo0|r^+l^Pk>0WXDFA5^I5Btx7Nyx3JU0fEfig5;bZy2`$XWsg2PoPC1s52}0$H0j z!9Zp#0m}kRL%|RNt+7!^r4V)3pdtm~=25P<5lJAD0v>}1_<=w>kZ5@V4PT+v1DZb2 z2?3A5rfVYsPbh>+H$2Z2C>DWYL7`9*`189zfw$f99yFSO5P*7dYF4EIwf-pp$xI}s z#efo!4uMKcjeqA1#SF`u3PnetwJy-|fM!4}70gf{ z0$1%*C{}>~`nR9pa{byb{5lqwbwhLw#f*Nj0kwX-Kni3`#cU)sN??*Y%*7yTrYdGx z&IF1XU^FW*mJ_ICHJF8r0qe*teA7f|nuvseGz>^XusV#OpoonM2-i*k69*8iyZ{*i z5mf=H&rm@@LPiQ|0+4GF45?645lkDfEd$q-9W;BuTGzlzM`E=N)I2~sK%uHIH3Pi& z<9`g~=77#A)Ea;c1hdwNO#`WNV)8J#O!hLM){g^7szXwl#LB#xs89_k11Nx;rLW1F z0wbW(7uz3X8SN z=hU9S+-plRpur;+5}?Gyq8U3pu?I`%iw-cE2PR7bQ$>NXf43ktdF%mGwZ{${{$m3jjjGY~e*hpqkDo80HL&<6O=n(`nPa_H=gnk4kk_bW* zL7*TE2}3A!#vCl1B?n2Ni{{`#8$HDzxJ-z;nDAX2alY@OAqE=TM`w60W)L!7&DVVC3{Hr zGH(l%U4@CffrAx+$q}G3oo5zCIRRw?{^Dsklcc+zMt1HftJLV?qp7`ehT@5jZ!;<2^&zk2+Li8MxeL>6R0GV461E9HUD{{AcQ^4Go*t@=g0;T@mZ)yqkB5|9OR-Qi&%P4KaTEij%H zm@NYbs|LmjfbCk424Gy5C;uMe@iv}rcW~WE9&-N(gO+>cQJAD+6$K9j!t)RC`}{=% z&J;li1Pca?(>1<^R4se9p+Xob$Uq{DB)olDs8cOOH#zV_iS}s)-=h zwM*|AaEkUKW=4#B@KP7K4)D>x`ZFv(`vC5E=Vwsc1(3wT#4BYMQeTm}8-_sM1S+n; zbOAU#W#G_=ftjiejOBqKf^$QGJy7$99R_PE=js4L%R~1142<3)?9wa)YSC7jg;SbE zw6p-XEMPv^#8YQiFr9TE=gP1f9>~XK)khmeY+hG@QwGF2AI3rmF=N9X5ip8zA2kYc zvB)n|F9kFCLegif_jmqEYOw^I8v~b()oU(cqyy|P3S51_z*ScpaO)PlQWj>d3prhc zGXt0u%X_#9lUND?^Oh2OtKxeN2=a=5?oF&}MO;C_7rzSQCrWIe=(xPU0iS@Jl90!1 zc(m5SHP=o-N(phY&JIx+Z$TiLb%7*jNdNYTsbdb?NI#J1MH1aW!C&&wlM-ipA&2!M z02SMWZ5YVe21>4l(VT@NBYB)&Rd{|)VYMgG2?UywoFUE7jwJi5nM$nH;J%2=+|z>v zMQgM=CDlr4!P3m6hF&H{76q=GFmPxJD33Y_t2r1;U6?l);Zy`HsvO&Zx#)Al;C|kr zEG$#NT<{_1s&MSH5S?>yM&=NG@vHn^>!7|SS}-B1S-7Wa_`wfXFr9NSopIsRJ)lbA zBL_~yXFH}F3#H_FYWqgofaqehLYVD{>_NY5q%*1B^M-*8b*Y4amopLeBJ?<}E71-W znn8qDPGq=o5raLYAT&MsIo#-orF4k8RF}a}26HTDpc5!usdPN2y8}~s144qmQ=t?l z^CqY|rt=2M8Q_K)6Niroj2&^|*A(QK16&MYE(fp=WMJ78TNSY8GO*^dun95*G#~w_cW_1VA1HoZu+chqqz|% z>eN}+9!1V%& z$*jpLZ8C2lYXLVNurPZN7@f2sCEzauxDdj&gl5U24|^^Hxnx4L4F--X1K({hknYUu z89>uIt(nq3!;HlJb%-+_12>&>ft#ujvsqYAtTE%{p{fRz; z8gba>U+gO6EQ<9?6kG$VJq_eaS7J10V5u!p-9x>bGAw=YN&>msk(e$R=y=3Lg8`k) z89dZPOr==tjfV{!I0)qT1K0iPA7Sy{uVb+dE)W69DwT$<7JP_G7P$lZ7)M`9q$83Px)5|ylh3vCVTZtCB-l0Z^ARWQ)@6a&}s2uKrNpfE|% zbE$CbdIN{92j<^&BVPF{AHnmV{VgmsNJj}Q^ni0c4IFJ}dJ4|z8Url8+kiM;2aead zvI$ss{~P#s_JCHUxUY^!SDV}?&U$MozU(0E<{Hq@anZ~RYrM(B6_^lkPuHQ2RAE^L z+hz)=+dS^68xy4&Tfm$vuno?b0>=Ivto>Om_yHWU&yx;&t=Y0%hw}ylT6G0lndiC` za}}ruZ5*o>HMKIlF&|9eo&cf19$2hI;Zf|7e9~Mv&0b1m_r4@ ztW3HHhYNJP0PD6g{Ie!9vl9MU1C~MUHh%Bqt%w%xgL!Ki58Qo*kKO+pzrg9SYJrb? zXAC$mtTHuxR3S_W`#BvI;=nw;oFY{x>WCx_Vk<T?3J zrwiH)J1_(>Q1|Z$&==a;78+lz;SdGdUjQ<9PypaIgy+5uYvxu?NxU-#Ui0=@PTg6F z?|n2&b2p{~^}W?rl7 z^T2e5=J*%_fnlK40gt(w#B?c8p(!nfg^rY{DucT#&4@IXLL-RyzNJox(OKZLD{Y;H zlxDf$bUAf9Iap%nfdmdX9Vlx|FO}veTK$x^$Lg(+L4DPM z3`Pq!+T94Pj?TYLZi5p%q z1LK)BJhawAC?$$;F=HzHzf(SzYCei%62eh9`GSJ$3Xb+rL@OgCT7kkjUvlFnn@TZT zPf^H@X74HfZJP$lu7z_Vw}FwvLZyf85}sQNFj3NYBsdLAH!-uA2X4FGMypUmVSkSS zZ06P=GB(bydRS_QeGthosvv~9-(!7!V8mo#Xc&uB>}<(EIS0&)2we09dM$+~9uBz@ z&-Nt5Lrv_zt`d8eaTtx5S`@5e2}F{Uu}Mh_v5=U_ESlTk%QNV<0F#{@foe{&?OO^WW^aX} zR`D~Nk>V&*kH%EVqov4DBzFWP$@4*jnJIR_O!H8w`av2MnXKx**hE#}+3p&iU6Cl{ zESz8S$RMEI3NdxCfOa!P(-LR~5~cAh48!Dcz!lZQe(A8?B=42fYc->Rv@#~TO7X0@ zV%~s3u~i{J#G8Ke?bvtI%i!K{HL6n=QCal(Tq6Y5f^`*Ci-78pEaZJPJoMNyW+^g# zst4zmpVpNzw!|p|+d9=}C4ooJp^X|x#SskTJoS6|MuCTGO)PYM%w!xU>a=TP%C*rD zJtnb=Y&>wrL$zq3IId6&eRM9EXnPV9Rf()&a~zt~H#K4!e4`)%fm`BkhE}oK%T)E0yiX|sz3^PU zZ$nAtek-c!>5`V78ku*2^R) zJ*!ySu6g%A$J2lMC04Hl{6;`i71;l|c@XiTn3W=+SBpadH3-O0{O04OXH~%iTxZrHf~BRb!A`W7BWCNOK!UkbFI|_tk(Q~-|qQ^0Pp$c#XgX1r&0yI z`qth`zPCt3e(t^({#V*ayC-qd-UATG^yt6G@z(`JA@92}_MP zmSFy~5>KNedr2rBE#+`DpTo_?T+Ac|^Nl&kxg5mt9(%c&g1|Ri3!iRT_*~1ympd7J z-Ou6vD31{vIOi0%Rj=u??*!~b-4cN5)F2?AeG=%l^{6*j3XNAae9cbs8cWVPh%ta< zOX(b`SOWHZGr*(`M0L$h*An>QvSju8>_S(MpvN1@A3wuGC7UEESi2+eitFEmV{iNu zAk{S?)w-1!x0ji*{@;9=Rc#`JtYljmAFA2~eV(E>Gq3Gm^Ds|zQh21<g3A?yfb1}ksfW=b8nWmF ztRF(HcGq9L+GV!V7Ii$nZnENHYCMPYR2UkWr8uXp)$57HF3*Ic5G56{R`>BI&t2Lx zOBXclg(fUad$5}db$fZk?|wIA=l;a}G5JIC4l}t);NU^N80$NkFBo5mBsmBWUUKiR?xNfA8WDEj0{Cvf#4gYv(6+ zg1D^IO|fX?KhzspdqDR^$!Q9;QR6^@2{dW46AuZ|ScAgdwE%y&qNibOs@g4DCKd2s ze0j0&&?NmwO4|<{?_U?Dx+IC3MJguSr=kSrDYh0f^h8tP1Q|C9!hia!u%EBR>O(t8 z4-+%vK)m`!8+fn{>jxcVS{>Z_ho8a+o|L#y-^{eZG9;i5EB7F%$vwLT)S`zSsakk$ zHRKfM<1jr<+I z2BDQ*UK_`XxxS-CzsV7jUukN9URQv<)Rk?)Q^J^i*hi<=4B|s+WN1i;(ASSFNRZD;oTiNf9!}y8UOEOusalYom zwKBZ_(N`34x)z}6OZ=~u?SV`H830Gq$y28_!zU(u9II*vBT=sjsQzDn8P30Y z8#66jxKE#({t1L<^zY~HA-fuPQ>X$Xg?S1Bv2mxanU3FDcfAV!@(+NDLjKwh^_T6v z`RDG$kIvA%Sh3am*DV|AAYcUWUgc-6E#s;gTgPUZk*QRWv7`7a*}9I$fDtPR$V9b@ zM6FWn(bYgsmT9#rJM^qx|7_9U5s_7n&Mv^JrmymSpCE((t{d0K`m3_m=BmUi<#_hjmWj-FMxI2c87# zeSagZX4mt+T{*Xs1pI`lgZB(Jj;m&XseQnK&X{KAAc(Y)IBu5JCaca)05<}13Mkno zvW~?-lDHzXsoz8eA~x-ojl&90tl!wf*S{ZHZT6ib>TB}vxG&`Y&wJ3m|9%G2 znz@C6WahPL765Sc|6Ih;dslGutE&j+sh_DA$GV3l!V^D0c=AK*K>qSpKyEL)4HhIU z9p+3WLdzNd;?LiYpT7h6(z%Q4%uE2>R(f4zXn{<|#dy)hk5;^GGn+7KJBDiJsUg5` z_V6}7Tj2w91&ohrPn+be*SdW#m7_l+WJ`5r7`Klwkm1?;A-_?BaYqTy-BZIm|NbHd z<&h8Xha&wMf9oLlRs-+&5zPotICl|fZVBY&Gjl734&GnL10VlSH)3M;Cj85P^B263 zi^1FpkY>>1lm=FhOjQtsQ6J3hjl3EP=++?e*=?UY6x7jmP{}DGITnwE=+(;TGt%1s z8r<-X&s=gn&4afTc%s*}$I~mNl0ohDd?v>?9~=Jsol2UOgAP)$An@D21pMx&1h1Rn z=g&@z@5~SGb@e1<)4<$#3ASb8i3{BwW@saz+XKm0^sn2g{Ko@%j8~lvVA5+DP|kwR z!_m7hZ262~-Ge$!o7-~r$DplD9~=JMy~r?@CeKX+zG*^NwX%^xt84Lk{20h#FBxpn zTV?*zHgxZW{(Tx-J>AAfZ>(q#M>eu@I}o=L4J0lL$es2ZcLI1~M-xy7pSuB_Nxl>U};eC&-G7BH7 z(ZprNAnq1Otu+!xZUsd8-0=MGW*e4=!O&kKTXkXjYSvR;KR`f%b&A2x>@VTm*#=zU zZm^rz?jMb9W^dQ_ZDVEhv$3HfE>~3io{@N__f90OUA9-P{W~_@yVJZ~P8qigHf&&K z60Rd4DLAljqJ}x!L58MW$3k5aujey66OZ#!nHxSTkhJFY#&9Ko+z<=hB3?0!6}oFA zcL3x@7AE)ZR4%uSgLzN0v~M$seV(TS=CnqG;;!`CRusW;Y`~{bp2ptIIDIvn6eLl{ zWMg+4G`~^3h9-T-rY^%nUW*q^$(ZSg} zkbBAZPGr!ryp+VuT)&tAOg&B~ZWfI;%^lUdl2{po>4jY^uIiZW0s%TV!n5}Fm5sh9 zJeaY)7IG`_cRD60Qm*`!0CFqG<#J`K#yG6e4s=Z}-PvVvv#_Pd-Yluv{$VT2fc6!3 zE98OeVVT-2!|dqr0$mAF+d5#w_jMR?=dxEXe7pUv&JA9dQnOoUCb@~aCW)M0X+a1R zZq(zbiXYE%Keyb`qbIhtgG$`=rX&~JjyCL8R4Q>^RfA5v4B8u=P0W=I+v!)(}^M zxm(Gm2oQhXa|@ve5Pi{#WVz`vkd3wnWb;7Qh3K{*BOe&gVYN<^M=vvsbvZXnx#P-P zzh<*Db*YNH)DYE6A^iqBJF#!m+iAuQPqZIkt?B8tg!wFe2F1W?v&*)0S1(SUJxu6* z1j3-U*o(+3^qea#8%MLRh$N1XWyiLShO0;w>0ztkmEf2rue&c~T!i!uF_%Ym`{(r+ zR8ueE&-c>jeB+j$8i`LI?+eYQzeIsO*@J87sVRE~Ri=);)S$lz@8Vje$>o3^`B-19 z0|cP~CnMm~*FNa8%ydIzJ!n8c3KgLcdGHGk&&K0>7nnXBtjn`j4dexN#|(kHV4>sklnQ{o^h8*0%CG)mOeE?MG7N$H0LsY zF3)B!WuO{5#>>~xj5+!$2u&7CiJ)kWW5TpdJ&`QQFn3J|s6C)!Uu12l zZm@oC3!!h)`q>P!(2c~C@uV~Q+VB>VFh4EH`_fv1fTKnc#qsIn+^`0c0GxmwMe)jV z8*rqBz*Vrl&A=zm()WZr(mH(;min}*n3)^fVCa%5mWjAcA6~}9KGQ;{7igQA%d)DC z=!+VTg9~d-`1|s3`J-_ImBe33GU$6K>nRESrthYtuSK$qkK;b%#&VPOcd|pS;5lLS7lY;T)BT*7@;s1Ku|}5oAuMS6al}?C9=% zX=2Hs?Q=|syvtt}VWIO0Q+YpC%H&vbJb6~~?||Za0~(4;-RmW>#K8gXc=m$3*LkPu zyrm^+K#9hp#+7b-yODH*PCa{5!`w#uZ28 zDlINb{?AhE4DoULovu5I_Q$Kn`eGRfI|1ze%y|tiInN~en^)`3Rnj=@#5Bj#K|wR@ zDIW>=$s8owPybFgt_@{PRXzcke#w^gGoX1$5{;BT7N?m_4c+XsyRS8d0o*UFK4;Uu zZ9*J6xXm1(K^CUKOC+gOy{13@^m8JVvt&QXW%_*Tnr=t3x7!D48}B!Ljn3Cb4UpWI z>t|}Cv^=@4MPlh|f?W!?)ue%JH!a52pP<{3c1Se}@+U5-IbtC&DIE@Is?wN!1C_X` zuF@<_%OHS!?Ro*av_dMCX?jnx-|yZGDO7S@a*d?_>y&D2bUdBM^n3VRqDj1n7shTS z>2fE}qc2A%LjU+J9M%|yfIHaMhaFF!PZ%2a5cT`gXst6>h(j-%Om=8h>_$5{gn|76 z5pctr+Tig4fRhSM12*^$INNL@Ghjx7kgA%EM+FmMN- zkx25aD5TDm>RTHE+RYdnnLR|f+Ad|+0YLzZ`Rn(mPb>N_IUAm|72A^Io8G+j`N7to z0G0-65X51CkZj23z`MKA@QO}X@})r7psokrwH=GMlC&1tsu3rkr&)eU)f}v^T4FE< zGJDyP;;mTK?hR+lmH=IbboNl;gKQpFjzqRA$5wJB%9jjuuz2ByPV4^%%!gvCc$k>U P00000NkvXXu0mjfTq$B} diff --git a/Assets/SpawnSelector/MapBG3.png b/Assets/SpawnSelector/MapBG3.png deleted file mode 100644 index 83d62de5354c154ddcd0b0b57600fbe4cb0a7b86..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4762 zcmV;L5@qd)P)FJw9g}P z-y4@2N1ro|nAcdikMCWp*44)6vb@%$G}_+lxoWQjdFRndCk)5Dm4#g-jLBngj)g&V z$P^*l>&K?l%j0rC=bS&Lz&e@wey~|f$u4zb$oovB@O8cKBArZql_gHsiS@8`FTu&J zwawfCaL${I=%MPEns!(nOM#`4_&5(I-Z1V*3d=^tb(8XW8DmG&DQK=y!%2LX<&*m9 zI!S$@gYN9;qwl9@DQ;7wQy!sNq-N=Kt3RT5HEeQZKF2;90Ka*mO3&W$ri8~pY=~Fv zRkG<=?V~e3r+O3o;rQ_QK=sclmgk<{#HD(>L%tZtbC1=vVZEu&H{D};Ppd|+dub0x zA6Z4(oG18-(e#{oaB`@AzjBiHPI#utW8fLsb_c#9Qlf1o z?KjuAN*4|67;+5s4{WU@g-BT(2%R`Ju`Z@GiSeK>>%{H(9(`=7r;f{4(#|e{{>u`n zBd{!LdS^<`IL%7Iu>bhhwy`P-Ju`vdT31TAwN-VkwX#B%AEdV4q>?%YiV7L@`9GB= zRU6gVNa!ENfZ_+eB;vBLSD=$5QUVTV(kTzRo)VXyT33;2(#b?{je=5}jt8BvuUH!> ztP~ylRI$=2hz$S_zgx8?{BScs*SusY;62qT;C+m z4=9M{m$M)-FpSf#jOnbkPOn7gf_j5)ABT}vgvT|Vp!DuI%rfkpJdffShK5cs7)*}+ zstrxkQ;eKy7-%PTg7t2G6H&RI(g}TI9Gv4!CJ7pmWh6{OUI!nyqWyT3mk;)p5P)th zE?}5oDI5sX3DnP-fUz)+=O@I0P${UVjm1X5y_R>9>Tl1TPIXcz;A#tfhgQEuc1UiN zzTw%gL}Nh)rxnh#d=2ePL^6pwq#imstdohfA|fTmwKh>d;VKqIPg^|sb2PFiBNdqj zmL$q^@>hB;APt?R2naOINn6d1BG5!)mQF9Z={n%nIH?{{KrtTptzRpCV zIuEl=h*Xkr`=?V1Vv`;XgQ~fOEG4*1uX$0Lmy(L0M<$LRs)U_^L=%xahI6mk?RcM! zz&e6lHsZ-7Nd3y_WZ)k8+*(x4>Zn&R0BQp28a-5Jy2SNe%OT;JHT z8swBCQxAmJQxWjCRxIZ=9m(jagURAcgRjP1-# z9!=`iu$%@!9usIHQcuIr-3=llDNeO|5u{!U{H?8mXfWL?(2C3{noBQ<+FT zDp_vR6p~fVE&@7FPFMihbXHrVXCAQVKkgo@MtY?LFSzA}1l61>H7#3t@#U>H9r+dV zCKKv3D%2eiwOb8xe2=<=NlYX!*U6O}{^fI+8-eSikhJ%SHyn%~^G}t0lfa>?>p?8r z3SKSocS+SS)%JXZXQC{0dS+)mQ%9@-K_`l2#ePehBY8Yj_Np!GRGBDUkiA$ZRI@08 zQthlUS&>L+%k$={KcLg<^y8d_HHrkNCGtoeDx3A%A0Gz+^~VD`?2nY!^(Pjs*+eIP zvf(%gh+3;n8hHU#EiAuPsc&242Z16FK*eVV$-3uY9FXnyX^lLpI~A%~;WfOlkuPnq zf9Tt^We4gPcxv0CYj;oS)br?$6)L(FjOdM#PZyjq{cseht=d{AH+uC1{6yQL$Lbb+ zw>O}NEswfZ7^Ro25xwdTGj;T)KRcygTp5Or9N7`=eySbNYwn01u|_nsvvvAJ<5U$u zUp`8zZe3?LAhn^7QN^KEZxGsILUbVJN=sDkxb~6ea7u@%r(Q6vryx@S#AuC1Y8%^C zwQbhJNW?Gi`>m#WK7+^drh|)*AGt2IMyG1~``u*ymCu>dqX{pb`f=(-70Z=u866S* z{5Yg90df>``#hca8FLos{U93Sh!pafbV%;>YxKHLRI$c!2!jAbmn`MIZjU;SO~Z<# zjC)qG=wfG;P}|<_p3-d)Q?1kO{wdYhIw~p^Y)c6N@ZvVFpd5`RWaBy(w8g8oFtXFn zlF5DIQ_twJN)pM}P}NGEke)Mjtc6Z|SfbQe3&Za3WyONtotUyiFr9US>wrXIqBL~ykpD{f$X{@ok&>6Z@( zGiZHdi;zXC{k|d*IP->zU>Ka$z~>d;caujDd{V)0E%@^aHc0#_h8RYc8XB6ITEWax)J32(p~ph>GYCo(+~b)lOFk<12rzj12$@v_`dIt zFm9z#CshEwT&xrN*&T4um@^@CRT)RqiFvYqwzI14R7CnU_3cVoK;R1(I%@w7FHE`Z zm70oBCU*a%M~$XK*3kSc35C#){w<9hgRedJ-fd+Zc>8B>PRQyX70S5p*Xh|StMsYw z?W_C0a~vA;iFG@(;(YGgtMsWSPw7KnO!C-oy>o-^_PT2SpAPdEK3FG2Hsgusy9-h5T$CM;Y1k(fT47- z0r3lb;fD!PSPPW~ytvkhi7fl=?5mOPQYQe_tqF2`=!~=}iI5*_Nxd$7{G(KV<6F^- z>9C^x>R*v^BH8Dn0U1?f>VIk=QwIY^V1-hhG#y1ClLj!kheMA>{eeokckXm!Z~Wbd zHkD#*1Ra07cO0iHUepGe5O_npZ9qyz+R+JJ5yyy3q$MU(A}=GDbiVzU;kq*u#o$Mf zG6fK41^_n5nnPy=^iYv0zY}GH$egT0K6CY>0_dza{pA`H{C0mF_b1=(|IOoDD#frd zpggD1KifTu=Lue|0iiq9#P~cv%8K)9G_RPxpwH7OD_Uhb2Bf?kbvjAXDH(Z@t$)!_ z7O;iXNs*~H3Yr_#bx-JpkEa!R`b)kdRRI3#d=&$ASP+ztypQYY)Nc31#OT>JAd{jvAS{4as?zw+f|V)r-0`QAaGBMBU(J6`4zdn$VZHn4UXFm_5ZL@TG{^`WN zmj8uIF`1^kZ-Sf)veq8+9+>$ay^V~{va$eWi3g-(Uitl_)B<`QvWVmRH~@evf7GLS z@xs&Pt6ByJfc4t1M+=+=!wlc{{?tvV(imlnfJK9=MUxD(AkP6znTWHLsSWm@e&Kw7 z6SD|%Rb=LoRs?C#JV(gtcb*93zVqa~85LCLeTyNBvON6u%^tnO8PSi%HT4T%zeC{) zSXX-;$0)k4t3 z8FiAgWacptp#X>lK};Hx1(Jd9?I(mX`G9l)d0w`c*Z%ExEhbcvY1G1?yc9am0c0C# zuw@{N@XJdYvuHe-u|Pf-Lx?6l8YSL;u`(6OMc~wY?N3*fgJq`KGDgz98D5-MB$@6h zgJl+0H%e69I_8;5^aw9gQ)IP~{Yu*?GV`MCJo8nV0%X=AWuAA0Wl)AVcGfKCGNt%s z!DI*P`O7(Po&~ly!nY&9{!uq|d@li6@~~YX=XnfnB99-Pcm?atgu}|RQFPKw`x3u* z$0g6p&h^!5Ql+7tJeKE+!1w+0&v;tIB=X)gMofMbEh^F_k^HB8@>*Kv1ag&)Wzo6N zZ7(^J3oxasS>PA`t2$+L6EU+8bYA@H&y`!0zM&Cja?C6z&I8|LdJg4trXZ1RvgDm7 zuSg8{AsFEVeL>Lo{-+2k;KC&X2apPL@-Rgdh_hz->cA-%d56?=?@_yMyUr#n= z2-Dd6FJ{YHW*XDwQIVPD1v1RB|A&X+Upzk$t@HzT-3fKw2|c=P^wp!favT8tGSL6^{ZTv)#{GwUj0!f zV@kQ==ghKU&4fPD9vaEg&r9N&1lbla^@ID^DSqI$;`_LNCKCAX7qe@)B12_W(`BBg z8OvIsniZv=GxgU}`f?mk?DgKaT%m^>ht$~o_iNc<|432hk!v${k_$qY7uY-LysEKUu!K2i#GJKi0jnf zTF&9v+oSQm1Q8r7|>CP;1 zzt|xQ&OAah!Fh_8?Q0g~k<=|9tcAUN$%B;MN z|IduOMSe<5<4J#4;u9Z?j4 zNR)ykNrIxt&PL9$?l#s|HnH+x4eP6$*xhcS z-yOhlTm*iwuioR5BrB-Q&tvh~tGN8dm*HJ~7PnvjGgRzbfEvK<*(fd6VK;lwdu1&B zvy1rn)pxnw#km^#TdlON&tH2P^`{s3_fLQF=NR7dkb6qQNB{M8K6dUaFW~-<-$dRl zpg22&-sUE9^*VyULvL#fYO#P`V;8nPK(1K8u-Aj*ItZfxiXy|6h^>uXv>Kflz+ntv5Ck+jo(RMkNEv#efa&uWapKu)sGc~5zPyZc3w;Js)isnC zr=X~DXGoIFK$hm~xcK+30TNK0ukl9o&c<~#KiU|11_3I7B${7356d3#V4!VxZ56Vt zqBuJXMb)4x3UY?Yzk@L3Ycy3uM399MVC_J<|0>>|?;>$}+c`8zNdrVi~? zY9uwnbv;;vAv&!tb~YP$^l%+vvkO-S|K3{PLA%vOzh^N=(tZ4bPlTkz9afy0!qk~_ zsGT^858Mc|_H9Ip4MkNTt1=`-!osz)C@s{HyP|RDnlIK+xflaTwD8bz$xVZwtYqLYg8hnnfp+-=n#r= zuY%@2du0SvD$DcpKqO)3joS?7u-SssZX<8z(QWK9ummWbBdH}gnYdV%LSXkpys-^b z78a2!S0G6$!XQN8#{d$T8IZWtPfWv8B)E+(94qcaAy&mTz8?cBul?WGBE>Yu(L&+O z96BG|hu0ZQ>{tSWIE>hPXgkcE?PdqNTTN`g{$b30pL+(uxdnt%CD51;lY5?oSWoK) z$_opay>JQVzxXnSUISO2&q3BD%s+bug%_qFD=M6KyKzTC!rdR!TlnHk8Ej9#;e>dXuSO4k|r0u)8% zK}h0Ia{7=T{St5b7nnn}e4fQEODht!iI{a0u!u92nJU}}u-iQhtsx(CNYo}A>Us&6 z`hFyLZ?B+q=_F)L9eIh+^&#tfBXttd=;KBt+-db~blN@a++0Rr4WTSf!)kPpe`X0Y zUwskNUwAIn#UwHx4^0`Gkz<`xo?C!v$hdl;if5iV16h$#y)?z*l||~Osth0*I;1Cw zD}{kWoOuxSH(MjzY29m1yl#H!9E;nzvrDjtL)PPxEG1%Af^S>g4&QP3`dE(=1B8gW zYlzn0fLX0UD->C;l9)|(B}~JBVfl#7)1im%?I}x~k=`U@kG5E&kPZdl z4uFk!k*`l9Uz>uYYAI6?COu`3NE*iaG!?Tn5P}el zTJQEMD$m9pL6ko|humxxY9V(lFonn!pwhPUH}CWL(zE9f`T-kOyTAH~jVsc}es2IJ zrymPQ8s(~yL!nk@k+yj41-$m1?_%z39q-?|!$3<)+?nR5YOvpm!4n_~`l51<%Uj>M zG4VNM00|>V7(Qgtj)S`S-~pG#xjD?8K8wL_Gu4l@dA^taPI`&^C+1F)nLGH|ttQM$ z1!~S@sl&kg0YXGD&!0f$rRNaVis-z09h-mjT?}^GC|tdO;)_oK)#9F*B^~O=TrE>a z@BH$8%zg11&isq7#3S&*28KHw$RrMrNvTo9z=r7DTt*ax?DmWpJ9M5zMZ15b7*C1x zPpO2;!U+_oXHhmxn39c13fTo=9VJUCpo6XUJ{N@OKmYA0H$JxzyB>mm_odG;S7xo+ zEU3Z|qTl4I#7)}+u|B^T8$gM;9o+zl-4Q_Y9YovjBUh=xD3$_DxT$tDsg>m{OHY*P9Hqn zJbWE~0n+S$3@~3Afo*!;DV{v{A-AQ7TUOHc|!zdN8P?a$^pJ(flT#@pHN}{u* z7{s|+tTQ)Tyb+*6R|<>vafrc7^rsNDNz1UkvJ5$S2Zk;4KIzY-47hva!H)hGezsPC zUMRAtMF{9KRTQpWgj>nOd;1QY^#+FRUMyCvAzC+=vHRu?Klmf@ezzt8CuSOl+#eSd2Bbm`k*cJs%Xd9= zA8erc-aWK$+-1F5CUH#0sL+{Y$&%=!5FPm>$!(x9Oir$9ljT!v97Le_QE3Nk8lC4BmG*YLs%v5O(e z5>_4_4HCH}f++fP7&i)ElfcWLucya_$c-PIaAn$b3FZ1UG)-fE(3DYCk^<`5hRrejkVvt!$3w7S;PTk>R|K4 zH0<>TyzT(xswl*bsuDk(e96J^$WGeV8UOlgT*s~d^1r#x+26m4bKm+pYR_LxK_lHv z;ykb%D24{TR)SW}kJLl@N7i)YN);AKi_cv}S@WT)DpXm)+wXpeYFHV4xCC}bgiDeo z5e3SM+QOw+Dvj$=0+E0d94U@vDZf->f0j9u5sl#Vda39o-#S)adjplh3_L{E4jVwS zroq~5BJA5x=4yy^6;88@VWY!f84Go;gRmeDWOvZ@U@R>FWJIbIq=+CJvsEa$7&u9Z z9~*iumr6e7B-xNh_Kzxa^A+aIjUT#tWM*?&Fo3W0qAhu83E@V}OUM?W? zLJZcnAlVMeU%AE{=ne+xJ=}yoQ%3I8EFv9oY}=3!$r6;4Q;^C9Xmb@-ld@u}7%cB{ z#|4%Ty+B#e|F55>#|f~_S8w3n|M)%{zrKU%&t5_4;u%z) zJ%h-Lf%E$w51ed$YC!{e%~~Nxo*c{^d31hk8nTLr2O`EKw21mV4iS*qNDu)>dNa$J zS-Ss|x44`=eI@}bZiMSP%$Y*;h7>GFKuizPu4m)N>ow5pXax;}`&+ZKtmK~hzmPdbU>o$tPN z8_tTu9rg67v$#BeY6M8ZmBQaVj^RUqlBgBjN!F{-m&BpMs(p|ENnDtnD$G}_C{Ir( zp}GiO;6YVL(nK7uj!}=d$QvSZ+JLUWw>(IuhMgb21q^IV|MQojmuj`tLs1{qjYHzk&pe?7j#5U2uW9HijFNd0#lJ?Xo|rlh4TbmnmvJW%8FV6s3?WL z%<9cw{Vbl#9Cu5ILj|yc><3Nscj8Ey-D<&VwbLm+O^wxsANcVMiyXI;d{MrH|AYvg z0BSW4XS>7w(fNzlq0N+G%uGQx6$CbQ4B0Lo@0VYC0l5o{@EZe)`@<(jF%|IBn4|mv zN=`*!JCIEkQ9tGsasId^>AcAIU`$uw>~;>kE(!vuMV+5FSlQsHlX;@fvftTh?_D2} zVwd@P60I`%lN3BtG+e!U5j)%4s08Ja4ko?Hy77hB5E}O@2}p75`s*L!g|ToZQ8sXp zrLEU)raF`Cf%`vs6VoS8!gC!KuZruSx4Q$`(Bt?jo14UyVH~zgB0=$qnB<%St(0ed z8+rkT>)WWb`zU|yMMQ7j1UdtFyB)?QckvVo*Dk<%^A?mSf>J!e{S#W)^D`-C>JMyo z^hIYr35A}I{{3}SKbiQe#~=cb29w{j;5Om`kfk8-5hk0U=dYfJ0tGT;RL@PNp}M%j zJq1c4_uqg1mDGwI7q!_rPN6S_h|L;8f=KLU0|%rpNt{}ZM*JQz%dyQsK@FkXlNTkS zj3^A^UH&UW&S~%lHX<)R?sY9h^)j@@X=t-Gpj?1dDMBupC_H}|{a?O^-fQp2=t(pI z9uExia+Bvo97Fw0fD}ZoNa1X39Zn(+`T23fnZkH(R3RsMY>JFJC8SAPX9&->;QA6| zNyP^@*BHp@vom<^+@*cb5Fim}{yexp(TXKtC&g(6SB`ThO@Rp_(JOpL60-x_LUVH? zo*9WE3_5L&+!$sdb}QILAt)0)OO+@(BBO#wn{UCEcOlJ3kWa`ceDXX3Q%B>wzd-jF z@4#8!grv%-eC8AIR=3dp#SPZE6r>=3ouw9msaFaxreZ%W8;Y8=e_ZO{TW2wQP;8gD z&|cqV5lcjADg@}nz&rb70R!o~4wgOY3Y`t0k8f}AOUXzqS^#&p*SK7M@G#}fAHVrp zI$I(r%b_&SndQ!Ljuar4=H{{ugLS_#5|gGp9=qL!n$I)aQ920?!o4(^vAJB$#MJVC zgV!4*p&}W^;ym&%Jq34t71qsVnm=Rz)0nHnTW_HA`UhN%%##aB%m@T1sUxaWEykT5 z4C6ePTs`*T)KdIXS~>3I;ftrzk~VRCyaYUsD9wEC>51pZOEs^sh?kQ-6vy=ng#jhV zc?piyM;N;J@a7I&sL)g$&s;tWLox6<}lSo^8`S)?B0HWC{mzTjfv;SOKOnU+uJ7~ z$?r6(2K>$tp)|y>)4|T2U&HbgymIj@9xgYb$qDe%9#`Mp*%)C0;!@J7S;HqwBI-kK z35EE?K7mB;2wAb&IBhIqV{X{nlKn8kpxxr%1_e5jV1fv+vw)@RBy|KxBICpy6q@z< z;5KJW@_W^CFlMI#Ie^<5ru`$U5!|gVf~_5R9fyz0^l;(~!4Z`1SDLS&xl~VqvoEP^ zI)_`UkgRR^yA)UkP2zc^}6$-uM8aV?(c3j^s=(qiBR9$=%4+OlXG21509~ z!9nP|=npBVEaMwX=b_4!mO+9x?ws43s|hzQP2|F?coo1-iqU38t>8%ZIn6u+OkBx< zx)eyU#g;1t+G(G%4ag;lC9Tk#5^Cp8i~vd57h0_XcXOA;uF!))(MK?}*f`4e7xim2 z=wa~Md+G61w$QvFA5diUFU&x;n+#U4@(}9TI-=bTL|4y2G89OKE&_WK(YYdnE$0p9 z(kzi2w>Nf?KRI*stP5FWlp`Z_GzSJ`PMg$p9ePfOA_a(ia(it2e5DTwIs9~E3;$^8 z6YQ!y_~9J}l>!G3@84%pn+@&#hhP2ALz_UNmVC|eIZgp0=}Y2H0Vshsec~i)3k!+M z5i*Emv6B12Vs|iLF`J6kWUHP#H3B4Ax4FexM6L_B*-p8VyMmI#igET{yf1MKn`WD6 zn$hpu>9w-xK;QFVm^la(jsrJ2j2x4n&>N2{pJ%rKao zD#GqbB62}~vBGg$elJBuWhu5hMu_Z_S{XsR3$JgbT*;?+!d-@^*>NVt$yx4CuhZvj zjVy8NML5dp4ba%!L3cicTFCPz7j@=F%;bOvtIUzK&z$K5h<~u=E z+ygR9{7&N3IK6a_yT-V3VJ4nAS=oR;utv^PeyspE_w+3ES{Z`}>#)~$;ajmckoFmy z)U`xcB_*7YIg%>o2RZ?yZfuoN8I?6ImD6V-eeNmv_wF%wvdGoK$4OE~&4{_PnuP7l2(HyfBzf5G5>5tm&A^4(Ip~T3UC|SZ zF=YRd0F49O@oQy`AM!s5(Cjf0G$2u%6}Kc-i3+BP!t_)Iq!7BQarQb}m5Rb80V&)O zPUzwwLWJ_!(NLoZ9%%I{Ksh}WI0*J4Lky;AunH=kUSPm`x0a!pVBcG>Y9swA(+{`h zLX^anO37p~OPrZLH~~}uN&BQv8Q{eN*W#H7ErMmeoU8 z3NiGDap~F6DjM9j1GS{G^`?|50~~O?F8W)$_|xxy58Jj5O*6?+0RgE@wRUA5@2p=(?d!9AFRd{V;B~h)QD0nSkci_*huTAnxsJ}$ z8XS7A(3`Ovf)vOs*YUn0L(b>mHCp?ZZBVXo&S3xBn66>C(}b&8BY0&?W`%K%ku)VX zdc1(aW4%dYmMGDmC^*v#4UwX~A|naEBHs6ZDl6=W%Og2j}Xu$SDR?NyQ)jyH{XdtKrh@Nmy?- zQSr)L5;qc;PzGPd9*Ma#`Q7-C0{;;{IsZIMi|SXW%#UR%Sn&wLW=PJ>ev z{dRysG(bD(qup%da+CTUT-um-5V1BBO_Ki*G#T?Yd90TiZ*jTuFHs#LdUv8l@ z-$ltPFn4Wq*3kT`P3AfZocG&J2GJ*DjS}IaI9{w)_VSoShM;&ivs~hdWbtlUAc@pc zkwxinbDQrG*YE@bfybF1HbU2fUM;a*L2VmPMnooPUm)T9fnOn;m zyk?KDlNU}xJ98egGyukwa+U&G%4a(S3?z^E2W11Ev0k&ry1576b3>kj253OEe?xd0% z>;$~tgGDX5C-j>D-+08)Bf6INlX9F0#KC|pm;ELt>7*>_<@lLy-$HkdxY6U7uIo6k zdtG!J+vqoU@#@dMkJYw{NGW1!zJ`)gh92n*V&qYfK149|IsO}X9?Yo{?)=qTaIV|D z5y+fZ;|0jo3m9IvIlsmoy0}=n$m=kTN|_Uz{UBcWL;#9Xuf<$E@-AaWOcvB}3I+qf z3-;?$0-N-2#!YdXi6~CyZ^r>;F-ulsFbvpw>_u)0XlT0(nBV9_sgeZ~LC$L|ZfW!T zw5CF4?v%U%!oCBkTEn7erS*w&(4V{jDQ$crUPMAMiF&elIQ3tapiWhwQE*~;1CkkG z*s(YSsOQSK*Rt^PQ`d02v4VQZM2jYfn-N;~HrNt$*AfGT7Wf8$VyG~dOn7+*!_EK; z&o7~QZxf29K|7_R@#+Ser3N+{k08$|7(DF8@2tqM`dtQ*^rcacflN~@lhhFLdtb1G zL?;yDX{+W9tip-huWQ53MV9pOXkRJ?Vh9Pk)`dOL1eEQo?%i#l5 z*2)D2ltAPgEBUyiBQUp8Cx`7J1E=J3%#Cy`%1;A>9!lFSI9&^cxiUn(ot^!2l>5OH zdL>x~M^>I9L8W{oLuX&i?^p<(KI~l!5(VGe4)W6#7+M+M`)C6OEy~h|Xx(X`JYT@h z>N-5vO+X|r4feJm)p!l43b~-B z9GPu<3T6Uc7SMPd48^G^Qzv9#>9=a;;1P$4JfXNUsQDaxdsHQnbP_-k`Jo5Njomml zkLX9XRQkl)7NAM27x@?r=2ilkvgi~qip8oELai6!Z?8d`JppMsj*SYjI?P0mj!P_Z z=_LX!S;OK((Nqj6W=YDwqQduFL`oZtmAf#DbzD4o3AcA6SeAmyVhw($i-KB)XYImq z?U7_E(ZR!3AGul)JFh-M@r4S5L>#YOG0=OviSSCqqB(GB@#`>I2;?JFL(V|o*KXko zCEUutNf&0)T2f$>W1J2o?}^}mj7(w4(wy%x*0GYfHDExgpI#iXW{HXg6Je{5fKwUc zyn0&W5Lq4~*JmKBiUQXOP;w*KN`Q(T!RYon5CYDa0!NYzCX&9h3qrrD=3>sZn{XTr=&{#JP zw%go+gZH|S>oSxX6`f!2!d~q|uFCL+4y1~N?t4v0g_t{syEXzp)|rxez`U?vQ(7uu zmb0FwDLInVr22rf>jF6%Mx-Y=h1z* zij!aZeEczop%c#|N)oS(CcRRBY5~rmi*9Eb!EFbsY2bIyT|o835;Wb!Up9R7tRJD4 z>!UGTkF)G=#J0eAn~1EI2b6T!D?KPvln`!AiW>C~Ld1XR0T9XxJPeKVO2~=pm3Tp00BJ0Rr2j7sQo|&*0kU|2}^Bi)9S& z-GFCL24=)6r72`nhwM!jgW2n|=O^V&rBR^+J4#|VY*POT8zgmU1PRMGGXVDKOzZM! zrd#3e$6V5fhYWqxpvgu%ChhNQTn4;Jua+IvTBXdPECQ0KzrKa)#dFyG;Pyl#pmjIS z2GB|>2GJ%q?mO_D0W5n5Q;V1JC;#zVcwCZ+V-BFyTFnA^09TF&5%y7%VtEveTfE~m z0%m{d4D{(dPdM|YY91dnHc=_+%#~R&JKk8KA5w5LFD^uHmc~1QXA%?{ zP9vWEAhH`RRL`G7>C`FoR#qmyOcaD@++0Wf$|C&M5RTQwoB!uK$Lgq&dZLhlJWRA6 z2I67H&Lkr4qhQ8J{bOOl>@lHB4+OJU*P$tW`1hKS>;lJNl`Bsp*m=kefBVr2>&;Hz z#dPL{#ETr}OYLv`en7|Xp}=zB?s2l$>!Wjj6_xX6;j~+DyS)SNZQfju>lpij%3-uO zV{OPty1cbGdl zjFlNVhrPhQcqNDF;!QL(TMsYS%Oph8yk2*88ST5Ps9wAPEi>0T>7^x#g&wHu_WZUi zh?46b31qg-+4nmxP3)_5-O2Ip9}nUSN{4Q#>4L|4Gl}R7EKV(+);iGC(WUB@VkH%` z;zb4*FK|gBd6Jtli4N@q1~W0q>DvXG3b)mPPhmt|MeWi>Y`^o~k)5DqW-^FVvjK`M zC-U#d;Kt*;%j1gMC!s8$O0i!5wumVjcEC{|3|z==#J;6vx#&3|rYm{=a@4@~ktS|3Jd+_rF;llYK;Sq$XKGZd zFsfw?8_i_;NJ^hKUSIkg$^fJY4yAHXjFjeWGac!S`rhTC|grXheD`G(slg+;8 zguy%RJBoJvHg(_Q7)uAyLG7VWc8opk@SBMx>caFdNZ-agtoO=-Md&A5+)qO+}pkczD zinYx^uJ6*yvG}WvNy=u1kqy zliKVb9*xRUcD5(WiIZHagYNxpa^B-o8eo_{zqD_7N1O%{a1Lmev}Av}T0litmIH`LQ(evojVdKvwq7({F(?25pM9@L?{C}qjc|gA@i9x7}1+nxMD49~|`J=nU zhBC&xT&K00x`Kk4!;rq}EQj>jkMul!DQe^)ymXDM;b`ZPM3*zUgGJ;8oPszH9 zK~Y7afBXRyOaL`|?C%`(1LCT`32`r~GE}QR`f&#$r9VJWFGFc|xg^RzYJg{^DcyoT ziz%y6as>?PIsSYJkz^!Ey6rgUht}$6DI8Az=mU{XQ|l8%ho4uW(szV1O?OQVnh>Lu zsGV?oB)$oh5Zz_vRpf`!=(Y4oP;n6rp5t`b_~4`G6EKrFEpzcsB!c-pb*m35%R4MUC zi739ylw2#x22b=#JvT0O4RS8x-$;%{ogM?nfM>ozD-qW>hv~V4$j_;es`Q^i;#^y4 z*oRNA5lZk5`lRgy>sqdu2s<{kU{6XAaGnzJNAHQmIXZsO01)7Nrj|+T^s$fih0V8O8_e6^DJt6mWAi? zMciH8fkhpkWiB!INsDs{WU8A=JD$Z)fu{vYxqN(`xR;JqsXh-Y|#>*o}%D;H!vEok>W$8KIzGG6|glxn!84QA{#V^AE>)(EFN6#$4?s-b)*A1Q}_75JWTpb zB9dZskFYP)$N4a@WYDM2;`pf8=aM><%wu}#yasu?5Ci3foSwH4um zDcX-HGd=+qYRJDs%CaX?k}^3jCEsI^wYVNJ2*Q>Pxn`yVDLb%6ev9XfQ>OC?NT#d` zn$$npd&UN5_E_3>#L_3dpZ-veFW=`M2(VB^;v5H8bPZDB(@#f7ftTHn8pRbSa-Rt&b@g2>U2|4euwNY$e`K!yuP zt{VezT=YhcH3}TvFZM-UlYkZ1CD%j^dvvhTx|mEGN1j9X1lpd&pmPUN=6%xoGFB=r z%||9(GNno2>Y1-v|P_`??dt}6OhI1vU`1{YL$H%#F5(kPGq7E1bjVl>D zJ`Ql&p;^GjpFx@P6FP$0L&rtC_;+=`pA5$uxo-R!yOgwWZVudNTsiid@6;$M6_3t7_}3)O&lM2@B|P?A3mn=#i+}G zG!EiKK#0aVQOZ6$dCoq`k$L`+AP|Xn7{B%~EV129&@-4lvE+}uTV3CD_t)R`ywCf+-_gB7N*qI*c=-QTM2I3Fh!R9ef~3k2Bn5Ir zfubmoG!05jhn`F#+LMMTi2Ri6xu~sXQ7sl>RjP0d1D0jMu3PXN3yx{SbsTuE1J~sz znmI~Z1fr(FH4HdLeWxoVgiqw~iKIom?Pk2wh2H7(WJv-f5uz+XRwE3Y7KxV6$tocTOT-~GpXOHU*=icmBalA=I~MiKAt!RSLD!hw%J zjlaFs2PrcRX=NIc;6aINa2Mwwr{WA|z&K-W4qmJajvR&8)ek9}f|cHd-#_Nz+E0Fl z**D)pd3hC9tp>-kU>PP{*M+309YNb}{RqeoI0<1ey#S17M|Hd~Tir4!A2c&Jlbxd*-4`(P@@uFSiZE*x*oFzuCe!QgSbMF5 zlORQe6!(z=1k|T*V1CarM%>C};W_rEGoiRtu&q3^-Sh(O9Q%_$=Q2ChN?SYuq9j99 zWvEddvF>h+KYRkG|MJiAqI3k;=avzjy990iJk;VmBHcYGR!oS+MVQ$oC{Z1ftia4? z;JGf8hz>yzAc_J+&xMm;f+`E}7A7GsPeaH|;ms=xxRJUKzw;+wKs}pgPR|oFy$`6f-m&yIvLb>kK~Xg*dKB@VH17YcGkAUIX*h-3(5);~(Skd3 z1EK)9E3<$gK3d_y)}R zS^oz0N84cX+S(~XkVUAGC?atk>G3g~{#W0?*~lRn*WN%^!b4Q`;N6}@?C4Qw!z0l4 z9|0U0$jw8PRVbtP;nax(m|s|dQ7IuhaRgqy%uE*~iOr`LPcl<&qs|P5Wk8ZuAU_YG zxC~)+7MGP>_}rJD!Rqx%jz>!3x(?t{_vYPGd#;633z+K(WlSBmb^RJAv=yOe~vR-3Qdmkcalbs}>;$ zB4jPXOr}4%X9%LE!!s&?5@CQ*UWG@1*0OjjBjUIJ=!;moa0zCu=Cj>%Au8$y-Ng1} z(_m8JgT@bMycrFnd(N$!s83HZkV}96-%&gN4xDOr+m&e7PC*nQD>AfL41N3d;KTp= zFYpg<7m+C4gid`YJ3>*!9z20LSI2E90&Q%Z%TIvPQT^EuAW909@xxGD(`Tb7K}z+Z zwlD)#k5NW`jRX;5Gy%7`;upv=;8_MheWYyw#T5wE9A3X=;4Mwp9*R~-> zb&US;H(9aCx{y+KQtGX;chg{YqV~p)$em~Do?R?*!OcvD`?#HQmdI-rWeI95ip0Pm zPXGCz;=A)v#530raqCDNJHlXjg)+QC36b#$F1vZ<8np3oe0m~+DMNu*7a(;HK$K-j zseT4g>gx9yY1bG;d2kQBN*+?*7~Iu)h}{F&J(5Nu5ko#-pk{~XxPW5gfb%_NfO6TY?$dzd%V5~-1rJR zJ3V;#_rHQ4n!C{Lt{~BuKy+jnk{*Yw$MBhl_u%M}2~1lN7?-ZHx%>R7U6553*J}#w ziXVf65 z5qJb>wE)zLI9o{Ilh2&O^5v_rYIRt}BJ!`k0xP$=rZY&44BB)@nYmVGrSos2eEuEe zU-{KNna!;@QlvzI^CZ!mG!LE-isJ4J4-$`cGbrTq56MyknNImkHud${DNtU6;b)<#{ar#?-hAy*&j}EvPP05%?jDa++P9ZWe zfoFH=m@-sM8Y(_Jrr=;o#P{Z0RL{PR_{V+&PSxR185xE;G6F%8VJ|MjUS3A@!Q)T{ z`WaBUw+C`hn#M4EJdpCREb9=W8tl0lW+r5Xhcz?3Gk^AV+7OLVRd9 z4u9$?{Gc|5Q;8yexng48jo=d#aUAT`G1of*QPD7Es`%`wW}q+fz^>=2DkRkIoM0f_{|50Fj;g^zjPT=PZ|$*18-(598I|B5-cp`4Y;+E z52j=Be6UFts{!V(=R}-7eF7_2uE13jJnRwlo*ijlNl)y1-YsYN!Uqu&kg<i;*KmDq2}`vqR6Png8pCZjhH0B7)uRwq z6}5LRFmMDE0s77_-s1BxcqE^lNaBh92znKZ;~h*%xO8m^(G$lpRrXLje-X~yb(k}g zn0{{(uHj;SA&bEt9jk(d-Tg^qvqg4vym}o_WO&sQM91Liz|Z{Qzrf=4Td3T+0Z&Q6 zE-vjz`%0Q6Gc!LZK)v!x1IRfBWV`90x(X#d0!1|N!0&ts-?{3bOREDnrx6(&gQyXR z5lFN`qG}Lig_%dd5kSOBYkq;R5s-g%G=-O!edkS_y@5(3f`i=&{LNIID~TH(tEj5(;Smf zI<@of!kxd)9yHAe360RpE%MmXSzh6IZlTEiYJY#1ACJbtf(H~c!0ihdJM|be#e$p~ zfLmSNc00&DBN+dqKj2V`YD3QpYRoUJ8uMp*o;w3;dIp~7FL#FTf6yT>7`xcOyB{kz~6Gw>V-Le~JCm05VQ%3iLy zyo?$|Bs>$KofmLr&13e-u4??}PW=b-r#>KV;hsrWTDNy>|l9+6wgU5g6Ae z@lxU>l!S;Emjp<<$UqXK^phu=X$R)^V0U0beRE2H1|~INFI}U)Gdq15kDWM-zs3o; zrh!kU4b)2|{O|9-hOd36-I zyYRYj82Zw@Up`rfBr1H!y?xO7hhb*?d+RDZ&)xbA6_sQX+VBCt0eg0>8yY7DnjsyX z;!y^%z4tSlDC7(`NVii+tTx}C#L5qUfFCT29MU;mS9*5wlv`@|VW^4&(KTUBPT}Ph zB7ndw(2w8GVQYWq%m4V^-I`C#r6U|KU@5Va9Hc-_J$MM89+B{^FFeNQl;>=@hT(V= zM^lYFLwS?9^*V1su^bNqnbdj_<7a=;1d_zEt9%6Ki6bYu{h|{`JGNtF{4gfI@l6g% z#9iO|w@@^j0kv0WIAS;?(1K7KNyC10oI^V5`&~W{$5#jUBmMMacy4bWhjiX4-Hk#a zK7`8kcVJZotXz4ULpm1{!*Fu9Aoq?Vo|G{t)nMP6fx34$>hE1e{qhy=d#dl8=g_|S zE+1h)!zP!m1xHxI=9Yf{N*%#pzgu8n|HGw1bM}YiR~Z+tth?0!!9jSd^Sr+2S}Met%F|GGr3UfP0Hh_4pCg5I zRtvb@KaT8=UxJy-K~NLTbhjMR-kXISoO<0)M--qW(me0F`_x0oI3n!jTM%-qJQSfN zEE<|Teg6<{=1e^Eg&GW6L9*&_X}2CZL9{&PxomcA%VHBee*bT^02u}_EJ{3z z+#44-ouD1n^bkhA`X$5;9mTU_I%bFOL*o7;5MQ`mMdpPcapXVxN{5DQwB$t_ zu&BTA$aFOpf9d%7rDZ&QxEC*;U+kD}n2pKLe--(+e%54gSb{0Prg$D+xNYNyvlfyg z1DMJc@p#&06B_K~^Y{ID@OTf9&tRSjg2!Xcu}8nYDImH2rUf}3X{kS9HUI7ZiQLa$ z0^vs?or|-7`)$+~ms%pnZbo^33r$zKrUM~!$0HSo#`#>Kq-sQ;&c!wS^@< zr;yIYPFi11-GCC;`H}D5rHNa{N*hQ-IUCsG_f1P6Ng~Yrlm}UO)kxY1`KUa zHwdHS#}Iw;B!}z8TQlt4$68*mNpJ-T(?T3V*C3RMalC#l4ufLjvypfN^#%J5;Fq{01beobLvk?gb^L0y$WM4 z%jf)TTe?9Q895Bm%c1Y^NjT+Mz8;g8&^4573B%91#hcJ~-Or)Yvk&I-b;#-6D9_En zs#@3;bzv{vLhb5RD7(iX_Kou_%+D{(!=(jYYET;A-F%l>7MNJ_P6G*mTT4iJDzCqZ z${TOO<1Lpas^`z+(S!-hFmNlI$AwG{S5|$;$0LVDk02%5&|#y0?{BWly3Go)vs1fL z*pZo{DzVc;>?H6gWHU>^HTuu?YnB^lrztSGozmqD6&ZbJK8MeY>PU8J3>+(f)XhgA z0k9<6&_SptCOG7V@7>4S7VCBdjv9mEh;YbTv`o}4UxBh`f*JGpo&>W(8a@DN@_HG@bClUSdFFmo|DVrcD4>N+1q?qigwaT z$v(V$Z2|g2AL3!g&_plJ{rJaxzr3;p{m`R4RH1`R&6|DstxS_G$wecok2pv6a^*}n47>`pt7TrSt*BOE6hKZF@PyeIX5v;%uq@rdB#^tAS-TFXBHXe8wJ!;~T!orW0FK884GToWg-~_)H?h^t z6DwnIimMPL9i9k8tUF#|*mM%pItj5bU}sq9nkKBU8E;;r89UyUCqhrga5ZZ{F3ceZ ziAhL{!X$IKI>dMyVj}H7N9BumL+n#kuyU$cbW+sKiJTjT)V!@v*piCM=6*~A`3v!I;yt?c^r>p3Tef~~*jWFmN z*OG95+38;36mfbzdwG>#>e_{+$yr#bQCMo6-@2;bm|`#{GM> zs(-IeY&Y=WfpL5?ZQ^@3D*pI->YN{sXKzfH(=-EP@IA+@)HqA(nKs|gI=E5BBv|FBCxdWUaHABgBn&)dV)Y3#| zsi}C)Lndc4)OT)Hh@E6Tsa>S51J6D$#d`e4YlQX1R{?s(yU}0qDmp|StTV`_4axH0 zNYqieP*O2CE2|LtM<9q@Tp3LnL)5$iseWryg$jd7AeNL049SBjR{5ac39kw#I_{T~ z-rS1zK-6S@N$48Q7iVunG)hnh`{9<#e!9Gq(L?0eaoE{a-m~M(PeO?Lz-ssH=OIQ{ zug-63-BMGqOLaK;Wd>5{8HJr+hMimDrL9AKDz06=$)E)ifER$f9-!^O2F_9dYG8)9 z3aAhr@xg4rsrNhzA!5MEFZ%lJco0MWe90cZIppvB;pR)I*2C%naE9M<9@M*CwJRz$>|5+*0-apJxa%vVU6 z>#%dnK(dctEm&C2!>qMBc>!<%z=6pPBzQHj6R7RL28<0r4X<;q*N+mI!o;WlOUqt` zTIHpVk*jm(pt~Ye1&AmTG*!lYs&$2&Jhx^AErT^RW%?D}2uxyQLA|5x)F9#Xf;35z z(Ni31u?YH}IgT^C;`mv~!>?Yw2?&8-E8vBB1qm{OQKg$2) zuPc&#^_$P(cCn0Ky?(tpW#_+_X`-}JysPYC-~wj0gW29T>q)q;P1K~0UhZ1`X_J`* zB5D0vq9h0573L6+DCq4uPHjmKuu~MQmD+p`C!_N(s_knjC1a=`Nsd%s`ds zb-WU0k|`MHrtr*15993QG9*-hLKblSnIE~Y7v`<&a4Q8kN>=`>z_P?_jsY5qY5Hh}V)Gpy!C{i@3 zE+8)`9f1s&vwfV|F2StOR;3e5oB4!*4dkvIYN|irZbqzXD+*h_#CN$g8>AYR; zfVTp4=t|eq>Ww6G`#T(JH^=bBM~>nj=zWjNKZfk(AQ?4OD|?V=-IlYVtVGuC@7u?f z;cM-()|hjveQGd94f@h{X#um06=;2FUU24{OBU?RDg*lX?oqrvJ&ROKV^-GqokFE! zVdm)>&v5*D`S9!rwuZeh>fbiAV7Fu8olkTX*%zY7mfXF>)gi zw_E|{gq);GV2I~X2q2FQCUbD-$km3HEUL2Y3stx?i+ojIN3$pPz) z3rOk1h_7BkvF8ZKA!ZiJ1*GCBSeCM75Z_O2Zci(#0O?Y7!>L08FaQzC`apIvrCR~$ zUhCQZdC9SG{9Ko%>BR94Q7eR^Uxu#`PIUT?wed@P?J#&Oo|TT483m9as{auW+S{O<)5i z2K8T0w&R@LtFpHDl^coB{nXdIwJOpwyK(a@&;F3~4)0=iUMMT5FTTkuEc_1Shz{(Y z;9YyJ+|%@gw^Ok7Dt9m9cF2FbKz1t6PFS1uELpqKhVzp*GuY+(6DN_(yu;IY1Y{tQ z!G{`v;*JNLl0lO&8#VrVUhVr~qTF>Hu(i$|dVO#Ud2FZLokjzjiQ68pX=c|eOz=?M zy5k)dmnR{nj-z}2H53g2RjbOA^7ZmXUOkc2jT^CD!iu$4g|^#Ric2pC+>uVo+dg*W z^Lz9@JC)^LWv%kahSxet5QVnx!^BJynwupc6R`+1)kY?7phUa!(s9_dbwq770oyTU zJ84!OEzz2GTbxep+^I6`G;`OIyJvvR#^=L2NVg)vFdO@4t4j>zT&9BZ_VaOlIC9J1K?yAq)-j8R2`9*M%RER+Vu{cpqt zLf^d!i=_D1C=A`_&ya<$H=l3h6L?b{#LG`Y=-RjWn%fcY5`AtJX!Mr^q%Fxv=2uYZjsRu@g~s69$@@FSC0+45r^X7G zQ(x!PVp3@LJTL7udNr{MxUKhuS_W<-KCwJtyJxoT{3AW9FOtjM64zIS)os>HFoX=aiy-t z(1px$qc3y~|2uNxKpgJUoh2yRKrN-CaI$S1gPn#lL^L?r(2|uX!L`Z&9rQeXmsipu zN%Y;m#q^Sa&7dJ?iQ zasWU}7zmx$9cE=TrlHp8GxIr`;#06Mt>e7WXy{}DVpM?}Ol}9m7(oLPD#ViMhZ+Gy zU)xZD#x)d63>*PY8?>6z6#??~=DoE<(kvhqfl%;GfZ)>JRbr{=1K&v+JI-6u>59V1 z*C1+l#?cI%L6*k1Ho-l*-jqOz8UP1i3ufb87O@If=!K-_;h6r5#9^WMyx-SsRg`tD zPSAxpA!`vo^+@Y7e}unt(md5OHI$PI_Q@)8WrNw-*PUcjYg!f(x{m9!8C3Uo1FqsL zKuda(4|2_FhFk&qoeP=xHYF0fBh9!iX_{;7C+(u|mg|0+fg-i7zuqOGaWg9w2`SiG z5-4C;f;?!ykjb83Qv^~>YENQbq0Z-CO@$COIoxRx^pg*5>EkoRoOYJbH6a~^sQG5X zt(g#`Duf0=UI>ifT5z4>avD*!aR6$4<~7}{toQQO|zRn7F>$4sf!S|YE`V81s9}b>rn#3qMIwD-d;X+Hjad(Oom09qxivj@N6ewgLpxlY(uM?43JyO*pd%D!4^F(hSlEGqL50HRBP{LL z?=m|dPn%x*nuYzdNzdsJ6yy%cEThTguir_nG z4L0*>002ov JPDHLkV1gp6sLlWY diff --git a/Assets/SpawnSelector/MapBG32.png b/Assets/SpawnSelector/MapBG32.png deleted file mode 100644 index 0061a6faba6c83e007299f9cb4a815edcd6c6c02..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4568 zcmV;}5hw16P)KfrW)*)|L?(H|W%zyI!c9g%IdtMli(9+{|AR3Rl96~jxgGHiena=hy-aG$Y_ zS_-YB5_u?zTOsk{^1N5ZYd@6b@sq{OB^hYjXs3kER3fk5pVbF{{=8~lY<5{~Ki{}S z%5{SZ?upIztb-)5q+u@>$Agz=N6`**sMg3mTieT$sK=C0mRCaAmLOFH21Em!^=3Dz zb~T|q+Yt#^QuRT$Licye-Z5Jal~75`H6G4Gy{U8@(xCV4GfAov7!mmv($42aL~1(| zAkGsM5=!aRW5ns=v?FxZSFKg`)9vT#w;$ejzaOT*=}DMJU@5%D+qGI^z4=n@CcPn` zMosKPd{3*w&kZ5o*v&E?c`DIXifx%_OuITeuI7$3Dv=ZvOLo-0kjlQU8DKXB+q|I? ziHGS;*&|X!YOm?a%M07a1Ci)iuYo0K=}10~X*vCE%cH(pXOA#j#@?q9fIWfyo{I>Lj+Fo;pH%B`tYrHtnNc~k=i~idNTS8S&mfVJ1bX`2o+ptYM;lwm zLywsHIvFpOQ14uggbKEBuRjn`{c~XZT7mIEB9AXFvt^Zr#2nf7UMSCd>b0oT;&gA|)W9q6 zcCIx(2Jq=&JR$nFa{T%nnyzm^VskgMq<88S*Paf0s!CV{N@Y|A$3ZluwiKtcqvUfz z96z`>>XGUM=-9S%;~KhJB|!VJ4e^&&@cjKXBXUKc#XIGfNE*lX4uC!PWU=Tzlt!;X zX&B`s5%|Js^1t^sO3Dn0~GC-UpVv(>^(9 zN)j8r#eHTVy`{LlTv>79tvZ|mM7SdQAiEMs%khh&hT@ZXCBd3j#hOU+ps^2|fz%eC}0*4QbB>Y9l z&?4!Y5Z`|LO*eZ|zhGNo5XImxRBZjSV)a@gZ3s+zyc!N92o0*L+d`#tz4=lTd3khF z@=9IY)k3Y+`tPP8l*g2`Tqx2;gCY{`cO`Kzef!~KFMR#>?1_L%UBC=qK%<9(h*!6d+O6 z=*{YD%>h2%HFyuV<*2`-LAVYI$RLmJB$9@YjZ!?U*V(Y1b-pQ;1HaCInqnLHnjWE% zdbRML4bs>K>W=Z8RqZsU$?{a&rcn}UZ~BR-pWDe6!BctFB(TVaZoxl)ES?P z6f%n?aXRaQrt6IYjjUW(-8_&&HbFtVr znD*&tHU&64@y9AOzDh<-knuNna(=zs7R6pwmz)!ovP!zw@p|!Rhj4v2{HA2(2&LcnAd*`9mOKtiw!QxP>`T|~nq$=? zQ|Hb=qPi#A6G|;X3s3)h;~_}@?=nAmTOyH%UPnTqO1l6;ZOHBFNd&wLr}}7tlU%+d z{+5rz4K!cbx`h<72a#mOOnU`<84L6h`v8=usC(B$hz9ahVBk<}L;}Z5e<|6#$L^tV zyEx|33a-b?$s{>RU=5nsEjjN3Gt5)I{_YR$J@!c1BAuTJa%{X6h7WJf2aw2ALT~Dr z;^yYIBa#M>x({PX__ZV$WU1dszs`fT=%Wh+`Dp-O`+L)NID0h;3PNo$ni26&P(0o zklvzWBERD=q|yrryw&=WZ9wQ4qB$38Rj9f+gM_v9W)O-?L4A4>Y7xb8EnIdeVc#uw z)$MXGl}a=uwo$$Qco3;r5=tWR(x2$(wZ^OU8~+!Wi%R#NO+sxXiN+ve%@`_FI#ZqB zhVc}T&f8_<_m?El5rf$5$HhzCz_6BXmrvbTX(yWjssk&{HXq27HWJB>!ep(8$Xt%k zYe5NQ)`8wrC$~K!@fSk{W7CYQTFs27N>Pj#Y@89(pe4?$)3(eDwRl^Y&Cxcp_aHqGx)T_AChj9>X zUe?XJY8C^sTCjFjVX&yyEKRV8)@pFQ2jikPTJu(J3Bk;}v9NB5U0B4AW>;9`VzR*H z*=|6T=K^|uzaP#^q|94Wo1s6dU8rU{wBFJ)CDlfEY$KP3=w5?)rn6XAgu{X6E@=Qk z!*+hAz+S?vMG7MCR+FNYWP~n&?ouu51CkPg2O+BCsmHEN`$8a5dr59-gRZ{PJk{6Y z(EFSwa%sn?S+BNJ&AQ~Xxu}B+wZcR$X0)s2;@@p)&zG`!3?SPvC z=HC9f?mN{sMa2FtMX8%|>X0-hPe@mwS?p6}hOyVwSZSB@rG_*w8dnc*t+!$0w7pu` z_4Qr;P8(D&$!^mJ*v%$1q<3c4Hrd}E7{|3bU`+0h1qm-*8J1gqkP6$CrdskIY!UMC zSUvZMw3vCBcV2~1=J=w?48v(_rFsz!E#n0pJVbe?K$ikpHCYC1a9!lH4T!a>RT0j3 z$ThYz(&bR8JjA!G6Qu*=NZS+Ta!cWp!B&+{wN!CqPbxL!q$)Ye*ejhT^R}x&xlccR zE|R|afo{&Bn`5K^3027?K{i~+H79fxRdlS-G#%=(nl(DO>G7URVb=%Zp)i~6_(}J~ zgYB_QvB>pg8|U?;c8oE#F~mo^pRk-qr0s0peB~H$Y(!h=(hxhY)(O?^b}z57L_M)Xsq48_pXnZ6(8NhreWBI{Ip!YxkPS$%?@U+{#6!1$)=7i!F4DomkelsqjLEnApJYbjfGX_pSFRHoE* zM5H&(<*jb!Un^})l2hsA_4GYirUbK+1wJ{b+NCi?mCc606cKV`wa0se=rQknlr%jz z>oAoZPOqg1vwo)sjq;F4blQ@2C!Q6HdoVeG^Ig%hJ{3AU?h;8Q9EmhHda~{bDyNZt z02ZLm@!7`Wyr!2aZzb6hIX3ukS`gK->Xl%pRB6Prfz!-5<{{d&>H6~A4eb%d^O<(M zOF6dn0DZP!4rh%aT@cgdlD0WMTxCUKG-F-YmUt3auQX$N=JV4ava>PUwCM-%<|N0! zx?{{`?UivNX*{lf)rarqCtWqX-)fE5M%()&yOq6pYVf8-=Vj~BHDNficLw664|L(xrS1yDz>p=7X=}es+x^8t-Ib} z_S7pKHvo>EDxJBtn6}aDM6l|(Hv_XVDm;}>l-qu^pSj;}O6!_+TLjcmvcB=?*&}Ro zPI1wCwE|NI?dxYdd(j#R2SOHY3^7_~zgInzfh%D%+PS3M4bcUJD&cw!(llO^{B`cE z2($1=^u8;+{RZvyp$8o&Yj@=SuGeX-FG^@^V0K7QSc3+b2yLNd-P-)I=SE+r>fny;Euv-i$cqa`~)yK(0Psj2dMjzIy&xT77q z>gya~%BkvE=d`AR=FWI&(WsukDsZLJ~;U2o2jnMJeMwN1ns;kpV z;RQBQbFDg7X-A6Q*CvN!sR3u2u*so?w@X*a>`JjUYyG3<@4Ms}M=8M=!8Om=*aCow zebuc`>2HcL4_06^Ri#Ajr7+B-sD^5;P?fRVw)#5QPtYgwsh=9T`j5YIItZT*lI)xr zEw=mQZ-4oIXJ1$wTEWR@`(HHhhT7v%VG^m}Mi)9xu$-P7gJz-4Q|~()_2g(;eR}by z^qRTZn^0m(!2igne)ie4x?K(T{Zmb5+lciT6FT*>^+0BCw~?GmvnogvaJ@>B90ebK zb~3Nds;|}RVcT0IgX5G{oWpPY&8=&(4fo@ES~t>C+IHZ#eZJ|D7)>pCK-rrg{$73f zwy8TvR3eo?9ST$cQrQ`Ypp#6`I}5}^QbDv8&}4WWl1NARsPw%2uj ze_cz|yX%kc@&JU^>~94~{Iil6JSQg{45Fu&_l4J*9NJpV{`KP@@!j2h$VN{HTANA? zVO6E7??|1NN}Yu^;)nJgs%{lfx5UHKP!%eaWa8`1kJ&opkRsOx?>&ncUWE6&_PPnl zgt&*>NvU2YR6TfvS~Bswlr(Ml6mq1DeHL9~Z`{LpsIXKBA@6G z!$hHyqXvst=1`LFHeajD(|6r>0Kb)V+ylRPuc$*<@^bJxK(hQBNi>Os=Cou2otQ-~ zfgKAQqoog?KU9VOzu|*J?id1JBe@ZoS7*l)J@*R~Rs`+=LCCfM0000<9|j2|&AHO7!8 zy;MW=fL@HoC|(Q~#m@_Rkr1QN3tqslg9PFM18tPFA+1#uiD{LZP|`*zyq31_l}gwA zr~NPgozCpn+qe7Pc791SJG=X4X6HBmnR%}dYScgc851zY6Pkj>pqUgN?A|pSxyZ#j zHNi1yUm7Gb6BUuWcg?adzAIzPDMC|86bZyFGU8dsM45>bxl9L>X|0)>;z!F&5L#w} zh(xA-3z8t2aqldb3woMO5L#w}&@vN*mRTft*+goYMS_=2q?VZ=icaPO_xu-k6AG51 zlX>>nm2o$rU@1D88Z}yGg3vM(gqFD+Wp2LxW`0|e05-?mN1kO~ytE>}ElB_uWA3BK zrrFZ+5@m`%Ua$MT-|uy&w2*ff-Z`q0!Y|`4;z_CaRwFdH@37LHlbnJsaZx-M9gda zLHjk|q`ZzuO)!GaECu`4WL0%VQKyKQ&lN9AitM_pOt*%s@?O%JbjDNax7@JO8KHhv zyJYS3+FwEOBih*BanuZZ#A%k|WkBajN{fsJKQn_<>V*ESNdXYnlA&c58BRiNGFMlx z@|60$zfjVolcEniou2WO`n|tU(tHfqLc(}#@5xa98N7L4mX*}_+f2=kXPEJGIa^Ll z2N;N63GI7}HC;Wn{CMj_O1U5rUvss3CrcXBWF`>Fb!MaGh@wM_OkjQbG%GDzh_oBC zS=%)@FP=-H$T$ggHw$v8Fc64xWqD1wtX#b=ZCO}su1uwJ7HfNJ zQn_vwnbWq+KEjpY9859$F^@=!-XFC;DBx8 z2N8(WRh3)9;eOzwV}p)m(?CLG0akP}fw_UNY@?nYm)!qUZ0&lf<1TjY@^x#9W7|4gf&_2$qSX;p|lbJxN8*cYiwCrKo-Y@y_ z+Lk?RviozMhFzcE*JDb>{WO^N)j!rV3i-g1DJxiWi;)c@e0{Dr8(7@nK;V)2WLy2> z&T8R36L6w$%sLO}Ag{S45`c}^@c2;dLNU;c!7G!>H50bXAhNM`g)I+a+nX2OH+hv@ zv8J45u4k8|Zr6jRB4L$_A}J7|jg{McwI>MB=jZ~sFm}_{|4U?oFknOFyd@8#7SBOS z??2lAFN=bqvOkw}V3Z7z`enb;%cVVyb>;kR3vlX>G#>y|9`z#f{_)G|$W%$hbFu=x ziha4IhNp+R$N2-$Pe5?j2V5A1mp!A^}>dSh-9D0^)G1j%9*8ar-X5)-4*`IBVYI`j$F{%oTd%Dgr`Nkl^xGa; z`{;lcXFqxlpn)XH+hGzE7P@l3rP%bN?&uugZlSh!mRIzb;m zB~Jzjg+V|gN+z?jp_$(Y&+$s{S;w|OnE(i*<={t!Sf`h=RBZu3tlz1ZuAeegqK$9Q zUo)v7EQFpzf;241lqG|9?u#e7*~jfI{5%|sbS_E-=yV0M0m#F$=-|X?QVGR+;2Ma- z`c-Xk0?Tihy^{q&jB3Pq;`sNFI)0?5n$GByf%85c#T9>5@!#FKfm11s7S(+Kb}-@; zIUVb_TI;23H%^xi5Q|djhxu49)-4Va%u}gezNxr>+k?uo@VR^lH&CWcs3?zujZ{r> zIQl6d74ae$a9S%dVkqY%^?I!bK#A}R<2SlbD`ilz6mc1#_c^r-@532UdH723(_qMO>%-3_h87x3-F}p|c7=1uwSE z`m>9oOq)=d46y^n9h~1ULd)c$V6W43KH0xG6$Xv`T#-dME*+l?_uKw{=Kn7}C-CtT RO-TR%002ovPDHLkV1hz9l@b5| diff --git a/Assets/SpawnSelector/MapBG34.png b/Assets/SpawnSelector/MapBG34.png deleted file mode 100644 index 590bd700a504c91fe4a5fd1ae5382e02cc265bc8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5236 zcmV-)6pQPLP)LxQ0~1KZ#DJk8!6<*I*x&<`iYN#q<*6bTHntSDRI5u1eQoJtcS{#a zsrk*lzq7yl?KgAIy}L{NC1>wF=gyh)&3yAcXXb3%6&J4wJ)74D!J!4G&W~Tr^|1Z5 zCqfx!o^V03EPwMbxbXP!+aE0t*FW%|u;t-(@fyzuZv9grO&_~>VR6rJ??8BFCaw=Jex2-^T6nm>D{YM!&jy zARZ4q`()_Z@SD)PV>ldq_pmVQm}%kd15-lxhYt^LZaWz7K{*W4C!YRRI56duSSNsM z_>Ox3+^>CrHpR9L>4NCHX7$Wo7abzH>`}$VSOm$Nh5zp`6^&}ZKrB2%K)51Dlv#GAVuCe?$LUz^y8e@ zSgwA4h_p;1BU23k!}wj9hzh_+UMI6GW6wBqMd+ILp@w>`EL_ zoU_g@d5(5A)hs&z^r9?iD}#N$(r?XBRgiI(u}UL9c|dLB&@!l_-u}qHc8`$+3W9Nz zN;1)Fpmrq6;~GA%zv1)YhU=clN-Dp1ZK|C^#R4xT=mH(EMd*wL8|Q}yg`P8nL8Kpm zl=O#b@xFLX`~uPnpia-u6*Sh{$$L@^UHiZtAv_Smk&{QRz3|Vc!dc;};+&GZwKupD zskG4kTAzS)EI4)kq4q?76$RO7ZMbcuGEyG^M&>$3fjV#<&d;JnGsD`o+mkebc|Dsi z2-k$=^@d&B(5b3P0I1rJg%QU|+q3laH^Po-M~5dj)Y@7`ueMhQ0qX-$XLt9p@%!25 zpIQ9Ae_&7e%bK4@1`i!vI!YC*8inS;Z^~#7)Rwq+a>x7T-kd88$0Mp*I7PxpR04-) z_6IJDpWpk^%JA6p50Bh8*cYbkKPmiV^)2xn4iEu{$O6CPc>CoS!hv(n3oowxMYNZ6 ztXL;Hlg<>L*LlS0HF~BWS2!%Z2cMuH*Ox4*IePEx9*)ika9a1vVfu_CLjSJa;gwzc z!MlV*$!Mfb^83Hk2*KJv;U>==9~M%VE?|b^OarkIC1XDVdl)K z;iNe;!p^>D!={%G3m^RWtgv_eP=j-{wFilrcMav_d7cITEfnGX7 zusf6hFmlUl3&SUtd^g;F$30p4z(mVPg;lqZyt7WbD)jg7iU+Xn$qk`%+Vrq#{kDd( z+IOID(Y%iE(5nB2t*dsp&!7W@vbU|iFnsFDsj>W|s<9yLpuNV9{Ne3CtHdB6*D1hD zSKk=gHofTHn?uj$^+m_9;p(h_p-^os14a^5ceG1m#ih3{iJc9GD!@?SH;>oa1;&9H zpa}=)Tm9|6V({S_=(*|c6>+e_bdgS!1ru@LykI6n4r_0;W4v-;A|9moK`K0ZNZj-E zud@tAS$dphpfdzODnSn#tOL(7)PkLe-;gX|sFNGqI?$|#4xm0T>XPrzE+jOCwY|f| zceaJv1Lx3icose}=op%TUbXR)PdV)?H#5-3r`j7Js;jy^(4arsqrtu+X@KiE(7BM- zM<2OA+8JdelLyZ}x_gu@vUq*h-=aM}aG=&uuPn|H_`_~odh3#CUzRRg92di`}EwAoBM|98a z>kF^Xs>z(nwVpA8dWISde>}B|!P8$?pJ*7Q%W9a0_^^H-y+GU(+i}vr!}6uG!k!)b z!c&`$YG}8%IYozu=t*C^upSq$EL1qoX&X~OdmxF|&#Q%Zpab{x!%RF_D?>&`HEY!o z)hN{#JC%oa5buHblc}0yNHy5H`Zk6m4LC<#sFMzjr+U@BzbnB=&#|)M%+TPzu%&Nn zbY2t)HMGr^UWF$Z=xET0P6rbqk-#@Dc`TX*FC4-kW4rJP)3jz?ZD6aZQ2XBC0BPgV zf!F@vf>9~2GN#glrT1sOz%o0i2?|07i#}898txs4jkMV+K)qo8rk#!s!L>g;y(aW* znKO!!L&JL-p6#{44i=m4gG3ccf>k>rt!xvWpA=9Y_rtcrIkKR1HaI{egdJ#M8^H!@ z2ix!30aTePfxHgM!+|<6Sbp{UFEl(0bm1C)Q#w%ozVH0Ca9mg~y*|$a*E$)X1E7O8 zpFsFRKvPjeuq`={Thnh;r(V7m@T61IkdR`uQ`>E&a}qsA5?j?4pd31vQmhGhg~q2g z=>U*{%=KC(df|=QR@?`bbj?M}3w2EMz~@jqc)3^(05Bi-K?Q2Z!hS;i4(+)&4j3@n zwlM`r6M;H;o|D2<9h$=Prr;Vv6Ld5}j4I)P$5coRnL!Er zo0%!0m(1^0S~;lr++4DPc2N(VT>&PywH#wqo5{Km=;YhJ_Uo80)ff~xPQ;ff$xhzoHn zm^M2~=h?H*s!f1TKQ5ep@<-xa57R$Jz!5gP2;uE11GK3F-pNsh4Fr+jo4a%pMG3%T(V?w%o0&s*o+sYlu{FIV_mY4(K&YNu~7nIcBj5nM(Nh?pa~MqKEY?C zBXovG?yEU%kUU5`X;t8wN+D-*aB$fSm`tfHB-67)7GbWEPz$eZ`W(_gyN>!SUAnR$2VD}w`wIssr(&xxfNEA% zt2Tu38>Y)N_VgT^RdQ>iOCMTQ&$0cCa2Y1lMR28DBHA zhCafS7}3m>Tzi$6&V$zoZ6sWI8y>{---Y)CU71d1JRCpedTRBZ2b=%(`Y$F5uACk2 zlR6jo&I#ee^~G7MYHIbSyUSNM=0Me7y3!yA+W<|n1F7$XuIigeMs77T_N286!@NWT zzAN2c980qU*hSimH>pxF@R^}PStJU;pk^0PkBONU+Buph&8@4Q2!|*IT_(!KTzXyM z4Mfj`%6gGi zmxq+mmBz3T2>`NHR1R1)#&ZU`w|c z0LV5eLsK@A;Y~`tHf&Ew!CT;*k^;MHO5J)(K+Xef6x=r z*(HcN4~T}0w8?O6Y5r(AHsM=M)uKmUD zT%n*#Fm>fYWt-`(<)N+MJRh0F)$Mj>!rKd?X~bq2o0{Y7n)ablo~Mp@RhjG%9Gqpb zAl*9QZU?BRsT4TJk`G-jV)L$6b8u~}1=ir|42s31)WWMANHEl^_fSkqduxcSl+u&U z?WnFohf1V<4ig5t^^fPU^IoT)1B}r-t^_?muBUoO3X!T7|qw_ z9G;ww_CgTSQ8xADt*5o+0PeufX^dv*w{#*jgSvzV3kihU}}7D{~NV$tCW! z5k$MHCc6w#r-gJwtCs0$GTRduan+xtoy+gu+-gc1`utSzrH zZ%f)NT~+RVX5;)Yt9K-22b=xSszz@*rABej+PdjbMv|t6?Fl;Kbn}nysPaOIlyjrt ztcflrE>n%3D)s8uH<5JLvnjgD4(Bx&zNXSu<0#D&k@UCPByK@`uBIYw%Fe2L{)Tc0 zZS>743bv|_lR!Xg=?pPKKg_CKuX=J80r0SLd-7sWf8KBqf^;Y23pF$a<0WV){X}2c9 zQ?of}ozNhZN-~EVo~*f``nAl&b$vky&|bx;vw<3J@Vw0V@Fb}flq~?Z(1f*zlqM;p z&&*%KH{e3;X2Q6Xe^F&sdvtp0llf6{< z0sHQo96H1UX(FrX7AJ7s?y^j?ogZ8xVkSg-`V0Y$^j}R`2PS^ znc6DGsCwr z+bTTOT)fj@tnfNI#gsDS)ZSPJ)H4}+#xr#CI+_lTjT=c4*a7t<5GsJ82>w!JJ~^5!kQ)zxEVWR-bGTUMo^zrOi~%l+-E zKNXW@f$4%X@@2Jt!dsngRj5j&szVFblX_9Gl}df5p53dGwV8@mCxRyeHr8rJiYA+t z!UyGTrRq&uRCTaaDs@#I7h!qM4DZWjf*7CD`C*-`A1b=C&1{8{RYI6Dq#PQrbNe$L z4n~ua%0Pu>WP`_?s5kXYrMt}AR`u%5vsy+f6P50!aUo=)?4>Zuvzq^AriCfd5k zVs{Bug((jf$k|Dq^cWS6IHsi3W@@F)I6&hG+qq+5s6~o#RqMBbJCXX2Ly9sc=Hg0z z*Jr?H;&aS)GpA--MHQ(nQ>}pRQl2Pi@DA9x(#y5x97Rn=D;p=Ow_lPi^WigZSV2CfN&B;cb!2VJuEi z*?_RuJ1VYxYeiCRIAj^AP9I-F!BiiZQ}$kVTTfL+#xMB)nFdWsXc@*+{Z^6m;gYo8 uM5$WKR4c($w>A_ZyjiL;$tNS(rvCxlT0H}kTH_1=0000d&0TWxjh#qCC^#v zyRIYDQAba2>GzeRgN=1a^HzU0{4D6muAP-KzSp7C5gMh^2X?I6y{7KfMgDx~Uz)+4@3{T`-+j9{ z#<|V^_GSSFz-a;!oQRE_%QDbc@BdKTgCj`*q)Bx0JnQN;doD~WHN=9&b6xI28MYKy zS4#&E{OJF6PrY6{Ya7Exya+5=c{&<=WZ#kE_w4!8D`K@BZsfH9Qm+S)xOOa}RYhN2 zgY7{h9QaWLl3W8Wu|0nNriVkvuAPNQWY6bwn?PZG6{5^RC0K_Xt z&le5&*LVGPeD+sD2rD;zHXPpiNCfK8#x1cfKn0;(l^xVgja_V5ic^qs)cWP!CBQtT zh9WveZFO3s1XhqBw*g3uY07Z~jtWc^q4~JS-wHnJ<9?RY35XS`v-SF4 zE#B#^rSp>7ZeM;q8hhQ~`OxzlpAI2^|A%I-2(wZ4xzC5&{_?LPkR$>ePPaH3lxl1M z!EqU)QKd-sJ{g!-L!NjgdAfjdaRp3(M<785p8alE{Fx8NV=FFMU%68OB?qJNZ*pGl z@xjs3??o48SL%H85C0^DXTMu2yY%^WVcZv=s(cIyz>VOV&wMa@xB1gclHrX%`_r)U z`f+6-MMTeAodMQls<3fE>>S=To|pxx7*@)Zxn|RfbxEDp-owW$7yy>aj&d0}O_dwv zJ`n3dM816Xr^PmKayV{E8+xZEl^?u=y>Hz|ef9ni#SVyfh7`dbW&Dlr`mL9bMj#;t zGL1Ro2<%ag1}1P(Ea!j&EN~+>6}uJ?54?8h!P)0y$H11daZ^98NE00MH_om7)<4AhUI#)s z0mYcAS~2ZgZ0HF1t=y;p0MHcoS>o8;M7+QE-X$=tO=&sJYOLU3Tjqg0e*cTfmm{d) zRES+{mUHo(DGQcWp5cuz+xtff&`1Ce!v^ky?b5n6C4j&U*sO`8KqyFR67e3MLIaSo zwF@XkHNK&a_)H6Emntj@43BwUfo5as_y}%1;5Z4uQR721DVLG}=*4|Uif3?-=UOox zX3Q==4xMnos~` zcATyhC)(qbQ=px36f`(86hasZz1?#nNEe4*FP$Gh=k{W3RW5~y9u|8Sdn^7)1H!Fu zJi0M#o&WdoSUVN2J(mLyTNc+Wnn5kP?5rTC7l7y7tY!_V&Y<_SQjbG*4Cgc1f!a~1 z;+RQol^UOFv{s94BJBXIp8*+)V+$k*W!P|Dl_mVv=i)sex>2qhNq@ic@ZS{57&#L* zF3tnQ7v6le(h)pPwPQ0xn#Za5-Ne0i4E4rQK2L34`y6%>?O0tjEfC_OZ`PU|O+;H$ zfrLXI1Ym5RB^Qz`xa49b+@Bogb%sF!)ZSO$t1{L~ncA#Y1bd-3a+lZOUKEAgOF-2* zq4hClcJ#D>q|NJf9;GgfZ2*zc5YMbYx%JiB@lze}Al!H7!7qgqiAGjHDSB-k(utRz z3`cXv#Sg#!jW8B^e#dvhy=(6(q)Un*YB`Q#jDo__4te5|u0D!adp{~gmKY(iAnLs= zkSg9wVY%9VociM9h=X|CYNVoUvWc*S!SvDRu zL7r2`J8d^!qdh`ZfVF{iZ1Tjd za-@deG)xDO(D3SSuJgZIAn6fmBD`Z%fH)S>2Mcg;41iLBW`KrsHgWKx09RZ!QsWI5d$}uri*3(T{DdNx*>*Zha&IN-@lipe{=|(iuME^B94lM2sEgG9<1Atk1>zySLouXa=QnglV zzK~Ft^_zmxsUScqHH8X~Mr7y$q;FR{0*+Ojdq6h113LkPavQ`e#zLlqC|P9)*D=vc zfxKt(wXyLaO2N^pfm%R8sOJGiPyq}Tq&h$s<-nl9lshSQ?PjmTbJ(D4IC55#h_ql6 zP~6W;hp|cxjv1Y4C-mh}7skECdJ1dD^AbTA`ZKy-eEqj165Fq|M&QhY?mt{6& zW0-Os6U<^bt0xoHI_^@bvD`-UgwNnTK&cojsf)(FO_lVxkmqp>(}Ss#*2ShKhXP5i z;uv}2rB)e01)u=fYOPH`^8B7WW#iz1G8b_C1(3E36r(g!Kh%4f~&AWO!Aln&;S-q5IPl7wkLq7Gt3F16_wO% z0Vsfs_T(MESpgE_TU~v&q1Q(sGY+tx9)O3&Rqh~1D#%{$E$Y)mP;u!cX^~s4xYql5 zgnAUcDQ%U+PGZGzDFgP6Q1?Q@rY!hU1jj-5%qB zRjt#CQY}|Po%x$Kw355Tv5p2#-M>!!m7*jPc2jy`tX z(ZVe^U`&uqk(v{p`S{|nz2DD8;xnx6xFA3F#^hAuGRrml{osKunduVal~p3>>wB8D zR|_hh)d`>=S^<#FgJlx462-AqiU0;VE>mWFhqy;t&*M(dIc{k~@6-ZF+u+K{59~fr z$z-q{gI*gOCDAcZl@jHoCZb}bMCSsZ%}vuzQlx1sF`*0GKv31ar#5CCk-Mp-78Q5E)wjAs1IH+MT6>;19M=IQ9$4}IU!UOS&1}pr(`LoC|*t21^ zgCGGLogRSVUI3KbrI`ji=5N*mSrZ3DpDca4HmuepYC&Cfb4u!RdfK6w&%@lFoCEc~ zIz|$30!hFYNv=+$JXA*Us(CyE0wg^>1erFdX3=L{Ik6arc|UB_I8lf92auZaK$|sl zQdBbz=sX9pUMm%(T%V>8%p&zFjm5QBINCvKUuu*@O_O$Git5A$kprOo=0z5zltuWF|ZdpxH4GV9|cG zl$umTi4cS1Ik$RA)&yC>e&3P@*8T+!=ve=k!zaVpcd{v1Q?8#7rj6?iqwi*ZT9jY- z@jJ!EH-Gr%@W0ny8y5CX34=rLg;@)4h`)~=JQB{2o(MB1PKo>T@1Icl7y|SDsXres zjSR=*%cIA`4cA-~rcIn0&RiG`m!{touYK#?%VE;xi-qE|Vs2*n?H(S9WvGAR{MkZO z-v5!ludjcjt}||MIZ zGh3f+5vM5n!lyL$X)?6cWTTVb86Wu`UP6~OTMBm`HCc~KbsB;ViGcvPnifiGkb9mS z&0W=NNOhe8WaE|_#A!~#7>EhDN_>~pct$S4+|YYNJ=HniQ%a1N)u)q()M-%a2ofT* z=OS{cC#kHUMy|2Y%jZtdDd#U(YH}^bw@x>7odyI|!S%FP1r?KV$dz=-rNUGo3sA}%!#WI3 zgX1hP*3KLp87ie`uuNxFQT*C#Q>%}#JyO#%D5;q5s@J9#$0#Nt34rRX7z^n$Dl*k_ zsSOtEOe`FyvfflVNrkNJ7^$43epHlE8PV&oe>}AA+nXy#8ZiN(?1@lz<7tWr$;-5} ziVhdtpoxNco}OW^~z{>+$5&ICbF_W%2T-VXlT~bhZtTw8;IB9n?y0q!-e~){c%fqZY%i-F2ycnqE zPA^DZ=R}B{Y1b)eht!Kh4VGM-nvdy?f7Fcl0D-Q% z6ftnm%wd(iIvQHX$@lt?vN}5lXIlq6iX?#t+Ya zk0wJ&F@Y)%W2p~T*A=quQkNNDm%F1Ag_z}T--VNG@jk1L{X*CkvRqp4p5C(xM|&Nm z9Pyqb0qgXHr?$HqYRa@wivH8V1Ie+`f_mum)MAVp$hlZM3$HzN`dq~j2LZ&pBgeL~ z&0{F7f271I05UZbyeS3J+J<&DE>XHrPx}nfGPHLWw}Cgo5&;Af*zRy>V4J%C7%M@?3~b z+He=eX4A51-hxg{=E5|nPlj{Cp_SAMX=p2cE!A}lUcct`GbKferijkFL?fp1 zbx<$!6t%MBVgmBEt)U-_MAZPP3C`Y%l$sqsmSFSh&gEg(d;O&jQkw+b&Q0rpMvtW; zMAL-R5q^@-yX4{#B)bx&4Oykg%e9FgIy>XYvd5)$|CnL7xVxkPaeX^#v^TF=8-B3) z3#CarZ~>z6zMNP#R2vuJu)VpTmZDk}9xfndzeUI9EN^yh953(X@b_B3>yLG3fhp&u z$Xgg#$;La83q+2;m`^p({2K)>Yt-(T&d9NhaYu5CMlr}`wlSX=o)~RYm@>GAn zLkphH{L<-tmSO^QKE(hUUu*tI2w~~^(&B~s5u8ep0i1#S%*Qk5cb2wMo(iW4$#g7a z;`vNrlRmIpoDky5Q*9MoicT{)G7$4=%lScBaGJ!9VHFulg2h09k2+@{%HbX3IsYoYDruDGT_YRY<@cva%+mdvsP*sxnMdm3dpe(MvTjDWI1J+Z0) zE4X?NAl^OUO60x=XD=#=u7L*Uf=UJ*r*%x$@K=g7nlbLFr;BoYC)#4(J-=3zF-0Vk z2<6VuI$za_o1`I0J90B5zo+Hmh@rc?pXOTsbZ^B||a86m!nOP{uQ&lmHiqbtYi?(5@ zQ#~F_TBRklPr-WRPP|xZa*#UN^*1{J!~#T(y82WktCD+6%!yoq!V;%<-f>G9GXHqMQae$QraIJUl~NjU1XI`l0dWjX zDMfa9HGU8{9Nej-^EN@uZbP(zbQ}I8BK4`&E|DnZH$-yl#B4cVV%b zNIRaK#m_wx7Rx$Ex)O?~PmCqY4)u`2xm>>{*Jy3F0!h!ta199%luYElP$IqzwIr_3LcW&HLQAp-V^gb0!EVA1q=vyAYTS|&uxDcI$ ztErIGy=T`)D$nRDuhr+RLEmJad5cWx(9=b(Wbe`!BFOFjyNh_8S%FeTGq@CXSjY0R zYl~wL%@A*nqzA5wJ`hqpYz_~pXsBT*P+7wk^Bg7grK^14-7wwGrZsY!qvzh^_p$?c zD}JT^nSdn*#aHiJ9yWz6+*YdqF@xP3+w7{9c3C!Wr7r!glXP{#Uz#Ia4U4mmy*24H zHrUQ=t34M8Sh?JCIDN7n2h(v+VrQd*!bCUq3gOtgHp>e`HHW$IjypnPDS~gcz)W#) zSJNaRoO^!XkvQhnt=MHLP6y17<7!{|Ag=1dEst&s|Mm2aiWa90X;+!F(F~7^`=W^S z(-n370lkLz&+1ecQo?nQt=bSaNG$XIbA(>sXh<>y zrXrLN@f_`_2jzy7YgqQjzj9x!yYU;37v=D};A5GU#%==92GX^3tl?cJqB_K9szl&D zF^u=+w|vuShvAv0LO6UXYz^gq>(MT?^MA*R07hbIShx)900o#G-Am_Pu_+*_m7no3 zbS9{GsBkdMpC0;N>&TQGOSv~g7sKVaMB-xeJkN&E1&}PIvfLIp_Tsj;VdaK!^se&4 zjjBPWru<_G*EvH&A@t_r{+^!VexOf1`Niz{z4fa-H?3LVSr~0lM_2qOGT{)qYyoIp z?9#4aY5zN)=QXmuQkS@n=fz;I`^PS%cK>18kzG5(bNJsTBx!j2p86ej@hV-~{0sTN z(C8eW zT))GTCtmBM6z}ute|;`lhwl$ghK@i|?u?FtC9_=R(gTyU?AZ59>hb>pcoW@e-z=&O P00000NkvXXu0mjfT9R`O diff --git a/Assets/SpawnSelector/MapBG36.png b/Assets/SpawnSelector/MapBG36.png deleted file mode 100644 index 9caa5e09ffec909d4e5fa2d3443c1c2c8f0f4e84..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7611 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 Uq#5Kmod5s;07*qoM6N<$f*~cvCIA2c diff --git a/Assets/SpawnSelector/MapBG38.png b/Assets/SpawnSelector/MapBG38.png deleted file mode 100644 index d89acb0a66dddf14c028242e7dec2ceccf7a9bfd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2580 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 diff --git a/Assets/SpawnSelector/MapBG4.png b/Assets/SpawnSelector/MapBG4.png deleted file mode 100644 index 1dc6974cc1ffcdb5b30e56bda1860f3b4b3198be..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5575 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 Qi2wiq07*qoM6N<$f)X9AVn<#g$Fe0$v?-Dz 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 IM6N<$f`91v8UO$Q diff --git a/Assets/SpawnSelector/MapBG7.png b/Assets/SpawnSelector/MapBG7.png deleted file mode 100644 index 6c0228133dd534210c3a13947dbb56f89da52984..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5501 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 diff --git a/Assets/SpawnSelector/MapBG8.png b/Assets/SpawnSelector/MapBG8.png deleted file mode 100644 index c944a3093f165af7be8aac5d9f3b23991b0cd0b3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7262 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 diff --git a/Assets/SpawnSelector/MapBG9.png b/Assets/SpawnSelector/MapBG9.png deleted file mode 100644 index 57f8c27bc5456f8f0881778707c90d18c322a1dc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7093 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 diff --git a/Assets/SpawnSelector/Question_Mark.png b/Assets/SpawnSelector/Question_Mark.png deleted file mode 100644 index c0519347d76ab5b694077230cbfb9611bde1fd54..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1710 zcmbVNZEVzJ9Ph}o7j%rL;?pAl#r?kD@ z?ULnCm+2P87^A>A;S)rVsL2w^!ic&U{IHFf_+b(zO3aoRh7-3Ld;_1}8=xqWChha~ zdw&1-e@8m}&sMD8xE{l>iq;ly0F8~-TULU;CzZXI&`_?mbQ>7 z4t6B{K`GfMaWc`c4X;n|h#(3~5l=)Ts=+4&BE!q0xwTCbcm`tj2}F}65byGJ;2x+0 zoTFG$Vi-H_;wY|;V??*>Dcr``oHS#nnL3i?c-F?F^V~xqak?Dh1KwwH!q7?}dQDT~ zX*wQ{Q*k>5^)StH97i)Y+GZmWf;0wHQ%sPmu{qD+1%{+6nyEk)w;0797&8R|shYJR zsugHeBj+dNF*+e?G)pm-O&Opp6>wTik7R_)5)C3C3RKfTShj%GdZ7u8UidH6h2uK} zAm93Y1sQkMB^oV=FwEwDWJb;*cSRe)0S(XrV8ECzf#!as=4Q(pjrZt4G@%}ZFp`f{ zM_y&z=Asz9rc+U67&o@ub^&-r69|MAHIijX))8b_-ciT1_F6Pym@L!>WhFH552%gd zolc&0-vLEABa5bZPp~ZUA*e@1WUvwy!+_S*Fo74`$a`P}>PRrs&Ysc2=i^&d!xU8s zw0Z>s*-R;l%*%GUPO{mZB*VxqQkETd(j5YBQglkJT@1NdM~^dq-wUOf71{iK`G4MT z*A-M+V&uMgtb(&rf^Sg_6s&<RdW% zQI&&5Wf)czYV|e+6X~lLNq;e0eePQ7sH3L1^gDMN8!vx#ZOB=(f8W%;sn;7%T`qa# zMQudD)-|_`9vQ7We0pXyoKm;_Y<@oZZvXMO+P1i>7Kb>|e=svpuT-6HU%dGK^o3Az zez;`gg8Fu7>&I}Vs=wjQ#L_Z`aMPEE{IdtvmY1%ttbX&_ncYWs4oo;a=$_+04)3u4YAI?sEdg<5BAtWQs9GJTKV8x!= w`Q4?7UA6V^AlR|*Q!n3g#irlZRbG9FTj+j*IDLG(^+#!K_Ip2g`uUgs0@q|!-~a#s diff --git a/Assets/SpawnSelector/Question_Mark_Blue.png b/Assets/SpawnSelector/Question_Mark_Blue.png deleted file mode 100644 index f504f5e26097266571686dde0c5de204e00ad616..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 316 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?3oVGw3ym^DWNDEQ9P z#W5tJHTlo~|MrI+n3geaott=tk%vczCG^Aw#}^+I436H|E|kCMXS~Qcjyd6db(b>Z=!|Cjhg<{P?&|2e*_Paq*lLQBzLamP%J(hYYEYMdU}N5w2=j<_?K zdxk`tm(+o$pL_Q0*C>n^J?j&4g7>aKg3D*is&@+4o;#bf6g({ts}tT+Au*vMq z?EJp(`+a}r+r8(7BtA2NvB%-}jyVVjG?K^w!(}omVo$apuUm zmG$~Fe@oK(OcoZFPaa}^o%;B~hh2ZYarA@w)SnlBsMns~f9mkl1{LV=GDBJB(M#ub zx>;-|x48_nWQ9LEm^Y8!!!UPD8@Um0MBNGyF#}K|c^s&kHbpbchD}u)qEYOzd0a58 z828KcCmd^NF>W}limDyQMI$-x;OzKN4vmi@MdLPYWH(d+RbXNdvQ@KWxu6>38hQa; z`=14lZ9u%y7}xI`WJlCA8z&BCm4L(}QS4)7C7?tU5k}>8Y)}k_1+h;MBfO*lDG2C! z^WmsDN7F$jG1xRlcQLN$c{UJ)N~IF0^aY4h5F|xW1TiQCgFHp>Zq4#wmABkgEe#3m zBFC^jgIKJu5#~wRi*c0dtPiH$R%^Mm1m#~Q~ z&!t$YjkSx!BW{sgM|J!78Ur-8s@k?OFBj8nn{d5>G3rJ$AoHT#T+PNp2D_x}AUrTe zX|D3Uu|eFy&?8QckWwpC=@w-+C$4QJjUUL^Jf-ywETRD%U`1&1lerHw0@4=)^H0b=WXr0SmTO;MjH;L7bF`Lk;`v z8Z1;5q%7Bi7Q(4SjH5mW3_}AbtRr2Qbv~kD#7A*R;-M}}d=yHdkgP;xF{-!Z69kq0 z%(mn;Dj$uaK1o54m%6Z2Q7tSvUkThJH ztXlI%Wbt#&Rmor*RRAFJt2@RaKdo5fnxBn%B5-pa%&M&vF;%)ix@Tc7(Y*?EaDRbD z>xShdT#vj9#}=l3bIDtP`rPun73$5fq9U{knD$D6^PLg=rZSrp;s5z+oXu%KEjaCJ z{<7Uq>89P0u|-uowBNqUoLxeD_2E>aKi7M3-@z~Me3|XKUEaC<*wy;GV;9yQ*uVTr zCVhEx&$>!#*|Re*PF~tI*tP!de(); - int recallFrames = config.AdventureMirrorRecallFrames; // 5 seconds = 60 * 5 - - Item.useTime = recallFrames; - Item.useAnimation = recallFrames; - Item.useStyle = ItemUseStyleID.HoldUp; - Item.UseSound = SoundID.Item6; - Item.rare = ItemRarityID.Blue; - Item.value = Item.buyPrice(gold: 5); - Item.noUseGraphic = false; - } - - public override bool CanUseItem(Player player) - { - var adventureMirrorPlayer = player.GetModPlayer(); - - if (adventureMirrorPlayer.IsPlayerInSpawnRegion()) - { - PopupText.NewText(new AdvancedPopupRequest - { - Color = Color.Crimson, - Text = "Cannot use in spawn!", - Velocity = new(0f, -4f), - DurationInFrames = 60 - }, player.Top); - - return false; - }; - - if (adventureMirrorPlayer.CancelIfPlayerMoves()) - return false; - - if (adventureMirrorPlayer.MirrorActive) - return false; - - return true; - } - - public override bool CanRightClick() => true; - public override bool ConsumeItem(Player player) => false; - public override void RightClick(Player player) - { - var adventureMirrorPlayer = player.GetModPlayer(); - - if (adventureMirrorPlayer.CancelIfPlayerMoves()) - return; - - if (adventureMirrorPlayer.MirrorActive) - return; - - var config = ModContent.GetInstance(); - int recallFrames = config.AdventureMirrorRecallFrames + 1; - - SoundEngine.PlaySound(SoundID.Item6); // magic mirror - - adventureMirrorPlayer.StartMirrorUse(recallFrames); - } - - public override bool? UseItem(Player player) - { - var config = ModContent.GetInstance(); - int recallFrames = config.AdventureMirrorRecallFrames + 1; - - var mp = player.GetModPlayer(); - mp.StartMirrorUse(recallFrames); - - return true; - } -} diff --git a/Content/Items/AdventureMirror.png b/Content/Items/AdventureMirror.png deleted file mode 100644 index fbff7c284f4a5011973f8338fbf549e0a1af1521..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 505 zcmVi}ntFbv+L+FbT`r3svj058XEvU<9%$kPc!j+RQf@w)sQxx?r z%gi9+;^JVsqOJiYPUz00Mj|FT44I_|KBL;->_6)lhV7g_Q4V`_U1r7V4 z*eI~T-2UxgT9v~eOnb7Zg6RW)pF!wfH&6@^VUYmS&wpP>Nlh?7zc^5pmj}~4%u*1S zK*M(XpW9&i&7T)oT@Dj}{`)kTK6Y9XB}dcV2b$2*QBh77s{&7G96(|Qk(#Fbz6Pex zeOm;k!}IjPbZ1LDeaj*i7z36A=dR8M)5)Pzv4;5+sLR*AF96dn-fCdl%@&gW*DYR# zqK|%MQE+@BI6rhWHK3ID$!I?L0?iM}g`Oy>4?XN*fc~YaCNx!P>gl3{?fplOQOYXx vuts true; - - // Force the item to always be favorited - public override void UpdateInventory(Item item, Player player) - { - if (item.type == ModContent.ItemType()) - { - item.favorited = true; // Force on every tick - } - } - - public override bool CanPickup(Item item, Player player) - { - // Disallow item pickup while timer is on - if (player.GetModPlayer().MirrorTimer > 0) - { - return false; - } - - return base.CanPickup(item, player); - } - } -} \ No newline at end of file diff --git a/Core/Debug/DebugKeybinds.cs b/Core/Debug/DebugKeybinds.cs deleted file mode 100644 index dddcf3e2..00000000 --- a/Core/Debug/DebugKeybinds.cs +++ /dev/null @@ -1,66 +0,0 @@ -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Input; -using PvPAdventure.Core.Features.SpawnSelector.Systems; -using Terraria; -using Terraria.GameInput; -using Terraria.ModLoader; -using Terraria.UI; - -namespace PvPAdventure.Core.Debug; - -#if DEBUG -[Autoload(Side = ModSide.Client)] -public class DebugKeybinds : ModSystem -{ - public ModKeybind OpenControls { get; private set; } - public ModKeybind SwitchTeams { get; private set; } - public ModKeybind AddPlayerToSpawnSelector { get; private set; } - public ModKeybind ClearPlayersFromSpawnSelector { get; private set; } - - public override void Load() - { - OpenControls = KeybindLoader.RegisterKeybind(Mod, "OpenControls", Keys.NumPad0); - SwitchTeams = KeybindLoader.RegisterKeybind(Mod, "SwitchTeams", Keys.NumPad1); - AddPlayerToSpawnSelector = KeybindLoader.RegisterKeybind(Mod, "AddPlayerToSpawnSelector", Keys.NumPad2); - ClearPlayersFromSpawnSelector = KeybindLoader.RegisterKeybind(Mod, "ClearPlayersFromSpawnSelector", Keys.NumPad3); - } -} - -public class DebugKeybindsPlayer : ModPlayer -{ - public override void ProcessTriggers(TriggersSet triggersSet) - { - var key = ModContent.GetInstance(); - - // Open controls - if (key.OpenControls.JustPressed) - { - IngameFancyUI.OpenKeybinds(); - } - - // Switch teams - if (key.SwitchTeams.JustPressed) - { - Player.team = (Player.team + 1) % 6; // Cycle through teams 0-5 - Main.NewText(Player.name + " switched to team: " + (Terraria.Enums.Team)Player.team); - } - - if (key.AddPlayerToSpawnSelector.JustPressed) - { - var sys = ModContent.GetInstance(); - sys.state.spawnSelectorPanel.DebugAddPlayer(); - Main.NewText("Added SpawnSelectorSystem player"); - //sys.state.spawnSelectorPanel.Rebuild(); - } - - if (key.ClearPlayersFromSpawnSelector.JustPressed) - { - var sys = ModContent.GetInstance(); - sys.state.spawnSelectorPanel.DebugClearPlayers(); - Main.NewText("Cleared SpawnSelectorSystem players"); - //sys.state.spawnSelectorPanel.Rebuild(); - } - } -} - -#endif \ No newline at end of file diff --git a/Core/Features/SpawnSelector/Hooks/ItemSlotHooks.cs b/Core/Features/SpawnSelector/Hooks/ItemSlotHooks.cs deleted file mode 100644 index dc3f9dbb..00000000 --- a/Core/Features/SpawnSelector/Hooks/ItemSlotHooks.cs +++ /dev/null @@ -1,70 +0,0 @@ -using Terraria; -using Terraria.ModLoader; -using Terraria.UI; -using PvPAdventure.Content.Items; - -public class ItemSlotHooks : ModSystem -{ - public override void Load() - { - On_ItemSlot.LeftClick_SellOrTrash += Hook_LeftClick_SellOrTrash; - On_ItemSlot.LeftClick_ItemArray_int_int += Hook_LeftClick_ItemArray; - On_Player.SellItem += Hook_SellItem; - } - - public override void Unload() - { - On_ItemSlot.LeftClick_SellOrTrash -= Hook_LeftClick_SellOrTrash; - On_ItemSlot.LeftClick_ItemArray_int_int -= Hook_LeftClick_ItemArray; - On_Player.SellItem -= Hook_SellItem; - } - - // QUICK TRASH / QUICK SELL (Shift + click) - private static bool Hook_LeftClick_SellOrTrash( - On_ItemSlot.orig_LeftClick_SellOrTrash orig, - Item[] inv, int context, int slot) - { - Item item = inv[slot]; - - if (!item.IsAir && item.type == ModContent.ItemType()) - { - //SoundEngine.PlaySound(SoundID.MenuClose); - return false; // skip SellOrTrash completely - } - - return orig(inv, context, slot); - } - - // DRAGGING ONTO THE TRASH SLOT - private static void Hook_LeftClick_ItemArray( - On_ItemSlot.orig_LeftClick_ItemArray_int_int orig, - Item[] inv, int context, int slot) - { - - if (context == ItemSlot.Context.TrashItem - && !Main.mouseItem.IsAir - && Main.mouseItem.type == ModContent.ItemType()) - { - //SoundEngine.PlaySound(SoundID.MenuClose); - return; - } - - orig(inv, context, slot); - } - - // SELLING TO NPCS - private static bool Hook_SellItem( - On_Player.orig_SellItem orig, - Player self, - Item item, - int stack) - { - if (!item.IsAir && item.type == ModContent.ItemType()) - { - //SoundEngine.PlaySound(SoundID.MenuClose); - return false; - } - - return orig(self, item, stack); - } -} diff --git a/Core/Features/SpawnSelector/Hooks/UnityHooks.cs b/Core/Features/SpawnSelector/Hooks/UnityHooks.cs deleted file mode 100644 index a6c1052c..00000000 --- a/Core/Features/SpawnSelector/Hooks/UnityHooks.cs +++ /dev/null @@ -1,45 +0,0 @@ -using Microsoft.Xna.Framework; -using PvPAdventure.Core.Features.SpawnSelector.Systems; -using System; -using Terraria; -using Terraria.ModLoader; - -namespace PvPAdventure.Core.Features.SpawnSelector.Hooks; - -/// -/// This allows the player to click on teammates to teleport to them. -/// -public class UnityHooks : ModSystem -{ - public override void Load() - { - Main.QueueMainThreadAction(() => - { - On_Player.HasUnityPotion += OnHasUnityPotion; - On_Player.UnityTeleport += OnUnityTeleport; - }); - } - - public override void Unload() - { - Main.QueueMainThreadAction(() => - { - On_Player.HasUnityPotion -= OnHasUnityPotion; - On_Player.UnityTeleport -= OnUnityTeleport; - }); - } - - private void OnUnityTeleport(On_Player.orig_UnityTeleport orig, Player self, Vector2 telePos) - { - SpawnSelectorSystem.SetEnabled(false); - orig(self, telePos); - } - - private static bool OnHasUnityPotion(On_Player.orig_HasUnityPotion orig, Player self) - { - if (SpawnSelectorSystem.GetEnabled()) - return true; - - return orig(self); - } -} diff --git a/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs b/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs deleted file mode 100644 index 9c48d582..00000000 --- a/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs +++ /dev/null @@ -1,273 +0,0 @@ -using Microsoft.Xna.Framework; -using PvPAdventure.Content.Items; -using PvPAdventure.Core.Features.SpawnSelector.Systems; -using PvPAdventure.System; -using PvPAdventure.System.Client; -using Terraria; -using Terraria.Audio; -using Terraria.GameContent; -using Terraria.GameInput; -using Terraria.ID; -using Terraria.ModLoader; -using static PvPAdventure.System.RegionManager; - -namespace PvPAdventure.Core.Features.SpawnSelector.Players; - -public class AdventureMirrorPlayer : ModPlayer -{ - public int MirrorTimer; // frames left - public bool MirrorActive; - - public void StartMirrorUse(int durationFrames) - { - if (MirrorActive) - return; - - MirrorActive = true; - MirrorTimer = durationFrames; - } - - public bool IsPlayerInSpawnRegion() - { - // Force SSS to be enabled when player is within the spawn region. - var regionManager = ModContent.GetInstance(); - Point tilePos = Player.Center.ToTileCoordinates(); - var region = regionManager.GetRegionContaining(tilePos); - if (region != null) - { - return true; - } - return false; - } - - public bool CancelIfPlayerMoves() - { - if (Player.velocity.LengthSquared() <= 0f) - return false; - - // stop the mirror channel - if (MirrorActive) - { - MirrorActive = false; - MirrorTimer = 0; - } - - // stop the actual item use / animation too - if (Player.itemAnimation > 0 && Player.HeldItem.type == ModContent.ItemType()) - { - Player.controlUseItem = false; - Player.channel = false; - Player.itemAnimation = 0; - Player.itemTime = 0; - Player.reuseDelay = 0; - } - - PopupText.NewText(new AdvancedPopupRequest - { - Color = Color.Crimson, - Text = "Cannot use while moving!", - Velocity = new(0f, -4f), - DurationInFrames = 60 - }, Player.Top); - - return true; - } - - public override void PostUpdate() - { - // Open SSS whenever player is in spawn region. - if (IsPlayerInSpawnRegion()) - SpawnSelectorSystem.SetEnabled(true); - - // Closes SSS whenever map is closed. - if (!Main.mapFullscreen) - SpawnSelectorSystem.SetEnabled(false); - - if (!MirrorActive) - return; - - if (Main.dedServ || Player.whoAmI != Main.myPlayer) - return; - - if (CancelIfPlayerMoves()) - return; - - // spawn dust - if (Main.rand.NextBool()) - Dust.NewDust(Player.position, Player.width, Player.height,DustID.MagicMirror, Player.velocity.X * 0.5f,Player.velocity.Y * 0.5f,150,default,1.5f); - - // countdown tick - MirrorTimer--; - //Main.NewText(MirrorTimer); - - // Show countdown every full second - if (MirrorTimer > 0 && MirrorTimer % 60 == 0) - { - int secondsLeft = MirrorTimer / 60; - PopupText.NewText(new AdvancedPopupRequest - { - Color = Color.Crimson, - Text = secondsLeft.ToString(), - Velocity = new(0f, -4f), - DurationInFrames = 60 - }, Player.Top); - } - - // Teleport to spawn - if (MirrorTimer <= 0) - { - // Close player inventory - //Main.playerInventory = false; - - if (!Main.mapFullscreen) - { - //SoundEngine.PlaySound(SoundID.MenuOpen); - //Main.mapFullscreen = true; - - float worldCenterX = Main.maxTilesX / 2f; - float worldCenterY = Main.maxTilesY / 2f; - Main.mapFullscreenPos.X = worldCenterX; - Main.mapFullscreenPos.Y = worldCenterY; - - Main.mapFullscreenScale = 0.21f; - - Vector2 spawnPos = new(Main.spawnTileX * 16, Main.spawnTileY * 16 - 48); - //Main.LocalPlayer.Teleport(spawnPos, 0); - CustomTeleportWithoutSound(spawnPos); - } - - SpawnSelectorSystem.SetEnabled(true); // This is redundant because spawn region already sets it to true - ModContent.GetInstance().state.spawnSelectorPanel.Rebuild(); - - Player.RemoveAllGrapplingHooks(); - - MirrorActive = false; - } - } - - private void CustomTeleportWithoutSound(Vector2 newPos) - { - try - { - Player._funkytownAchievementCheckCooldown = 100; - Player.environmentBuffImmunityTimer = 4; - Player.RemoveAllGrapplingHooks(); - Player.StopVanityActions(); - if (Player.shimmering || Player.shimmerWet) - { - Player.shimmering = false; - Player.shimmerWet = false; - Player.wet = false; - Player.ClearBuff(353); - } - int extraInfo2 = 0; - - float num = MathHelper.Clamp(1f - Player.teleportTime * 0.99f, 0.01f, 1f); - Vector2 otherPosition = Player.position; - //Main.TeleportEffect(Player.getRect(), 0, extraInfo2, num, TeleportationSide.Entry, newPos); - float num2 = Vector2.Distance(Player.position, newPos); - PressurePlateHelper.UpdatePlayerPosition(Player); - Player.position = newPos; - Player.fallStart = (int)(Player.position.Y / 16f); - if (Player.whoAmI == Main.myPlayer) - { - bool flag = false; - if (num2 < new Vector2(Main.screenWidth, Main.screenHeight).Length() / 2f + 100f) - { - int time = 0; - Main.SetCameraLerp(0.1f, time); - flag = true; - } - else - { - NPC.ResetNetOffsets(); - Main.BlackFadeIn = 255; - Lighting.Clear(); - Main.screenLastPosition = Main.screenPosition; - Main.screenPosition.X = Player.position.X + (float)(Player.width / 2) - (float)(Main.screenWidth / 2); - Main.screenPosition.Y = Player.position.Y + (float)(Player.height / 2) - (float)(Main.screenHeight / 2); - Main.instantBGTransitionCounter = 10; - Player.ForceUpdateBiomes(); - } - //if (num > 0.1f || !flag || Style != 0) - //{ - // if (Main.mapTime < 5) - // { - // Main.mapTime = 5; - // } - // Main.maxQ = true; - // Main.renderNow = true; - //} - } - - PressurePlateHelper.UpdatePlayerPosition(Player); - Player.ResetAdvancedShadows(); - for (int i = 0; i < 3; i++) - { - Player.UpdateSocialShadow(); - } - Player.oldPosition = Player.position + Player.BlehOldPositionFixer; - //Main.TeleportEffect(Player.getRect(), 0, extraInfo2, num, TeleportationSide.Exit, otherPosition); - Player.teleportTime = 1f; - Player.teleportStyle = 0; - } - catch - { - } - } - - public override void UpdateDead() - { - // debug - //Main.NewText(Player.respawnTimer); - - // Keeps the player from respawning until they have selected a spawn. - if (Player.respawnTimer <= 10) - { - //Player.respawnTimer = 10; - if (!Main.mapFullscreen) - { - Main.mapFullscreen = true; - SpawnSelectorSystem.SetEnabled(true); - } - } - } - - public override void ProcessTriggers(TriggersSet triggersSet) - { - var keybinds = ModContent.GetInstance(); - - if (keybinds.AdventureMirrorKeybind.JustPressed) - { - TryUseAdventureMirror(); - } - } - - public void TryUseAdventureMirror() - { - // Find a mirror in the player's inventory - int mirrorIndex = -1; - - for (int i = 0; i < Player.inventory.Length; i++) - { - if (Player.inventory[i].type == ModContent.ItemType()) - { - mirrorIndex = i; - break; - } - } - - if (mirrorIndex == -1) - { - Main.NewText("You don't have an Adventure Mirror!", Color.Red); - return; - } - - CancelIfPlayerMoves(); - - // Force the player to use the item - Player.selectedItem = mirrorIndex; - Player.controlUseItem = true; - Player.ItemCheck(); - } -} diff --git a/Core/Features/SpawnSelector/Players/ModifyPlayerDrawInfo.cs b/Core/Features/SpawnSelector/Players/ModifyPlayerDrawInfo.cs deleted file mode 100644 index 67dd894b..00000000 --- a/Core/Features/SpawnSelector/Players/ModifyPlayerDrawInfo.cs +++ /dev/null @@ -1,47 +0,0 @@ -using Microsoft.Xna.Framework; -using Terraria; -using Terraria.DataStructures; -using Terraria.GameContent; -using Terraria.ModLoader; - -namespace PvPAdventure.Core.Features.SpawnSelector.Players; - -public class ModifyPlayerDrawInfo : ModPlayer -{ - public static bool ForceFullBrightOnce; - public override void ModifyDrawInfo(ref PlayerDrawSet drawInfo) - { - if (!ForceFullBrightOnce) - return; - - drawInfo.shadow = 0f; - drawInfo.stealth = 1f; - - var p = drawInfo.drawPlayer; - p.socialIgnoreLight = true; - - drawInfo.colorEyeWhites = Color.White; - drawInfo.colorEyes = p.eyeColor; - drawInfo.colorHair = p.GetHairColor(useLighting: false); - drawInfo.colorHead = p.skinColor; - drawInfo.colorBodySkin = p.skinColor; - drawInfo.colorLegs = p.skinColor; - - drawInfo.colorShirt = p.shirtColor; - drawInfo.colorUnderShirt = p.underShirtColor; - drawInfo.colorPants = p.pantsColor; - drawInfo.colorShoes = p.shoeColor; - - drawInfo.colorArmorHead = Color.White; - drawInfo.colorArmorBody = Color.White; - drawInfo.colorArmorLegs = Color.White; - drawInfo.colorMount = Color.White; - - drawInfo.colorDisplayDollSkin = PlayerDrawHelper.DISPLAY_DOLL_DEFAULT_SKIN_COLOR; - - drawInfo.headGlowColor = new Color(drawInfo.headGlowColor.R, drawInfo.headGlowColor.G, drawInfo.headGlowColor.B, 0); - drawInfo.bodyGlowColor = new Color(drawInfo.bodyGlowColor.R, drawInfo.bodyGlowColor.G, drawInfo.bodyGlowColor.B, 0); - drawInfo.armGlowColor = new Color(drawInfo.armGlowColor.R, drawInfo.armGlowColor.G, drawInfo.armGlowColor.B, 0); - drawInfo.legsGlowColor = new Color(drawInfo.legsGlowColor.R, drawInfo.legsGlowColor.G, drawInfo.legsGlowColor.B, 0); - } -} \ No newline at end of file diff --git a/Core/Features/SpawnSelector/Systems/SpawnSelectorState.cs b/Core/Features/SpawnSelector/Systems/SpawnSelectorState.cs deleted file mode 100644 index c1d7ae6b..00000000 --- a/Core/Features/SpawnSelector/Systems/SpawnSelectorState.cs +++ /dev/null @@ -1,47 +0,0 @@ -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Graphics; -using PvPAdventure.Core.Features.SpawnSelector.UI; -using PvPAdventure.Core.Helpers; -using Terraria.GameContent.UI.Elements; -using Terraria.UI; - -namespace PvPAdventure.Core.Features.SpawnSelector.Systems; - -public class SpawnSelectorState : UIState -{ - public UISpawnSelectorPanel spawnSelectorPanel; - public override void OnInitialize() - { - spawnSelectorPanel = new(); - Append(spawnSelectorPanel); - - UITextPanel chooseYourSpawnPanel = new("Choose Your Spawn", 0.8f, true); - chooseYourSpawnPanel.HAlign = 0.5f; - chooseYourSpawnPanel.VAlign = 0f; - chooseYourSpawnPanel.Top.Set(10, 0); - chooseYourSpawnPanel.BackgroundColor = new Color(73, 94, 171); - Append(chooseYourSpawnPanel); - } - - public override void OnActivate() - { - base.OnActivate(); - UISpawnSelectorPanel panel = null; - foreach (var element in Elements) - { - panel = element as UISpawnSelectorPanel; - if (panel != null) - break; - } - if (panel != null) - { - panel.Rebuild(); - Log.Info("SpawnSelectorState: Rebuilt panel on activate"); - } - } - - public override void Draw(SpriteBatch spriteBatch) - { - base.Draw(spriteBatch); - } -} diff --git a/Core/Features/SpawnSelector/Systems/SpawnSelectorSystem.cs b/Core/Features/SpawnSelector/Systems/SpawnSelectorSystem.cs deleted file mode 100644 index 4d174412..00000000 --- a/Core/Features/SpawnSelector/Systems/SpawnSelectorSystem.cs +++ /dev/null @@ -1,94 +0,0 @@ -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Graphics; -using PvPAdventure.Core.Features.SpawnSelector.UI; -using Terraria; -using Terraria.ModLoader; -using Terraria.UI; - -namespace PvPAdventure.Core.Features.SpawnSelector.Systems; - -[Autoload(Side = ModSide.Client)] -public class SpawnSelectorSystem : ModSystem -{ - private UserInterface ui; - public SpawnSelectorState state; - private UISpawnSelectorPanel teleportPanel; - - // Track whether the spawn selector is enabled - private static bool Enabled; // whether the spawn selector is currently showing in the fullscreen map - public static void SetEnabled(bool newValue) => Enabled = newValue; - public static bool GetEnabled() => Enabled; - - // Load and unload hooks - public override void Load() - { - if (!Main.dedServ) - { - ui = new(); - state = new(); - state.Activate(); - - Main.OnPostFullscreenMapDraw += DrawOverFullscreenMap; - } - - On_Main.TriggerPing += OnTriggerPing; - } - - public override void Unload() - { - if (!Main.dedServ) - Main.OnPostFullscreenMapDraw -= DrawOverFullscreenMap; - - On_Main.TriggerPing -= OnTriggerPing; - } - - private void OnTriggerPing(On_Main.orig_TriggerPing orig, Vector2 position) - { - // Skip ping execution if our panel is being hovered - if (state.spawnSelectorPanel != null && state.spawnSelectorPanel.IsMouseHovering) - { - return; - } - orig(position); - } - - public override void UpdateUI(GameTime gameTime) - { - if (ui == null) return; - - bool visible = GetEnabled() && Main.mapFullscreen; - - if (visible) - { - if (ui.CurrentState != state) - ui.SetState(state); - - ui.Update(gameTime); - } - else if (ui.CurrentState != null) - { - ui.SetState(null); - } - } - - // Draw AFTER the map, with our own Begin/End for UI - private void DrawOverFullscreenMap(Vector2 _mapPos, float _mapScale) - { - if (ui?.CurrentState == null) return; - - var sb = Main.spriteBatch; - bool began = false; - - try - { - sb.Begin(SpriteSortMode.Deferred,BlendState.AlphaBlend,SamplerState.LinearClamp,DepthStencilState.None,RasterizerState.CullCounterClockwise,null,Main.UIScaleMatrix); - began = true; - ui.Draw(sb, Main._drawInterfaceGameTime); - } - finally - { - if (began) - sb.End(); - } - } -} diff --git a/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs b/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs deleted file mode 100644 index 23a90a74..00000000 --- a/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs +++ /dev/null @@ -1,378 +0,0 @@ -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Graphics; -using PvPAdventure.Core.Features.SpawnSelector.Players; -using PvPAdventure.Core.Features.SpawnSelector.Systems; -using PvPAdventure.Core.Helpers; -using ReLogic.Content; -using System; -using Terraria; -using Terraria.GameContent; -using Terraria.GameContent.UI.Elements; -using Terraria.ModLoader; -using Terraria.ModLoader.UI; -using Terraria.UI; - -namespace PvPAdventure.Core.Features.SpawnSelector.UI -{ - /// - /// Vanilla-like character row. - /// - internal class UISpawnSelectorCharacterListItem : UIPanel - { - internal const float ItemWidth = 260f; - internal const float ItemHeight = 72f; - - private readonly Asset _dividerTexture; - private readonly Asset _innerPanelTexture; - private readonly Asset _playerBGTexture; - - private readonly int _playerIndex; - - public UISpawnSelectorCharacterListItem(Player player) - { - _dividerTexture = Main.Assets.Request("Images/UI/Divider"); - _innerPanelTexture = Main.Assets.Request("Images/UI/InnerPanelBackground"); - _playerBGTexture = Main.Assets.Request("Images/UI/PlayerBackground"); - - _playerIndex = player.whoAmI; - } - - public override void OnInitialize() - { - BorderColor = Color.Black; - BackgroundColor = new Color(63, 82, 151) * 0.7f; - - Height.Set(ItemHeight, 0f); - Width.Set(ItemWidth, 0f); - - SetPadding(6f); - } - - private void DrawHeadOnMap(Player p) - { - float scale = Main.mapFullscreenScale; - - Vector2 headPos = new( - ((p.position.X + p.width / 2f) / 16f - Main.mapFullscreenPos.X) * scale - + Main.screenWidth / 2f - 14f * scale+48, - - ((p.position.Y + p.gfxOffY + p.height / 2f) / 16f - Main.mapFullscreenPos.Y) * scale - + Main.screenHeight / 2f - 14f * scale+58 - ); - - Color color = Main.teamColor[p.team]; - - //Main.PlayerRenderer.DrawPlayerHead( - // Main.Camera, - // p, - // headPos, - // scale: 1.3f, - // borderColor: color - //); - Utils.DrawBorderString(Main.spriteBatch, p.name, headPos, Color.White); - } - - private void DrawNineSlice(SpriteBatch sb, int x, int y, int w, int h, Texture2D tex, Color color, int inset, int c = 5) - { - x += inset; y += inset; w -= inset * 2; h -= inset * 2; - int ew = tex.Width - c * 2; - int eh = tex.Height - c * 2; - - sb.Draw(tex, new Rectangle(x, y, c, c), new Rectangle(0, 0, c, c), color); - sb.Draw(tex, new Rectangle(x + c, y, w - c * 2, c), new Rectangle(c, 0, ew, c), color); - sb.Draw(tex, new Rectangle(x + w - c, y, c, c), new Rectangle(tex.Width - c, 0, c, c), color); - - sb.Draw(tex, new Rectangle(x, y + c, c, h - c * 2), new Rectangle(0, c, c, eh), color); - sb.Draw(tex, new Rectangle(x + c, y + c, w - c * 2, h - c * 2), new Rectangle(c, c, ew, eh), color); - sb.Draw(tex, new Rectangle(x + w - c, y + c, c, h - c * 2), new Rectangle(tex.Width - c, c, c, eh), color); - - sb.Draw(tex, new Rectangle(x, y + h - c, c, c), new Rectangle(0, tex.Height - c, c, c), color); - sb.Draw(tex, new Rectangle(x + c, y + h - c, w - c * 2, c), new Rectangle(c, tex.Height - c, ew, c), color); - sb.Draw(tex, new Rectangle(x + w - c, y + h - c, c, c), new Rectangle(tex.Width - c, tex.Height - c, c, c), color); - } - - protected override void DrawSelf(SpriteBatch sb) - { - base.DrawSelf(sb); - - CalculatedStyle inner = GetInnerDimensions(); - - Player player = Main.player[_playerIndex]; - var dims = GetDimensions(); - - if (player == null || !player.active) - { - var rect2 = dims.ToRectangle(); - - Utils.DrawBorderString(sb, "Unable to find player :(", rect2.Location.ToVector2() + new Vector2(50, 0), Color.White); - return; - } - - // Left player background - Vector2 pos = new(inner.X, inner.Y); - //sb.Draw(_playerBGTexture.Value, pos, Color.White*0.5f); - - Rectangle rect = new( - x: (int)pos.X-6, - y: (int)pos.Y-6, - width: 100, - height: 72); - - - //DrawMask(sb, Ass.CornerMask4px.Value, rect, 9); - DrawNineSlice(sb, rect.X, rect.Y, rect.Width, rect.Height, _playerBGTexture.Value, Color.White, 5); - DrawMapFullscreenBackground(sb, rect, player); - - sb.End(); - sb.Begin(SpriteSortMode.Deferred, - BlendState.AlphaBlend, - SamplerState.PointClamp, - DepthStencilState.Default, - RasterizerState.CullNone, - null, - Main.UIScaleMatrix); - - ModifyPlayerDrawInfo.ForceFullBrightOnce = true; - try - { - Vector2 playerDrawPos = pos + Main.screenPosition + new Vector2(32, 8); - - //Main.PlayerRenderer.DrawPlayer(Main.Camera,player,playerDrawPos,player.fullRotation,player.fullRotationOrigin,0f,0.9f); - - Color myTeamColor = Main.teamColor[Main.LocalPlayer.team]; - Main.PlayerRenderer.DrawPlayerHead(Main.Camera, player, pos+ new Vector2(40,37), scale: 1.3f, borderColor: Color.Yellow); - } - catch (Exception e) - { - Log.Error("Failed to draw player: " + e); - } - finally - { - ModifyPlayerDrawInfo.ForceFullBrightOnce = false; - } - - // Switch back to "normal" UI batch - sb.End(); - sb.Begin(SpriteSortMode.Deferred, - BlendState.AlphaBlend, - SamplerState.LinearClamp, - DepthStencilState.None, - RasterizerState.CullCounterClockwise, - null, - Main.UIScaleMatrix); - - // Use the actual layout widths, not the texture width - const float leftColumnWidth = 106f; // player background column - const float rightAreaWidth = ItemWidth - 22f - leftColumnWidth; // 260 - 12 - 106 = 142 - - float rightAreaLeft = inner.X + leftColumnWidth; - float rightAreaCenterX = rightAreaLeft + rightAreaWidth * 0.5f; - - // Name centered in the right-area - string name = string.IsNullOrEmpty(player.name) ? "Unknown player" : player.name + ""; - float nameScale = 1f; - if (player.name.Length > 16) nameScale = 0.85f; - Vector2 nameSize = FontAssets.MouseText.Value.MeasureString(name) * nameScale; - - Vector2 namePos = new( - rightAreaCenterX - nameSize.X * 0.5f, - inner.Y - ); - - // Draw name - Utils.DrawBorderString(sb,name,namePos,Color.White,nameScale); - - // Draw divider - sb.Draw( - _dividerTexture.Value, - new Vector2(rightAreaLeft-12, inner.Y + 21f), - null, - Color.White, - 0f, - Vector2.Zero, - new Vector2(rightAreaWidth/8+2.2f, 1f), - SpriteEffects.None, - 0f - ); - - // Stat panel settings - float statScale = 0.88f; - float statGap = 5f * statScale; - - // Draw stat panel - float panelWidth = rightAreaWidth+24; - Vector2 panelPos = new(rightAreaLeft-14, inner.Y + 29f); - DrawPanel(sb, panelPos, panelWidth); - - string hpText = $"{player.statLife} HP"; - string mpText = $"{player.statMana} MP"; - - Vector2 hpSize = FontAssets.MouseText.Value.MeasureString(hpText) * statScale; - Vector2 mpSize = FontAssets.MouseText.Value.MeasureString(mpText) * statScale; - - var heart = TextureAssets.Heart; - var mana = TextureAssets.Mana; - - float heartW = heart.Width() * statScale; - float manaW = mana.Width() * statScale; - float hpBlockW = heartW + hpSize.X; - float mpBlockW = manaW + mpSize.X; - float totalWidth = hpBlockW + statGap + mpBlockW; - float startX = panelPos.X + (panelWidth - totalWidth) * 0.5f; - float y = panelPos.Y + 4f; - - // Draw health - sb.Draw(heart.Value, new Vector2(startX, y), null, Color.White, 0f, Vector2.Zero, statScale, SpriteEffects.None, 0f); - startX += heartW; - Utils.DrawBorderString(sb, hpText, new Vector2(startX+1, y + 1f), Color.White, statScale); - startX += hpSize.X; - startX += statGap; - - // Draw mana - sb.Draw(mana.Value, new Vector2(startX, y - 2), null, Color.White, 0f, Vector2.Zero, statScale, SpriteEffects.None, 0f); - startX += manaW; - Utils.DrawBorderString(sb, mpText, new Vector2(startX+1, y + 1f), Color.White, statScale); - - // Set hover teleport tooltip - if (IsMouseHovering) - { - Main.instance.MouseText("Teleport to " + name); - var old = Main.UIScaleMatrix; - - //Main.spriteBatch.End(); - //Main.spriteBatch.Begin(SpriteSortMode.Immediate,BlendState.AlphaBlend,SamplerState.PointClamp,DepthStencilState.None,RasterizerState.CullCounterClockwise,null,Matrix.Identity); - - //DrawHeadOnMap(player); - - //Main.spriteBatch.End(); - //Main.spriteBatch.Begin(SpriteSortMode.Deferred,BlendState.AlphaBlend,SamplerState.PointClamp,DepthStencilState.None,RasterizerState.CullCounterClockwise,null,old); - } - //Main.NewText(Main.mouseY); // 482,435 is spawn - - } - - public override void MouseOver(UIMouseEvent evt) - { - base.MouseOver(evt); - - BackgroundColor = new Color(73, 92, 161); - } - - public override void MouseOut(UIMouseEvent evt) - { - base.MouseOut(evt); - BackgroundColor = new Color(63, 82, 151) * 0.8f; - } - - public override void LeftClick(UIMouseEvent evt) - { - base.LeftClick(evt); - - Player player = Main.player[_playerIndex]; - - Main.LocalPlayer.UnityTeleport(player.position); - - // close map and SSS - Main.mapFullscreen = false; - SpawnSelectorSystem.SetEnabled(false); - } - - private void DrawPanel(SpriteBatch spriteBatch, Vector2 position, float width) - { - spriteBatch.Draw(_innerPanelTexture.Value, position, - new Rectangle(0, 0, 8, _innerPanelTexture.Height()), Color.White); - - spriteBatch.Draw( - _innerPanelTexture.Value, - new Vector2(position.X + 8f, position.Y), - new Rectangle(8, 0, 8, _innerPanelTexture.Height()), - Color.White, - 0f, - Vector2.Zero, - new Vector2((width - 16f) / 8f, 1f), - SpriteEffects.None, - 0f - ); - - spriteBatch.Draw( - _innerPanelTexture.Value, - new Vector2(position.X + width - 8f, position.Y), - new Rectangle(16, 0, 8, _innerPanelTexture.Height()), - Color.White - ); - } - - public static void DrawMapFullscreenBackground(SpriteBatch sb, Rectangle rect, Player player) - { - if (player == null || !player.active) - return; - - var screenPos = Main.screenPosition; - var tile = Main.tile[(int)(player.Center.X / 16f), (int)(player.Center.Y / 16f)]; - if (tile == null) return; - - int wall = tile.wall; - int bgIndex = -1; - Color color = Color.White; - - if (screenPos.Y > (Main.maxTilesY - 232) * 16) - bgIndex = 2; - else if (player.ZoneDungeon) - bgIndex = 4; - else if (wall == 87) - bgIndex = 13; - else if (screenPos.Y > Main.worldSurface * 16.0) - { - bgIndex = wall switch - { - 86 or 108 => 15, - 180 or 184 => 16, - 178 or 183 => 17, - 62 or 263 => 18, - _ => player.ZoneGlowshroom ? 20 : - player.ZoneCorrupt ? player.ZoneDesert ? 39 : player.ZoneSnow ? 33 : 22 : - player.ZoneCrimson ? player.ZoneDesert ? 40 : player.ZoneSnow ? 34 : 23 : - player.ZoneHallow ? player.ZoneDesert ? 41 : player.ZoneSnow ? 35 : 21 : - player.ZoneSnow ? 3 : - player.ZoneJungle ? 12 : - player.ZoneDesert ? 14 : - player.ZoneRockLayerHeight ? 31 : 1 - }; - } - else if (player.ZoneGlowshroom) - bgIndex = 19; - else - { - color = Main.ColorOfTheSkies; - int midTileX = (int)((screenPos.X + Main.screenWidth / 2f) / 16f); - - if (player.ZoneSkyHeight) bgIndex = 32; - else if (player.ZoneCorrupt) bgIndex = player.ZoneDesert ? 36 : 5; - else if (player.ZoneCrimson) bgIndex = player.ZoneDesert ? 37 : 6; - else if (player.ZoneHallow) bgIndex = player.ZoneDesert ? 38 : 7; - else if (screenPos.Y / 16f < Main.worldSurface + 10.0 && (midTileX < 380 || midTileX > Main.maxTilesX - 380)) - bgIndex = 10; - else if (player.ZoneSnow) bgIndex = 11; - else if (player.ZoneJungle) bgIndex = 8; - else if (player.ZoneDesert) bgIndex = 9; - else if (Main.bloodMoon) { bgIndex = 25; color *= 2f; } - else if (player.ZoneGraveyard) bgIndex = 26; - } - - // Vanilla - //var asset = bgIndex >= 0 && bgIndex < TextureAssets.MapBGs.Length? TextureAssets.MapBGs[bgIndex]: TextureAssets.MapBGs[0]; - - // Our textures with rounded corners - int safeIndex = (bgIndex >= 0 && bgIndex < Ass.MapBG.Length) ? bgIndex: 0; - var asset = Ass.MapBG[safeIndex]; - - rect.X += 10; - rect.Y += 10; - rect.Width -= 20; - rect.Height -= 20; - - if (asset == null || asset.Value == null) return; - sb.Draw(asset.Value, rect, color); - } - } -} diff --git a/Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs b/Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs deleted file mode 100644 index 96f1184c..00000000 --- a/Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs +++ /dev/null @@ -1,150 +0,0 @@ -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Graphics; -using PvPAdventure.Core.Helpers; -using System.Collections.Generic; -using Terraria; -using Terraria.GameContent.UI.Elements; - -namespace PvPAdventure.Core.Features.SpawnSelector.UI -{ - public class UISpawnSelectorPanel : UIPanel - { - private UIPanel _randomPanel; - private readonly List _playerItems = new(); - - private const float Spacing = 8f; - private const float HorizontalPadding = 16f; - private const float VerticalPadding = 12f; - - public override void OnInitialize() - { - HAlign = 0.5f; - VAlign = 0.0f; - Top.Set(52, 0); - - BackgroundColor = new Color(33, 43, 79) * 0.8f; - SetPadding(0f); - - BuildLayout(); - - Log.Info("UISpawnSelectorPanel.OnInitialize: layout built"); - } - - private void BuildLayout() - { - RemoveAllChildren(); - _playerItems.Clear(); - - var players = new List(); - var local = Main.LocalPlayer; - -#if DEBUG - // If we have debug players, use them instead of scanning teammates - if (_debugPlayers.Count > 0) - { - players.AddRange(_debugPlayers); - } - else -#endif - { - // ADD TEAMMATES - if (local.team != 0) - { - for (int i = 0; i < Main.maxPlayers; i++) - { - Player p = Main.player[i]; - - if (p == null || !p.active) - continue; - - if (p.whoAmI == local.whoAmI || p.team != local.team) - continue; - - players.Add(p); - } - } - } - - int playerCount = players.Count; - - float itemWidth = UISpawnSelectorCharacterListItem.ItemWidth; - float itemHeight = UISpawnSelectorCharacterListItem.ItemHeight; - float randomWidth = itemHeight; // square random panel - - float contentWidth = playerCount * itemWidth - + playerCount * Spacing - + randomWidth; - - float panelWidth = contentWidth + HorizontalPadding * 2f; - float panelHeight = itemHeight + VerticalPadding * 2f; - - Width.Set(panelWidth, 0f); - Height.Set(panelHeight, 0f); - - float startX = HorizontalPadding; - float y = VerticalPadding; - - // Players in a row - for (int i = 0; i < playerCount; i++) - { - float x = startX + i * (itemWidth + Spacing); - - var row = new UISpawnSelectorCharacterListItem(players[i]); - row.Left.Set(x, 0f); - row.Top.Set(y, 0f); - - Append(row); - _playerItems.Add(row); - } - - // Square random panel to the right of the last player - _randomPanel = new UISpawnSelectorRandomPanel( - startX, - itemHeight, - playerCount, - itemWidth, - Spacing, - y - ); - Append(_randomPanel); - - Log.Debug($"UISpawnSelectorPanel.BuildLayout: players={playerCount}, panelWidth={panelWidth}"); - } - - public void Rebuild() - { - BuildLayout(); - Log.Debug("UISpawnSelectorPanel.Rebuild: UI rebuilt"); - } - - public override void Draw(SpriteBatch spriteBatch) - { - base.Draw(spriteBatch); - } - - #region Debug -#if DEBUG - private readonly List _debugPlayers = new(); -#endif - public void DebugAddPlayer() - { -#if DEBUG - _debugPlayers.Add(Main.LocalPlayer); - BuildLayout(); - Log.Debug($"SpawnSelector DebugAddPlayer: debugPlayers={_debugPlayers.Count}"); -#endif - } - - public void DebugClearPlayers() - { -#if DEBUG - _debugPlayers.Clear(); - BuildLayout(); - Log.Debug("SpawnSelector DebugClearPlayers: cleared debug players"); -#endif - } - #endregion - - - } -} diff --git a/Core/Features/SpawnSelector/UI/UISpawnSelectorRandomPanel.cs b/Core/Features/SpawnSelector/UI/UISpawnSelectorRandomPanel.cs deleted file mode 100644 index 886a5461..00000000 --- a/Core/Features/SpawnSelector/UI/UISpawnSelectorRandomPanel.cs +++ /dev/null @@ -1,91 +0,0 @@ -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Graphics; -using PvPAdventure.Core.Features.SpawnSelector.Systems; -using PvPAdventure.Core.Helpers; -using Terraria; -using Terraria.GameContent.UI.Elements; -using Terraria.ID; -using Terraria.UI; - -namespace PvPAdventure.Core.Features.SpawnSelector.UI -{ - internal class UISpawnSelectorRandomPanel : UIPanel - { - public UISpawnSelectorRandomPanel(float startX, float itemHeight, int playerCount, float itemWidth, float Spacing, float y) - { - Width.Set(itemHeight, 0f); - Height.Set(itemHeight, 0f); - Top.Set(y, 0f); - - float randomX = startX + playerCount * (itemWidth + Spacing); - Left.Set(randomX, 0f); - - BackgroundColor = new Color(63, 82, 151) * 0.8f; - BorderColor = Color.Black; - } - - public override void LeftClick(UIMouseEvent evt) - { - base.LeftClick(evt); - - if (Main.netMode == NetmodeID.MultiplayerClient) - { - NetMessage.SendData(MessageID.RequestTeleportationByServer); - } - else - { - Main.LocalPlayer.TeleportationPotion(); - } - - Main.mapFullscreen = false; - SpawnSelectorSystem.SetEnabled(false); - } - - public override void MouseOver(UIMouseEvent evt) - { - base.MouseOver(evt); - BackgroundColor = new Color(73, 92, 161); - - } - - public override void MouseOut(UIMouseEvent evt) - { - base.MouseOut(evt); - BackgroundColor = new Color(63, 82, 151) * 0.8f; - } - - public override void Draw(SpriteBatch sb) - { - base.Draw(sb); - - if (IsMouseHovering) - { - Main.instance.MouseText("Random Teleport"); - } - - // Draw question mark - var d = GetDimensions(); - var tex = Ass.Question_Mark.Value; - var rect = new Rectangle( - (int)(d.X + (d.Width - tex.Width) * 0.5f), - (int)(d.Y + (d.Height - tex.Height) * 0.5f), - tex.Width, - tex.Height - ); - sb.Draw(tex, rect, Color.White); - - // debug - //sb.Draw(TextureAssets.MagicPixel.Value, rect, Color.Red * 0.45f); - - // Draw teleportation potion - Item icon = new(ItemID.TeleportationPotion); - Vector2 pos = new(rect.X + 37, rect.Y + 36); - //ItemSlot.DrawItemIcon(icon, 31, sb, pos, 1.0f, 32f, Color.White); - } - - public override void Update(GameTime gameTime) - { - base.Update(gameTime); - } - } -} diff --git a/Core/Helpers/AssetLoader.cs b/Core/Helpers/AssetLoader.cs deleted file mode 100644 index 747b6dd3..00000000 --- a/Core/Helpers/AssetLoader.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System.Reflection; -using Microsoft.Xna.Framework.Graphics; -using ReLogic.Content; -using Terraria.ModLoader; - -namespace PvPAdventure.Core.Helpers; - -public static class Ass -{ - public static Asset Question_Mark; - public static Asset[] MapBG; - - public static bool Initialized { get; set; } - - static Ass() - { - // Load MapBG1..MapBG42 - MapBG = new Asset[42]; - for (int i = 1; i <= 42; i++) - { - MapBG[i - 1] = ModContent.Request( - $"PvPAdventure/Assets/SpawnSelector/MapBG{i}", - AssetRequestMode.AsyncLoad); - } - - // Load single texture fields (NOT MapBG array) - foreach (FieldInfo f in typeof(Ass).GetFields()) - { - if (f.FieldType == typeof(Asset)) - { - var asset = ModContent.Request( - $"PvPAdventure/Assets/SpawnSelector/{f.Name}", - AssetRequestMode.AsyncLoad); - f.SetValue(null, asset); - } - } - } -} - -public class LoadAssets : ModSystem -{ - public override void Load() => _ = Ass.Initialized; -} diff --git a/Core/Helpers/Log.cs b/Core/Helpers/Log.cs deleted file mode 100644 index 856a1ff0..00000000 --- a/Core/Helpers/Log.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System.IO; -using System.Runtime.CompilerServices; -using log4net; -using Terraria.ModLoader; - -namespace PvPAdventure.Core.Helpers; - -/// -/// A static logging helper for PvPAdventure. -/// Example usage: Log.Info("This is an info message."); -/// Example usage: Log.Warn("This is a warning message."); -/// -public static class Log -{ - public static ILog Base - { - get - { - var m = ModContent.GetInstance(); - return (m != null && m.Logger != null) ? m.Logger : LogManager.GetLogger("PvPAdventure"); - } - } - - public static void Info(object message, [CallerFilePath] string file = "") - => Base.Info($"[{Class(file)}] {message}"); - - public static void Debug(object message, [CallerFilePath] string file = "") - => Base.Debug($"[{Class(file)}] {message}"); - - public static void Warn(object message, [CallerFilePath] string file = "") - => Base.Warn($"[{Class(file)}] {message}"); - - public static void Error(object message, [CallerFilePath] string file = "") - => Base.Error($"[{Class(file)}] {message}"); - - public static Prefixed For() => new(Base, typeof(T).Name); - public static Prefixed ForCaller([CallerFilePath] string file = "") => new(Base, Class(file)); - - private static string Class(string file) => Path.GetFileNameWithoutExtension(file); - - public readonly struct Prefixed - { - private readonly ILog _log; - private readonly string _p; - public Prefixed(ILog log, string prefix) { _log = log; _p = prefix; } - public void Info(object m) => _log.Info($"[{_p}] {m}"); - public void Debug(object m) => _log.Debug($"[{_p}] {m}"); - public void Warn(object m) => _log.Warn($"[{_p}] {m}"); - public void Error(object m) => _log.Error($"[{_p}] {m}"); - } -} diff --git a/Localization/en-US.hjson b/Localization/en-US.hjson index 4fee0157..5dbb6eeb 100644 --- a/Localization/en-US.hjson +++ b/Localization/en-US.hjson @@ -14,12 +14,6 @@ Mods: { BountyShop.DisplayName: Bounty Shop AllChat.DisplayName: All Chat Dash.DisplayName: Dash - AdventureMirror.DisplayName: Adventure Mirror - OpenControls.DisplayName: Open Controls - SwitchTeams.DisplayName: Switch Teams - AddPlayerToSpawnSelector.DisplayName: Add Player To Spawn Selector - RemovePlayerFromSpawnSelector.DisplayName: Remove Player From Spawn Selector - ClearPlayersFromSpawnSelector.DisplayName: Clear Players From Spawn Selector } Configs: { @@ -135,16 +129,6 @@ Mods: { Tooltip: "" Label: Minimum Damage Received By Players From Player } - - RTPRecallFrames: { - Label: RTP Recall Frames - Tooltip: "" - } - - AdventureMirrorRecallFrames: { - Label: Adventure Mirror Recall Frames - Tooltip: "" - } } PointsConfig: { @@ -1076,15 +1060,5 @@ Mods: { FatalCarCrash.Label: Fatal Car Crash Part2.Label: Part2 } - Items: { - AdventureMirror: { - DisplayName: Adventure Mirror - Tooltip: - ''' - Gaze in the mirror to go on adventures - Right click to use - ''' - } - } } } diff --git a/Properties/launchSettings.json b/Properties/launchSettings.json index 280b6ecf..07e2f8d0 100644 --- a/Properties/launchSettings.json +++ b/Properties/launchSettings.json @@ -11,12 +11,6 @@ "executablePath": "dotnet", "commandLineArgs": "$(tMLServerPath)", "workingDirectory": "$(tMLSteamPath)" - }, - "TerrariaSkipSelect": { - "commandName": "Executable", - "executablePath": "dotnet", - "commandLineArgs": "$(tMLPath) -skipselect", - "workingDirectory": "$(tMLSteamPath)" - }, + } } } \ No newline at end of file diff --git a/PvPAdventure.csproj b/PvPAdventure.csproj index d01b9a47..fed5da73 100644 --- a/PvPAdventure.csproj +++ b/PvPAdventure.csproj @@ -1,32 +1,28 @@ - - - - PvPAdventure - latest - - - - - - - - - - - lib\Discord.Net.Core.dll - - - lib\Discord.Net.Rest.dll - - - lib\System.Linq.Async.dll - - - - - - - - + + + PvPAdventure + latest + + + + + + + + + + + + + + lib\Discord.Net.Core.dll + + + lib\Discord.Net.Rest.dll + + + lib\System.Linq.Async.dll + + \ No newline at end of file diff --git a/PvPAdventure.csproj.user b/PvPAdventure.csproj.user deleted file mode 100644 index 62b33ede..00000000 --- a/PvPAdventure.csproj.user +++ /dev/null @@ -1,9 +0,0 @@ - - - - ProjectDebugger - - - TerrariaSkipSelect - - \ No newline at end of file diff --git a/System/Client/Keybinds.cs b/System/Client/Keybinds.cs index 8d7699b5..d72d756f 100644 --- a/System/Client/Keybinds.cs +++ b/System/Client/Keybinds.cs @@ -9,13 +9,11 @@ public class Keybinds : ModSystem public ModKeybind Scoreboard { get; private set; } public ModKeybind BountyShop { get; private set; } public ModKeybind AllChat { get; private set; } - public ModKeybind AdventureMirrorKeybind { get; private set; } public override void Load() { Scoreboard = KeybindLoader.RegisterKeybind(Mod, "Scoreboard", Keys.OemTilde); BountyShop = KeybindLoader.RegisterKeybind(Mod, "BountyShop", Keys.P); AllChat = KeybindLoader.RegisterKeybind(Mod, "AllChat", Keys.U); - AdventureMirrorKeybind = KeybindLoader.RegisterKeybind(Mod, "AdventureMirror", Keys.M); } } \ No newline at end of file diff --git a/icon_small.png b/icon_small.png deleted file mode 100644 index e06b69194deb74c1c306133c9d1b382ca427a528..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 942 zcmV;f15x~mP)M6pQy zf>x*!QmGGuAi{>?L#3snh=w8}BBBXc5c{wXf*+s{Qn3%UVL=c|4J4E{+DJ{)TBBx@ zw7c8gnfsT?_QA)UbvGWkFTfV^5}os z&R$^n>;ld$ZpYU*{6JUEeZJCY@Ug3xW{#{*P3inn1k=lYEEZ}zj>?NO$?E_L+R!k| zB?J^WH%qC*L~Y30QoYG9ewfO190fb37;qXCZGnzaYQh$J?*Bs#I$b?L7`MpXA*_%T_0aRrTTh z%^Q67D+f|~VLC;w_LK7i%+IB0UrCa=Z9MZ`lCiMg2Jlo>FKon&+P8jN|Xx@)D_GM{P2!DW6qxYlRW)dHoYa1H~Q$&9z^^OI2yB|BZ<41kv!Hu{iU1#lu3Rs*;93YKyvT3XzD6Q7bC zZ}eTAJ~V2nJ9_=%GYIXh^$Sm3u2%5X><>QXatc;Z!>A0l=6ZmSeLK0#nb{H@yHX>y z^eE-^1(JW4Z5}x}S>(y=O Date: Sat, 15 Nov 2025 20:39:46 +0100 Subject: [PATCH 170/206] Fix item pickup --- Content/Items/AdventureMirror.cs | 6 +++--- Content/Items/AdventureMirrorGlobalItem.cs | 8 ++++---- Core/Features/SpawnSelector/Hooks/ItemSlotHooks.cs | 2 -- .../SpawnSelector/Players/AdventureMirrorPlayer.cs | 4 ++++ .../Features/SpawnSelector/Systems/SpawnSelectorSystem.cs | 1 - .../SpawnSelector/UI/UISpawnSelectorRandomPanel.cs | 6 ++++++ 6 files changed, 17 insertions(+), 10 deletions(-) diff --git a/Content/Items/AdventureMirror.cs b/Content/Items/AdventureMirror.cs index 9b9dcbd1..12f91493 100644 --- a/Content/Items/AdventureMirror.cs +++ b/Content/Items/AdventureMirror.cs @@ -26,9 +26,9 @@ public override void SetDefaults() public override bool CanUseItem(Player player) { - var gm = ModContent.GetInstance(); - if (gm.CurrentPhase != GameManager.Phase.Playing) - return false; + //var gm = ModContent.GetInstance(); + //if (gm.CurrentPhase != GameManager.Phase.Playing) + // return false; var adventureMirrorPlayer = player.GetModPlayer(); diff --git a/Content/Items/AdventureMirrorGlobalItem.cs b/Content/Items/AdventureMirrorGlobalItem.cs index 12d66652..16f0e599 100644 --- a/Content/Items/AdventureMirrorGlobalItem.cs +++ b/Content/Items/AdventureMirrorGlobalItem.cs @@ -20,10 +20,10 @@ public override void UpdateInventory(Item item, Player player) public override bool CanPickup(Item item, Player player) { // Disallow item pickup while timer is on - if (player.GetModPlayer().MirrorTimer > 0) - { - return false; - } + //if (player.GetModPlayer().MirrorTimer > 0) + //{ + // return false; + //} return base.CanPickup(item, player); } diff --git a/Core/Features/SpawnSelector/Hooks/ItemSlotHooks.cs b/Core/Features/SpawnSelector/Hooks/ItemSlotHooks.cs index 0e1dc632..d4d77291 100644 --- a/Core/Features/SpawnSelector/Hooks/ItemSlotHooks.cs +++ b/Core/Features/SpawnSelector/Hooks/ItemSlotHooks.cs @@ -43,12 +43,10 @@ private static void Hook_LeftClick_ItemArray( On_ItemSlot.orig_LeftClick_ItemArray_int_int orig, Item[] inv, int context, int slot) { - if (context == ItemSlot.Context.TrashItem && !Main.mouseItem.IsAir && Main.mouseItem.type == ModContent.ItemType()) { - if (Main.mouseLeft && Main.mouseLeftRelease) { PopupText.NewText(new AdvancedPopupRequest diff --git a/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs b/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs index 9c3f269e..cd9ce9e7 100644 --- a/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs +++ b/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs @@ -79,6 +79,10 @@ public bool CancelIfPlayerMoves() public override void PostUpdate() { + //var gm = ModContent.GetInstance(); + //if (gm.CurrentPhase != GameManager.Phase.Playing) + // SpawnSelectorSystem.SetEnabled(false); + if (!Main.mapFullscreen) SpawnSelectorSystem.SetEnabled(false); diff --git a/Core/Features/SpawnSelector/Systems/SpawnSelectorSystem.cs b/Core/Features/SpawnSelector/Systems/SpawnSelectorSystem.cs index 0d081ef2..b2096ac6 100644 --- a/Core/Features/SpawnSelector/Systems/SpawnSelectorSystem.cs +++ b/Core/Features/SpawnSelector/Systems/SpawnSelectorSystem.cs @@ -12,7 +12,6 @@ public class SpawnSelectorSystem : ModSystem { public UserInterface ui; public SpawnSelectorState state; - private UISpawnSelectorPanel teleportPanel; // Track whether the spawn selector is enabled private static bool Enabled; // whether the spawn selector is currently showing in the fullscreen map diff --git a/Core/Features/SpawnSelector/UI/UISpawnSelectorRandomPanel.cs b/Core/Features/SpawnSelector/UI/UISpawnSelectorRandomPanel.cs index 886a5461..7ef5c9a1 100644 --- a/Core/Features/SpawnSelector/UI/UISpawnSelectorRandomPanel.cs +++ b/Core/Features/SpawnSelector/UI/UISpawnSelectorRandomPanel.cs @@ -2,9 +2,11 @@ using Microsoft.Xna.Framework.Graphics; using PvPAdventure.Core.Features.SpawnSelector.Systems; using PvPAdventure.Core.Helpers; +using PvPAdventure.System; using Terraria; using Terraria.GameContent.UI.Elements; using Terraria.ID; +using Terraria.ModLoader; using Terraria.UI; namespace PvPAdventure.Core.Features.SpawnSelector.UI @@ -28,6 +30,10 @@ public override void LeftClick(UIMouseEvent evt) { base.LeftClick(evt); + //var gm = ModContent.GetInstance(); + //if (gm.CurrentPhase != GameManager.Phase.Playing) + // return; + if (Main.netMode == NetmodeID.MultiplayerClient) { NetMessage.SendData(MessageID.RequestTeleportationByServer); From 78e6a468c57d4730c5025b4d095ed4b66ebde7d1 Mon Sep 17 00:00:00 2001 From: emyhrberg <121192176+emyhrberg@users.noreply.github.com> Date: Sat, 15 Nov 2025 21:21:19 +0100 Subject: [PATCH 171/206] Fixed all bugs after first playtesting --- Content/Items/AdventureMirror.cs | 54 +++++++++++----- Core/Debug/DBStartGameCommand.cs | 40 ++++++++++++ .../Players/AdventureMirrorPlayer.cs | 62 ++++++++++++------- System/GameManager.cs | 27 +++++++- 4 files changed, 143 insertions(+), 40 deletions(-) create mode 100644 Core/Debug/DBStartGameCommand.cs diff --git a/Content/Items/AdventureMirror.cs b/Content/Items/AdventureMirror.cs index 12f91493..c95a18bc 100644 --- a/Content/Items/AdventureMirror.cs +++ b/Content/Items/AdventureMirror.cs @@ -26,26 +26,34 @@ public override void SetDefaults() public override bool CanUseItem(Player player) { - //var gm = ModContent.GetInstance(); - //if (gm.CurrentPhase != GameManager.Phase.Playing) - // return false; - var adventureMirrorPlayer = player.GetModPlayer(); - if (player.whoAmI == Main.myPlayer) + // BLOCK BEFORE GAME STARTS + if (!adventureMirrorPlayer.IsGameStarted()) + return false; + + // BLOCK IN SPAWN + if (adventureMirrorPlayer.IsPlayerInSpawnRegion()) { - PopupText.NewText(new AdvancedPopupRequest + if (player.whoAmI == Main.myPlayer) { - Color = Color.Crimson, - Text = "Cannot use in spawn!", - Velocity = new(0f, -4f), - DurationInFrames = 60 - }, player.Top); + PopupText.NewText(new AdvancedPopupRequest + { + Color = Color.Crimson, + Text = "Cannot use in spawn!", + Velocity = new(0f, -4f), + DurationInFrames = 60 + }, player.Top); + } + + return false; } + // BLOCK IF MOVING if (adventureMirrorPlayer.CancelIfPlayerMoves()) return false; + // BLOCK IF ALREADY CHANNELING if (adventureMirrorPlayer.MirrorActive) return false; @@ -56,16 +64,30 @@ public override bool CanUseItem(Player player) public override bool ConsumeItem(Player player) => false; public override void RightClick(Player player) { - var gm = ModContent.GetInstance(); - if (gm.CurrentPhase != GameManager.Phase.Playing) - return; - var adventureMirrorPlayer = player.GetModPlayer(); - if (adventureMirrorPlayer.CancelIfPlayerMoves()) + // BLOCK BEFORE GAME STARTS + if (!adventureMirrorPlayer.IsGameStarted()) return; + // BLOCK IN SPAWN if (adventureMirrorPlayer.IsPlayerInSpawnRegion()) + { + if (player.whoAmI == Main.myPlayer) + { + PopupText.NewText(new AdvancedPopupRequest + { + Color = Color.Crimson, + Text = "Cannot use in spawn!", + Velocity = new(0f, -4f), + DurationInFrames = 60 + }, player.Top); + } + + return; + } + + if (adventureMirrorPlayer.CancelIfPlayerMoves()) return; if (adventureMirrorPlayer.MirrorActive) diff --git a/Core/Debug/DBStartGameCommand.cs b/Core/Debug/DBStartGameCommand.cs new file mode 100644 index 00000000..9c6097b2 --- /dev/null +++ b/Core/Debug/DBStartGameCommand.cs @@ -0,0 +1,40 @@ +using Microsoft.Xna.Framework; +using PvPAdventure.System; +using Terraria.ModLoader; +using static PvPAdventure.System.GameManager; + +namespace PvPAdventure.Core.Debug; + +#if DEBUG +public class DBStartGameCommand : ModCommand +{ + public override string Command => "dbstartgame"; + public override string Description => "[Debug] set GameManager.Phase=Playing"; + public override string Name => "[Debug] set GameManager.Phase=Playing"; + public override CommandType Type => CommandType.Chat | CommandType.Console; + + public override void Action(CommandCaller caller, string input, string[] args) + { + if (args.Length == 0 || !int.TryParse(args[0], out var time)) + { + caller.Reply("Invalid time.", Color.Red); + return; + } + + var gameManager = ModContent.GetInstance(); + if (gameManager.CurrentPhase == Phase.Playing) + { + caller.Reply("The game is already being played.", Color.Red); + return; + } + + if (gameManager._startGameCountdown.HasValue) + { + caller.Reply("The game is already being started.", Color.Red); + return; + } + + gameManager.DebugStartGame(time); + } +} +#endif diff --git a/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs b/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs index cd9ce9e7..e471f20f 100644 --- a/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs +++ b/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs @@ -28,6 +28,24 @@ public void StartMirrorUse(int durationFrames) MirrorTimer = durationFrames; } + public bool IsGameStarted() + { + var gm = ModContent.GetInstance(); + if (gm.CurrentPhase != GameManager.Phase.Playing) + { + PopupText.NewText(new AdvancedPopupRequest + { + Color = Color.Crimson, + Text = "Cannot use before game starts!", + Velocity = new(0f, -4f), + DurationInFrames = 60 + }, Player.Top); + + return false; + } + return true; + } + public bool IsPlayerInSpawnRegion() { // Force SSS to be enabled when player is within the spawn region. @@ -43,6 +61,9 @@ public bool IsPlayerInSpawnRegion() public bool CancelIfPlayerMoves() { + if (Player.whoAmI != Main.myPlayer) + return false; + if (Player.velocity.LengthSquared() <= 0f) return false; @@ -63,25 +84,22 @@ public bool CancelIfPlayerMoves() Player.reuseDelay = 0; } - if (Player.whoAmI == Main.myPlayer) + PopupText.NewText(new AdvancedPopupRequest { - PopupText.NewText(new AdvancedPopupRequest - { - Color = Color.Crimson, - Text = "Cannot use while moving!", - Velocity = new(0f, -4f), - DurationInFrames = 60 - }, Player.Top); - } + Color = Color.Crimson, + Text = "Cannot use while moving!", + Velocity = new(0f, -4f), + DurationInFrames = 60 + }, Player.Top); return true; } public override void PostUpdate() { - //var gm = ModContent.GetInstance(); - //if (gm.CurrentPhase != GameManager.Phase.Playing) - // SpawnSelectorSystem.SetEnabled(false); + var gm = ModContent.GetInstance(); + if (gm.CurrentPhase == GameManager.Phase.Waiting) + SpawnSelectorSystem.SetEnabled(false); if (!Main.mapFullscreen) SpawnSelectorSystem.SetEnabled(false); @@ -231,19 +249,21 @@ private void CustomTeleportWithoutSound(Vector2 newPos) public override void UpdateDead() { + base.UpdateDead(); + // debug //Main.NewText(Player.respawnTimer); // Keeps the player from respawning until they have selected a spawn. - if (Player.respawnTimer <= 10) - { - //Player.respawnTimer = 10; - if (!Main.mapFullscreen) - { - Main.mapFullscreen = true; - SpawnSelectorSystem.SetEnabled(true); - } - } + //if (Player.respawnTimer <= 10) + //{ + // //Player.respawnTimer = 10; + // if (!Main.mapFullscreen) + // { + // Main.mapFullscreen = true; + // SpawnSelectorSystem.SetEnabled(true); + // } + //} } public override void ProcessTriggers(TriggersSet triggersSet) diff --git a/System/GameManager.cs b/System/GameManager.cs index 0373b9a3..c95f296c 100644 --- a/System/GameManager.cs +++ b/System/GameManager.cs @@ -21,7 +21,7 @@ namespace PvPAdventure.System; public class GameManager : ModSystem { public int TimeRemaining { get; set; } - private int? _startGameCountdown = 0; + public int? _startGameCountdown = null; private Phase _currentPhase; public Phase CurrentPhase @@ -120,6 +120,7 @@ private void OnMainStartRain(On_Main.orig_StartRain orig) orig(); ChatHelper.BroadcastChatMessage(NetworkText.FromKey("Mods.PvPAdventure.Rain"), Color.White); } + private bool hasPrintedGameOver = false; public override void PostUpdateTime() { @@ -143,7 +144,7 @@ public override void PostUpdateTime() else if (_startGameCountdown <= (60 * 3) && _startGameCountdown % 60 == 0) { ChatHelper.BroadcastChatMessage(NetworkText.FromLiteral($"{_startGameCountdown / 60}..."), - Color.Green); + Color.Crimson); } } @@ -152,13 +153,21 @@ public override void PostUpdateTime() case Phase.Playing: { if (--TimeRemaining <= 0) + { CurrentPhase = Phase.Waiting; + + //if (!hasPrintedGameOver) + { + ChatHelper.BroadcastChatMessage(NetworkText.FromLiteral($"The game is over!"), + Color.Green); + //hasPrintedGameOver = true; + } + } break; } } } - public void StartGame(int time) { CurrentPhase = Phase.Waiting; @@ -169,6 +178,18 @@ public void StartGame(int time) NetworkText.FromLiteral($"The game will begin in {_startGameCountdown / 60} seconds."), Color.Green); } +#if DEBUG + public void DebugStartGame(int time) + { + CurrentPhase = Phase.Waiting; + TimeRemaining = time; + _startGameCountdown = 1; + + ChatHelper.BroadcastChatMessage( + NetworkText.FromLiteral($"[DEBUG] The game has started (GameMananger.Phase=Playing)"), Color.Green); + } +#endif + // NOTE: This is not called on multiplayer clients (see CurrentPhase property). private void OnPhaseChange(Phase newPhase) { From 53a273591e4d7ea3939245b636cf6cb2496f4fdc Mon Sep 17 00:00:00 2001 From: emyhrberg <121192176+emyhrberg@users.noreply.github.com> Date: Sun, 16 Nov 2025 04:27:29 +0100 Subject: [PATCH 172/206] Added cool new arrow feature --- AdventureClientConfig.cs | 1 + Assets/SpawnSelector/Arrow.png | Bin 0 -> 359 bytes Assets/SpawnSelector/CornerMask4px.png | Bin 268 -> 0 bytes Assets/SpawnSelector/FadeHorizontal.png | Bin 80 -> 0 bytes Content/Items/AdventureMirror.cs | 88 ++---- Content/Items/AdventureMirrorGlobalItem.cs | 31 -- Core/Debug/DBStartGameCommand.cs | 40 --- Core/Debug/DebugKeybinds.cs | 31 +- .../SpawnSelector/Hooks/UnityHooks.cs | 45 --- .../Players/AdventureMirrorPlayer.cs | 264 ++++++++++-------- ...yerDrawInfo.cs => ModifyDrawInfoPlayer.cs} | 7 +- .../{Hooks => Systems}/ItemSlotHooks.cs | 52 ++-- .../Systems/SpawnSelectorState.cs | 1 - .../Systems/SpawnSelectorSystem.cs | 4 +- .../SpawnSelector/Systems/UnityHooks.cs | 28 ++ .../SpawnSelector/UI/PopupTextHelper.cs | 42 +++ .../UI/UISpawnSelectorCharacterListItem.cs | 72 +++-- .../SpawnSelector/UI/UISpawnSelectorPanel.cs | 106 ++++--- .../UI/UISpawnSelectorRandomPanel.cs | 7 +- Core/Helpers/AssetLoader.cs | 1 + Localization/en-US.hjson | 7 + System/GameManager.cs | 21 -- 22 files changed, 422 insertions(+), 426 deletions(-) create mode 100644 Assets/SpawnSelector/Arrow.png delete mode 100644 Assets/SpawnSelector/CornerMask4px.png delete mode 100644 Assets/SpawnSelector/FadeHorizontal.png delete mode 100644 Content/Items/AdventureMirrorGlobalItem.cs delete mode 100644 Core/Debug/DBStartGameCommand.cs delete mode 100644 Core/Features/SpawnSelector/Hooks/UnityHooks.cs rename Core/Features/SpawnSelector/Players/{ModifyPlayerDrawInfo.cs => ModifyDrawInfoPlayer.cs} (90%) rename Core/Features/SpawnSelector/{Hooks => Systems}/ItemSlotHooks.cs (55%) create mode 100644 Core/Features/SpawnSelector/Systems/UnityHooks.cs create mode 100644 Core/Features/SpawnSelector/UI/PopupTextHelper.cs diff --git a/AdventureClientConfig.cs b/AdventureClientConfig.cs index 9307cbb0..434c6ef0 100644 --- a/AdventureClientConfig.cs +++ b/AdventureClientConfig.cs @@ -15,6 +15,7 @@ public class AdventureClientConfig : ModConfig [DefaultValue(true)] public bool ShowPauseMessage { get; set; } [DefaultValue(false)] public bool OpenMapAfterRecall; + [DefaultValue(false)] public bool ShowPopupText; public class PlayerOutlineConfig { diff --git a/Assets/SpawnSelector/Arrow.png b/Assets/SpawnSelector/Arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..07067dee08422b61d9afaacb5fa6bef3a04c9058 GIT binary patch literal 359 zcmeAS@N?(olHy`uVBq!ia0vp^(m*W7!3HGnN~S&oQk(@Ik;M!Qd`Cc-ajG^SPz9r; zr;B5VM`!Y%|Nrfo_c93I%}Gi~NN{|1f?HMK>Dl)8Vg{3vCGVskiE`mgIH+c!`-7ux zM(Hhe3+bDQ@Ae+FsI}C-DBjvHn0`a&5PO-}dQ~eIHoe9N%bTAgTe~DWM4f DxbB2V literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/CornerMask4px.png b/Assets/SpawnSelector/CornerMask4px.png deleted file mode 100644 index 8f03f4353fab813910a3a823b9e04bef34e0e43c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 268 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=mpxq^Ln`LHy=};MSV4p(@ZbLb zb3H{lZ)&8@W3iUKarBMIyO`v|bBf=+^Ixzk%l7-{*2%~FKi<2(UvA#1U7O3Nn}4_) z{raKXuV){VbL^V7Ph^O4m`oRZzCJU5@$riP0X5vAp?l?)oZ0{L-P^lQU#_vX7hI@P Tt+JF6FS$$$R;|6k9>*7jZH eLAl2peun<-g8yqaZ{Y?iVeoYIb6Mw<&;$Vdrx$+! diff --git a/Content/Items/AdventureMirror.cs b/Content/Items/AdventureMirror.cs index c95a18bc..c30aaa0c 100644 --- a/Content/Items/AdventureMirror.cs +++ b/Content/Items/AdventureMirror.cs @@ -1,8 +1,7 @@ -using Microsoft.Xna.Framework; -using PvPAdventure.Core.Features.SpawnSelector.Players; +using PvPAdventure.Core.Features.SpawnSelector.Players; +using PvPAdventure.Core.Features.SpawnSelector.UI; using PvPAdventure.System; using Terraria; -using Terraria.Audio; using Terraria.ID; using Terraria.ModLoader; @@ -26,89 +25,54 @@ public override void SetDefaults() public override bool CanUseItem(Player player) { - var adventureMirrorPlayer = player.GetModPlayer(); + var amp = player.GetModPlayer(); + var gm = ModContent.GetInstance(); - // BLOCK BEFORE GAME STARTS - if (!adventureMirrorPlayer.IsGameStarted()) + if (gm.CurrentPhase != GameManager.Phase.Playing) + { + if (player.whoAmI == Main.myPlayer) + PopupTextHelper.NewText("Cannot use before game has started!"); return false; + } - // BLOCK IN SPAWN - if (adventureMirrorPlayer.IsPlayerInSpawnRegion()) + if (amp.IsPlayerInSpawnRegion()) { if (player.whoAmI == Main.myPlayer) - { - PopupText.NewText(new AdvancedPopupRequest - { - Color = Color.Crimson, - Text = "Cannot use in spawn!", - Velocity = new(0f, -4f), - DurationInFrames = 60 - }, player.Top); - } - + PopupTextHelper.NewText("Cannot use in spawn region!"); return false; } - // BLOCK IF MOVING - if (adventureMirrorPlayer.CancelIfPlayerMoves()) + if (amp.MirrorActive) return false; - // BLOCK IF ALREADY CHANNELING - if (adventureMirrorPlayer.MirrorActive) + if (player.whoAmI == Main.myPlayer && player.velocity.LengthSquared() > 0f) + { + //PopupTextHelper.NewText("Cannot use while moving!"); return false; + } return true; } + public override bool AltFunctionUse(Player player) => true; public override bool CanRightClick() => true; public override bool ConsumeItem(Player player) => false; public override void RightClick(Player player) { - var adventureMirrorPlayer = player.GetModPlayer(); - - // BLOCK BEFORE GAME STARTS - if (!adventureMirrorPlayer.IsGameStarted()) + if (!player.GetModPlayer().TryStartMirrorChannel()) return; - - // BLOCK IN SPAWN - if (adventureMirrorPlayer.IsPlayerInSpawnRegion()) - { - if (player.whoAmI == Main.myPlayer) - { - PopupText.NewText(new AdvancedPopupRequest - { - Color = Color.Crimson, - Text = "Cannot use in spawn!", - Velocity = new(0f, -4f), - DurationInFrames = 60 - }, player.Top); - } - - return; - } - - if (adventureMirrorPlayer.CancelIfPlayerMoves()) - return; - - if (adventureMirrorPlayer.MirrorActive) - return; - - var config = ModContent.GetInstance(); - int recallFrames = config.AdventureMirrorRecallFrames + 1; - - SoundEngine.PlaySound(SoundID.Item6); // magic mirror - - adventureMirrorPlayer.StartMirrorUse(recallFrames); } public override bool? UseItem(Player player) { - var config = ModContent.GetInstance(); - int recallFrames = config.AdventureMirrorRecallFrames + 1; - - var mp = player.GetModPlayer(); - mp.StartMirrorUse(recallFrames); - + var amp = player.GetModPlayer(); + amp.TryStartMirrorChannel(); return true; } + + public override void UpdateInventory(Player player) + { + // Force favorite every tick + Item.favorited = true; + } } diff --git a/Content/Items/AdventureMirrorGlobalItem.cs b/Content/Items/AdventureMirrorGlobalItem.cs deleted file mode 100644 index 16f0e599..00000000 --- a/Content/Items/AdventureMirrorGlobalItem.cs +++ /dev/null @@ -1,31 +0,0 @@ -using PvPAdventure.Core.Features.SpawnSelector.Players; -using Terraria; -using Terraria.ModLoader; - -namespace PvPAdventure.Content.Items -{ - public class AdventureMirrorGlobalItem : GlobalItem - { - public override bool InstancePerEntity => true; - - // Force the item to always be favorited - public override void UpdateInventory(Item item, Player player) - { - if (item.type == ModContent.ItemType()) - { - item.favorited = true; // Force on every tick - } - } - - public override bool CanPickup(Item item, Player player) - { - // Disallow item pickup while timer is on - //if (player.GetModPlayer().MirrorTimer > 0) - //{ - // return false; - //} - - return base.CanPickup(item, player); - } - } -} \ No newline at end of file diff --git a/Core/Debug/DBStartGameCommand.cs b/Core/Debug/DBStartGameCommand.cs deleted file mode 100644 index 9c6097b2..00000000 --- a/Core/Debug/DBStartGameCommand.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Microsoft.Xna.Framework; -using PvPAdventure.System; -using Terraria.ModLoader; -using static PvPAdventure.System.GameManager; - -namespace PvPAdventure.Core.Debug; - -#if DEBUG -public class DBStartGameCommand : ModCommand -{ - public override string Command => "dbstartgame"; - public override string Description => "[Debug] set GameManager.Phase=Playing"; - public override string Name => "[Debug] set GameManager.Phase=Playing"; - public override CommandType Type => CommandType.Chat | CommandType.Console; - - public override void Action(CommandCaller caller, string input, string[] args) - { - if (args.Length == 0 || !int.TryParse(args[0], out var time)) - { - caller.Reply("Invalid time.", Color.Red); - return; - } - - var gameManager = ModContent.GetInstance(); - if (gameManager.CurrentPhase == Phase.Playing) - { - caller.Reply("The game is already being played.", Color.Red); - return; - } - - if (gameManager._startGameCountdown.HasValue) - { - caller.Reply("The game is already being started.", Color.Red); - return; - } - - gameManager.DebugStartGame(time); - } -} -#endif diff --git a/Core/Debug/DebugKeybinds.cs b/Core/Debug/DebugKeybinds.cs index 24eda970..8dd6a11f 100644 --- a/Core/Debug/DebugKeybinds.cs +++ b/Core/Debug/DebugKeybinds.cs @@ -1,6 +1,4 @@ -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Input; -using PvPAdventure.Core.Features.SpawnSelector.Systems; +using Microsoft.Xna.Framework.Input; using Terraria; using Terraria.GameInput; using Terraria.ModLoader; @@ -14,15 +12,11 @@ public class DebugKeybinds : ModSystem { public ModKeybind OpenControls { get; private set; } public ModKeybind SwitchTeams { get; private set; } - public ModKeybind AddPlayerToSpawnSelector { get; private set; } - public ModKeybind ClearPlayersFromSpawnSelector { get; private set; } public override void Load() { - OpenControls = KeybindLoader.RegisterKeybind(Mod, "OpenControls", Keys.NumPad0); - SwitchTeams = KeybindLoader.RegisterKeybind(Mod, "SwitchTeams", Keys.NumPad1); - AddPlayerToSpawnSelector = KeybindLoader.RegisterKeybind(Mod, "AddPlayerToSpawnSelector", Keys.NumPad2); - ClearPlayersFromSpawnSelector = KeybindLoader.RegisterKeybind(Mod, "ClearPlayersFromSpawnSelector", Keys.NumPad3); + OpenControls = KeybindLoader.RegisterKeybind(Mod, "[DEBUG] OpenControls", Keys.NumPad0); + SwitchTeams = KeybindLoader.RegisterKeybind(Mod, "[DEBUG] SwitchTeams", Keys.NumPad1); } } @@ -44,25 +38,6 @@ public override void ProcessTriggers(TriggersSet triggersSet) Player.team = (Player.team + 1) % 6; // Cycle through teams 0-5 Main.NewText("[DEBUG] " + Player.name + " switched to team: " + (Terraria.Enums.Team)Player.team); } - - if (key.AddPlayerToSpawnSelector.JustPressed) - { - var sys = ModContent.GetInstance(); - sys.state.spawnSelectorPanel.DebugAddPlayer(); - sys.state.spawnSelectorPanel.Rebuild(); - - sys.ui.SetState(null); - sys.ui.SetState(sys.state); - Main.NewText("[DEBUG] Added player to UISpawnSelectorPanel"); - } - - if (key.ClearPlayersFromSpawnSelector.JustPressed) - { - var sys = ModContent.GetInstance(); - sys.state.spawnSelectorPanel.DebugClearPlayers(); - Main.NewText("[DEBUG] Cleared all players from UISpawnSelectorPanel"); - sys.state.spawnSelectorPanel.Rebuild(); - } } } diff --git a/Core/Features/SpawnSelector/Hooks/UnityHooks.cs b/Core/Features/SpawnSelector/Hooks/UnityHooks.cs deleted file mode 100644 index a6c1052c..00000000 --- a/Core/Features/SpawnSelector/Hooks/UnityHooks.cs +++ /dev/null @@ -1,45 +0,0 @@ -using Microsoft.Xna.Framework; -using PvPAdventure.Core.Features.SpawnSelector.Systems; -using System; -using Terraria; -using Terraria.ModLoader; - -namespace PvPAdventure.Core.Features.SpawnSelector.Hooks; - -/// -/// This allows the player to click on teammates to teleport to them. -/// -public class UnityHooks : ModSystem -{ - public override void Load() - { - Main.QueueMainThreadAction(() => - { - On_Player.HasUnityPotion += OnHasUnityPotion; - On_Player.UnityTeleport += OnUnityTeleport; - }); - } - - public override void Unload() - { - Main.QueueMainThreadAction(() => - { - On_Player.HasUnityPotion -= OnHasUnityPotion; - On_Player.UnityTeleport -= OnUnityTeleport; - }); - } - - private void OnUnityTeleport(On_Player.orig_UnityTeleport orig, Player self, Vector2 telePos) - { - SpawnSelectorSystem.SetEnabled(false); - orig(self, telePos); - } - - private static bool OnHasUnityPotion(On_Player.orig_HasUnityPotion orig, Player self) - { - if (SpawnSelectorSystem.GetEnabled()) - return true; - - return orig(self); - } -} diff --git a/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs b/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs index e471f20f..00ce866a 100644 --- a/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs +++ b/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs @@ -1,6 +1,7 @@ using Microsoft.Xna.Framework; using PvPAdventure.Content.Items; using PvPAdventure.Core.Features.SpawnSelector.Systems; +using PvPAdventure.Core.Features.SpawnSelector.UI; using PvPAdventure.System; using PvPAdventure.System.Client; using Terraria; @@ -9,7 +10,6 @@ using Terraria.GameInput; using Terraria.ID; using Terraria.ModLoader; -using static PvPAdventure.System.RegionManager; using static Terraria.ModLoader.BackupIO; namespace PvPAdventure.Core.Features.SpawnSelector.Players; @@ -17,32 +17,41 @@ namespace PvPAdventure.Core.Features.SpawnSelector.Players; public class AdventureMirrorPlayer : ModPlayer { public int MirrorTimer; // frames left - public bool MirrorActive; - - public void StartMirrorUse(int durationFrames) + public bool MirrorActive; // currently channeling + public int MirrorCountdownLastSecond = -1; + private bool didRebuildOnDeath; + public bool TryStartMirrorChannel() { - if (MirrorActive) - return; - - MirrorActive = true; - MirrorTimer = durationFrames; - } + if (ModContent.GetInstance().CurrentPhase != GameManager.Phase.Playing) + { + if (Player.whoAmI == Main.myPlayer) + PopupTextHelper.NewText("Cannot use before game has started!"); + return false; + } - public bool IsGameStarted() - { - var gm = ModContent.GetInstance(); - if (gm.CurrentPhase != GameManager.Phase.Playing) + if (IsPlayerInSpawnRegion()) { - PopupText.NewText(new AdvancedPopupRequest - { - Color = Color.Crimson, - Text = "Cannot use before game starts!", - Velocity = new(0f, -4f), - DurationInFrames = 60 - }, Player.Top); + if (Player.whoAmI == Main.myPlayer) + PopupTextHelper.NewText("Cannot use in spawn region!"); + return false; + } + if (MirrorActive) + return false; + + if (Player.whoAmI == Main.myPlayer && IsMoving()) + { + CancelMirrorUse(); + PopupTextHelper.NewText("Cannot use while moving!"); return false; } + + SoundEngine.PlaySound(SoundID.Item6); + var config = ModContent.GetInstance(); + int recallFrames = config.AdventureMirrorRecallFrames + 1; + + MirrorActive = true; + MirrorTimer = recallFrames; return true; } @@ -59,23 +68,16 @@ public bool IsPlayerInSpawnRegion() return false; } - public bool CancelIfPlayerMoves() - { - if (Player.whoAmI != Main.myPlayer) - return false; - - if (Player.velocity.LengthSquared() <= 0f) - return false; + private bool IsMoving() => Player.velocity.LengthSquared() > 0f; - // stop the mirror channel - if (MirrorActive) - { - MirrorActive = false; - MirrorTimer = 0; - } + private void CancelMirrorUse() + { + MirrorActive = false; + MirrorTimer = 0; + MirrorCountdownLastSecond = -1; - // stop the actual item use / animation too - if (Player.itemAnimation > 0 && Player.HeldItem.type == ModContent.ItemType()) + if (Player.itemAnimation > 0 && + Player.HeldItem.type == ModContent.ItemType()) { Player.controlUseItem = false; Player.channel = false; @@ -83,39 +85,44 @@ public bool CancelIfPlayerMoves() Player.itemTime = 0; Player.reuseDelay = 0; } + } - PopupText.NewText(new AdvancedPopupRequest - { - Color = Color.Crimson, - Text = "Cannot use while moving!", - Velocity = new(0f, -4f), - DurationInFrames = 60 - }, Player.Top); + public bool CancelIfPlayerMoves() + { + if (Player.whoAmI != Main.myPlayer) + return false; + if (!IsMoving()) + return false; + + CancelMirrorUse(); + PopupTextHelper.NewText("Cannot use while moving!"); return true; } public override void PostUpdate() { - var gm = ModContent.GetInstance(); - if (gm.CurrentPhase == GameManager.Phase.Waiting) - SpawnSelectorSystem.SetEnabled(false); + if (!Player.dead) + { + didRebuildOnDeath = false; + } - if (!Main.mapFullscreen) - SpawnSelectorSystem.SetEnabled(false); + if (Main.dedServ || Player.whoAmI != Main.myPlayer) + return; - // Open SSS when player is in spawn region, and close it when player is outside spawn region. - if (IsPlayerInSpawnRegion()) + + if (ModContent.GetInstance().CurrentPhase == GameManager.Phase.Playing && Main.mapFullscreen && IsPlayerInSpawnRegion()) + { SpawnSelectorSystem.SetEnabled(true); + } else + { SpawnSelectorSystem.SetEnabled(false); + } if (!MirrorActive) return; - if (Main.dedServ || Player.whoAmI != Main.myPlayer) - return; - if (CancelIfPlayerMoves()) return; @@ -131,47 +138,37 @@ public override void PostUpdate() if (MirrorTimer > 0 && MirrorTimer % 60 == 0) { int secondsLeft = MirrorTimer / 60; - PopupText.NewText(new AdvancedPopupRequest - { - Color = Color.Crimson, - Text = secondsLeft.ToString(), - Velocity = new(0f, -4f), - DurationInFrames = 60 - }, Player.Top); + PopupTextHelper.NewText(secondsLeft.ToString(), Color.LightGreen, showInMultiplayer: true); } - // Teleport to spawn + // Ready to teleport to spawn if (MirrorTimer <= 0) { - // Close player inventory var config = ModContent.GetInstance(); - if (config.OpenMapAfterRecall) Main.playerInventory = false; - - if (!Main.mapFullscreen) + if (config.OpenMapAfterRecall) { - if (config.OpenMapAfterRecall) - { - //SoundEngine.PlaySound(SoundID.MenuOpen); - //Main.mapFullscreen = true; - } + // Close player inventory + Main.playerInventory = false; + + // Open fullscreen map + Main.mapFullscreen = true; + // center the map float worldCenterX = Main.maxTilesX / 2f; float worldCenterY = Main.maxTilesY / 2f; Main.mapFullscreenPos.X = worldCenterX; Main.mapFullscreenPos.Y = worldCenterY; - - Main.mapFullscreenScale = 0.21f; // arbitrary zoom out value that fits the entire map - - Vector2 spawnPos = new(Main.spawnTileX * 16, Main.spawnTileY * 16 - 48); - //Main.LocalPlayer.Teleport(spawnPos, 0); - CustomTeleportWithoutSound(spawnPos); + Main.mapFullscreenScale = 0.21f; // arbitrary value to zoom out that fits the entire map } + // Teleport to spawn + Vector2 spawnPos = new(Main.spawnTileX * 16, Main.spawnTileY * 16 - 48); + //Main.LocalPlayer.Teleport(spawnPos, 0); + CustomTeleportWithoutSound(spawnPos); + SpawnSelectorSystem.SetEnabled(true); // This is redundant because spawn region already sets it to true ModContent.GetInstance().state.spawnSelectorPanel.Rebuild(); - Player.RemoveAllGrapplingHooks(); - MirrorActive = false; } } @@ -247,25 +244,7 @@ private void CustomTeleportWithoutSound(Vector2 newPos) } } - public override void UpdateDead() - { - base.UpdateDead(); - - // debug - //Main.NewText(Player.respawnTimer); - - // Keeps the player from respawning until they have selected a spawn. - //if (Player.respawnTimer <= 10) - //{ - // //Player.respawnTimer = 10; - // if (!Main.mapFullscreen) - // { - // Main.mapFullscreen = true; - // SpawnSelectorSystem.SetEnabled(true); - // } - //} - } - + #region Keybind Handling public override void ProcessTriggers(TriggersSet triggersSet) { var keybinds = ModContent.GetInstance(); @@ -278,29 +257,96 @@ public override void ProcessTriggers(TriggersSet triggersSet) public void TryUseAdventureMirror() { - // Find a mirror in the player's inventory - int mirrorIndex = -1; + int mirrorIndex = EnsureMirrorInInventory(); + if (mirrorIndex == -1) + { + PopupTextHelper.NewText("No Adventure Mirror found in inventory or banks!"); + return; + } + + if (CancelIfPlayerMoves()) + return; + + Player.selectedItem = mirrorIndex; + Player.controlUseItem = true; + Player.ItemCheck(); + } + + private int EnsureMirrorInInventory() + { + int mirrorType = ModContent.ItemType(); + + // 1. Look in main inventory first for (int i = 0; i < Player.inventory.Length; i++) { - if (Player.inventory[i].type == ModContent.ItemType()) + Item item = Player.inventory[i]; + if (!item.IsAir && item.type == mirrorType) + return i; + } + + // 2. Try to pull from personal banks + if (TryPullMirrorFromBank(Player.bank, mirrorType, out int invIndex)) + return invIndex; + + if (TryPullMirrorFromBank(Player.bank2, mirrorType, out invIndex)) + return invIndex; + + if (TryPullMirrorFromBank(Player.bank3, mirrorType, out invIndex)) + return invIndex; + + if (TryPullMirrorFromBank(Player.bank4, mirrorType, out invIndex)) // void vault + return invIndex; + + return -1; + } + + private bool TryPullMirrorFromBank(Chest bank, int mirrorType, out int inventoryIndex) + { + inventoryIndex = -1; + + if (bank == null) + return false; + + // Find the mirror inside this bank + int bankSlot = -1; + for (int i = 0; i < bank.item.Length; i++) + { + Item item = bank.item[i]; + if (!item.IsAir && item.type == mirrorType) { - mirrorIndex = i; + bankSlot = i; break; } } - if (mirrorIndex == -1) + if (bankSlot == -1) + return false; + + // Find a free inventory slot + int freeInvSlot = -1; + for (int i = 0; i < Player.inventory.Length; i++) { - Main.NewText("You don't have an Adventure Mirror!", Color.Red); - return; + if (Player.inventory[i].IsAir) + { + freeInvSlot = i; + break; + } + } + + if (freeInvSlot == -1) + { + if (Player.whoAmI == Main.myPlayer) + Main.NewText("No free inventory slot for Adventure Mirror!", Color.Red); + return false; } - CancelIfPlayerMoves(); + // Move the item from bank → inventory + Player.inventory[freeInvSlot] = bank.item[bankSlot].Clone(); + bank.item[bankSlot].TurnToAir(); - // Force the player to use the item - Player.selectedItem = mirrorIndex; - Player.controlUseItem = true; - Player.ItemCheck(); + inventoryIndex = freeInvSlot; + return true; } + #endregion } diff --git a/Core/Features/SpawnSelector/Players/ModifyPlayerDrawInfo.cs b/Core/Features/SpawnSelector/Players/ModifyDrawInfoPlayer.cs similarity index 90% rename from Core/Features/SpawnSelector/Players/ModifyPlayerDrawInfo.cs rename to Core/Features/SpawnSelector/Players/ModifyDrawInfoPlayer.cs index 8d6342bb..af783918 100644 --- a/Core/Features/SpawnSelector/Players/ModifyPlayerDrawInfo.cs +++ b/Core/Features/SpawnSelector/Players/ModifyDrawInfoPlayer.cs @@ -1,12 +1,13 @@ using Microsoft.Xna.Framework; -using Terraria; using Terraria.DataStructures; -using Terraria.GameContent; using Terraria.ModLoader; namespace PvPAdventure.Core.Features.SpawnSelector.Players; -public class ModifyPlayerDrawInfo : ModPlayer +/// +/// Useful for forcing the player to be drawn with full brightness even when in player is in darkness. +/// +public class ModifyDrawInfoPlayer : ModPlayer { public static bool ForceFullBrightOnce; public override void ModifyDrawInfo(ref PlayerDrawSet drawInfo) diff --git a/Core/Features/SpawnSelector/Hooks/ItemSlotHooks.cs b/Core/Features/SpawnSelector/Systems/ItemSlotHooks.cs similarity index 55% rename from Core/Features/SpawnSelector/Hooks/ItemSlotHooks.cs rename to Core/Features/SpawnSelector/Systems/ItemSlotHooks.cs index d4d77291..d4a974ed 100644 --- a/Core/Features/SpawnSelector/Hooks/ItemSlotHooks.cs +++ b/Core/Features/SpawnSelector/Systems/ItemSlotHooks.cs @@ -2,10 +2,15 @@ using Terraria.ModLoader; using Terraria.UI; using PvPAdventure.Content.Items; -using Terraria.Audio; -using Terraria.ID; -using Microsoft.Xna.Framework; +using PvPAdventure.Core.Features.SpawnSelector.UI; +using PvPAdventure.System.Client; +using Microsoft.Xna.Framework.Input; +namespace PvPAdventure.Core.Features.SpawnSelector.Systems; + +/// +/// Prevents the Adventure Mirror from being removed from the player inventory via trashing or selling. +/// public class ItemSlotHooks : ModSystem { public override void Load() @@ -31,6 +36,10 @@ private static bool Hook_LeftClick_SellOrTrash( if (!item.IsAir && item.type == ModContent.ItemType()) { + if (Main.keyState.IsKeyDown(Keys.LeftShift) && Main.mouseLeft && Main.mouseLeftRelease) + { + PopupTextHelper.NewText("Cannot quick trash Adventure Mirror!"); + } //SoundEngine.PlaySound(SoundID.MenuClose); return false; // skip SellOrTrash completely } @@ -38,29 +47,30 @@ private static bool Hook_LeftClick_SellOrTrash( return orig(inv, context, slot); } + private static bool IsAdventureMirror(Item item) + => !item.IsAir && item.type == ModContent.ItemType(); + // DRAGGING ONTO THE TRASH SLOT private static void Hook_LeftClick_ItemArray( On_ItemSlot.orig_LeftClick_ItemArray_int_int orig, Item[] inv, int context, int slot) { - if (context == ItemSlot.Context.TrashItem - && !Main.mouseItem.IsAir - && Main.mouseItem.type == ModContent.ItemType()) + // 1) Hard block: putting mirror into any chest/bank slot + bool isStorageSlot = + context == ItemSlot.Context.ChestItem || + context == ItemSlot.Context.BankItem; // Piggy bank + + if (isStorageSlot && + IsAdventureMirror(Main.mouseItem)) // we are dragging the mirror onto this slot { if (Main.mouseLeft && Main.mouseLeftRelease) - { - PopupText.NewText(new AdvancedPopupRequest - { - Color = Color.Crimson, - Text = "Cannot trash Adventure Mirror!", - Velocity = new(0f, -4f), - DurationInFrames = 60 - }, Main.LocalPlayer.Top); - } + PopupTextHelper.NewText("Cannot store Adventure Mirror!"); - return; + // Do NOT call orig -> cancel the placement + return; } + // Fallback to vanilla behavior orig(inv, context, slot); } @@ -71,12 +81,14 @@ private static bool Hook_SellItem( Item item, int stack) { - if (!item.IsAir && item.type == ModContent.ItemType()) + if (IsAdventureMirror(item)) { - //SoundEngine.PlaySound(SoundID.MenuClose); - return false; + if (Main.mouseLeft && Main.mouseLeftRelease) + PopupTextHelper.NewText("Cannot sell Adventure Mirror!"); + + return false; } return orig(self, item, stack); } -} +} \ No newline at end of file diff --git a/Core/Features/SpawnSelector/Systems/SpawnSelectorState.cs b/Core/Features/SpawnSelector/Systems/SpawnSelectorState.cs index c1d7ae6b..77c71bfa 100644 --- a/Core/Features/SpawnSelector/Systems/SpawnSelectorState.cs +++ b/Core/Features/SpawnSelector/Systems/SpawnSelectorState.cs @@ -17,7 +17,6 @@ public override void OnInitialize() UITextPanel chooseYourSpawnPanel = new("Choose Your Spawn", 0.8f, true); chooseYourSpawnPanel.HAlign = 0.5f; - chooseYourSpawnPanel.VAlign = 0f; chooseYourSpawnPanel.Top.Set(10, 0); chooseYourSpawnPanel.BackgroundColor = new Color(73, 94, 171); Append(chooseYourSpawnPanel); diff --git a/Core/Features/SpawnSelector/Systems/SpawnSelectorSystem.cs b/Core/Features/SpawnSelector/Systems/SpawnSelectorSystem.cs index b2096ac6..6dbf5979 100644 --- a/Core/Features/SpawnSelector/Systems/SpawnSelectorSystem.cs +++ b/Core/Features/SpawnSelector/Systems/SpawnSelectorSystem.cs @@ -1,6 +1,5 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; -using PvPAdventure.Core.Features.SpawnSelector.UI; using Terraria; using Terraria.ModLoader; using Terraria.UI; @@ -14,11 +13,10 @@ public class SpawnSelectorSystem : ModSystem public SpawnSelectorState state; // Track whether the spawn selector is enabled - private static bool Enabled; // whether the spawn selector is currently showing in the fullscreen map + private static bool Enabled; public static void SetEnabled(bool newValue) => Enabled = newValue; public static bool GetEnabled() => Enabled; - // Load and unload hooks public override void Load() { if (!Main.dedServ) diff --git a/Core/Features/SpawnSelector/Systems/UnityHooks.cs b/Core/Features/SpawnSelector/Systems/UnityHooks.cs new file mode 100644 index 00000000..5952bdc4 --- /dev/null +++ b/Core/Features/SpawnSelector/Systems/UnityHooks.cs @@ -0,0 +1,28 @@ +using Terraria; +using Terraria.ModLoader; + +namespace PvPAdventure.Core.Features.SpawnSelector.Systems; + +/// +/// This allows the player to click on teammates to teleport to them. +/// +public class UnityHooks : ModSystem +{ + public override void Load() + { + On_Player.HasUnityPotion += OnHasUnityPotion; + } + + public override void Unload() + { + On_Player.HasUnityPotion -= OnHasUnityPotion; + } + + private static bool OnHasUnityPotion(On_Player.orig_HasUnityPotion orig, Player self) + { + if (SpawnSelectorSystem.GetEnabled()) + return true; + + return orig(self); + } +} diff --git a/Core/Features/SpawnSelector/UI/PopupTextHelper.cs b/Core/Features/SpawnSelector/UI/PopupTextHelper.cs new file mode 100644 index 00000000..baa755fa --- /dev/null +++ b/Core/Features/SpawnSelector/UI/PopupTextHelper.cs @@ -0,0 +1,42 @@ +using Microsoft.Xna.Framework; +using Terraria; +using Terraria.ModLoader; + +namespace PvPAdventure.Core.Features.SpawnSelector.UI; +public static class PopupTextHelper +{ + public static void NewText(string text, Color color=default, bool showInMultiplayer=false) + { + if (color == default) + color = Color.Crimson; + + var config = ModContent.GetInstance(); + if (!config.ShowPopupText) + { + return; + } + + if (showInMultiplayer) + { + PopupText.NewText(new AdvancedPopupRequest + { + Color = color, + Text = text, + Velocity = new(0f, -4f), + DurationInFrames = 60 + }, Main.LocalPlayer.Top); + return; + } + + if (Main.LocalPlayer.whoAmI == Main.myPlayer) + { + PopupText.NewText(new AdvancedPopupRequest + { + Color = color, + Text = text, + Velocity = new(0f, -4f), + DurationInFrames = 60 + }, Main.LocalPlayer.Top); + } + } +} diff --git a/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs b/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs index 935295d0..8a539b45 100644 --- a/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs +++ b/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs @@ -4,13 +4,15 @@ using PvPAdventure.Core.Features.SpawnSelector.Systems; using PvPAdventure.Core.Helpers; using ReLogic.Content; +using ReLogic.Graphics; using System; using Terraria; using Terraria.GameContent; using Terraria.GameContent.UI.Elements; +using Terraria.ID; using Terraria.ModLoader; -using Terraria.ModLoader.UI; using Terraria.UI; +using tModPorter; namespace PvPAdventure.Core.Features.SpawnSelector.UI { @@ -27,6 +29,7 @@ internal class UISpawnSelectorCharacterListItem : UIPanel private readonly Asset _playerBGTexture; private readonly int _playerIndex; + public int PlayerIndex => _playerIndex; public UISpawnSelectorCharacterListItem(Player player) { @@ -52,24 +55,61 @@ private void DrawHeadOnMap(Player p) { float scale = Main.mapFullscreenScale; + Vector2 mapPos = new( + (p.position.X + p.width / 2f) / 16f, + (p.position.Y + p.gfxOffY + p.height / 2f) / 16f + ); + Vector2 headPos = new( - ((p.position.X + p.width / 2f) / 16f - Main.mapFullscreenPos.X) * scale - + Main.screenWidth / 2f - 14f * scale+48, + (mapPos.X - Main.mapFullscreenPos.X) * scale + Main.screenWidth / 2f, + (mapPos.Y - Main.mapFullscreenPos.Y) * scale + Main.screenHeight / 2f + ); + headPos += new Vector2(34f, 44f); - ((p.position.Y + p.gfxOffY + p.height / 2f) / 16f - Main.mapFullscreenPos.Y) * scale - + Main.screenHeight / 2f - 14f * scale+58 + CalculatedStyle inner = GetInnerDimensions(); + Rectangle rect = new( + (int)inner.X - 6, + (int)inner.Y - 6, + 100, + 72 ); + Vector2 arrowStart = new(rect.X + rect.Width / 2f, rect.Bottom + 8f); + + Texture2D arrowTex = Ass.Arrow.Value; + Vector2 arrowOrigin = arrowTex.Size() * 0.5f; + + Vector2 dir = headPos - arrowStart; + if (dir.LengthSquared() > 0.001f) + { + dir.Normalize(); + float rotation = dir.ToRotation(); // adjust with +- PiOver2 if your texture points up + Vector2 arrowPos = arrowStart; + + Main.spriteBatch.Draw( + arrowTex, + arrowPos, + null, + Color.White, + rotation, + arrowOrigin, + 1f, + SpriteEffects.None, + 0f + ); + } + Color color = Main.teamColor[p.team]; - Main.PlayerRenderer.DrawPlayerHead( + Main.MapPlayerRenderer.DrawPlayerHead( Main.Camera, p, headPos, - scale: 1.3f, + scale: 1.6f, borderColor: color ); - Utils.DrawBorderString(Main.spriteBatch, p.name, headPos, Color.White); + + Utils.DrawBorderString(Main.spriteBatch, p.name, headPos + new Vector2(-20f, 20f), Color.White); } private void DrawNineSlice(SpriteBatch sb, int x, int y, int w, int h, Texture2D tex, Color color, int inset, int c = 5) @@ -132,7 +172,7 @@ protected override void DrawSelf(SpriteBatch sb) null, Main.UIScaleMatrix); - ModifyPlayerDrawInfo.ForceFullBrightOnce = true; + ModifyDrawInfoPlayer.ForceFullBrightOnce = true; try { Vector2 playerDrawPos = pos + Main.screenPosition + new Vector2(34, 9); @@ -149,7 +189,7 @@ protected override void DrawSelf(SpriteBatch sb) } finally { - ModifyPlayerDrawInfo.ForceFullBrightOnce = false; + ModifyDrawInfoPlayer.ForceFullBrightOnce = false; } // Switch back to "normal" UI batch @@ -238,15 +278,15 @@ protected override void DrawSelf(SpriteBatch sb) if (IsMouseHovering) { Main.instance.MouseText("Teleport to " + name); - var old = Main.UIScaleMatrix; - //Main.spriteBatch.End(); - //Main.spriteBatch.Begin(SpriteSortMode.Immediate,BlendState.AlphaBlend,SamplerState.PointClamp,DepthStencilState.None,RasterizerState.CullCounterClockwise,null,Matrix.Identity); + Main.spriteBatch.End(); + Main.spriteBatch.Begin(SpriteSortMode.Immediate,BlendState.AlphaBlend,SamplerState.PointClamp,DepthStencilState.None,RasterizerState.CullCounterClockwise,null,Matrix.Identity); - //DrawHeadOnMap(player); + DrawHeadOnMap(player); + //DrawGuideMarkerOnMap(Main.spriteBatch); - //Main.spriteBatch.End(); - //Main.spriteBatch.Begin(SpriteSortMode.Deferred,BlendState.AlphaBlend,SamplerState.PointClamp,DepthStencilState.None,RasterizerState.CullCounterClockwise,null,old); + Main.spriteBatch.End(); + Main.spriteBatch.Begin(SpriteSortMode.Deferred,BlendState.AlphaBlend,SamplerState.PointClamp,DepthStencilState.None,RasterizerState.CullCounterClockwise,null,Main.UIScaleMatrix); } //Main.NewText(Main.mouseY); // 482,435 is spawn diff --git a/Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs b/Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs index 15264461..fb802b1c 100644 --- a/Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs +++ b/Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs @@ -38,30 +38,19 @@ private void BuildLayout() var players = new List(); var local = Main.LocalPlayer; -#if DEBUG - // If we have debug players, use them instead of scanning teammates - if (_debugPlayers.Count > 0) + if (local.team != 0) { - players.AddRange(_debugPlayers); - } - else -#endif - { - // ADD TEAMMATES - if (local.team != 0) + for (int i = 0; i < Main.maxPlayers; i++) { - for (int i = 0; i < Main.maxPlayers; i++) - { - Player p = Main.player[i]; + Player p = Main.player[i]; - if (p == null || !p.active) - continue; + if (p == null || !p.active || p.dead || p.statLife <= 0) + continue; - if (p.whoAmI == local.whoAmI || p.team != local.team) - continue; + if (p.whoAmI == local.whoAmI || p.team != local.team) + continue; - players.Add(p); - } + players.Add(p); } } @@ -69,7 +58,7 @@ private void BuildLayout() float itemWidth = UISpawnSelectorCharacterListItem.ItemWidth; float itemHeight = UISpawnSelectorCharacterListItem.ItemHeight; - float randomWidth = itemHeight; // square random panel + float randomWidth = itemHeight; float contentWidth = playerCount * itemWidth + playerCount * Spacing @@ -78,13 +67,18 @@ private void BuildLayout() float panelWidth = contentWidth + HorizontalPadding * 2f; float panelHeight = itemHeight + VerticalPadding * 2f; + if (panelWidth <= 0f) + panelWidth = itemWidth + HorizontalPadding * 2f; + + if (panelHeight <= 0f) + panelHeight = itemHeight + VerticalPadding * 2f; + Width.Set(panelWidth, 0f); Height.Set(panelHeight, 0f); float startX = HorizontalPadding; float y = VerticalPadding; - // Add players in a row for (int i = 0; i < playerCount; i++) { float x = startX + i * (itemWidth + Spacing); @@ -97,7 +91,6 @@ private void BuildLayout() _playerItems.Add(row); } - // Square random panel to the right of the last player _randomPanel = new UISpawnSelectorRandomPanel( startX, itemHeight, @@ -108,45 +101,70 @@ private void BuildLayout() ); Append(_randomPanel); + Recalculate(); + RecalculateChildren(); + Log.Debug($"UISpawnSelectorPanel.BuildLayout: players={playerCount}, panelWidth={panelWidth}"); } public void Rebuild() { BuildLayout(); - Recalculate(); - RecalculateChildren(); Log.Debug("UISpawnSelectorPanel.Rebuild: UI rebuilt"); } - public override void Draw(SpriteBatch spriteBatch) + public override void Update(GameTime gameTime) { - base.Draw(spriteBatch); + if (NeedsRebuild()) + { + Rebuild(); + } + + base.Update(gameTime); } - #region Debug -#if DEBUG - private readonly List _debugPlayers = new(); -#endif - public void DebugAddPlayer() + public override void Draw(SpriteBatch spriteBatch) { -#if DEBUG - _debugPlayers.Add(Main.LocalPlayer); - BuildLayout(); - Log.Debug($"SpawnSelector DebugAddPlayer: debugPlayers={_debugPlayers.Count}"); -#endif + base.Draw(spriteBatch); } - public void DebugClearPlayers() + private bool NeedsRebuild() { -#if DEBUG - _debugPlayers.Clear(); - BuildLayout(); - Log.Debug("SpawnSelector DebugClearPlayers: cleared debug players"); -#endif - } - #endregion + var dims = GetDimensions(); + if (dims.Width <= 0f || dims.Height <= 0f) + return true; + + if (_randomPanel == null) + return true; + var randomDims = _randomPanel.GetDimensions(); + if (randomDims.Width <= 0f || randomDims.Height <= 0f) + return true; + + var local = Main.LocalPlayer; + var players = new List(); + + for (int i = 0; i < Main.maxPlayers; i++) + { + var p = Main.player[i]; + if (p == null || !p.active || p.dead || p.statLife <= 0) + continue; + if (p.whoAmI == local.whoAmI || p.team != local.team) + continue; + players.Add(p.whoAmI); + } + + if (players.Count != _playerItems.Count) + return true; + + for (int i = 0; i < players.Count; i++) + { + if (_playerItems[i] == null) return true; + if (_playerItems[i].PlayerIndex != players[i]) return true; + } + + return false; + } } } diff --git a/Core/Features/SpawnSelector/UI/UISpawnSelectorRandomPanel.cs b/Core/Features/SpawnSelector/UI/UISpawnSelectorRandomPanel.cs index 7ef5c9a1..237cf2d2 100644 --- a/Core/Features/SpawnSelector/UI/UISpawnSelectorRandomPanel.cs +++ b/Core/Features/SpawnSelector/UI/UISpawnSelectorRandomPanel.cs @@ -30,9 +30,10 @@ public override void LeftClick(UIMouseEvent evt) { base.LeftClick(evt); - //var gm = ModContent.GetInstance(); - //if (gm.CurrentPhase != GameManager.Phase.Playing) - // return; + // Redundant check, just to be sure we don't allow any shenanigans + var gm = ModContent.GetInstance(); + if (gm.CurrentPhase != GameManager.Phase.Playing) + return; if (Main.netMode == NetmodeID.MultiplayerClient) { diff --git a/Core/Helpers/AssetLoader.cs b/Core/Helpers/AssetLoader.cs index 747b6dd3..61d92e86 100644 --- a/Core/Helpers/AssetLoader.cs +++ b/Core/Helpers/AssetLoader.cs @@ -9,6 +9,7 @@ public static class Ass { public static Asset Question_Mark; public static Asset[] MapBG; + public static Asset Arrow; public static bool Initialized { get; set; } diff --git a/Localization/en-US.hjson b/Localization/en-US.hjson index c2b1f977..3d32fd4a 100644 --- a/Localization/en-US.hjson +++ b/Localization/en-US.hjson @@ -19,6 +19,8 @@ Mods: { AddPlayerToSpawnSelector.DisplayName: Add Player To Spawn Selector RemovePlayerFromSpawnSelector.DisplayName: Remove Player From Spawn Selector ClearPlayersFromSpawnSelector.DisplayName: Clear Players From Spawn Selector + "[DEBUG] OpenControls.DisplayName": "[ D E B U G] Open Controls" + "[DEBUG] SwitchTeams.DisplayName": "[ D E B U G] Switch Teams" } Configs: { @@ -369,6 +371,11 @@ Mods: { OpenMapAfterRecall: { Label: Open Map After Recall + Tooltip: Opens the map instantly after the mirror has finished channeling + } + + ShowPopupText: { + Label: Show Popup Text Tooltip: "" } } diff --git a/System/GameManager.cs b/System/GameManager.cs index c95f296c..aa925483 100644 --- a/System/GameManager.cs +++ b/System/GameManager.cs @@ -120,8 +120,6 @@ private void OnMainStartRain(On_Main.orig_StartRain orig) orig(); ChatHelper.BroadcastChatMessage(NetworkText.FromKey("Mods.PvPAdventure.Rain"), Color.White); } - private bool hasPrintedGameOver = false; - public override void PostUpdateTime() { // The Nurse is never allowed to spawn. @@ -155,13 +153,6 @@ public override void PostUpdateTime() if (--TimeRemaining <= 0) { CurrentPhase = Phase.Waiting; - - //if (!hasPrintedGameOver) - { - ChatHelper.BroadcastChatMessage(NetworkText.FromLiteral($"The game is over!"), - Color.Green); - //hasPrintedGameOver = true; - } } break; @@ -178,18 +169,6 @@ public void StartGame(int time) NetworkText.FromLiteral($"The game will begin in {_startGameCountdown / 60} seconds."), Color.Green); } -#if DEBUG - public void DebugStartGame(int time) - { - CurrentPhase = Phase.Waiting; - TimeRemaining = time; - _startGameCountdown = 1; - - ChatHelper.BroadcastChatMessage( - NetworkText.FromLiteral($"[DEBUG] The game has started (GameMananger.Phase=Playing)"), Color.Green); - } -#endif - // NOTE: This is not called on multiplayer clients (see CurrentPhase property). private void OnPhaseChange(Phase newPhase) { From 5aca4de1ae3f5f21aa6955e59c808ee3959e520f Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Sat, 15 Nov 2025 19:54:44 -0800 Subject: [PATCH 173/206] Revert "fixed a small issue with pirahina gun" This reverts commit a690c82cadaf78458494e94ee7bf681f66a68159. --- AdventureProjectile.cs | 43 ++++++++++++++++++++++++++++-------------- Dogshit.cs | 41 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 14 deletions(-) diff --git a/AdventureProjectile.cs b/AdventureProjectile.cs index 5dda8065..b3f3cdb6 100644 --- a/AdventureProjectile.cs +++ b/AdventureProjectile.cs @@ -790,7 +790,7 @@ public override void ModifyHitPlayer(Projectile projectile, Player target, ref P modifiers.SourceDamage *= 0.75f; } } - public class VanillaPiranhaGun : GlobalProjectile + public class VanillaPirahinaGun : GlobalProjectile { public override bool InstancePerEntity => true; @@ -807,12 +807,6 @@ public override void SetDefaults(Projectile projectile) projectile.friendly = true; } - public override void OnSpawn(Projectile projectile, IEntitySource source) - { - attachedPlayerIndex = -1; - attachOffset = Vector2.Zero; - } - public override void AI(Projectile projectile) { if (attachedPlayerIndex < 0) @@ -871,7 +865,7 @@ public override void OnHitPlayer(Projectile projectile, Player target, Player.Hu { attachedPlayerIndex = target.whoAmI; attachOffset = projectile.Center - target.Center; - projectile.ai[0] = 1f; + projectile.ai[0] = 1f; // Set to "attached" state projectile.ai[1] = target.whoAmI; projectile.netUpdate = true; } @@ -891,11 +885,12 @@ public override bool PreAI(Projectile projectile) { shouldDetach = true; } + else if (!owner.channel || owner.HeldItem.type != ItemID.PiranhaGun) { shouldDetach = true; } - else if (Vector2.Distance(projectile.Center, owner.Center) > 2000f) //distance until detatch + else if (Vector2.Distance(projectile.Center, owner.Center) > 2000f) // this will detach the pirahinas if theyre too far away when attached to a player, we can change this { shouldDetach = true; } @@ -921,7 +916,7 @@ public override bool PreAI(Projectile projectile) if (projectile.localAI[0] <= 0f) { - projectile.localAI[0] = 40f; // amount of frames it hits + projectile.localAI[0] = 40f; // Attack every frame (temp), we can change ts if (Main.myPlayer == projectile.owner) { @@ -937,7 +932,7 @@ public override bool PreAI(Projectile projectile) projectile.localAI[0]--; } - return false; + return false; // Don't run vanilla AI } public override bool CanHitPlayer(Projectile projectile, Player target) @@ -966,7 +961,9 @@ public override void ReceiveExtraAI(Projectile projectile, BitReader bitReader, attachOffset.Y = binaryReader.ReadSingle(); } } - public class PiranhaGunItemSystem : GlobalItem + + // GlobalItem even though in adventureprojectile because FUCK YOU + public class PiranhaGunItem : GlobalItem { public override bool AppliesToEntity(Item entity, bool lateInstantiation) { @@ -981,7 +978,7 @@ public override void HoldItem(Item item, Player player) Projectile proj = Main.projectile[i]; if (proj.active && proj.owner == player.whoAmI && proj.type == ProjectileID.MechanicalPiranha) { - var modProj = proj.GetGlobalProjectile(); + var modProj = proj.GetGlobalProjectile(); if (modProj != null && modProj.attachedPlayerIndex >= 0) { hasAttachedPiranha = true; @@ -1005,7 +1002,7 @@ public override bool CanUseItem(Item item, Player player) Projectile proj = Main.projectile[i]; if (proj.active && proj.owner == player.whoAmI && proj.type == ProjectileID.MechanicalPiranha) { - var modProj = proj.GetGlobalProjectile(); + var modProj = proj.GetGlobalProjectile(); if (modProj != null && modProj.attachedPlayerIndex >= 0) { return true; @@ -1015,4 +1012,22 @@ public override bool CanUseItem(Item item, Player player) return base.CanUseItem(item, player); } } + public class NoKnockbackProjectiles : GlobalProjectile + { + public override bool AppliesToEntity(Projectile entity, bool lateInstantiation) + { + int projType = entity.type; + + return projType == ProjectileID.Meteor1 || + projType == ProjectileID.Meteor2 || + projType == ProjectileID.Meteor3 || + projType == ProjectileID.HeatRay || + projType == ProjectileID.FlyingKnife || + projType == ProjectileID.LaserMachinegunLaser; + } + public override void ModifyHitPlayer(Projectile projectile, Player target, ref Player.HurtModifiers modifiers) + { + modifiers.Knockback *= 0f; + } + } } \ No newline at end of file diff --git a/Dogshit.cs b/Dogshit.cs index 58ab5461..f7c7c875 100644 --- a/Dogshit.cs +++ b/Dogshit.cs @@ -16,6 +16,47 @@ using Terraria.WorldBuilding; namespace PvPAdventure { + public class IncreasedRainSystem : ModSystem + { + private int rainCheckTimer = 0; + private const int RainCheckInterval = 60; + + public override void PostUpdateWorld() + { + if (Main.netMode == NetmodeID.MultiplayerClient) + return; + + rainCheckTimer++; + + if (rainCheckTimer >= RainCheckInterval) + { + rainCheckTimer = 0; + + if (!Main.raining && !Main.bloodMoon && !Main.eclipse) + { + if (Main.rand.NextBool(1200)) //this is just the chance each second that rain starts, so basically 1/20 every minute, so 1 rain every 20 mins + { + StartRain(); + } + } + } + } + + private void StartRain() + { + Main.StartRain(); + + // Set a reasonable rain duration + Main.rainTime = Main.rand.Next(18000, 54000); // 5-15 minutes + Main.maxRaining = Main.rand.NextFloat(0.3f, 0.9f); + + // Sync to clients in multiplayer + if (Main.netMode == NetmodeID.Server) + { + NetMessage.SendData(MessageID.WorldData); + } + } + } public class MechBossSpawnSystem : ModSystem { private bool hasAnnouncedTonight = false; From c881788b1aaac9ed72d872344e7167612abf264e Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Sat, 15 Nov 2025 20:07:13 -0800 Subject: [PATCH 174/206] Reapply "Merge branch 'feature/RTP-Spawn-Selector' into feature/missinginmaster" This reverts commit 4ede504aa5e0aa470b50663670dab059713d0195. --- AdventureConfig.cs | 5 + Assets/SpawnSelector/CornerMask4px.png | Bin 0 -> 268 bytes Assets/SpawnSelector/FadeHorizontal.png | Bin 0 -> 80 bytes Assets/SpawnSelector/MapBG1.png | Bin 0 -> 4406 bytes Assets/SpawnSelector/MapBG10.png | Bin 0 -> 2262 bytes Assets/SpawnSelector/MapBG11.png | Bin 0 -> 2836 bytes Assets/SpawnSelector/MapBG12.png | Bin 0 -> 3447 bytes Assets/SpawnSelector/MapBG13.png | Bin 0 -> 10442 bytes Assets/SpawnSelector/MapBG14.png | Bin 0 -> 6003 bytes Assets/SpawnSelector/MapBG15.png | Bin 0 -> 5034 bytes Assets/SpawnSelector/MapBG16.png | Bin 0 -> 10951 bytes Assets/SpawnSelector/MapBG17.png | Bin 0 -> 5892 bytes Assets/SpawnSelector/MapBG18.png | Bin 0 -> 7861 bytes Assets/SpawnSelector/MapBG19.png | Bin 0 -> 10791 bytes Assets/SpawnSelector/MapBG2.png | Bin 0 -> 3466 bytes Assets/SpawnSelector/MapBG20.png | Bin 0 -> 3376 bytes Assets/SpawnSelector/MapBG21.png | Bin 0 -> 4971 bytes Assets/SpawnSelector/MapBG22.png | Bin 0 -> 14635 bytes Assets/SpawnSelector/MapBG23.png | Bin 0 -> 4431 bytes Assets/SpawnSelector/MapBG24.png | Bin 0 -> 4523 bytes Assets/SpawnSelector/MapBG25.png | Bin 0 -> 291 bytes Assets/SpawnSelector/MapBG26.png | Bin 0 -> 3331 bytes Assets/SpawnSelector/MapBG27.png | Bin 0 -> 4784 bytes Assets/SpawnSelector/MapBG28.png | Bin 0 -> 7876 bytes Assets/SpawnSelector/MapBG29.png | Bin 0 -> 9729 bytes Assets/SpawnSelector/MapBG3.png | Bin 0 -> 4762 bytes Assets/SpawnSelector/MapBG30.png | Bin 0 -> 10879 bytes Assets/SpawnSelector/MapBG31.png | Bin 0 -> 9307 bytes Assets/SpawnSelector/MapBG32.png | Bin 0 -> 4568 bytes Assets/SpawnSelector/MapBG33.png | Bin 0 -> 1879 bytes Assets/SpawnSelector/MapBG34.png | Bin 0 -> 5236 bytes Assets/SpawnSelector/MapBG35.png | Bin 0 -> 6505 bytes Assets/SpawnSelector/MapBG36.png | Bin 0 -> 7611 bytes Assets/SpawnSelector/MapBG37.png | Bin 0 -> 2454 bytes Assets/SpawnSelector/MapBG38.png | Bin 0 -> 2580 bytes Assets/SpawnSelector/MapBG39.png | Bin 0 -> 2804 bytes Assets/SpawnSelector/MapBG4.png | Bin 0 -> 5575 bytes Assets/SpawnSelector/MapBG40.png | Bin 0 -> 5072 bytes Assets/SpawnSelector/MapBG41.png | Bin 0 -> 5990 bytes Assets/SpawnSelector/MapBG42.png | Bin 0 -> 4794 bytes Assets/SpawnSelector/MapBG5.png | Bin 0 -> 4478 bytes Assets/SpawnSelector/MapBG6.png | Bin 0 -> 5718 bytes Assets/SpawnSelector/MapBG7.png | Bin 0 -> 5501 bytes Assets/SpawnSelector/MapBG8.png | Bin 0 -> 7262 bytes Assets/SpawnSelector/MapBG9.png | Bin 0 -> 7093 bytes Assets/SpawnSelector/Question_Mark.png | Bin 0 -> 1710 bytes Assets/SpawnSelector/Question_Mark_Blue.png | Bin 0 -> 316 bytes Assets/SpawnSelector/Teleportation_Potion.png | Bin 0 -> 1776 bytes Content/Items/AdventureMirror.cs | 82 ++++ Content/Items/AdventureMirror.png | Bin 0 -> 505 bytes Content/Items/AdventureMirrorGlobalItem.cs | 31 ++ Core/Debug/DebugKeybinds.cs | 66 +++ .../SpawnSelector/Hooks/ItemSlotHooks.cs | 70 ++++ .../SpawnSelector/Hooks/UnityHooks.cs | 45 +++ .../Players/AdventureMirrorPlayer.cs | 273 +++++++++++++ .../Players/ModifyPlayerDrawInfo.cs | 47 +++ .../Systems/SpawnSelectorState.cs | 47 +++ .../Systems/SpawnSelectorSystem.cs | 94 +++++ .../UI/UISpawnSelectorCharacterListItem.cs | 378 ++++++++++++++++++ .../SpawnSelector/UI/UISpawnSelectorPanel.cs | 150 +++++++ .../UI/UISpawnSelectorRandomPanel.cs | 91 +++++ Core/Helpers/AssetLoader.cs | 43 ++ Core/Helpers/Log.cs | 51 +++ Localization/en-US.hjson | 26 ++ Properties/launchSettings.json | 8 +- PvPAdventure.csproj | 56 +-- PvPAdventure.csproj.user | 9 + System/Client/Keybinds.cs | 2 + icon_small.png | Bin 0 -> 942 bytes 69 files changed, 1547 insertions(+), 27 deletions(-) create mode 100644 Assets/SpawnSelector/CornerMask4px.png create mode 100644 Assets/SpawnSelector/FadeHorizontal.png create mode 100644 Assets/SpawnSelector/MapBG1.png create mode 100644 Assets/SpawnSelector/MapBG10.png create mode 100644 Assets/SpawnSelector/MapBG11.png create mode 100644 Assets/SpawnSelector/MapBG12.png create mode 100644 Assets/SpawnSelector/MapBG13.png create mode 100644 Assets/SpawnSelector/MapBG14.png create mode 100644 Assets/SpawnSelector/MapBG15.png create mode 100644 Assets/SpawnSelector/MapBG16.png create mode 100644 Assets/SpawnSelector/MapBG17.png create mode 100644 Assets/SpawnSelector/MapBG18.png create mode 100644 Assets/SpawnSelector/MapBG19.png create mode 100644 Assets/SpawnSelector/MapBG2.png create mode 100644 Assets/SpawnSelector/MapBG20.png create mode 100644 Assets/SpawnSelector/MapBG21.png create mode 100644 Assets/SpawnSelector/MapBG22.png create mode 100644 Assets/SpawnSelector/MapBG23.png create mode 100644 Assets/SpawnSelector/MapBG24.png create mode 100644 Assets/SpawnSelector/MapBG25.png create mode 100644 Assets/SpawnSelector/MapBG26.png create mode 100644 Assets/SpawnSelector/MapBG27.png create mode 100644 Assets/SpawnSelector/MapBG28.png create mode 100644 Assets/SpawnSelector/MapBG29.png create mode 100644 Assets/SpawnSelector/MapBG3.png create mode 100644 Assets/SpawnSelector/MapBG30.png create mode 100644 Assets/SpawnSelector/MapBG31.png create mode 100644 Assets/SpawnSelector/MapBG32.png create mode 100644 Assets/SpawnSelector/MapBG33.png create mode 100644 Assets/SpawnSelector/MapBG34.png create mode 100644 Assets/SpawnSelector/MapBG35.png create mode 100644 Assets/SpawnSelector/MapBG36.png create mode 100644 Assets/SpawnSelector/MapBG37.png create mode 100644 Assets/SpawnSelector/MapBG38.png create mode 100644 Assets/SpawnSelector/MapBG39.png create mode 100644 Assets/SpawnSelector/MapBG4.png create mode 100644 Assets/SpawnSelector/MapBG40.png create mode 100644 Assets/SpawnSelector/MapBG41.png create mode 100644 Assets/SpawnSelector/MapBG42.png create mode 100644 Assets/SpawnSelector/MapBG5.png create mode 100644 Assets/SpawnSelector/MapBG6.png create mode 100644 Assets/SpawnSelector/MapBG7.png create mode 100644 Assets/SpawnSelector/MapBG8.png create mode 100644 Assets/SpawnSelector/MapBG9.png create mode 100644 Assets/SpawnSelector/Question_Mark.png create mode 100644 Assets/SpawnSelector/Question_Mark_Blue.png create mode 100644 Assets/SpawnSelector/Teleportation_Potion.png create mode 100644 Content/Items/AdventureMirror.cs create mode 100644 Content/Items/AdventureMirror.png create mode 100644 Content/Items/AdventureMirrorGlobalItem.cs create mode 100644 Core/Debug/DebugKeybinds.cs create mode 100644 Core/Features/SpawnSelector/Hooks/ItemSlotHooks.cs create mode 100644 Core/Features/SpawnSelector/Hooks/UnityHooks.cs create mode 100644 Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs create mode 100644 Core/Features/SpawnSelector/Players/ModifyPlayerDrawInfo.cs create mode 100644 Core/Features/SpawnSelector/Systems/SpawnSelectorState.cs create mode 100644 Core/Features/SpawnSelector/Systems/SpawnSelectorSystem.cs create mode 100644 Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs create mode 100644 Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs create mode 100644 Core/Features/SpawnSelector/UI/UISpawnSelectorRandomPanel.cs create mode 100644 Core/Helpers/AssetLoader.cs create mode 100644 Core/Helpers/Log.cs create mode 100644 PvPAdventure.csproj.user create mode 100644 icon_small.png diff --git a/AdventureConfig.cs b/AdventureConfig.cs index 99b3d97e..0d9f7fcd 100644 --- a/AdventureConfig.cs +++ b/AdventureConfig.cs @@ -1,3 +1,4 @@ +using PvPAdventure.Content.Items; using System; using System.Collections.Generic; using System.ComponentModel; @@ -65,6 +66,10 @@ public class InvasionSizeValue [DefaultValue(4 * 60)] public int RecallFrames { get; set; } + [Range(0, 60 * 60)] + [DefaultValue(4 * 60)] + public int AdventureMirrorRecallFrames { get; set; } + [Range(0, 30 * 60)] [DefaultValue(1.5 * 60)] public int SpawnImmuneFrames { get; set; } diff --git a/Assets/SpawnSelector/CornerMask4px.png b/Assets/SpawnSelector/CornerMask4px.png new file mode 100644 index 0000000000000000000000000000000000000000..8f03f4353fab813910a3a823b9e04bef34e0e43c GIT binary patch literal 268 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=mpxq^Ln`LHy=};MSV4p(@ZbLb zb3H{lZ)&8@W3iUKarBMIyO`v|bBf=+^Ixzk%l7-{*2%~FKi<2(UvA#1U7O3Nn}4_) z{raKXuV){VbL^V7Ph^O4m`oRZzCJU5@$riP0X5vAp?l?)oZ0{L-P^lQU#_vX7hI@P Tt+JF6FS$$$R;|6k9>*7jZH eLAl2peun<-g8yqaZ{Y?iVeoYIb6Mw<&;$Vdrx$+! literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG1.png b/Assets/SpawnSelector/MapBG1.png new file mode 100644 index 0000000000000000000000000000000000000000..b981a57d181cb2d141f0111f55f8f900749a0fbf GIT binary patch literal 4406 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 literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG11.png b/Assets/SpawnSelector/MapBG11.png new file mode 100644 index 0000000000000000000000000000000000000000..596da6219c45e4154b793f48f5328d7044f824e1 GIT binary patch literal 2836 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 Z`#;INucwpDS}Xtn002ovPDHLkV1j3tr<(u( literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG13.png b/Assets/SpawnSelector/MapBG13.png new file mode 100644 index 0000000000000000000000000000000000000000..0faf8c72b57e5894cf98f4174dba7df52ebfb493 GIT binary patch literal 10442 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 A&j0`b literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG14.png b/Assets/SpawnSelector/MapBG14.png new file mode 100644 index 0000000000000000000000000000000000000000..4faf6041dc378e69e8e371f677587b097e583962 GIT binary patch literal 6003 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 literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG15.png b/Assets/SpawnSelector/MapBG15.png new file mode 100644 index 0000000000000000000000000000000000000000..9a9a161874bee64b8d50adece645f80ff22526e3 GIT binary patch literal 5034 zcmV;b6IJYqP)gwMQg zj~}GZ^ZeFhk97Bsj!J&?I&kZ;N4neZz8~ggP?qzP?y23ql12;28}GyM!S(CiGdsuO zy}x_&kc>>C zZom6}+7OsdpY{l;%p?@}`^oNL-y%99__M;*>D9%6%-Qy|zmOG_8K_lQ3zXJKO3)y9 zy{eik5;d<#rvFZRB@$z)L3 zUNM`tFl`7uae<1Bh=f$CnvELOY=eHhZ2IniRK14xM-sUIVBTMk@}xv4xw=L0dq&jt z;)?eR3X$a4tlnGBkB&-(jxlm(4ec=`eQAWT9=xpmH8i9f zyWO3m2i?bev(m7NLA2z!?>FCh`%c(5Dj8$yP5as?4F$D8VX;_;t3reZ&-QdJp(x=o zDp=Jlt=Yrtdto|yA0?w#f1--@-r8{uPNYjM-;caP8c|Om6jrRl)oUi9nUrR~X&TyC z^nKGYeNhB&HEOif;1Z{e#~Xv5Q^oduSaR>&NanSujLft4i&;J3{pc4VnE<4d1QS%X zaN#1!B5Hl0{_c{Uk?flaL{_O+SPPMn!wSmMz;&0*misd|KNRQg z%WeV?&ISb{A)Po!ew1Xs7lh*7kp`<-wJK?uH0oZ{nYvo_b7UOXl(iBH2}VWAdPk6IruXGil`BpDE28 z8Q~TI8AkFO*DwAM-?H?gq*6eQncwfGH~R)pw3dW|$#weat+1q=9-MfY@{K!<_eil$zzpT)&=);RVWBN_x@KKc@#Jqqee6JOj7%| z{q4g=*+?Yz$S^ily^ua7#7Wi4@|N!v$aL{ujR1Lis1#HZeYyxUsXVnlfxf>@45Lkf z^sr^dQpwx()M8Ss05X+)LS$fMxvWx;zB5^$19tIXXnxy$?K~-suNMPFPFEk@`*n0^G zT6z|;T_4ZlU|K8njydZV;7KZCLc zo7y3&f}_6mN~;xW43p-$x3EprRpgQ|gJV!C=;)~QvEJ9s`+V#yBQ_++B1@4kx>mWX z@@j*|zNq@^OV{ME5nN}KNRR2xMDGmiKgctVqrP=iq#$ask=`Gp|NVDJUFMHP5}?MI z=VhiA>nhJA7~`@0jo>wwG0d-3IDJe9)GMMvN?K+#MM&SD#H*uvu96wGR)Bt7pOK0c zn*seG)hB$+mSnvZ-GKq(#?4F`l;%H5KNy$~C0*4e2!U}3QsD(?L!+A#5xJ?L z==&pAD$<67aGq~|oiC-Th@>&=FZDi?Ee6^Fj%R{UYK?wsi*4xV-FtAKcGLO+`k;Ycq>rhj`Y@Pg25N<^ zeyn6M!z76Ne(<|exEFr;-R{%i?#Uz#Il8KiDwKUB8;{1XagACAghFemnnu6OP2b_= zbWP}J8Jfk<#DNCbNnT4zRi(`7vIH+2xEiZWqVTW0b9qmxjQM}6{i+k`R`on`IZiLS zn>))v1hm`vd9_HFX|2L^ELRyJVXv?vRtcq=)vg2N(Pi+E6a7`S@ z95Pzd?b>H)KT}?A1yFJnkj^_t50^;L@Y!`0+ZV8sr@6$6eH4hk87lkf{ezN@2d#S- zM9RnpzrT~$6E>EQ5`Q^!BQ86h(L6@wB8hAuga+%^Mol*9Gx_4E4^UOXenyF;Wvck$ zm-o`bKq|Ms{hMI{D^B+y7F;8J^;=}=YJdWH*YV4!o^+rBQVk>Tdr$0_ezZ1-;czvp zl9Dx^~Q8aij%1QCa=21ndODb&l=R~@I35<-fgkicFP@cLf2**D4fW_e4WHmSIY|-)p1fyldTqeZ^1wP+R}IP z>yS=bwM-{+o#y67q0(?))Hk9Mp_UmQgi2-E)MBTqrJ7Y~Vt)@r4N%L7hD@VpJ*K=F zlt`dhv#mZr$2f`Bd{-WW&{8=f>DoxN@F+0PQTZtJ^EcKt0|fq`V| z&5@KMGtrupwTQo{2G1BOiv!<2tHIyJN^sKE0Q&XMU+(k8iiifKFWrJ=qaw06Fr*Lf z#9rt15LDM*7f4&R2#%wf8V<2ehoF0bzm2=)f95UK79Dz??AY9YJ3fmTr>Id2Fm zmMT=^vZ`7m_`D>|s|NwHxlWGO0-;PgtCGpg=}1b;jme~h(iBNQj2^WHDT!XO%tQ9R zc|t1Z#pq0x_cjfIL!O>N_V_C@6H$J-PUBQY=xl7R)0;2j;>E`Y+qYz>OQT*{iW(~O{4G1 z`l4EhPw&rMC50~~h-S#?Ue|omH_ZYYn$IX7h+fgptO3tbV=%0!7I$Q=whWPtg!o4|*+4pt;)Qyd|!oXoA0ud?)54u&Ijh9Wi^LY#hzC=mcDrn>crT4Y(f!Q(~{ zkgXcyZ^ZzL3=iw7l5>}hPBEv9`rLHNB7J}%F|&;i~% zzta8enPnZIJjgo@DVCRn@*2*O|IZyf(!KS;{bI}jzIUiZ@}3d_as#L~?b7u>BQi8N zqUc8^Z9d9?mK=o?9j=ON(m$8{wC1u>LK)^`gh%&ym!?Dilrse)sm-WOcGJ9*Jy4oet%K-g;_uD(`OCNMVzzw6pOapzWHN#rL%y48rdp47tmMcQk zmg)1D{n!1Yqvoe&)Bu8Jp?1+_c>oARKgs0?`W_xbD%lWW_^1`D1JWv)ZlSA?l;wcQ zf?PF_eC|&_qkYUwZw+=wnQDO&tnP`<)Z=-pG5H{Q)KG4%ELeh-&!v7O8+%&1zGeh~ zB*Ne3R1zTaR~58mqxnFp-6AWU*J?{GBEM55b%JlNWy{+lHJb$!qIHc9AGcJDakL|N zKL%(eJF&I%?E80AzaD^KfIy{_pjAsPl+Bq{mCJWU6TE99Da0r;3D1ybhSNi$wHgXW zS9Hpyrnd?7n+tPW7_8%!9tkQRO>Bc0ETj9ty-X=(qG%`=S_G!cI7zNlCZZ!u6% zYiuB0^At^DRstRT4STm>Bcn&_GE%{w*V=at_aIPs;{tz~|Z>d=w)Y~;V?zh){Z zLo`q6z#={aubg()4Gs?A8}loLhdsxa*+GNlI4sF?;nho`1$v%XX3ux1tL0r#j? zj+yb`E&d>|V58-6(cnN7P(Z~}YoL6p0-3%`BQ*<%R;w7#@{??lR^$7$98sQXL;}5J z4hn25xmv?lKCs-+l?^Z^vgDJd#|$SaBDW#a6f}bLL%_P~%cq7AluTE>QNNo(%N;eA zY^g#vL^h44?0f$?W_E#Qkn><7P%E5MezJ7oBfk97CeK_E*%v$ePcLjaUCR0JRtZvDA zAOWa-+b2q1zaFopk&%h|(Zxk9FY-3SsZMA#o(V#qJh(I-2$ja?u-wo5 zHm!IiK%v)pyj;FF&T@xzzSu3l;RjN(DItK*304$ANz|#I`^qoCjn|@PYvSGddPuDg zB%*~s0F41vvp9xSg3Jg|zkD|8KMw=xto=72-kU{?D8-QLD_5yH*B0=10yR=2 zcf`SFIEv7SOqWt`q2BR(0SS`b8nnJO+wE@8*U33FgUk_;@5rRse^V0Fg@At@Nus{H zwLCKW&W|JLHzy_K)rA3}3XR*gtU#YY%nGK|xrDj|f0{8($Kj{^4g(RXcDFbqaBZfh zqmA3wX=ckH`CF?W6-k}Yn(ds>D3O}F1)}g*P5pZ7olF*M5{Euh-IPd5)o>yv%QpHy z!zEn<;ebY()DY6=NF?VHl@C%>{=HS^mQ*a-LS!j7{@4v6p{<3q8v9iB+nSlS33;`9 zo?KlgGD2I{^jP?(ylL4+lg%P&u8|d?MI>(eFZOpxy1{HC%>V!Z07*qoM6N<$f+42h A-2eap literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG16.png b/Assets/SpawnSelector/MapBG16.png new file mode 100644 index 0000000000000000000000000000000000000000..3af0977db3e2648901ad5bba7a3e61f353b38f9c GIT binary patch literal 10951 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 literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG17.png b/Assets/SpawnSelector/MapBG17.png new file mode 100644 index 0000000000000000000000000000000000000000..8d8592098518f261ed9f4d1b1c294ce2c38d0043 GIT binary patch literal 5892 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
  • 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 TjRc4l00000NkvXXu0mjfT}fgv literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG19.png b/Assets/SpawnSelector/MapBG19.png new file mode 100644 index 0000000000000000000000000000000000000000..e09d63beca3e9c4df18b0f9cc353e702410e045e GIT binary patch literal 10791 zcmV+?D%jPDP)yqZzW*a` zq21{r8+h_}J>q$Ux#V}d)kLq;L8se8-07m%>%#MV`AgzHDVGV5E0&PWgxIxha_F;H zsx`D5b=j{*_W6w(>di==ohCkW>&8)J3q>rf)KSg=XBVp|mCLABt7tac$#s4Z$bQ#p zYbG#l%Va`q9xvnCeOKd0fBzVE@7#*0(ZKZlGW;NeUMGU@`zYlCREkA&-1l+GwoMo< z7qMKerL9{x558dLEKn{9sAbdz&}^ZEdUGjxK525Sh^1;9 z*Iu<3bF;I_?K%MT`^x1qW@qOB1Z)5@*$kpq6P<1>y`=*r?zFKQ0n$FLvQ-Gh((3?Ay(HZh8glN0icx!HO1E#nnr3I!PiIop3%?AeKfhmWI@ z3kK1#ls@M4d(S-`jFgK>e-C*Mf^ZP;4aE?nV`EretwC`lQ0VoNt<&kE+w&0EQQmGx z@Q80Fi!hTxCJbcX_dSGRVD7V&FBTC5KC%H&ER_VvTW)&?UODkHw(r=1k&zJrt6Hrg zm(3#X0fk%!jaGzalK^xQAb0KDi7lHZ@cNr>#M08TT>siDb|dt9xO-!a>qmea$9z1y z3e@X$8DK#WO1lGe&}_waVD#X5p6u5fb<8i<@Edo(4^KUN5c7*GXf|57{@SZBQYqu{ z$9|3vf8aeBuZ&=EwTkNU3ZfqHt~+i+DWAvUY7KFtA>21HQpRPMZpHlE0xE?Z$|ED_ zc49PJ?V+H$;D)}Z{eLfjFS=l^D=*Vv7BW6g&#j=>i4)))9Fxtrog&X*=Y+PCfPyLMw?{#*iRs~sWeMp&se z(d`;8y5ns(qf#l$cKr=EVR8PP?2~xk!_#&Ad?Cicnvn>r)tYouF&6-S2(N3ztUgb= z$o4RSKYU~g*Il(2r_atIjypJV%c<&vzVrgZWa$E-Z6_@SAvoF0YV0PmeXBJikByJhsywGztmmHxefcobHQpBah zk=&?vdU0DmGy%mD#SynKn?pA1$jS6`vzcT=uMeb%ybSe5Q8<#@FP?fj0aEGFM;==9 z%!PWKh(mH1?;(+^U7DFWi)8^0BF;a#y?;)`zjj)f6CJ6#Jl&JawFVBpIE6RvdkuDP z-H6SbCvo!)SK+H){W@NM<8_#yoyQAP$FWka^(X;j(QL!r=t+*wl*{->?C3Cq`wY0`$7rcilBOd29;pE`&Qjb*Yb^&eY+19)d8J zw7uKyA@Dh9rLP9s&rZw)0Zz{@`VCo}>|~J% zdg%2iDa^aGp)c)Iam!;tF_*oUowYo&ZH6AOw=cznxAbT>7nV{-ppNwc9wiu!43JBZ`b= zbNTL_c+Y$9viEGTe2@))P$X->DO)@b)*|fT&T&Qmuh@tA!)SPh#7q4S476x8U(7e}QwebI90krbvD3 z>#xJ=$_hTRBZt2~az>0f>ZejRz(dCu@ymr4o?d9<>G>ACZj6syQo!*jgGM{TNHK$A zzJP|+tsE2tH7FPJ_fjtm0O|z;Vv<}*B4;ix8*|zvibxL}IrjFRF@SUcbULxqG4pF`Yk8KcYUx9wXd zarHIVia6f6Ymac%v8lsJdw1`-0#k<%V`;T6V3ISRS%^?;M&h2Roe=b5(Vrn=bb3aG zkUntFOeR+qdG`7pG8dwD8fp z?!;qH{zBeyMajd9D-m{IvITcd0&jm~9!F*~s1)-8I@Qp>d+!E}YzpzW2bSfYaNx4!*>@Xk+z8BE2H%0@uAa0ABvF2Lq4)D3Z^ShtJFd_)9p8U>V z{}|QU_vFLGa<(pv65kiCBl>^($U}JRZMO@63g}NC*`J)J-rR9b4mfH$C*yv<<6gya zU!D+1{ZY_C?*X-H4gc-y-@?t;Ux6Fnb34BB7Z1p(Q|F!#3;nmQ9FuqbmmluO?EE6G z+_fD)oUP-%lRkD_)4=^t&G~UM7pYX&bBEL{tfM9BaEE5fy zszk&gHF!t_l7`P3A{YDQ2#==k8oyJ0PIlUd@47Pqi2BbZ{eAk>DI7d-2!Hnvj|~`D zVpzG-qZ^BO;WacCTzdZS%c3id5!B~O1(ZgRh&2FF#6d9V6T9TaO+@ld*0^%dIS1;E zcCvrqrI+#ebBA&Do=Xrl8#p<;C=%c+FD(Ht0r!50escl;^}!l`@13T9PaSF@YIZSw z*%c^cm*jhwYAt+pX9@pfe*<$XCPjPnXU%1K zMi8J}DkKg*f!D~4{w9r-jlW2s2quC1hy6dn{eSTt0h^HWw$O4o^SzjI?!iP23~}mb`~5!g8iJ zc&^rHqg=?Yv3B|Mg{hPH{PmOgRy+!{n^>&1WI*1xzk#WldHm_ecL<0-p6#GkZ=%)d z;?1|b83$fCjB4CNIqbV8foIehBTM9NZ)$CnXw8?nx>CWQP8w*aBjR#sBU>07xQE~= z5kz$p2;dV>ACeFn#X5m&rru8w380O$2#`wJ4h4D`kfckuZGzG*x7{uvx?+|pZL;|V>mOvvL-$oWU|Tiov1DE==oU_ zqw2;9kc=2f$F8Fn)8sk(uHoYju$3cIYmNujul5`f+lxC!N2Z>gyu$+LZnZ`vKpH@O zk!B}nmvG-KuxoNuxbdsMTCl?v`13<^$Ob;%_tqQnqbHxm3&&5QUT z39;D&w1T}gT-GvGap zc#cMq0!hGzxwWo1bxFZ>MXO6`AW3s`3)sEq^2BIyIh4AT29Qe}=}InO3oDJGK)NE= z9o`BgeLjt!x}ulh(yd|m@BSAS5FQEe@9*9!_x#~EPa*1bP|9cViM^xvv+ti1iGTyP#4tzJh?pU;8!jUO}Xw;CaF5NmIfHGqsqBdpm>Hw&spXm?)EoW1FYl_Jg zs}~|y%ns9!!*rz*fp^90pw2XcY2E_$gXszWY1AYn=mNR0un6A=^1g>Mqg0+1!VZvm z&%dqX_%^La6TYW0SEf1}Z~?f@|21-N-+6tnF%+Kz6@ zc^*c5A8)KwFdMbeX57?vDr3Cnui+nI0^9jAAbM0+mP-@P@1a_6;;~ptLQX zC+f-7os9Fk-@v`L^_eM}satvB<_#m5C>LZvOij;%mrxJqGQJEPjY)|!V)L2zvOnmQ zX0wJHI~~Jaji`&P*TL*c!-VO2o&=<&v$~xGNYRU}w&;y8^apaFjG4w!BtTNlF$U~1 z6dNx2Oy)Hue`q%Oprm|*?eUZ6>Au___|mqX^GwO7dLABr^hsQP*$xRFFrOKU7(9B(wi)IryFt%y#?@FAG&FLqfj z3}inRz>L_|>w1i2Ib1CRH;S-atD_f3*f>(ccrk}+i*aItYVRXQsx6doCXJr5P2ScT z33rh@nJY}|QgWhL!M%>?Mf!jOSU4D@=Y8ZZjmxS5hDGh%rvmB zC{CMlX|8mC6Hsk+$2B^f>y*okKI{KBV4C;lSl<+SsI_8La?CUV&A5ZW^U;puM1{Fh zrjQNbQF?W|B3ff{4?|=_<9MkRO+fqdaEQyHV7TOhL^4HL-F`+SbzVbZO#*)1* z>L`ENV1N~&Y&SEIdM&xQ+hd;w@|$jvq~)087Z7cDj$BD{gX~JK=wvW~G*H$!Y%uVp zR*a@;7*`HEpOkHAJJyN%yjlvGShm{$4U6;)oVNC&1`Qk_T{k4rW2s|>02s|0eOYIO z%{Ru84ggn=@?A`fa}elt+=_|l9*hOALCr03bj7O+GJ^^9{}QgW21z>bpuu#dVUZsf zNQ&c(71hd>=hKlFD`L~6qL7)GX1gPRYEjuRa>0Geb(iDAAAG;~fPeG7AK;1Sr`E(~ zU3XlMQLGZkek`|#ayCRE^sv&ley6>WqLU>!iHoDpvRtUo-8jh-PV?JXvz5}l%9SpV z%QX`f(Q{hoCe#?#1;$azNr^t!yK{}5Ir@IG=OEjAK6mG_(4T2tPb zShBQooqc&%Y%2g>1qHrogBgsfr~18=7(xzr?b%epAO8O5P|juW@cu_p&StP}^CZGv zgcE1xO}UICHevTEg4Y5mV?lD0;+EKOr|Z7(+cS318DRTu%J@FUY<+l=aZDmWQc0cE z&n85_Q$?=}wD_J@Jadx@1(z$Wg`0Nzl{ET8eMt^?MX_=^En|lN&S&@}&kF+C&PVC< zId^2P!-aG!Nc1Z|``ORn#Id8|)V*%s)p+K)LwM%E^VsK`pm*2myhPtIdK3EMj*wdP zz8o<+AWl=6m#6NjBWni-fy=5WW^C7KW4CIIC~dcZDHg1gR6euRPXN0h(nUFSZVAUu zOb>(r)1@XZkgm=nNCZ(5+NHu!U1`!_!vhGz=zJl@VL%QC-43|aqZlYC=5l!BzP<2z zJ?z}gdLrPL&pnS9PR+_j`pk8k*W8}?k7D!yt(c*_ew>w&G`*f7Ll?|9+*cg5t`lF> z444tim94fhE}3<4#qj`O8VO1RS!YsNMcO*nFEi$@*yG0xlzUh|c0Ed4x8y?Q%3(%N z+CVxVU5I;!(e53a@P_NJ#ff7k|M|-Uhp=_igt#2}On`5{(vkr9Z(p~0!01ttYAjbr zggOAR9EJC^rSt{(*{4`l-@k@|c75Jxo>s6gn;ff#XmxrRpQJ%#j!DmnU#YG|%Ei$0 zE|A*cX@iH!XZnS12kX9aoC_#*B}J(wqmxdzT&X_hz&lcavQza~CJ4kKzZd{7#Ltyd zPUeMt`Zqr==EVcweE>73XYjgx*N7W%_ZD(v5AmTVhd!IWBSECaN<)VtQuQN?mjy^0 zo^;#uq!?fQV6sQw(Ghmxt1&k3Cl}{>Ca)5POP(YY00ifan!+QK68%%_R7>zeCUH8kj{JN zz#%;S-1CSJJt06!WnYTKAY=^I8fmq5jJ#7A@A{;qv8*|H%l#$XVu5_y$ue*|@RLhd z2P0GL(`tZ~MvS~Qkn}rz*Qk*sbEeOouKr9SJ=S$t!<8&@w(bNwS~*fd(p;v3lm;v9 zkLqs%m^OU)?0h~eZOIo3vj1wyEh0-3yXc-zd;pLC#H7(K-Lp3-H@U%E#`V65?+yc! zq;X{>8Zphdixx8@tr*MA4w@EdTD0b`x#!VO8jgJUpI3*rOR3h5klSD_dTWswEu%}zW{KBH#dfUbjpS*e!-*|pD(VgmA47`W# zMBB{c94njtY{os|;zzA$71|HHduCL2JsaLvYC7N0TrkdOVgQk=G#=}^D4J{@CL-N1 zpZb*qJ8kUHvUM$Ak{Vb_X|XLa*;nB^UN}(KCzEyT6Ej4^=;fnF;n@oLfA!n{QpD_N zY0zqa`P?Gr8y$S&ZKa`H$_~zkVc%$Rj_WZc0rGYL@7!npT3T&eAjcuW1=2#@)EtqT zPO=~zi13V%lIAr26b z;%cU~Jak0VYI(|e^<^r^>L${=c5dfq|HVh-!sExLFg-nkn{R%L9KUhjHNe5g6<163r3OJ1Ah~pm_!bUojhEv|v<&MjK595=CuH zwiO>UA#!E%_W*kLn~TS{4`Rgo%aengNx#*XfI&Nw;5h>a!%|@K0BgiZ);wk4FapGW z4`K8xH&@)MWjoAJA!iP=T+_r3Q6STESX9vDo#(F?OmNF7NulKmH#U3x=#hat-hAuL zB4&j%Eq#9`#-r6x-aX%l1z2vb$RCp!9s>r{iG$*u0RV0!;ZTa!2M?H&4<5kn|H~vZ zc8nU)Ua0o%j?ETa`kHPZ$d~aVmlNrVtY?(CpmHl^S$#0raRhg4d@Qjv3&oNFe@LJq z&6&f1b=?oTBl5nuCF>55k)RPitlK?R8xb!fA_gdGbAJ z(8!g0F4-jDrq8L=lQI*Apd1b<=X{il&+NR-ou)0=^MOeE^4GtG-xa+H96xppGpA-SJ$p{p9;n9#q7QB*SH#%y zroL6~c5qUmC&_>~nZcz;ljSAIX~j%pmi@B_HsH+s0`_g&fY*!`aSRP$5fW|cA;N}Y zU*xKPsqggF;7BI_*f=c>prLujj_GhN?=oRcYi7^O#i9VoX$p6~=T50^=fV*D%h_M9 z@0tcH5uX-R>egX3vgB@cN7k%z(lgJbH28l()SL2m_Z|_m+a@RR?mKS9TdutlyEjkZ zx$X!an(K>KZr?xIOwwy=bZI$=%SBAkNL?&Lf~*V5WU-WM$&9qcW(T=a9tWlu@Z9tQ zc16VjuFh*;RKo#FmUQ00=0E~D=mSYTM;)8VWU*nSlmN-;>jaPUOt`Pa`IW!_d&B2q zN`?i&Km>?7R%5ax{hR3FxFuqh1IjgoGJ%JT1^Z%y@JUCcRK>sjgFnW<{=%Omzu$7p z&A4>;UOe~0Vcc-t)mU<(Vx;e$Y@u2=s!AsK1SXB$;6f}8m{N}En{&*JjO9Zt=lajm z>n114^7pyvdF(0|F*RS8-=~(Fm^l><4i3#{77F=$1)zK;@hh1fVnyDT(L7e_v_P5a z;=BnTTgD2q?f_?cQEzi*H0ho1dWV2mTV0Zw&YUpx;^CtL>S#HSzk1*Y`1sxL!?Oop z9H_q2=kgdSYB7&$%Q@{ROr|!_w-2*YNjMO|pdJrHV^RB|nXPTz44EsXUi>;DmUakJ zSTXI-OjUQ9VAf8c`{H{j6>?~YMk0l66Di_AVBU5q>Y~vFURh=Rp9v50UJCk^ zW{k;7R<2J9z&1}#^e)+GtMa0?E(-N#B8p1|5x+X$l3Ylz2%N6hqcgu;QoTuf^NrWw z!Jj;Z^@!C5I@>Glnvg?j01edUl1p7TC2nE4I%rgx&h-0J2JLg%p{!HotZ4Ggrcsl6 z(n_X(IO;A%fU*im~I?x>a~xCzHeU z6p0+-Qnkej*dgITdw~9+)~ce{2aP~Vhg%88+M;^9Bb%!$38dWX`4}mLsO1eOmYR7v z-*CQ@Ad>Scg;0vmDO$C){L6DB&bHQaONjsxFeabfd70c-5cQl(oYL-cHAyGiy0fKK z$0ebx0bzqu7hkk987I zH-^gf5-M2>f=wt#9ph?{YApj~K5I%iWa@zJTw=rP)erA#T@ZC*m_-K-VVj}v4VCSq2BK6Ngcc5nh+#eNbo$a!!V*)b%9i(5u_`HaIGE{ zvm7wwP!-2~C&jJmK32$+Q?-Jfh7Lt;vN;hYnR(rAiT}urG1)q&2{hY7XIH25fsq(U zHYDkAXT3Q%-Ct?7&2U`LaDjay|JL1DFjwewW`s)dv#q9cxt+k0E8BUa*Lgiba|hyL zqa&puVVJ?mC8IZY>j!dQhorxGvH=HA0tlRZhOA~-}rAZaB`kSJbT&t^x z5L8~HJ}B>{?xolzhtkENVMTyO%LQ4$aH6y}i=u$0lihA2ytmGT+_c`Kh#YoJF`pAa z6;uJiUfb69rQ8g5ZXusdu4Shtt*}*q($RJT5&7O{(1RS>EC{D9G~%SLr&ncAv=0)u zF*_rVM2;TGoBPk6>jRmD^IXG+9p`2;C}M|+S8^D^QPMT)c$}QcY4FsU%AM+iQrv#} z)AxwsMB+0DEW>{cK9E|e_9(fWN^4SeDmTx@i-&DWVvR=B$-|%Tf;fzNc3OPB(L&8~ zWs&h<%Y78F8m?m}^BMt!tArFX{c9{&wjzqm{`*;Nx73KGu19{`hVULGg3o6*S2F`Z z%48|GvFe7Lk1LhiXu-M*QjiFsawx%5gGdJeIh0&UfEn&1smsE5a!Ju@tBbki=DOmZ z$8^&`1GiizNI2Ksl(?2&(Xk#0Dzh-|Pcdg({q2xdD$;9s8?(zyjK^Mhc6gvzD`H2`@Gx z0g2br)i3~CUoz3jhL)N!wpy!|L_d_z;yufazJICj_SFp$t2UJ=CJifsCdZM>$ek3W z3KWUQ2_(<)IK`=g$7{*GJg!sGDQ0<$-0oI6FdM^-8iX4I8{D>xW-(s$2R4n@y5zbj zTqT;IPK=bWb@QYw$E{qNp4O)vsrzZ8C`q^FLNTJKOIgMt)%OmdjVLx9Epu7}G~%vs z)kwjJ$67=#>~n0#{^gVdX;-5p5vW|nPQYq#sdFxaZUE$_>m}&Gk_Zq-HW#8$e^aaT zT+Sqz8z+aanNE<%nFNWT(e2P$B61wTB4`TeSH5!J!2KFU(zVyQ)QplYIkS1ZD6!yS z6h&>(v#WK};Pf(WBcmhOY9~8!SsA4>XJ;k!mQGmf&+$@TYE${U(QK_La@N0@j4#s` zG!!f)m2np%c~eEVdBn849d(hnr3Wp}FL55ofCFiZU5~0^bz;eaSzR$Ym&6t=HzLu) zuw0r14ak*TbjhW(h*dXa&3frJfI!YtAf@3A0|+^jU{T}}Eb2?wa3Xlhsl1NwW#yc1 zB#O+rcKG!q^`%n zIW@8bdD5Zjzea5KEXQynt#DyZw*L^Ld_>FXW}Hf)k5$N_+B= zvg!vHb7-O7ieyujU$qN^nxs%007KKbGWgCpCGWx@NDSnq5ZHfBO8VwmF=yuVH*19;tPeN!ZZav2{~V9d|dJrwbzL@$|%@^hkG?Vbj!pf=76~kMD2d`%Y0M_ec^_AF2I^9_U+;zzAv$KW60~l)tvJ~g7f4RX zaY^EyvSf}8YFi7Eez9okSy>bqcfE~BQBBUPVUj>z7k{}^d9N=66&-Hf5 zfw^p$R3e;@$cahEI))D4LE?J|jJpP(O9AIWIwci(M{P8R6sVDwt8FRiNEQGV9TeF~ zKX#5xXqHFgHRMX_Q5r)mOW|5c6t8R-xz$YTGi@6y=VXR+n90epIBq9p9%jx--vZyc zxxatnEQ9cC9sT9HCZs)#7RIn`K@ z%UE^Spw0Or(k?_UfEPN?_b7~4?plM>Y9qWBWhedrcs+@2ku3L}Rb2VJr zI9eD8@44dlLe#OAEv@2~1vXg#**2NRl7i?Gvnp=&y9DHE7&?ne)mjmfFBJK2 zL4AoaKG9#UX3j2^M&g~Vp1F2oF%WBZemN%w&Zy-`-zM9msAb)b{*yTf-2j6bLN>dk zqO_7>!-IcR$CHD2UX2!ZwtKyvPv7H`-lrgO-+iwO-h8#arlS6Qb&XC1@nV(&?&?x!XR4@QXk*AM1MJK%}~G?>Q6 z#|F+Z?p<+0rPX@>yC#c98mbOt$Whu78C~g;>g@i%w6g8)%4$I3XWBN3vRqp+ah@er zhLLMgx-=}*cCqwoN+$m)q-|UGZO#cUW|%&#x-^--Zu6GwJR+f-*ImFMnqUu81yy}*`j4c43TXd7fkaCDp6{(LkaC|5EToIXxEu~=d%4p$hCNp;xWojpaSlj>r002ovPDHLkV1gnn3nKsk literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG2.png b/Assets/SpawnSelector/MapBG2.png new file mode 100644 index 0000000000000000000000000000000000000000..29e70dfc4ce50a1c4c5a039f112251fb76f66858 GIT binary patch literal 3466 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 literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG22.png b/Assets/SpawnSelector/MapBG22.png new file mode 100644 index 0000000000000000000000000000000000000000..31894cc715fccc23807cde0fd83770c535300b4a GIT binary patch literal 14635 zcmV+`In>69P)C zSO&nX@4cS?zwbQ^Kv0sCo?f2EH_My1-0%MTcQ2&(ocIuiqfuB*Ha3ivL=HDKN&M$8 zSFyU5hp$|yXTQ4_{tsjcUGg%6j|oiEuk*_w5>TD*mqkJCZqFwE2GgE zUl)*}$O>eMHW{kyKwoG`d0J@<;rq7`9adZql znE@S!Veosp3_UMhuW(=3UG%Q9LiB<4DLpyeL%80Hcr1gareZ`Q8GerWrL6r+`Uk_{ zd!p;wpV|9eRO~kdCN&dK`>55`m76+p?~UEuXb|i^&fecGA2dJ!?Cg6V^7+vj4)guc z{;hzdHW{1e&L!Xoz|Q7+I8+CmsuM1!3r?q#Un`0L_r^$s0eNF+RCJ9_Ac~HgpPxfj zrHcAS7c@;n-Vh*9O>KjYstdZH>pJ4`Gy-)l%+99w+*9Fm(sKvv+;*1}hy;3LLpfB3 z3Wus79!o-1R36~t<2!T^gBYEo^Ae1C0jQz9C7?E#bVQ+qQj?91Ti#^hd91VD44Am! zK>*(hPy(~C5ug@`;hHM@^Vq^NCZls0iAEtwGT#Gr)(6kt%|N;wF3iMM;Bq+ObhzMD zoZM-2EVb7LhPgwIceSuY(LYTWot8*nK|^yX#z$9>*Ye2e8Uvft@(9!wV`gR@(OAlq zn7yrzz$@sTV6c?&iO(j5R**?+$Y^V;gv+VI?Q-J34^~1_9Dt;lf=N=Tqxhv4`F;%K zSz8D|dDxl#x))Fj%me$oP!a~FFYss-Dp=YDRkGyc=0+-M_vANUVn6u%rF1{Qg_3Gt zm3m47+UrA*Wf{$(IxH-&!{hQG5?g`W>4DqfW^ffn#jDpwSk(WK`mhQ2+1f3m~aJ$|3 z%Jph|=HGn|AHA&w4_=M)(f|9phTN4$u(>=AB|-C0nrX()-%2fV7&o z;F!YUQ}3_BzxlcMv5lNtN}wrR2e-?GB5x6jii>gK`5XA&lNaHT9Z)0{3QIAmV{u2+ z+QW4?b+p}<&X+Df3(e3l72D$Xc_Yi}R!0sxfeTGYiYX=gpQ})FSsJ50>|r&ps){fH z4hLK=7aR^Jevs+LuYc}W@xO=SQK8?M)ojOnKcQ5}|;Oz(TR>wzIml0oB;d^Tg z*0N2a*Ryl0h(^co_s_fxr{aP`cG_UlCKNN!(NKqzeFP-X-BXX}U;RFg^p)fBM;4(< zPDnC!9`#=q65YFGK&JN++1S0$WC0lry7$;f+6YM6+FJc^yIqJzx1c(lP@OLPx~~@B zdhi)+uEoXgoG$q8`6T{Dn~rb(^*^Avstw7L8d@T6AZL_7*G#nw9g@Co_l4A0b%O8X zAV6Efbu4WY(K)o$2ia?+j(Ys{%M2zY8KnZ|eU6niUUd^#9sWwc=@klzB@hTG6aZzt zKd2RgNmulmot1)wu&)xI{pbU%M#)CH+-`i~%io4Wa>6fr;8L7$N(3l@sUlSGW-yzN zc+u2dZl0CwqK?tQCEU2Wj;!QI-pH}NoSB+LZMY8o(-T5E4chYXnkvtdP^(o|IQObn z8ay&>3OYK<(0#ZXjpgshjmbGUTy9*vK8|yzdLbz?zPhr8(()iSmZnj0*DoOR+G9}K z&LHvBSMgDg6Y0zjGWiVhIr79wLl_vH8Q|+ue8J6fehLAdFddA}`g%Na>1CG4$nuH_ zq=Jq>2#QQj1$l`Q-qF*8m##j;VCJPtoa|^tHlO9~jnNVDfEJ)8K!pJA2lXHuM0Pf1 z9xK#45KpWiHouI9U=4!7a`az|vh=Bv0+l6EfhsEurbAM(5;ss6b|Q8?kJyc6G%Yvq zKs)p2wX9&uoF{PUjREL7{T}$2AASINEr&af9L953E+d=IV0bQq>Z&R%F3$4P(0z~% zC7;3y?W{r0YF$Qj4q5#P&YeDi3xngh_x4`M4ky04mc$o6`w9HzgBRhy z|C2DXIwVzvq$+@-qOYq3$?YU|(mTjzGsxw0tR1%VV{F>gSV0J4IT{wQmWqAy${Tjq zNg$6)MrU0ZclPwcsXFlD;1KTV>*a6Hp8Q!{xOx?5dk*tn({sF$dY)cb;89%f_p>yS zblysR76NH`h*t-bwp1ScJ4tw^6!#fGnJht(BnFiLB`{SqXQRDk zCzn^r1j(kiEn{vWkNO63)Kth6jwmwDojiimz0LUe%Om*0zy28h>c=m`dF(D^uUx{{ z+e`8Do3kh(6DLc2ZXx)R?PTteOlpO|QWG7%`x$j)OHBZ(BJ9s=!($xRk#t_V zcEj!+`s{0uK8_>xVcV3FG&WZU(Af~ez~qFjl@9`DzeG|jx8L(Ek|bL?sZB=a&`?*y zD!fDq*tW{rNJ4o}5-O>z`mDi9Dlj#l!e{^Vv-s0r{ZlO7A7PJ`j?m3ci%u>I30G9K zv<9)A-bQnMHNN}k-`ZYqUC@ob=5u_$sn`OBlo(c)mJzJ>V17wML!B2A0V#$;g8qj&YzGr-0S@9Z+pPJb(7FoS!mA7_vE@-NOF>*G;P>M5N|v#x*X#sD6D^;J8gfm=uz z0cQbvt7L1f#HC5ugeuNM>vI(A*^$zbi67^%Y@! zApHRT()m4pt{3~ShTj`lS1Ac#elMTSY1@!@wqfa~K^(2Tqt%F*xI8$)oa zF5FO@fZ{}b-5MW%w(l5Z)ge@;?KJL6*Xo5w@EiV8^HT%gJ==%7f91D%kXnPLuw9*c z?(Km|YLL3B-d~CCrY5*l7mv<6x_jVpdhp`)A-*31@>Fj-KKgTK?cYv~&*7E+VJHUK zD;1YV$1$-{Z0rn;fr-oM&E z!m8xO>o+hwJIkL_Y-)wP+ds|4_W^jbvN0G;VM8SNd@8oqERR}8d8Lf4RSga(_|Dh= z6z~9vl>}6$3gvMHvLWNKtB>Nx*Zu*~wHR_wj=9@ zc3NbY$Qf&-FyEx3&+3E$H(LAWcB2t*mA_mui>+ zK1o%Fvl@Tj?PAXFZ-&qwXfV?DbW7gOEQ zt%)SQ%87u^rh0TVhA|ag5H@yh$v*Z-d*iN(g`GY3V1a7cP7BcO0zh|P@2yJE zMqx^Pb%mWZ(p9l>8UO7&e}<;YTF%G1WGC-K4GmBf2OjvsFXE`Dfj!#V(pvU#HOawJ z^(%M&3Vw9;A{)5()@q@$U`u7S}>&gRf@l;o#I-&14N ztmV+tUXP)PS=`z8PL@v6Px)*HhAhF5Wb_?r1ZjMJ_T&~i8+_Q>N+O$1BW;4o;Rs7- z9z|*!lDQEC>q-%iZwfHqY{YX1-PEW}&@_KQZNRa!DIw`k=t z-(2D>@T|QBBmpnfw3&U8B+`~h!$5p>6&GI{z&%Ibi8`N;M=#kFO3Tqkoe*lMqErDQ z)6?vMUtOGG6-nVt-q7)#_>;K9)q>C6^*Q{}^MAzm|H9=#obK)5v>qKt=N%lHMrV77 z0ds0joa#BuKwBFDC~_l)NYLkUNXu#Dav5B_Hh?on&*Fuv&mfo0fbuv;yBe^aOqxBb z!_W+9bgoIL;xrn(Zdm zxRVs}5%aS+Z-$~LkG9ztB$Yr_2Qu>UdFpZl#RQA+L>Qng^9seL7;l@et-UyA7gUiJ z+|2_^rixC(z%%_-4d}6~)5IE3SRfD#04aTNp90rg?X0$A7!wP425-S;OkRxK~ zc=0>mL*iQreChcw;fLFU$R+b=3kUcadJfk!Nd4C)AgNA_P0XYBa5MJ-eNWGt$!3tv zWs%8=fSw1Grty1f>1+y`p2c(hmvQ^ycOaG75sCdbuA{3hWXH(jcX?>kfB8J0D^G)j z)UuYxc!bh^221BwZj6CsZ9xAW2qZgsW}<)%p9KJLtc}V>0x*$~PGM$d5@(L~;L7Bz zxPfdI>1>+S5T(9qs~xDVa-z1{#p+sYD(_1;U=Z$IU(6j~$kn zuZzGw4adc7DOoBFM3$E^Ium0F&^bk}A=uc2*mM$s#s+wNUer_;p|-jN*Z}_E(jVZ# z?Q6*EIo<|mrrGhJXKiW;;ACHisFOO}7#^ENvAY>!)VFyNx+WsEOnAt@^7bg7kDscI{eL75v)V(TciDg*3-3w17-1T?Hj z&5BpzpKPbk=v3jVYLOsNoX{!mYpu6`OC1t!Y(ZAbB2-@~280B>=fC^{Cbk!N5YS){ z>RiV+9(fY~^T@yDYDZgVn2X*0*CzRn28V=w?K{%Ul@Kn1%fhc19*VJwY;LF(17Fk7 z7_Q{Z5#8}?H!h;5^#uBdM$y(7#K@#5nsc$-^jHnuus^e%JX4EV4w@yIik{1V(SN9# zC9m>OIRo0=(8!<>SR+$cvAVv5)wKmIugzm=bq;H58rIfwSXmXZpa=S~`=smuWEB;VuqFW&hK_`;qg>BZ6pe7efx}%z zqOtCI0>3u4Ne5&^7dhYH?3@C##c_JuP_Z^=~t<1H(ylcb6fb)6m{p z3SBeM+(>6sun@~3u}b7C8GgTWH(pUHIfS|qi{pB17Iz;%COlu4hwqo_i1fTdG6ivq zB)}@sg{sOivy?DTC;DM15*Jb^s@i7GSL93SJbk^*+|8H!N7)w`8jYc)xf%||!64-& zQ5W?pt!(QE=#Fp*LlGfaLo+jI3e_Bpl2z>A*RD-n*z?}Z-tN}j2ryEwom_V-!_S=l zSMa*Mym{OnL6CB|Av;4Hw~>0AUCd*Sm}Q26rfR`TV1um-y*{zD%-}JQ4liU^5oA}f zxfS79dpqtseFC!6iQ7+fq5sAVYlIs&cKDvgMp95z1<~m&+d!A%f=6|uNGU=?bvYVq z%TeqoLXo2gUeyD)l!OxrltV^2B>efqkMbZL7@C1Y655ttF_b_QL5<@$S=~ zG{F-cpr|V5m)3FN+8}51C1VTG*eNGbv8 zh2$)P#J7mZ+yK&A99OQ5A{=O9(4vcr91jbp zg2uLtjqS8xCddwv<&jk+HnwqR?_nJB7h`KZh1!4*%PX4<*3#lSYHG`I;kEDc`BV8A zc5<^&r7DhbITc5C*c{-6s+8i%jTAYHIri(x7Fx{$&}!tIcGS1QDf`gb(1V)t2HS2b zzG6Rv+0tB$HjLt>L-;0rW?rSlHM^CP`^6;R)8& zih5pS0}u$Fz~-8Uqg|Ewn@65QB9(=tk~DiDI|Z1>+nX@Z96anH{XH=PmQpJUxtQ&K=O(@z9KHK&gJTmqIO3G^i zxfnWcMbPz4l$9w+tY@*dkwZ4Ep|V<3V-^=Ph%W6QTwRH3-yy`8sHh-%m%vQ!WT1e6 zba2UxVpfV>L;gzK(|-oR*%0Q!b68m-FonOdxVVmtCOTiliw2IipTyk467rgc!Ko?u z50&zF&EZJKIOv=dk&;?-6ZJ!J!=t$2RlTT25tdR*I9%F@3v;7bSl>X!p(4)cXz=3l z%n~f}W5NWqs@jR_Y8Mukoro?j;XU`9VlQ)Uc}3)sB?((QX{ZdK(*)81r|f{9(eU1? zGw}SX2e1C_E69cf_#F0-T~>lfYeHR8)@Wr}<;)GS6Dmqe*fZVEjUkzI*Z`G!y~w9_ zuxd&t0kywb3=jhHAo3l7DRZ*ev>~+Jf9hZ1XHNg}uF5iP1bd=fhjT!3I1q`?Lvpww zIb4uwQyrL^${{k7$HIz^AN~EG;mX95Se#$51NZ*YK8XF9;0PO+jWBG9mzUR>gzHP_Ub-m(}(1fUMqt+u8(klP!L-*UZKhQg{l1+|SV} zPi2us((*43D_6G{V$3JIy&lYe{^PYgbe^w-k( z^q+kiJ5R1Kkj9b-nNFQNgYoMrObn-RWoQfr=V}eKHUw?Q>Q>FF+1?7sgScAueShrC zFBw!oy}hpoBNKDD<5)MYT%R;44HTU#3?yZ3zNwbu*+2L=e&*q2=)d;`;V@9DE0>0z zOToyeVdS!aMyxeaIOQ0SNMEWG>rOW$rx$)_5um!TF3TK>ROB;QrE_FEG#E0u)6`iagTZ5*KA`WkJTtUO_BOOEpP$aLLg42!&@}=v1Lzby z6N8(eprWtNDY?9CAghC=Mbf}&H;0sCFt1H-A!F!B>v`nZUK-G-yaXA2EiGI?r~8?T z=g<@q&Kk+!OgxReejYFOQ?z+#w{&jj@^zHKK$dAI!Zy<9i{lBr=iB$8>TiO4_&1*W zhLAWjY0q^>PRkjPv^9)OEg+}oQB$YxA*#jWDF$vSA&BBuE2PWZ*>^Cnd4H1+w>IF$ zctpfPJUdIm`TlF{?3}+k$UsVp0;mc;(W&5XrVS{MJPV1X%)>TQBIkzYN>G~4BuQJj z7)#Hs(L)h6Fqc6hy#qbH1wEbQeJSm;+W<+oo`InYZmLkPLdrFY0*xH9dIl*ig`NBk zlKCVy@|)PqZDK3Gg>5Z`w4Om08jdtIz#z$2D86-w7?%?k4%RaColav(0%CI+G4Qli zCSXyuriiK%(9u*$HC!DMse2M<;;Ht>`LPH{?5(Bn6s6>O#epNF2wS8`xP}GYpY3 zq`_$b4IvMvBS~yR$L2y7&DB*%Vj1PE4|JxU&~+#VEhhT2p2zs~EZ@tAcHWKr2l9CO zcb>-V+AQ4nRS2&&n?WX<=8fx*W-Yf+i4ur`0I7Q+{+0%-s&Mj=g;MD=XT`mprjk?+ zOh%v*Sxa%^>P&$SQQh30+a3lXg&5ygvG4{N2zp`ak|_JYXbpxCl$Cx1tK` z@}_ALM0F2B!fmuVxUabcmFnk%I>cT#)gVFa9Q0mR6wrP(dUS!IWY+>c^87Tkr(Qr`pb`!BWiVKsQo2f% zY7%B#SfdBD3fOpfts8gII$V)yQfYNRo!Eku^O< zO0YXvGVeLjh4(%@k4HXG3*-BLf~6{|WA);L@SXWEa)U2pb7huC`q8ObW|v(a8%JMV4Fk#EtT{)6!K8AHBq3qf zC&~VhEfheK3QL-E55)ny6hc8C5x*-kM{G)>VzeMZhy7I?!$lGaNHXPqJ?Lm?#ygH3 zfzw+A)$PU)kG>NhZIC%h|Fv&?4_#xI(bs$!+0+g)scrO+jBp4fF%w?G{MtHaeJHjp zCk~P9f>RcJB4QRB9B+7-Cf$p z{t3HEG#UF8qQdSj2{>Cc| z(65&l^OUpmxeSba7RN#X4olAUcH{izD|YpSZ%QC&dx?iwwUUZ8R-xHm8dd3!Uaw=8?+L-m|RPKiJg{t-D zws*#uIbqP$+L4td4o^q{Q^!$frm|_|6%{#I#(VBLj7QJE0Hxt5PZpvOS)`GP&TyIZB8BgJ$Uwwe*X2$)RaBd zNSv>5F22r=kM(Yg!+=`@S?IQV3xEy!dv?EUCLRt=)enn0v6~ zi=I5vj8okWIC(hCz(Lc|`1)1+)x$5N;;s+k%0z@I_0PUG0A0&+7U=llMjY>M64GYq zXliP-xiz${a|+9<#+!v~6JT%(*p9%;xN0L4AKmFzMotsjr?uzz@1HZ;OW6_ z02r(U-$LLHP!!uE|h3j~;;zEm}SynC~$MZBTFoi9oc$R>j zT3%o;Hc(fNy1EK9gsK=wlGGfEQBkh&%yEmqv&&c#|EN})NNBvRt?7aS!^9T_W6@dO zMq_dALjsbVp_lrvqRK~!kG+lM)KZHlkF-H?sv;)TWi$nSY&)mt5;)r(#@XCDp8e(@ zqb^vH#qVPylf=e%zl`76+{PV23EDWB zhFwqEvehg{hK_n)B?G&ZNTbT<#yUxmK{2e33^_lQ6+DV&SA~N!IWvd)P!+4y<`Ah} z9Yc{QlS?anMS#9x&)*bOm)(gL46aE|Ge5$5Vx8@#MMrtL{~Eu3DY3dcu+13NI*V-O z341#m@hXv+IrFBYvA&WM;znMFknG6hI1;b6L~`%6Jm!?cE*R zIYb8$v#rFGI%}d1G4CekW>L&l5CNhkT^4|E2S__-X*yORR<#B~<%fjo&t-Aj#G^Pp z_9*o9HuOvq?o1N5jXw(Q*&nfHp+VbRSHlj5sOk$tEC3aQkDQyul?)D*%Pet}ILI2L zO2x7=RTX6%2a=s6MgS>kCS>s-u^4^^bg2}pi9D)&E;~a;NqMf7^1M-pJ$FnN3NabP4V0Li3|jeQ%~(tr*N|vDIZUO0DEWo*c6bhfPLyhc{oT7tOUkcHqXRV+G7N14Gd$Mxvr( ze_!7*bTkMDq{3ebpHIQUN`~{Sln)O2{RP}yjSJ0mY(ucxo|;Zw*cKLZR_y2T(L`Jc z)jk(b0Iuaqc+ zq`<`^PK-!;FiKxl`Uo&F8~W|Gn}D~yX9FD}N_>-@*UaPvdE6NUON-H7Tg{9-^1MkE z((&P%N?{V%Uy#tz5a!~-a3m@U4U&STWewF;E|KP-gNYX_i4@}DmS!%0H8%uIwMQDm zTv^L7gcoX&wWUK02H8deabq0__`O^Jud6IE<5_d#H5f!}%V0C5RPc#z1*l9ap}nb& zsrBhxidAMX>}P5`fvDy3@YNI}R9AsqCX1I|yN-M=gU-fk?4$%EyRxzr6JxXR`P|Ib zrr#cEZeRe56%UFOH;Pm$C()>LqSo(WRbtHqCJEd>BY3}576#J?tqTOhK*;CAa3o?9 zhJ_vq{BRdWrsNpxehJ@+(5*O$nxc@Gkzcj#vE=8uk zutETF!rQyMI59v{Nqk%@F5r?OCAhd)B-U0Ki^j$JL*zq1#>N_0ttJyP+`Ly&TkFP- zyqo#bWiwti!=fA{Y_8={dPv4>nwYi0>#Xum{D&7;nmR41vg%rh# zAhc%C@xvWRtnP4DOjTU`Igz(%kP@l-?6KpVExY4b4^H=W3o5FM7>#1BhxVqB>ExI- zVKW%vrPdT5s;X*C)k(Bbl0Y{$m#FaWfmiXuEqm;ZzNex%+0W`qFV@$oo=Xxgq|%a3 z(p>Upc8KF7QnL(ZdK))}Cz0GrBAMJoNtuGt>oX`hr0{#1jsMfZWQD+Z-EGw=Ail5O2+)TE>VdiZI@qil^t{^*CALydD*9 zx5BU8ZW$BPb0{nJpsd7$^3q~HzPmjrxZgZdRFh}xz;i!(4j*ay2u|K}0`g@U55*pW z9$15`SjYNC8dU)m8=F}amniIwm6WRcst6f-v5K7()ffFXbIk&hV$EQk#OyR`#37xG zZ{GwwaZ$^PcjspFYZ-X{^+8ls_^_JX#)*zD)CU77@)l!wVh%414vXbf1(_D-j?v;9 zLe-w?>p)W*t!hGQbDKZ*SC|bX zg8-X|##!}p4zse@p72Swuddq1^m=>ww1Uh@Y<`KIog3q?aBa_frw7k9oX31%3}rP2 zf9DS<_OhVDvh8(B3RSHoeHI;&fTZt_Hl5+kqUldY=NL$8)@PR5EnM2vqWRO(abn)7 zg6`%P^mVjDb$j6Sy5VrUadBvZDKS)#r%>eH6UP|LQ+@6B>~Lz+6XHC~_@{*q%{e(D z6xp?z)+8qa^l)2)Jw1}Px_aT=OT>=&5b)oQ{2qJH_vm*)`H6zwzSC?ciQQq%0V;IH ztfsUEy1tm$OtKoHxelZ{H7Q0=ZNvt_+RuuD!$400rxi79(`Hy*Sa^4sTI0 z{`|oUxcAgio;-B!cn=zDYw*$k{%i0qCTyled4-rlu$D;f;s5aRa=9#qC!+QsUEfHe zvb5l-H2nmCWrD0Kg!B0 zpn6xZmdKzcNG2+W+B!NHt%FM(2=ne}4I3+yVWs#;?a~6gv=7ymV*u!C2hdVq$IcDWV-9!JLvgtk1O zKK)}D4;c8=nNMMEect?qS)f;2Q5P072m(QoY!8_IV@5~9b)SgL7BYnqofpfWMB=Mr zg3bIABD1T!6*epQj>K0GsII_$x4jpw^~X_FS&F+(-HWN2Wwh1Zj!1NssTI-K8fxmi zdsdse6_B@TbiB1$Z8AEyXLc0XM+-;-+n$7DOQ)#Wk}4gEtYC0z2`>*{$M>QJp8o9* zF}+lB5_t`H&-cZWFa-$m>MEl5OaU+x5$#Puv{FXMTwrRqs$)e-VjhYhc8dfDyE2A> zr>{MQcOH2cp8VpIc>LO9_|%=BGM5`LkjxAtnH#$)8lRmNyep+O(D}u}FA^I`-pb9H zNE=(*tV%bMDc(~DSzckdjyVKo|48iN(s6XPl46f}!#a|B1as@-@DwYE#Wt8Yxv`Pv zRWdd=GN=oRr6{OvZf4&Uz|v9|Z&tIwnw?FDBd?~Qxpoi;mZ3AzkN=wL#wTxYz*k?mjO*h|c=D7RRiQF$Z=`K> zNYy4*H__N!%d^C5>&h{|xXiu=&HO4WEyCLRrn&B{SY4At6h%c%bsZAx8cNH{u(-K{ z{HBiLLki?0t6036#Qi<@i!pHg-{Wf^zZ)0lCh_AHHxe&CiHbYl4`PfgKk?U? z{>_gFkJd1-Fii_r3G+l9IyMqTP2C|3TpvSnC&_C$5D#c(I1F}Pg{D_Rl2OdK#5r@CThv~!&eyQ)5@RQajFnE1Ju>bODb|i-; zubNBbXly%eF#j=tvYTH3?$zj%7OHGTsH67-Ko^V0gaj2zWFas=jmmwqfpE0xjD2s9 zy!7|{-l~=p({LdA3i{gbg~Q{)jfESydg9mc&3|?p&&DEnaNdE$^ADrq9Y2T10t;L{ zs;nzD|2ze-FultD!}w?nbzvW8%LZ?ZbK-?IDp*jwNq^aa3eD{4a)yakDsjQ>pf&Y8 zn3-C_SK59H>ibkY@h4AUVS|=&HBePriD)8*^5Sx&@;fMbcL|?&Xl$BI)p}-FaF?Ru zuR8Fb=O|pG{jJt&C!2FCfD7X|g3_9zecQ>7-Hx9Z>*u|l9PIxKFoWixu#PDNb71-f z_GBsiP@En(JVkJLi{bGW!R2z|-6!9T&TtJ^ekf&nVc^@itK%0$;ht;08pg+HHIW=r znG`CkOK^Q?0y~_$7K=NH!m@-&e356=WwaTV&gEGhjZI}(j_Yu#l;IJRdH?V;UxNCq zYA=ZOgW(?_x*mmctcazN))OL$CyA^MsEEe4cL`$@_ufh}-wyGXfVI5H{d4TuIjODt z>A^7p|EGW&ERbwVJJ{b_Ya7WjLZLFuE@S}8Sh>7#xIMhg_AkEoV<>ie;B`3h`ou$! zi9D_61(@c%%Zbq#14cRRs_IeBz$A{t#sZz4jJ0#bBIK?P*tZekd}(IA_AqnC}2B4 zG?CNV_5*8uUN{kyX6;fux1Ds_uL)RkHd5L=N=r&@fUMVV)i$?oEolTuq4QJNN=?UT z|M&FX0@QY{Os8~nlO`Qmi5*dluMc^VO%|cV?Zk^i4>JAa#^3_V%Tzq}%o8}=avY;0 z5nj!b7U8I>D#h^FG^#7h@Pntmh4{(@J9ngfwvtYiA1Yx@RbEz%<+T_bN`)YDtuLEX zFT~`cntGMvM_L!&RctW1o7d{ImT}W|fsDm=?3KI5P7N)f5pF0)bNpTUu)Gd6i^aQc$D zVu`4nlseluc`y|jr8UVo0~D(F+C}HNXa<3LT9Z)B!J(`imAhh*ZB*9@)oSMf_QmNp z{q+Q^?FX3BX%>hU@wV{2_4=&<-4EwBy1u9LSbeYTA}07(9Q0hs139js!1nq~p|{~OHU+m*i&b(is-5Rvv}Z8x^HJCl;7A`ujc0$n)|rcGoCT= zdrIE>QMrib>-Y6q&)k=&ydnj!+_Qe8|K9UaiNT!PyHIUDTvvfgfErB_SVchQ8jbE7fH*)0_8&@v##w>v zVu(KPjgf(X%;3chl7cM}NBo>sv7J5DrXBXK@t!fF zRc7PajQ5BopvN% zsowV{Of;}k3GH=A%qZm91lrf!I+_F2lR%FzLukjRlMEn>G>%e&WJVoDy=*-3S*gqT z;dWR>%{!`U6!O|HsW&Il${$Z4aMrc5gr+0p=k_n9GsHPZJfl37f(c`F>CEMGM3Jg3 zecz)lL(AGL0hF0uVi>BHQsbsXLoz1J?@2DyNMsEp-^-CU?5QDUA`V=8ggUs~^BhL} zyNgiv!P;sw28@%(kZJ^hCQC$^EAWU_r&_JtVO~?!c<~r*jNA?C z59$6y<-Kv{0As0SYlzTquN#Ew$oz^)wBRrMhtsAPYb5`i64t9>7*MH3!FOlt_ zO9M-#Cm?L44nt_KrDj`eB>@RyhZTpX5+Wc<-Gp%iIWEF@xqsjT2>j>@fGCj0TMx*V zkk!w%9M<+p4@h1!xxy|L;8~Lxkg8ZFzK&Gx%R=|bpH{0>`SUz(ks4DGkVfdwqz7Q5 zX6qO28Fy3-f+)}sIr94aMFQ6wL!>COqP?ZWBL#-vV@bz(<&(Dm&SgOZk_j^KRHp;% z5*4Vb7w_zL2(F7tW52n6mad&%Jx1Uw0|`E>P{5sIq488Y`sISDlBw59U7;#v;QvdN z_6vjHy0+um+l9$F_TKosa^Ndm7u9$Qq6cV_Oan?)tOuHB5TRnWK0SlTQ>}VGDnD-O zJMEVQ&)F7GiHvLsuihiCzt_43Fp)oB65_-4q`D$5khP_y6>DfN>Oc;_XgldeP`@Kc zKk8apYK^!2PS`Gv`&SyDZPY9z)H9j2;atZR;F9gF7qxcwf_9_!RT908_?(~V(XFe$ zZ+=HA+LO?u$4+#D+JLF<$S7;07XgYK=t%YMCiO>{P`n?DYY>l2o%a za>)Wa5up7`)xx3U&BJKd#PcJ)*z2gq#%@zD)1R(jenegSzedb2Zx9?OrSC=j>c)4M3RNJn_C?!a9&sE1d(Bb#0m;NH@c^|BcoiYd!H$S=9=(jg^m$o2 z)SAUT21J)0CJo4_RGP~XWp$uz|DC!FcKSq#Xv^JrUlt?PoqbQ*JQ3SUX-~4fQuQ+v+dZ?6ICfOpqy_y?zOYO z^{D##x!2O~Q{OnU)6bJ%N$2nU=-sB>h}eo{qX%a%{gjE_J|<85Y0w?~wfkx$DPBcE zgGl8v19$+D)fgEI(XPa}s5diP9bJAk0lKtwG~KgnYkTF^XAPj*2TWGZ-$9?fEI{PB zGMS3>gdzf&0U8J!l99yOj!kUV14Nv< zQ}qOh5_#>cFZ9i1 za=)To3Z`K~ct)%?)xa?xvio!J=$l2pf0<-va#MJ~SW9{BR23Q-6QgFd=gM!$w=HQb zYj=_%ac|{%OVT(Kkfl^@fG&4LE#KUFX??MNV1pWJ(@W)KA&Qp7sbjAkzcjOF#~7%# zx2nfm{q!@Px3{YFtiC_fo2}OGeVVR~rl+Q>FTdQ_X<*NMdTs~m*tf7)t*<|58UtW6 zGqdSP6JXDL_2kKubpOcVW9c`Z+r13yam(RzJ04?^%85AGC(` zdF``*?MTM@gX&?;I0M_>wFAUJHv5iy=F__vBkps5QICy(YHFr>{OF5Td9z~eUV5+Q znE_P8*-~Dd7Q>c?Ly34d2Huf$oY!C1AF_@#fj; zT?7|M}N+4@&`S2mXyjG;YUp{KIukRA}V3 zaIO!x4|QyPM#xoDdce174iMN2(OTIwUPmE#KsM93^E_xPZ!;WB@jg%B0a&?ctzwE8 zdA}pI-_#nv2leU&*7ZXu@8c(Jt7I3YiMSEpF}ct_$6-A|(`139bx?7n+qnXCL_Y!o zXg0IJO!z?xXcVmW&bgF{=&Q1g0@sECg=F%Y*bg z(v~F7F_6GJNG9)|czl^I*_c)b6`fg>K|rN(OtMMW+}pMi)m>2_Bg$nw%#$UmYLolO zWRvXXt$(!c!C1=WHF;;xI;DyEt;g6VoP3>yw22OVzC#cU$Wp z*9`*C;3nqcvuJOc0kawN;p**{L_x#>oZZL0+}BIF4{E#i`ASK1Q0I7eqMq$uCcUb9 zNFsyh^}l5s)XY|+jq8Oq%)3%*$autU+tL;7W1_#{>ol*GHe({y+DhD&kdm$o{2K!W zBec#@h$TV+)&3bnJ)=maF1HrvjH)QBKQanA34pa$SAw+%ym|u@KmGZyTmLbImvInD z0ZV{}mY6(=8I`yn!+te2*HNA)h*Bh}UgX9m5R4=3w~j>tDP2~){!IMf!mnCjy5YSV z1n&6q+3ya3-^Hk|?>v=8`Mhmz1fado?AU$4*jZ(3WQfysKOtU|G_K}A}S z#KMK1hVv51jX3L0`%9 ztO`{k?Kyx3 zakgiB4<1d=IgpNEygfsi?d|Pq?bDB{)!WyqyLVSoVB6j)B^!vfYlj8(5rpR7scj2N z)4j*_H8uqH9bT?B*Y7p`#L?9kW0;jo0d?oFz_u~a0^w|ZF28oVI(Yna3rLIw8x^d^ zt$zkQg69Sv`e^;e8f=>dta7;@MhNO#f6|%>$%J%4=ktA@Jv{5Itof%(f4uyg9dP7- zFEN78sx#B>Yse4#p(mD4r?W+CI6@O`srBW(VWg9DZ8&C{#y|Lf*CqA({>7g)!2l&l z8GzLKb4HH3bnHc7t#15Gyo`WBHl>05BmSh}FCYAFAb1=B#iU`hhBgK>54bGisQABn za(S>fgHRnCF<`DS)_yC1Opp?G*zF#GG@hhz9YuLKmaBrpYjR}lD3Al}s(H`~=S90F zZ-4V#E1&A+`Kv7XS7Lz_28N!N2(B zh3d-HdjsJ*n>d&-nqA;o&{(er0yiBo^t1(LbnfD*1~6;T0Bi<$<8Bii)()Xj?w}Ev z$~zAX7C>O@&;z;)pw_(&e~{J(&z*qO+H(d-1LU3xlnswyknapw>I)~=5v&yqy4pV8e?uU4Qy6nz?dD7M5A+O z52iA_eZ#vUUfSg_faH>%8ED>xNCR~;B`VP%{EPwBGn0lY*&yL(c5PrLKq)BBYL%tY zGlC#EW_#%R*~)mAB~Ue4qh_gtK2BUqUtL8j)emY+G#I%q4yv` z>tuXj99OPBoADliJU+ETbu)pbLj&a+wAa7^z+pbX*aAO4{PPvpAN66xm9d~Oq@S+;VHzPnZclFWCyd3XN@PFYTZUV_7R{O`;AnpuI(O0k~z#S4!d7D z7Xu(LX~ar_^>$Cx=wcP`ZTKfJc^3qLn%FCOK?Lone)Yry7)A=2foNOTHtxqlCWk3f zp(Pb~e1QVXc09W6i=HF%aRFCSald>Vnb4f%?dD z^)f4XqM?ncV~0;(vcPTH4Y+%|ntZ%j{rD%}s&4*!tLlI8pQb_!7;`o??t$zX4htUN zzWz}<8}Zqm+o0`?IyA74vjwg#aE~(F9+TbQ%m8VWvdZfN<#7#4jNIO8W$J_Rc5P<_ z!f_zG-|ECTF;>f*=ZyM;ue@3<>|3mkeCbP3>9ixT)MsJ*W zM^!p+Xd}(UYd>d1Y6vj7ChWj^`;s1&u7M?#GhVd4E+98Yuuk#2gi7l746Ej|4N5`L z%=O5KjPk2^!n%30{4)F>k6Ni9nY^JK@j5)N^V|>;=LH}1x7X*~xSMiL#vor?dWo)& z&?ssZgV@+XG8wPQW&qjwX;=P9F4;&a%JWoabcNKIMs@rn8dcQ}lneaDh>SO!3F5F-xj0?vks6cr zw!=8jC<4-POVS^AYyFkJ#RG>1{JfArM+l|KEGiy@#Tv(AgXj+?rYxhkS)J83t8W8$3;Si9M1^3LbU(@002ovPDHLkV1je0t!w}Q literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG24.png b/Assets/SpawnSelector/MapBG24.png new file mode 100644 index 0000000000000000000000000000000000000000..bfdde406dbd4ed6f6626a58dc541f4cf5c9fa891 GIT binary patch literal 4523 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 JPDHLkV1ipLy4?T( literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG25.png b/Assets/SpawnSelector/MapBG25.png new file mode 100644 index 0000000000000000000000000000000000000000..55894c3432d1665d13a58fb7626f2425f5fcc2b6 GIT binary patch literal 291 zcmeAS@N?(olHy`uVBq!ia0vp^#X#)H!3HEBeVpw8q&N#aB7uV3!XV7ZFl&wkQ1Gg! zi(^Q|oVRxkxtJUUTo2~HuTMXkkZ{ygxI`}Wrq7iRd>@`yl<)uX*#7MC_6gCmR?l#H zmwnE#_0D~pWG>0V-(MMP`e!I6wRK1;rFGDskyNO$&0-6O)J>*nmfkgAberUESG@er Za4wg#av{@;n?MgTc)I$ztaD0e0szuAYOw$S literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG26.png b/Assets/SpawnSelector/MapBG26.png new file mode 100644 index 0000000000000000000000000000000000000000..9e0ca8525a3041e233990b08a0f493defc327be6 GIT binary patch literal 3331 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 N002ovPDHLkV1g_MTpa)a literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG27.png b/Assets/SpawnSelector/MapBG27.png new file mode 100644 index 0000000000000000000000000000000000000000..9e1777bf7462fc822391c62ffdfe64780570244d GIT binary patch literal 4784 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 KMNUMnLSTXk6kMzT literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG28.png b/Assets/SpawnSelector/MapBG28.png new file mode 100644 index 0000000000000000000000000000000000000000..cd98391369e763e2ebb7189d856cc685bda3b3bf GIT binary patch literal 7876 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 i)URfItR4_a*Z&`sSpvlvkTRYC0000mZ*1 literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG29.png b/Assets/SpawnSelector/MapBG29.png new file mode 100644 index 0000000000000000000000000000000000000000..398b4026506be17dc52a781e222846b10510d6e3 GIT binary patch literal 9729 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 P00000NkvXXu0mjfTq$B} literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG3.png b/Assets/SpawnSelector/MapBG3.png new file mode 100644 index 0000000000000000000000000000000000000000..83d62de5354c154ddcd0b0b57600fbe4cb0a7b86 GIT binary patch literal 4762 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 JPDHLkV1gp6sLlWY literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG32.png b/Assets/SpawnSelector/MapBG32.png new file mode 100644 index 0000000000000000000000000000000000000000..0061a6faba6c83e007299f9cb4a815edcd6c6c02 GIT binary patch literal 4568 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 RO-TR%002ovPDHLkV1hz9l@b5| literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG34.png b/Assets/SpawnSelector/MapBG34.png new file mode 100644 index 0000000000000000000000000000000000000000..590bd700a504c91fe4a5fd1ae5382e02cc265bc8 GIT binary patch literal 5236 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 P00000NkvXXu0mjfT9R`O literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG36.png b/Assets/SpawnSelector/MapBG36.png new file mode 100644 index 0000000000000000000000000000000000000000..9caa5e09ffec909d4e5fa2d3443c1c2c8f0f4e84 GIT binary patch literal 7611 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 Uq#5Kmod5s;07*qoM6N<$f*~cvCIA2c literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG38.png b/Assets/SpawnSelector/MapBG38.png new file mode 100644 index 0000000000000000000000000000000000000000..d89acb0a66dddf14c028242e7dec2ceccf7a9bfd GIT binary patch literal 2580 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 literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG4.png b/Assets/SpawnSelector/MapBG4.png new file mode 100644 index 0000000000000000000000000000000000000000..1dc6974cc1ffcdb5b30e56bda1860f3b4b3198be GIT binary patch literal 5575 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 Qi2wiq07*qoM6N<$f)X9AVn<#g$Fe0$v?-Dz zDT>2&_T|o2eCN)8=btn8&O%YLgz5th&T`K^+jsuuoI8{}FTJuz8X9`RV?4C*$c$He z_?XB?3k^3i9~1d#qM?)dn8-&P4JLEfL_Ynwh6<1IP@v)8&0D7~lvNxF8!DEBzV~jM zO@53A2;Bkd3$s^(Ds1FUmCx5(@ulBw(2;YMy&dIa^o6dH8S&MrQ1iOx6{#u}Y?g37 zK%WL8J;pm|ey{r*^!;A-b#xuM{^B4L{WMVMG2TJ*d)?ol@As;&!^@0IxaIY@SN*-t z-|zk-1GfKZuZN!ZvgpczA^-a?*Xf%tH|Y7_YuL{b%e<^F8+!v|2k7kr z-R38s4>BIc{T#pNrB@ak`oe?AI(eu7rxlK>hiD~Lrs>h3oqz3rJUxl)2B(GK@=IT8 z*!>`W@6GlN)NMfvJ>q+P->toV+JzwK>vrjRkDBKjKekQ;_c9*Ox4%1YpDVaS8x5ko zSyRb$sY=n1U+LxF{BP$D9wdM1>(=olTdvX7W?KLzHXLg8j}7H*9)o}MU%T&buktzu zssF+^s3jm|k@x&Jtoh~2)_O3}dV6>m`1k+l-d`J;5=Xya9XA;BZ&_!`djUus4z{|( zBsh5I`N|dH3E+{}T7w-frfc%+x#PsLxxDi^sg0F8AcYmCU^a4@gc* zCzJCMOriuPdf`&5?8+OBT@iV|31t#N-cZn|2t(Y9Sh=|e9ou~+^Rr*JCL#yOkh@V% zn9KC~Zlo9UgOU260Sz}53w96-@Y?7a3R1WmO*jylwXGkLZ~Uc!Cld>Gzcs|90G?z& zfDPX(_5Yy2rVHfCx$<1@bv{ZAVgajRJNEztvS*(H^(ouTv%Kc|AmPmkrl; zW&41hAGE$(J-7DU^1bR0+F!5t5Gyq+3qJVu-_uj4E-8|jytCt{==zp*>pDI(PLrX1 zv{u?w`Q`ObR2^V!^2Lr0`i&X=mhZM+`XP)bg0Hs`W!As6t9F!R%7!47+dD~`o<5@_ z6R{)_q#_MS!a?Mqa3f@|+e!Cmzt?;HZlK+?%S0MR*nV!BMHO$9ztUH`wq)vL0+3Ds z63UQ7A`QH|bXlodmd@P}Iw(fZS%>7*HLpq|-c1{+YhF6>jGu-=MDPE+<$yd$7~Y?^ z5y>PX&uK_$zi1X8F6*>0o_*2Rb{x9; zdUa39bdpGkLCEYFJ%|Kpl1LEvxkDEfd8}gDZlau3EmSnZql8c1t|}6BBA@z--zE~s znKgA5L>Znv2qL*&zpzIIoy$Z5QX+xtG^|BEkrDO2|DN>ckJQr7QBLcMZgkjAUCZzxHG^8=ua2?CLjNDvGU zR~}Q4MqSv=dp(aa?&tey;Y7&yK+d(Fn3PfH-;yE`3Kpa$vvpd{lxc3GOgA?wwD`;N zK;vOzb_2ZE^PKs;KfkHYnXs3TOb`NaTB=%kERmip6AGL8X}kHchdk~_Dy0LYBka56 z+P)%_EB^BGKiEeSNi4itR=2Q`@_53YEC@yYFJAnMUG2R84=C2&aP(dWC9|uVm9|59 zrPF6Dl^IW{G*mAGQpu9aGU)vsdK6%mUvn%sg3mh= zDJ4%zYA>nnCZUceZYBrdTOddw6Uhz{+e&~{@@|Nf0I3|h)oa6XPb+ZV0jtS>ru$8# zVFbumkEozOv+HX_A>WICOC zd({V7Z=x1kfcEZIWPuM!A|P7jZ7wl)g{Lu%P`hdeC*gcl|KLE zarNxbfvAeJ>Hk)t8>Bt#c&4dWNoZH{K^zAGc`T5GOeMbSSl$iY>VZHVexpH=VZS02 z0HI1^tA&obtXg#<`yo~*)b)ENOC=LLK9-;ZlMNb+jwnI_)CqD`m92+1_(gav@``IR1#V%S?bqle%+H&x>st~ z?{*%N6Ne;@#?Mh|XT!0P6Gto?3PQ7)055O0a%TD!mDh>X!Gv*rn^U{d~m`F$_ z2dG|FztXNs+bSKUUUt;BnLqr+KhpJ^|E3Bn=@r_{v<9@bomA4Pt64c{xw|kZJY(r% zEZv1_G7g|KO>r5h#BO01i1SM%pD0s&;*+ouF1H zfsVX#)w4TfMB|FcbY_zdj6b2CFWVX@I?yYSxWN2Jc!B1rig9 zqcm=e(oSKA&K-D4NhqsT1{Py9a!4%@7ILrnfl#*hOeDs$x-oB)hQK5;sZ1aT03=FPD+3^j1bm^23cRLL?ap3bp!vC^3JgiC z@8pSNufG4$93{7w=vMM3jf_mFO93215)*N%m>$~LUZO~Nn0C@TG(9;*o9Q$Sg`<{^ z_gVI4VWmRxk#^gKXZX2fty-tq#d*r-cgXa6C?1K^YW6ObiWwRXHxz-5hNS`#8$mBc zLNTf}igaY=6h(*P6fnHBky@l!EJmf0Nws>FymkEkbc;4K?~@VAP{?OVJ!4|zydo6O z5kTm|onO)6qZc}e2a!NFeV5|<4$=DE4;9(P!X_0;8H=>o3`LAF@_KwK3=fScLJjXI zl`3fp`iCi%TUGTje!%M^3WWnyF+2YT1!dhrz2;Hx)@pV7@WTbFRLZn3Hc5uhpg_1r zwOUmLd%b`Asjt7fw$Zwl%Vexy-I->R!b35NMGZPQIYSMvpGu_y8No0W%`#EVu!ySF z>E_%foj-7%K2EMvDpPMG70++XZ7Qh*nSP&-qLEQbW!9D2-9KhcI#ax(779c%uqYrB zYBu8AuZRRBvDy5NQop8Ip@O+UOY6U&Cq{pZK3M)2n?U4E!=$CPpHMIupvcgKO(3Tc zgG7*t0DwqEaJHb{GpjiY_`>#vQwvBDHFmXT)m(?9@*03tJ%B7HKw2?J1b#o@-A`V_ zpz%le+4|aa(mI`b$SYr7tZC9ExU>E^g zHD6i!0bMxs9YrM6?s^3|pHRLtrZs+0jWkHAh2U*Adc5F_wd*c2eJx|KnC zwz`*#wd3`}`zy&gO6{!C-F%XUjbW;kJ8zRbfBc=l>-pyiAI-g?yxF6Nj;TDKGXb16 z@r{#z*u}rGJu=;CM=j~GyaQjowJWhPFgYd_g3Vx7Vq8o*iJuncDmzS+V?M$ zAeA5yP7tHqNYVDrCcR6SZHEcJ71D{k^1%u{d+MuXdah9>vrQu-V{I-ytCq;H<*lx+ z&nndk=LZWf7fzChI#Z#es(zwbt{jNw4b1BLjW)tSEZUno^mJR_AdpGK7GuXo63-jW zUbv=%gStFE)Il0Vf>)!%!}pmsxi5}rY|_Gvmr~6O z_}2GN;QB1l*;6f*efr1+noBLvbfR4?%Co5i1_|}57G4}jlq=83v<~7}^h9%y;XQuG zip#G308FAvH>I(qUf1mQrzVcJNh%XAiMEbC?WFGpxt#`uhOBd}->}9$;yF)r@O{eW zvJ@RA@>EaIYV+4048PM=lv5rT2T-%HnKzeiD=7uRu&r;uXMGX_p}5{dp2#8-3&}Qe zdwY`(%~-$wTS;QD)_})`3goMIs%0!rZKPE$?=!9A!jeT;(vnD3?w#p4m&&6P+B7p8 zN(JkZ*zNF-V+l*C6P%t^&Hn!hol@SUylKsEJU-giM!?yz(qvh&V$G#k zHfd})LPJKRqaIMHFH&l!N8WfMiYiu8f8!=d1 ziM*LoF&0<{7Muyv-*YO{$zuY`wG0J)BZ^3tO1F0W{sN81$Eavls8KCZqnx3{M2mRL z)AQojzNakt%Gw>8o;;{x9i!2b`i6P>&=cx94@Z@9dAOrqF;{BKhlfLUyWGb!7cM9# z=*A}tcDW9a-~=Xy?TBq%^7I9EBG#=A%8{1R z2Y^7pjl^z1dyRmHB9SN+(^fkYo-^lO?l_u60^_Z8c+36-1~OqUp=MKCe#(|C^31CB zx9Em{$T830awq6@dm$PM*&7C%DBO&7B(rxY5k1&ZcTmVp2`Dep^pel$yxH-3S`s5k z1cBk8LE(U(GP#nyewYi|ksHAYZv6px*Yo9zf7Td{wf>|am2TYz)jW5UMDo`X5X$$n zAa!xB{n8!n@cS5Op|WLf45Wc)PdrC&e)2Q>9ls|;#}1yLTX)($GbXs(29Wg%T3<-Z zvO&R{h3C>O@3uKWcs~FU3u|}iNOQADGNm@a1^`Axe<3aW5MR52>rXdc8qUOiohOSEkf<$tH4Ncpq)&EYea%>zGoh7wPEK zaoWnP)2ZptP$Uqce)7B@hTq#XOvq-hNS8XVyIj@MSR_%~4lvLQs zY*8kcrBbP`(v^yjO68gg0Z)Kp!{byel&Dejw1v$~&ibTQCzVEBl!wA$%I8YtHT)`O zEN$JUk?0sLt>FqZqUu3jm1N3YG7+7mwcM39?-iaa!0MKNZNO6c*41CrzQB{TS=?-s zY;G?$G(zco#*P7`=hi;9clu0X%6&Cr_#vb)Z@Ss8`el z^!fnT1F*S(*_97F>d89#b5`L_;0?~ee6VpbSHuiRIjdYJ@N=ng0A2ey+RS|;*deXB zTN&VM9JCjc2aQRLMXXM?3s&aXd(uvaZPUS4o zZsf|%A@T9nES(%bMGG4XcG;1MBWhfDhs&Kd14sb!rq$PwF=D6P2$7n@39KO`Dqd4< z6rCKbD{msHg-{P1a9-C?UCERp4RAyHz~qAHlBY|jzW7`Ru^VwZbOQ7~HZ^J2+jW98 z1Ns<1W;b*rnhA4)bQl4aJa$N#OhB%?B#;S3?3>ts=2h7N8q1qmm4;(+YVt|-&k-Kk zcT!DqYB8bC*h#eSMcv**u%hj^VNdh6hhR^N; z{V|Y6;6Ay(-zDY{V2Uyv@O$9TjoH*3u zK37w>DOKE}fIpzph%2=+89u9Bq_LnwLF??zX~fg<8LImlR4Nyh^kV%uk7vlEKahcS zR-`n1DsX#%5jLpqsnK?3!zO+>IHJZ2AZ~Mjq~pM>GxVM9w%dEDMX5$vg4D*T8*O%R zexu`mLZYJ+hgCUZUNr1tysJajV-*Y4%DWhO25SXCS7A=}PPcQq^vLJ1wYXAcXO0~^ zKuRUQCvByZYL;V=5)630_59y9^a(gk#EDED-BcvhjSlwc*t^rcJbtEw$>TQVMgW{t z`#bZOiQ%TYbh{_l!D(J{-8c{OSnWDFH&V6gWVjJ3H?3?_7d|DKPLu0KLNDlq=!D%X zm`o=R_lS@IPeM9*u7g0T zWk6T2u`b#Jn-bnFd%FEVo^gSGy;Zm4Mz;;n3;HIKTB(`#Fqs{My6t`^X^;)O)sgkO zp%+0C{d&9Ue5Or8)_tSnibR)>^NTH+KMF+rkSC|_Q(uzzmp@y4{)Lz~*X>-~X zgOd7bAnkH_(aXos$?lh6uHzsSp0ek(4L?^egj3zq1%f%-YO%DQ}p?RG-wSLKRvw|y)8KU-&ZWr9w}FaQ7m07*qo IM6N<$f`91v8UO$Q literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG7.png b/Assets/SpawnSelector/MapBG7.png new file mode 100644 index 0000000000000000000000000000000000000000..6c0228133dd534210c3a13947dbb56f89da52984 GIT binary patch literal 5501 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 literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG8.png b/Assets/SpawnSelector/MapBG8.png new file mode 100644 index 0000000000000000000000000000000000000000..c944a3093f165af7be8aac5d9f3b23991b0cd0b3 GIT binary patch literal 7262 zcmV-k9HHZhP)OIvfcO;OhKYYX5f~Z5VstnUrg;;5~&+KX9ZYl4!d1Dcra3 zYZw?GGl?VmMgmw_RAJsg60hL0A*K`RNTWH93iO%J~Ra`s7;iqgXI0X({CO>P_;}cl`7r&KDOWrk`S}bnTk*< zlFD0GR<81z2m0~-wnMm~v|1^b8|PASiWbc(QTtTv=G|Yx&YQkvE%plD2Z)(fCXys_ zBcUW`|G6Hukt~`~&X+oQvM&x2%`x-oI9C9`?Fndh3)>wLTW;!nn(_nND{eE(g<0ebVi0% zDjqHKC67dsM44Z&tT`{EGCALg0!b40Wo=1x#z~_Bg={L7$0S#Xq{8V4y%&nHrkA^X z=X+eA=^i_{lOJDC5}lD@WokE<%u~mr&{+;+$s%B$9!M~jF##1dYQ?a6K*SKeO6B;2 zo)Vez1v4#|crWYkP!D?W8RY-(r%W%EN~2P_))Z4p1rk)Og!yES6sJi{Ebj|u8PV2? z==odjh#?k@!Dfd_-`HzUd)-V@;!<{?lsA=f@7@~2@1IM)?zTIku-Sm^uh=fSKDJMN z*Gx|TDREiSlYLif&K)hUiPSwvdQl!-RV6qcL5({04V>UvLxjz({KvhwW zc`V>HJZ1-63~rAPBEiL$H`QnAZSEXQZKJi_dcCC1XZ^+~IPs=7+AUCIQk8^+@ANrS z2ouvP`-D!u4pI0YZuys_3h9lKid)ImAtdTxLpR)%AZ5>P`;3TuuL%_rNuJl4qX=V~ zjaYqfPq%I<$|MnbTvnVLraI(0QLauhK{7e--ucU)Csk0Ok4C-0l4rd>6X~Jg^hkZb zv1EN1^NO7*#1cZT)k0B)lPNG0Y>!lLjgc%Nf^k=Zp*x)%ImdhwD{)%^-?H%hw^wgb zYt_!US4>>}y`M~42{ww5MotC(@VH86(&)=cEJ1Shwn|$rwml9}9oL4&Tv(&xuq2Y? zkR&Qkh!r9kT-T#Qf7`G_5lOI|LxYL=_Q+$OM)kk{5Wf6e<((G09jXCCBjd^`kd)2< z)A_Sp>b%WvLt(BR9fOgi^X(_{5%lLGznE%_sx;_-@6wgwT^JpSA zdPmW&j_ulcr+MAQw8!@3@-M_l2$vjmVuTzX)05>olSJ`N3d4N5^TXu|*PF5yl}Hi2 zS<_5E`~&qMePm`Eh5B_QuyJ4Nb=HOmtjE*6-b!F52!WZ7iQ~SFGp<)Qq$AY!iPC#x z;;nXSOAH}W4-ODIfi$N=KKDtYtTiPH#5_Fm%d8_yFxC8-UKgCE0`0zntcujrq1K^k zE0zd__nU2)U2*-)lqqwj1lX-_LnKzK=Sj?#NR0v+`{E#x$V|vY$aImdoM4vn=e6!s z9WQWI7!F-V;^rBIp(*(~D}-3VsftZ0^%Wv>TnXzlF%nK9G+TR2WqxhZ!!do?p|2M^ zBg3Xbg;aTuDS1kH@nww!3}j!eH^2BSE+r}!7$2Z@pZ2JIrZXv{`?LqES4^NdZv^eX zKafOX66%wkz^sT9tYf5mIE7FlK_`+V5ro+CLVseiRT+~g^KxTh_v`T8dL4QL5!iBUC_LSgLg0e=*QzuSv123(yx8$~i3dGEEAkf5qkcrH5*>kZXBuONetu?}T^JaNalb?s(?S8f2+wk3t?Xrss z38tJQMOlpCsILYbxu&V@j0~$hok)_e&$T2}A0P$3oN1*qy{}*j_v=K8bCS0r9!3K2 zs}pbGXD8o$KtjnhJpMX5?Xuk-7}!GTk`{ z?2Xt{2Frf`YGi}E%m{IjJi$%X#Y&}fRzIGx-O9`gk>bqI?8+P|DwEGj^k|Xf>CjCq zRmlehE=+tN((=YXCK0K;&=o<9jzm@dwq7HZ|EyG#r~=iXBPi+~_pY-McnS zI#25Aq%vtADoY{E5sYt%o_w$VHv;EC~jmHB2`k?8^h&O6oY7lyimSkmeoOoRE z#INx|!o1Uok3d}&@u{IcF%YSwB#b1yPK6Uw_;P=VF)bw?WX#KAcDHRarYEcSDk!?@ zyEynp46AOi;n)d}B5%R0s7WZ58a(s;jE^_$z$3p@W>b_Y%F|=B;>?gx?laV<2MMgE zRtHDUWaw;qGiB57%amHn4`g_bo}Z3LDl&;gok)^sA(Dzqms+o-vdw2$h)f5PMj|&X zD^bo5iL9Ihoy?>tZex*!3!}XodrkGJ7k0Cvh$)7J&-tI%}kI4$`e&PX@PF0mc z8exw&GHMyERrTv}sZ{9_A~iCT6q!Yh1<1?zjC1*oY4bhRw_x<(UbUaeyfVLS?0ZUy zLR@>>up+fBII6Cp6GZH3>{q1I+-4)LL-DdB!~MKQ(}K8=||CsHR< zhY*{MP>(n9OSaIEM;$ZGW?m;Xts0S&k!U3{cTTZN$9fZA{5$$xlbTnVC$Cx(QbbXa zvBDfRXOd8Yq>^A_@Yv(1UA7^mjFd0hb%?^&oq7b7Wkrza;ayu+qNKDG+q;32XI@l! zi|5~inG%@^Bv=To?|&QxB{l^5V`wV*Zbl;YR7X1VnvF;+iA4*Nzd970>up3dY(y0*hCaGMWu5mK8@1@PnmP%0vJS6i2~+_&$%#{Q()ts6hfyI5N+@FqwCxt z)~&2jn?Q)PyYtn)9A|<)A6j8GuVw{ZZsfoH1uk&n~wbW0zVTnn%8L( z+1&e@Nu)qmB_ZUFmsmcVh!aU-WqnBqpc%# zx~|ugRGAxJSLQmCgW~3K29LFJHMNj{JV%IRA8;cQ3QZavxKwBgE9w z%yRovLr~?lw#C%8akUog&|tsoaW|H&oWR|Gm5=LggCdk2VeKHAS#CssUtdxoQgI>l z-9yit9m=%nz#EtesMe}lV@hw@8Ni`k3}NQl!d8rJeKrhw@;#BoUB6S(ZG!!Kd<= zl3Xrhbak>`c5g*4>TdR8sCx{Jhm1&qUU3qmE3>aZ{fN^WB#ojPXF?=N9EzU7=8~V{ z$kCWGubr(nloXG{<;y`$ow3xIOqnKuI-we2neqvp$aLk>`dEo1Bu_t=Nufe4x1!Nc zE0P%Dd338=DNjh`KGjJFi2F3XR4tt#fe`8-iRYWcipapZ2~6B?#2R%H)0x^#VCC2V z-d}(@mO1GOjtWQzsQdA<2#awOgmS`HXA!f_hT&34UG4st(%meu5YZwWkMz*39c{c=rCkQ z(tf(fSOPMoH%n6K1j$^Cp zHbQ0jVZH8P^}TULLJ>$JNh0$&XHvCOflHPoi_$Mi#@7DO1juuWT~{?y}C*p%ZE+k>dCqb=;*?M?!T{t>%?W6MD4P z#jzD)ZV8>ROls7zKJYs=KX!E(?^2mkjr4BC8M?jy$Lbl!2GhS&Oo#0+yA+X=K?WKL zoeq(ikgcCYodk&^VG?8~#s-2WiOgq!L6$apG|Beu&#jBm@j0;Q@61dplmsqbyigsV zJbB7grJn!f!8)_D>Y=@U3^f_S`moc;n^WUPZ(A6%%d&q)D8%38cuvig#Z`tg!a0*p z4@I1e;%jH$M-du;FYp zp6bQi@?zK!g~#K;fga;Go6+Ei+DN4H_CG_xhE)g*OrZR(wHVs*7D^xbFot(EAg{=& zo)L?GxuACfpDU=hA4i_YhQ2f7@Xm3lwCP|J;hqtcFLS}|HKqlgn|rgz{3O;5>j~&hDr}jOnE&c_C5J{q}brmpQ&ROeEVsZ*x)7o?tm0pXg&Lg<< z>N>2PGaIW`EWr^}t3Fos^NhnDPW2gb<~;D^6C_fvpls*t^{7CT@?=S3XYZg&Jsy`L zbAPMTYy=w+KHG;tM;{87FMuP@g}#P1jQh$FXd6K3JvS*roh60p9=(&S9YJzDEk_U@ zv15GDcx&KsMU`4}9CoG1){{`@bY*EA+vywL% zIN+?;EdIeWD1G+``mb4$=!cGXP*GNdS-v8;-EJHV&Q|y7gjz|>x_H_?u)#F31f3tw ztDG|>lqV*lXjO7!pji6VTeouCNi zwEU+ZspGB=pnIc1@>DTa?=YX^87xSN0cV>VbxbxVrfW+!r-$VEo%vW(QigZ?&!wC% zpY2tIP6jn-<8Ngg=_c}Y$5Tb+rVpX(^_StVtO2^(lv2Z8P>(C9T&)@{jm*|qLC{x@ zr3;OpL7Yt!@6^j2)Asdih>)s9z$8|Y7!UYd43U|TZLl8w$X&qiUQ$FB=j5W})*SPm z$~i^TR=;DihUg6tPj)hVeC~c6KHi2d7z_2{jm8(*;XmzzyYR4p%vR+$F}Zv40%3|rJ+}_Vf{*+YB5wv zb?S9zy8hTVvAgt(N$nvV(_QS!vcyWFnBd032T{2R=xu9LI-q%_I%$3hZ++s=o2Gl~ zU=rEii@ebQa##3(_;R$Rtp})DjG1CgYq)huk?C081WgrFwKh6ly(95Hl}nK0hk>Hj zUFulKl)971>+jA**}iXM<@H7QhZjC)-fNoK$tqJlT&!MDQ<*j@zAlG;{++1(A`r+?t!$enuGQZhWV4REBr(_P6j=q5ty(=-hMEiDU1{mx0XMJ6z z=jj7Ho!P$Fx=a;fY6k}RivdFft*6IuJ#ulbFBgYi7)+|$)B>EAP@brh#L}#iM0k@c zDoW%$8JLDCn`k|V9IR5Re7E0&HT8#3>MKCsg@8)qzXnmLe{Lt5w#I|y8DM?an(3N! z>Le~Dk<%)#HK9r!h0B+tW#3U;f42uM`;yndw!8oSmCU~=l>(ZcR-cP-y~$L*HjoI= zrADaHSjKpk89z`e>D{Z;Niz2g$DjG~Hf$`dK}%o&9b0b5Sk`pOusT!OU@d>Tb7m%R z?j)I9XU>{s1ZVcVc}SUInK$3O>KjSVbVSBdzr8uze-iUb7Q>nAHUsS>lBujSNoKlx zvq8#E2R@Hw3W+*Mq>d%Gm&1D~vthXqI1gXJ>=||LbndxSYK1PzBzBCson1_aS^(`sNWtnT$V3sTAvQg!Hg>CS&pz&Uea zU2W2wnGU8ht4;aE5`_* z?H)7=j|79T!;XQ75quws8PST4k(Q*C5G!Cs&bSSgE`yxv>MDHmRb!BORv1f{{766z zqI{PZ=Ld~no(Y&g*w~5SGGmbO8o8Dv3iSO*#C2+|tZbo5NW>7tTcq)+5c`SjU|xu+CKgXI%x_-`r)cG4<$A&ZzMTpj#@wutME` zb728u_5eoP{5aw>2p(zktJvY(&wLCW|NSfTdC_@!C|$S`eWw!ZP=UwhK`0h7mD%3j ziO3iSj?FajB!V4Q-*H|ILSn3C5V>_lW-3axrjtQbuKFYxggd{`v^+cx<{J)D5XRt0 zOQ^G8%2QFg=|>zO&YKZ`*d%mzQR1^t4qy_@=Qv0t31B+X(hS$4#C*m4;F~`(=S-Sf zDpS1KcN&c#IB~-@HE`A}Q1=idlDPUp2;MDgF?8X8N}b+3RCx1@yd4MNU9%Q@8;&XB zNVvN?@pVhdEjOb7HGbMZY|feXv#D<}a%w#2zVBYF`mOOv2Y=K~A~{f|Gq1~_VqL;H z#@FNah+Pe+P{6Q0Jg535nDBgMKk78z&cr5cu;s)M8?>3$#hIUvobpOc#DBM{Lo67H z;r^QFaqy})qSs*SoM!y+L>az%gCF16VO)P|-vLyvS*oms+fis*7RMX!#J?3)X&yX& z8-lHg7t^caA3@941~jo^Y9CqFjPGo7D*{gX=3;SMB3eVmtF&%DoHbSOZgQ$L(%K2{ zrVVP}S>3J3zs8#fSKT5Y{?kR~d2hWDk+##QE$>IMw*ZX`x8NRUD;@>#n_w;eddVpM z>7{tb#NTku{>;ZP^x9smZSOFiU6}5(C#@6X*AX0C#E=?;so&VhH5`CCq@Ah@hZ2LE za4)KWr)GiL@7u8rp14>f|LvTT|k~xF2`b@Y_iycFpW&HD_KpI*d~-Js4~p$AA9i zB7CV4=z90KvO0rJoe0$#md3VVZ78|*My&A0M{QdZ zoHg~xt1MH;qg{z0vgAoVuT`B=Q_oL?6@gT^+2O5*({!@La8knYW3$6*jW6t1cqjio zNG3#D(|`CJX)!)76U)WH#ep&tunc9j;)7kRmzDgmHn<3i#F{r59Fq~LfBQose;&CF z4>?~o^W?*>f4i4oxbMMl+o-~N6kfkU5oIMy_60(^UL9$)PN=iC3b2m)IEk)GBLJW0 zO>WBYzCH1J80yWdH0Bu|C-%?58862Q<}0G3P(-S{y7`&9%dDpiKJMQ)I*bJ?jUWDe z>v+^`tE8K?!SwYH)vEOVXAK806dz0_n>L{T^*u?coD-sDYD!Y35JU3nkpdxfq|5kJG87*)>#ts(_Wr{|qbW*erwW0Y2+mZN)LXCbR@*rg`CORo zo{QzH4MLx6ci<~a6R(g-FmcP^5fr=UCJ`?rpDd|R<*RnJoI%O08`ZJCFUaxDzv-I* zo*He!3^HhgsAMJ)0kKx5eGkcr_Satia!O(&7(h=$G!W~Ii4`jA`fL#XXEY%z!G zq+FjDz6ZD&rL#(<|VX@5@qk2bQi9lm09 z%zVD*XMJSb|Mn>?_So>lAqR^4&Z4%u9KmA^a0FcNl^fI1YWEnr_Uyxk4XaQ#uMjW% z_+{kTXW_%k^RcVhkAp*_W_in_VJy61jd~vInLDdk^#KPq(@@J9o9(KH%%8`_tg`iJ zW<^&6N3}76Q{$a9GkU&mc4Q=zC^`mA1-7WuR3%5a?t}^QYnQ8hrZQ6LMI)O06*@aX zzmD+TcpWb6eM`0D+9k=3kv^vF&p-^|kot zGcJ6!%8OEO9$whF8yl`!r_}rKA6oI#57**oLw}N*rTj@?W1DSjzwxqZgFSWgV@uC> zskwm;fcMsoW+7J7ldkY|B$}{C&|sPOLM`zaY~3QYFR2dZrPMs?#44Ied;D)?N1aLa zV`sW5=b%3RXH>&Z0a2v$$kBef_o9S&NE(UGb1^-d?G sLv?VT((lpB%XBPI1Mt!!>Gu}@54lGTsb0@A?EnA(07*qoM6N<$g8arW(EtDd literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG9.png b/Assets/SpawnSelector/MapBG9.png new file mode 100644 index 0000000000000000000000000000000000000000..57f8c27bc5456f8f0881778707c90d18c322a1dc GIT binary patch literal 7093 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 literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/Question_Mark.png b/Assets/SpawnSelector/Question_Mark.png new file mode 100644 index 0000000000000000000000000000000000000000..c0519347d76ab5b694077230cbfb9611bde1fd54 GIT binary patch literal 1710 zcmbVNZEVzJ9Ph}o7j%rL;?pAl#r?kD@ z?ULnCm+2P87^A>A;S)rVsL2w^!ic&U{IHFf_+b(zO3aoRh7-3Ld;_1}8=xqWChha~ zdw&1-e@8m}&sMD8xE{l>iq;ly0F8~-TULU;CzZXI&`_?mbQ>7 z4t6B{K`GfMaWc`c4X;n|h#(3~5l=)Ts=+4&BE!q0xwTCbcm`tj2}F}65byGJ;2x+0 zoTFG$Vi-H_;wY|;V??*>Dcr``oHS#nnL3i?c-F?F^V~xqak?Dh1KwwH!q7?}dQDT~ zX*wQ{Q*k>5^)StH97i)Y+GZmWf;0wHQ%sPmu{qD+1%{+6nyEk)w;0797&8R|shYJR zsugHeBj+dNF*+e?G)pm-O&Opp6>wTik7R_)5)C3C3RKfTShj%GdZ7u8UidH6h2uK} zAm93Y1sQkMB^oV=FwEwDWJb;*cSRe)0S(XrV8ECzf#!as=4Q(pjrZt4G@%}ZFp`f{ zM_y&z=Asz9rc+U67&o@ub^&-r69|MAHIijX))8b_-ciT1_F6Pym@L!>WhFH552%gd zolc&0-vLEABa5bZPp~ZUA*e@1WUvwy!+_S*Fo74`$a`P}>PRrs&Ysc2=i^&d!xU8s zw0Z>s*-R;l%*%GUPO{mZB*VxqQkETd(j5YBQglkJT@1NdM~^dq-wUOf71{iK`G4MT z*A-M+V&uMgtb(&rf^Sg_6s&<RdW% zQI&&5Wf)czYV|e+6X~lLNq;e0eePQ7sH3L1^gDMN8!vx#ZOB=(f8W%;sn;7%T`qa# zMQudD)-|_`9vQ7We0pXyoKm;_Y<@oZZvXMO+P1i>7Kb>|e=svpuT-6HU%dGK^o3Az zez;`gg8Fu7>&I}Vs=wjQ#L_Z`aMPEE{IdtvmY1%ttbX&_ncYWs4oo;a=$_+04)3u4YAI?sEdg<5BAtWQs9GJTKV8x!= w`Q4?7UA6V^AlR|*Q!n3g#irlZRbG9FTj+j*IDLG(^+#!K_Ip2g`uUgs0@q|!-~a#s literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/Question_Mark_Blue.png b/Assets/SpawnSelector/Question_Mark_Blue.png new file mode 100644 index 0000000000000000000000000000000000000000..f504f5e26097266571686dde0c5de204e00ad616 GIT binary patch literal 316 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?3oVGw3ym^DWNDEQ9P z#W5tJHTlo~|MrI+n3geaott=tk%vczCG^Aw#}^+I436H|E|kCMXS~Qcjyd6db(b>Z=!|Cjhg<{P?&|2e*_Paq*lLQBzLamP%J(hYYEYMdU}N5w2=j<_?K zdxk`tm(+o$pL_Q0*C>n^J?j&4g7>aKg3D*is&@+4o;#bf6g({ts}tT+Au*vMq z?EJp(`+a}r+r8(7BtA2NvB%-}jyVVjG?K^w!(}omVo$apuUm zmG$~Fe@oK(OcoZFPaa}^o%;B~hh2ZYarA@w)SnlBsMns~f9mkl1{LV=GDBJB(M#ub zx>;-|x48_nWQ9LEm^Y8!!!UPD8@Um0MBNGyF#}K|c^s&kHbpbchD}u)qEYOzd0a58 z828KcCmd^NF>W}limDyQMI$-x;OzKN4vmi@MdLPYWH(d+RbXNdvQ@KWxu6>38hQa; z`=14lZ9u%y7}xI`WJlCA8z&BCm4L(}QS4)7C7?tU5k}>8Y)}k_1+h;MBfO*lDG2C! z^WmsDN7F$jG1xRlcQLN$c{UJ)N~IF0^aY4h5F|xW1TiQCgFHp>Zq4#wmABkgEe#3m zBFC^jgIKJu5#~wRi*c0dtPiH$R%^Mm1m#~Q~ z&!t$YjkSx!BW{sgM|J!78Ur-8s@k?OFBj8nn{d5>G3rJ$AoHT#T+PNp2D_x}AUrTe zX|D3Uu|eFy&?8QckWwpC=@w-+C$4QJjUUL^Jf-ywETRD%U`1&1lerHw0@4=)^H0b=WXr0SmTO;MjH;L7bF`Lk;`v z8Z1;5q%7Bi7Q(4SjH5mW3_}AbtRr2Qbv~kD#7A*R;-M}}d=yHdkgP;xF{-!Z69kq0 z%(mn;Dj$uaK1o54m%6Z2Q7tSvUkThJH ztXlI%Wbt#&Rmor*RRAFJt2@RaKdo5fnxBn%B5-pa%&M&vF;%)ix@Tc7(Y*?EaDRbD z>xShdT#vj9#}=l3bIDtP`rPun73$5fq9U{knD$D6^PLg=rZSrp;s5z+oXu%KEjaCJ z{<7Uq>89P0u|-uowBNqUoLxeD_2E>aKi7M3-@z~Me3|XKUEaC<*wy;GV;9yQ*uVTr zCVhEx&$>!#*|Re*PF~tI*tP!de(); + int recallFrames = config.AdventureMirrorRecallFrames; // 5 seconds = 60 * 5 + + Item.useTime = recallFrames; + Item.useAnimation = recallFrames; + Item.useStyle = ItemUseStyleID.HoldUp; + Item.UseSound = SoundID.Item6; + Item.rare = ItemRarityID.Blue; + Item.value = Item.buyPrice(gold: 5); + Item.noUseGraphic = false; + } + + public override bool CanUseItem(Player player) + { + var adventureMirrorPlayer = player.GetModPlayer(); + + if (adventureMirrorPlayer.IsPlayerInSpawnRegion()) + { + PopupText.NewText(new AdvancedPopupRequest + { + Color = Color.Crimson, + Text = "Cannot use in spawn!", + Velocity = new(0f, -4f), + DurationInFrames = 60 + }, player.Top); + + return false; + }; + + if (adventureMirrorPlayer.CancelIfPlayerMoves()) + return false; + + if (adventureMirrorPlayer.MirrorActive) + return false; + + return true; + } + + public override bool CanRightClick() => true; + public override bool ConsumeItem(Player player) => false; + public override void RightClick(Player player) + { + var adventureMirrorPlayer = player.GetModPlayer(); + + if (adventureMirrorPlayer.CancelIfPlayerMoves()) + return; + + if (adventureMirrorPlayer.MirrorActive) + return; + + var config = ModContent.GetInstance(); + int recallFrames = config.AdventureMirrorRecallFrames + 1; + + SoundEngine.PlaySound(SoundID.Item6); // magic mirror + + adventureMirrorPlayer.StartMirrorUse(recallFrames); + } + + public override bool? UseItem(Player player) + { + var config = ModContent.GetInstance(); + int recallFrames = config.AdventureMirrorRecallFrames + 1; + + var mp = player.GetModPlayer(); + mp.StartMirrorUse(recallFrames); + + return true; + } +} diff --git a/Content/Items/AdventureMirror.png b/Content/Items/AdventureMirror.png new file mode 100644 index 0000000000000000000000000000000000000000..fbff7c284f4a5011973f8338fbf549e0a1af1521 GIT binary patch literal 505 zcmVi}ntFbv+L+FbT`r3svj058XEvU<9%$kPc!j+RQf@w)sQxx?r z%gi9+;^JVsqOJiYPUz00Mj|FT44I_|KBL;->_6)lhV7g_Q4V`_U1r7V4 z*eI~T-2UxgT9v~eOnb7Zg6RW)pF!wfH&6@^VUYmS&wpP>Nlh?7zc^5pmj}~4%u*1S zK*M(XpW9&i&7T)oT@Dj}{`)kTK6Y9XB}dcV2b$2*QBh77s{&7G96(|Qk(#Fbz6Pex zeOm;k!}IjPbZ1LDeaj*i7z36A=dR8M)5)Pzv4;5+sLR*AF96dn-fCdl%@&gW*DYR# zqK|%MQE+@BI6rhWHK3ID$!I?L0?iM}g`Oy>4?XN*fc~YaCNx!P>gl3{?fplOQOYXx vuts true; + + // Force the item to always be favorited + public override void UpdateInventory(Item item, Player player) + { + if (item.type == ModContent.ItemType()) + { + item.favorited = true; // Force on every tick + } + } + + public override bool CanPickup(Item item, Player player) + { + // Disallow item pickup while timer is on + if (player.GetModPlayer().MirrorTimer > 0) + { + return false; + } + + return base.CanPickup(item, player); + } + } +} \ No newline at end of file diff --git a/Core/Debug/DebugKeybinds.cs b/Core/Debug/DebugKeybinds.cs new file mode 100644 index 00000000..dddcf3e2 --- /dev/null +++ b/Core/Debug/DebugKeybinds.cs @@ -0,0 +1,66 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Input; +using PvPAdventure.Core.Features.SpawnSelector.Systems; +using Terraria; +using Terraria.GameInput; +using Terraria.ModLoader; +using Terraria.UI; + +namespace PvPAdventure.Core.Debug; + +#if DEBUG +[Autoload(Side = ModSide.Client)] +public class DebugKeybinds : ModSystem +{ + public ModKeybind OpenControls { get; private set; } + public ModKeybind SwitchTeams { get; private set; } + public ModKeybind AddPlayerToSpawnSelector { get; private set; } + public ModKeybind ClearPlayersFromSpawnSelector { get; private set; } + + public override void Load() + { + OpenControls = KeybindLoader.RegisterKeybind(Mod, "OpenControls", Keys.NumPad0); + SwitchTeams = KeybindLoader.RegisterKeybind(Mod, "SwitchTeams", Keys.NumPad1); + AddPlayerToSpawnSelector = KeybindLoader.RegisterKeybind(Mod, "AddPlayerToSpawnSelector", Keys.NumPad2); + ClearPlayersFromSpawnSelector = KeybindLoader.RegisterKeybind(Mod, "ClearPlayersFromSpawnSelector", Keys.NumPad3); + } +} + +public class DebugKeybindsPlayer : ModPlayer +{ + public override void ProcessTriggers(TriggersSet triggersSet) + { + var key = ModContent.GetInstance(); + + // Open controls + if (key.OpenControls.JustPressed) + { + IngameFancyUI.OpenKeybinds(); + } + + // Switch teams + if (key.SwitchTeams.JustPressed) + { + Player.team = (Player.team + 1) % 6; // Cycle through teams 0-5 + Main.NewText(Player.name + " switched to team: " + (Terraria.Enums.Team)Player.team); + } + + if (key.AddPlayerToSpawnSelector.JustPressed) + { + var sys = ModContent.GetInstance(); + sys.state.spawnSelectorPanel.DebugAddPlayer(); + Main.NewText("Added SpawnSelectorSystem player"); + //sys.state.spawnSelectorPanel.Rebuild(); + } + + if (key.ClearPlayersFromSpawnSelector.JustPressed) + { + var sys = ModContent.GetInstance(); + sys.state.spawnSelectorPanel.DebugClearPlayers(); + Main.NewText("Cleared SpawnSelectorSystem players"); + //sys.state.spawnSelectorPanel.Rebuild(); + } + } +} + +#endif \ No newline at end of file diff --git a/Core/Features/SpawnSelector/Hooks/ItemSlotHooks.cs b/Core/Features/SpawnSelector/Hooks/ItemSlotHooks.cs new file mode 100644 index 00000000..dc3f9dbb --- /dev/null +++ b/Core/Features/SpawnSelector/Hooks/ItemSlotHooks.cs @@ -0,0 +1,70 @@ +using Terraria; +using Terraria.ModLoader; +using Terraria.UI; +using PvPAdventure.Content.Items; + +public class ItemSlotHooks : ModSystem +{ + public override void Load() + { + On_ItemSlot.LeftClick_SellOrTrash += Hook_LeftClick_SellOrTrash; + On_ItemSlot.LeftClick_ItemArray_int_int += Hook_LeftClick_ItemArray; + On_Player.SellItem += Hook_SellItem; + } + + public override void Unload() + { + On_ItemSlot.LeftClick_SellOrTrash -= Hook_LeftClick_SellOrTrash; + On_ItemSlot.LeftClick_ItemArray_int_int -= Hook_LeftClick_ItemArray; + On_Player.SellItem -= Hook_SellItem; + } + + // QUICK TRASH / QUICK SELL (Shift + click) + private static bool Hook_LeftClick_SellOrTrash( + On_ItemSlot.orig_LeftClick_SellOrTrash orig, + Item[] inv, int context, int slot) + { + Item item = inv[slot]; + + if (!item.IsAir && item.type == ModContent.ItemType()) + { + //SoundEngine.PlaySound(SoundID.MenuClose); + return false; // skip SellOrTrash completely + } + + return orig(inv, context, slot); + } + + // DRAGGING ONTO THE TRASH SLOT + private static void Hook_LeftClick_ItemArray( + On_ItemSlot.orig_LeftClick_ItemArray_int_int orig, + Item[] inv, int context, int slot) + { + + if (context == ItemSlot.Context.TrashItem + && !Main.mouseItem.IsAir + && Main.mouseItem.type == ModContent.ItemType()) + { + //SoundEngine.PlaySound(SoundID.MenuClose); + return; + } + + orig(inv, context, slot); + } + + // SELLING TO NPCS + private static bool Hook_SellItem( + On_Player.orig_SellItem orig, + Player self, + Item item, + int stack) + { + if (!item.IsAir && item.type == ModContent.ItemType()) + { + //SoundEngine.PlaySound(SoundID.MenuClose); + return false; + } + + return orig(self, item, stack); + } +} diff --git a/Core/Features/SpawnSelector/Hooks/UnityHooks.cs b/Core/Features/SpawnSelector/Hooks/UnityHooks.cs new file mode 100644 index 00000000..a6c1052c --- /dev/null +++ b/Core/Features/SpawnSelector/Hooks/UnityHooks.cs @@ -0,0 +1,45 @@ +using Microsoft.Xna.Framework; +using PvPAdventure.Core.Features.SpawnSelector.Systems; +using System; +using Terraria; +using Terraria.ModLoader; + +namespace PvPAdventure.Core.Features.SpawnSelector.Hooks; + +/// +/// This allows the player to click on teammates to teleport to them. +/// +public class UnityHooks : ModSystem +{ + public override void Load() + { + Main.QueueMainThreadAction(() => + { + On_Player.HasUnityPotion += OnHasUnityPotion; + On_Player.UnityTeleport += OnUnityTeleport; + }); + } + + public override void Unload() + { + Main.QueueMainThreadAction(() => + { + On_Player.HasUnityPotion -= OnHasUnityPotion; + On_Player.UnityTeleport -= OnUnityTeleport; + }); + } + + private void OnUnityTeleport(On_Player.orig_UnityTeleport orig, Player self, Vector2 telePos) + { + SpawnSelectorSystem.SetEnabled(false); + orig(self, telePos); + } + + private static bool OnHasUnityPotion(On_Player.orig_HasUnityPotion orig, Player self) + { + if (SpawnSelectorSystem.GetEnabled()) + return true; + + return orig(self); + } +} diff --git a/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs b/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs new file mode 100644 index 00000000..9c48d582 --- /dev/null +++ b/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs @@ -0,0 +1,273 @@ +using Microsoft.Xna.Framework; +using PvPAdventure.Content.Items; +using PvPAdventure.Core.Features.SpawnSelector.Systems; +using PvPAdventure.System; +using PvPAdventure.System.Client; +using Terraria; +using Terraria.Audio; +using Terraria.GameContent; +using Terraria.GameInput; +using Terraria.ID; +using Terraria.ModLoader; +using static PvPAdventure.System.RegionManager; + +namespace PvPAdventure.Core.Features.SpawnSelector.Players; + +public class AdventureMirrorPlayer : ModPlayer +{ + public int MirrorTimer; // frames left + public bool MirrorActive; + + public void StartMirrorUse(int durationFrames) + { + if (MirrorActive) + return; + + MirrorActive = true; + MirrorTimer = durationFrames; + } + + public bool IsPlayerInSpawnRegion() + { + // Force SSS to be enabled when player is within the spawn region. + var regionManager = ModContent.GetInstance(); + Point tilePos = Player.Center.ToTileCoordinates(); + var region = regionManager.GetRegionContaining(tilePos); + if (region != null) + { + return true; + } + return false; + } + + public bool CancelIfPlayerMoves() + { + if (Player.velocity.LengthSquared() <= 0f) + return false; + + // stop the mirror channel + if (MirrorActive) + { + MirrorActive = false; + MirrorTimer = 0; + } + + // stop the actual item use / animation too + if (Player.itemAnimation > 0 && Player.HeldItem.type == ModContent.ItemType()) + { + Player.controlUseItem = false; + Player.channel = false; + Player.itemAnimation = 0; + Player.itemTime = 0; + Player.reuseDelay = 0; + } + + PopupText.NewText(new AdvancedPopupRequest + { + Color = Color.Crimson, + Text = "Cannot use while moving!", + Velocity = new(0f, -4f), + DurationInFrames = 60 + }, Player.Top); + + return true; + } + + public override void PostUpdate() + { + // Open SSS whenever player is in spawn region. + if (IsPlayerInSpawnRegion()) + SpawnSelectorSystem.SetEnabled(true); + + // Closes SSS whenever map is closed. + if (!Main.mapFullscreen) + SpawnSelectorSystem.SetEnabled(false); + + if (!MirrorActive) + return; + + if (Main.dedServ || Player.whoAmI != Main.myPlayer) + return; + + if (CancelIfPlayerMoves()) + return; + + // spawn dust + if (Main.rand.NextBool()) + Dust.NewDust(Player.position, Player.width, Player.height,DustID.MagicMirror, Player.velocity.X * 0.5f,Player.velocity.Y * 0.5f,150,default,1.5f); + + // countdown tick + MirrorTimer--; + //Main.NewText(MirrorTimer); + + // Show countdown every full second + if (MirrorTimer > 0 && MirrorTimer % 60 == 0) + { + int secondsLeft = MirrorTimer / 60; + PopupText.NewText(new AdvancedPopupRequest + { + Color = Color.Crimson, + Text = secondsLeft.ToString(), + Velocity = new(0f, -4f), + DurationInFrames = 60 + }, Player.Top); + } + + // Teleport to spawn + if (MirrorTimer <= 0) + { + // Close player inventory + //Main.playerInventory = false; + + if (!Main.mapFullscreen) + { + //SoundEngine.PlaySound(SoundID.MenuOpen); + //Main.mapFullscreen = true; + + float worldCenterX = Main.maxTilesX / 2f; + float worldCenterY = Main.maxTilesY / 2f; + Main.mapFullscreenPos.X = worldCenterX; + Main.mapFullscreenPos.Y = worldCenterY; + + Main.mapFullscreenScale = 0.21f; + + Vector2 spawnPos = new(Main.spawnTileX * 16, Main.spawnTileY * 16 - 48); + //Main.LocalPlayer.Teleport(spawnPos, 0); + CustomTeleportWithoutSound(spawnPos); + } + + SpawnSelectorSystem.SetEnabled(true); // This is redundant because spawn region already sets it to true + ModContent.GetInstance().state.spawnSelectorPanel.Rebuild(); + + Player.RemoveAllGrapplingHooks(); + + MirrorActive = false; + } + } + + private void CustomTeleportWithoutSound(Vector2 newPos) + { + try + { + Player._funkytownAchievementCheckCooldown = 100; + Player.environmentBuffImmunityTimer = 4; + Player.RemoveAllGrapplingHooks(); + Player.StopVanityActions(); + if (Player.shimmering || Player.shimmerWet) + { + Player.shimmering = false; + Player.shimmerWet = false; + Player.wet = false; + Player.ClearBuff(353); + } + int extraInfo2 = 0; + + float num = MathHelper.Clamp(1f - Player.teleportTime * 0.99f, 0.01f, 1f); + Vector2 otherPosition = Player.position; + //Main.TeleportEffect(Player.getRect(), 0, extraInfo2, num, TeleportationSide.Entry, newPos); + float num2 = Vector2.Distance(Player.position, newPos); + PressurePlateHelper.UpdatePlayerPosition(Player); + Player.position = newPos; + Player.fallStart = (int)(Player.position.Y / 16f); + if (Player.whoAmI == Main.myPlayer) + { + bool flag = false; + if (num2 < new Vector2(Main.screenWidth, Main.screenHeight).Length() / 2f + 100f) + { + int time = 0; + Main.SetCameraLerp(0.1f, time); + flag = true; + } + else + { + NPC.ResetNetOffsets(); + Main.BlackFadeIn = 255; + Lighting.Clear(); + Main.screenLastPosition = Main.screenPosition; + Main.screenPosition.X = Player.position.X + (float)(Player.width / 2) - (float)(Main.screenWidth / 2); + Main.screenPosition.Y = Player.position.Y + (float)(Player.height / 2) - (float)(Main.screenHeight / 2); + Main.instantBGTransitionCounter = 10; + Player.ForceUpdateBiomes(); + } + //if (num > 0.1f || !flag || Style != 0) + //{ + // if (Main.mapTime < 5) + // { + // Main.mapTime = 5; + // } + // Main.maxQ = true; + // Main.renderNow = true; + //} + } + + PressurePlateHelper.UpdatePlayerPosition(Player); + Player.ResetAdvancedShadows(); + for (int i = 0; i < 3; i++) + { + Player.UpdateSocialShadow(); + } + Player.oldPosition = Player.position + Player.BlehOldPositionFixer; + //Main.TeleportEffect(Player.getRect(), 0, extraInfo2, num, TeleportationSide.Exit, otherPosition); + Player.teleportTime = 1f; + Player.teleportStyle = 0; + } + catch + { + } + } + + public override void UpdateDead() + { + // debug + //Main.NewText(Player.respawnTimer); + + // Keeps the player from respawning until they have selected a spawn. + if (Player.respawnTimer <= 10) + { + //Player.respawnTimer = 10; + if (!Main.mapFullscreen) + { + Main.mapFullscreen = true; + SpawnSelectorSystem.SetEnabled(true); + } + } + } + + public override void ProcessTriggers(TriggersSet triggersSet) + { + var keybinds = ModContent.GetInstance(); + + if (keybinds.AdventureMirrorKeybind.JustPressed) + { + TryUseAdventureMirror(); + } + } + + public void TryUseAdventureMirror() + { + // Find a mirror in the player's inventory + int mirrorIndex = -1; + + for (int i = 0; i < Player.inventory.Length; i++) + { + if (Player.inventory[i].type == ModContent.ItemType()) + { + mirrorIndex = i; + break; + } + } + + if (mirrorIndex == -1) + { + Main.NewText("You don't have an Adventure Mirror!", Color.Red); + return; + } + + CancelIfPlayerMoves(); + + // Force the player to use the item + Player.selectedItem = mirrorIndex; + Player.controlUseItem = true; + Player.ItemCheck(); + } +} diff --git a/Core/Features/SpawnSelector/Players/ModifyPlayerDrawInfo.cs b/Core/Features/SpawnSelector/Players/ModifyPlayerDrawInfo.cs new file mode 100644 index 00000000..67dd894b --- /dev/null +++ b/Core/Features/SpawnSelector/Players/ModifyPlayerDrawInfo.cs @@ -0,0 +1,47 @@ +using Microsoft.Xna.Framework; +using Terraria; +using Terraria.DataStructures; +using Terraria.GameContent; +using Terraria.ModLoader; + +namespace PvPAdventure.Core.Features.SpawnSelector.Players; + +public class ModifyPlayerDrawInfo : ModPlayer +{ + public static bool ForceFullBrightOnce; + public override void ModifyDrawInfo(ref PlayerDrawSet drawInfo) + { + if (!ForceFullBrightOnce) + return; + + drawInfo.shadow = 0f; + drawInfo.stealth = 1f; + + var p = drawInfo.drawPlayer; + p.socialIgnoreLight = true; + + drawInfo.colorEyeWhites = Color.White; + drawInfo.colorEyes = p.eyeColor; + drawInfo.colorHair = p.GetHairColor(useLighting: false); + drawInfo.colorHead = p.skinColor; + drawInfo.colorBodySkin = p.skinColor; + drawInfo.colorLegs = p.skinColor; + + drawInfo.colorShirt = p.shirtColor; + drawInfo.colorUnderShirt = p.underShirtColor; + drawInfo.colorPants = p.pantsColor; + drawInfo.colorShoes = p.shoeColor; + + drawInfo.colorArmorHead = Color.White; + drawInfo.colorArmorBody = Color.White; + drawInfo.colorArmorLegs = Color.White; + drawInfo.colorMount = Color.White; + + drawInfo.colorDisplayDollSkin = PlayerDrawHelper.DISPLAY_DOLL_DEFAULT_SKIN_COLOR; + + drawInfo.headGlowColor = new Color(drawInfo.headGlowColor.R, drawInfo.headGlowColor.G, drawInfo.headGlowColor.B, 0); + drawInfo.bodyGlowColor = new Color(drawInfo.bodyGlowColor.R, drawInfo.bodyGlowColor.G, drawInfo.bodyGlowColor.B, 0); + drawInfo.armGlowColor = new Color(drawInfo.armGlowColor.R, drawInfo.armGlowColor.G, drawInfo.armGlowColor.B, 0); + drawInfo.legsGlowColor = new Color(drawInfo.legsGlowColor.R, drawInfo.legsGlowColor.G, drawInfo.legsGlowColor.B, 0); + } +} \ No newline at end of file diff --git a/Core/Features/SpawnSelector/Systems/SpawnSelectorState.cs b/Core/Features/SpawnSelector/Systems/SpawnSelectorState.cs new file mode 100644 index 00000000..c1d7ae6b --- /dev/null +++ b/Core/Features/SpawnSelector/Systems/SpawnSelectorState.cs @@ -0,0 +1,47 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using PvPAdventure.Core.Features.SpawnSelector.UI; +using PvPAdventure.Core.Helpers; +using Terraria.GameContent.UI.Elements; +using Terraria.UI; + +namespace PvPAdventure.Core.Features.SpawnSelector.Systems; + +public class SpawnSelectorState : UIState +{ + public UISpawnSelectorPanel spawnSelectorPanel; + public override void OnInitialize() + { + spawnSelectorPanel = new(); + Append(spawnSelectorPanel); + + UITextPanel chooseYourSpawnPanel = new("Choose Your Spawn", 0.8f, true); + chooseYourSpawnPanel.HAlign = 0.5f; + chooseYourSpawnPanel.VAlign = 0f; + chooseYourSpawnPanel.Top.Set(10, 0); + chooseYourSpawnPanel.BackgroundColor = new Color(73, 94, 171); + Append(chooseYourSpawnPanel); + } + + public override void OnActivate() + { + base.OnActivate(); + UISpawnSelectorPanel panel = null; + foreach (var element in Elements) + { + panel = element as UISpawnSelectorPanel; + if (panel != null) + break; + } + if (panel != null) + { + panel.Rebuild(); + Log.Info("SpawnSelectorState: Rebuilt panel on activate"); + } + } + + public override void Draw(SpriteBatch spriteBatch) + { + base.Draw(spriteBatch); + } +} diff --git a/Core/Features/SpawnSelector/Systems/SpawnSelectorSystem.cs b/Core/Features/SpawnSelector/Systems/SpawnSelectorSystem.cs new file mode 100644 index 00000000..4d174412 --- /dev/null +++ b/Core/Features/SpawnSelector/Systems/SpawnSelectorSystem.cs @@ -0,0 +1,94 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using PvPAdventure.Core.Features.SpawnSelector.UI; +using Terraria; +using Terraria.ModLoader; +using Terraria.UI; + +namespace PvPAdventure.Core.Features.SpawnSelector.Systems; + +[Autoload(Side = ModSide.Client)] +public class SpawnSelectorSystem : ModSystem +{ + private UserInterface ui; + public SpawnSelectorState state; + private UISpawnSelectorPanel teleportPanel; + + // Track whether the spawn selector is enabled + private static bool Enabled; // whether the spawn selector is currently showing in the fullscreen map + public static void SetEnabled(bool newValue) => Enabled = newValue; + public static bool GetEnabled() => Enabled; + + // Load and unload hooks + public override void Load() + { + if (!Main.dedServ) + { + ui = new(); + state = new(); + state.Activate(); + + Main.OnPostFullscreenMapDraw += DrawOverFullscreenMap; + } + + On_Main.TriggerPing += OnTriggerPing; + } + + public override void Unload() + { + if (!Main.dedServ) + Main.OnPostFullscreenMapDraw -= DrawOverFullscreenMap; + + On_Main.TriggerPing -= OnTriggerPing; + } + + private void OnTriggerPing(On_Main.orig_TriggerPing orig, Vector2 position) + { + // Skip ping execution if our panel is being hovered + if (state.spawnSelectorPanel != null && state.spawnSelectorPanel.IsMouseHovering) + { + return; + } + orig(position); + } + + public override void UpdateUI(GameTime gameTime) + { + if (ui == null) return; + + bool visible = GetEnabled() && Main.mapFullscreen; + + if (visible) + { + if (ui.CurrentState != state) + ui.SetState(state); + + ui.Update(gameTime); + } + else if (ui.CurrentState != null) + { + ui.SetState(null); + } + } + + // Draw AFTER the map, with our own Begin/End for UI + private void DrawOverFullscreenMap(Vector2 _mapPos, float _mapScale) + { + if (ui?.CurrentState == null) return; + + var sb = Main.spriteBatch; + bool began = false; + + try + { + sb.Begin(SpriteSortMode.Deferred,BlendState.AlphaBlend,SamplerState.LinearClamp,DepthStencilState.None,RasterizerState.CullCounterClockwise,null,Main.UIScaleMatrix); + began = true; + ui.Draw(sb, Main._drawInterfaceGameTime); + } + finally + { + if (began) + sb.End(); + } + } +} diff --git a/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs b/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs new file mode 100644 index 00000000..23a90a74 --- /dev/null +++ b/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs @@ -0,0 +1,378 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using PvPAdventure.Core.Features.SpawnSelector.Players; +using PvPAdventure.Core.Features.SpawnSelector.Systems; +using PvPAdventure.Core.Helpers; +using ReLogic.Content; +using System; +using Terraria; +using Terraria.GameContent; +using Terraria.GameContent.UI.Elements; +using Terraria.ModLoader; +using Terraria.ModLoader.UI; +using Terraria.UI; + +namespace PvPAdventure.Core.Features.SpawnSelector.UI +{ + /// + /// Vanilla-like character row. + /// + internal class UISpawnSelectorCharacterListItem : UIPanel + { + internal const float ItemWidth = 260f; + internal const float ItemHeight = 72f; + + private readonly Asset _dividerTexture; + private readonly Asset _innerPanelTexture; + private readonly Asset _playerBGTexture; + + private readonly int _playerIndex; + + public UISpawnSelectorCharacterListItem(Player player) + { + _dividerTexture = Main.Assets.Request("Images/UI/Divider"); + _innerPanelTexture = Main.Assets.Request("Images/UI/InnerPanelBackground"); + _playerBGTexture = Main.Assets.Request("Images/UI/PlayerBackground"); + + _playerIndex = player.whoAmI; + } + + public override void OnInitialize() + { + BorderColor = Color.Black; + BackgroundColor = new Color(63, 82, 151) * 0.7f; + + Height.Set(ItemHeight, 0f); + Width.Set(ItemWidth, 0f); + + SetPadding(6f); + } + + private void DrawHeadOnMap(Player p) + { + float scale = Main.mapFullscreenScale; + + Vector2 headPos = new( + ((p.position.X + p.width / 2f) / 16f - Main.mapFullscreenPos.X) * scale + + Main.screenWidth / 2f - 14f * scale+48, + + ((p.position.Y + p.gfxOffY + p.height / 2f) / 16f - Main.mapFullscreenPos.Y) * scale + + Main.screenHeight / 2f - 14f * scale+58 + ); + + Color color = Main.teamColor[p.team]; + + //Main.PlayerRenderer.DrawPlayerHead( + // Main.Camera, + // p, + // headPos, + // scale: 1.3f, + // borderColor: color + //); + Utils.DrawBorderString(Main.spriteBatch, p.name, headPos, Color.White); + } + + private void DrawNineSlice(SpriteBatch sb, int x, int y, int w, int h, Texture2D tex, Color color, int inset, int c = 5) + { + x += inset; y += inset; w -= inset * 2; h -= inset * 2; + int ew = tex.Width - c * 2; + int eh = tex.Height - c * 2; + + sb.Draw(tex, new Rectangle(x, y, c, c), new Rectangle(0, 0, c, c), color); + sb.Draw(tex, new Rectangle(x + c, y, w - c * 2, c), new Rectangle(c, 0, ew, c), color); + sb.Draw(tex, new Rectangle(x + w - c, y, c, c), new Rectangle(tex.Width - c, 0, c, c), color); + + sb.Draw(tex, new Rectangle(x, y + c, c, h - c * 2), new Rectangle(0, c, c, eh), color); + sb.Draw(tex, new Rectangle(x + c, y + c, w - c * 2, h - c * 2), new Rectangle(c, c, ew, eh), color); + sb.Draw(tex, new Rectangle(x + w - c, y + c, c, h - c * 2), new Rectangle(tex.Width - c, c, c, eh), color); + + sb.Draw(tex, new Rectangle(x, y + h - c, c, c), new Rectangle(0, tex.Height - c, c, c), color); + sb.Draw(tex, new Rectangle(x + c, y + h - c, w - c * 2, c), new Rectangle(c, tex.Height - c, ew, c), color); + sb.Draw(tex, new Rectangle(x + w - c, y + h - c, c, c), new Rectangle(tex.Width - c, tex.Height - c, c, c), color); + } + + protected override void DrawSelf(SpriteBatch sb) + { + base.DrawSelf(sb); + + CalculatedStyle inner = GetInnerDimensions(); + + Player player = Main.player[_playerIndex]; + var dims = GetDimensions(); + + if (player == null || !player.active) + { + var rect2 = dims.ToRectangle(); + + Utils.DrawBorderString(sb, "Unable to find player :(", rect2.Location.ToVector2() + new Vector2(50, 0), Color.White); + return; + } + + // Left player background + Vector2 pos = new(inner.X, inner.Y); + //sb.Draw(_playerBGTexture.Value, pos, Color.White*0.5f); + + Rectangle rect = new( + x: (int)pos.X-6, + y: (int)pos.Y-6, + width: 100, + height: 72); + + + //DrawMask(sb, Ass.CornerMask4px.Value, rect, 9); + DrawNineSlice(sb, rect.X, rect.Y, rect.Width, rect.Height, _playerBGTexture.Value, Color.White, 5); + DrawMapFullscreenBackground(sb, rect, player); + + sb.End(); + sb.Begin(SpriteSortMode.Deferred, + BlendState.AlphaBlend, + SamplerState.PointClamp, + DepthStencilState.Default, + RasterizerState.CullNone, + null, + Main.UIScaleMatrix); + + ModifyPlayerDrawInfo.ForceFullBrightOnce = true; + try + { + Vector2 playerDrawPos = pos + Main.screenPosition + new Vector2(32, 8); + + //Main.PlayerRenderer.DrawPlayer(Main.Camera,player,playerDrawPos,player.fullRotation,player.fullRotationOrigin,0f,0.9f); + + Color myTeamColor = Main.teamColor[Main.LocalPlayer.team]; + Main.PlayerRenderer.DrawPlayerHead(Main.Camera, player, pos+ new Vector2(40,37), scale: 1.3f, borderColor: Color.Yellow); + } + catch (Exception e) + { + Log.Error("Failed to draw player: " + e); + } + finally + { + ModifyPlayerDrawInfo.ForceFullBrightOnce = false; + } + + // Switch back to "normal" UI batch + sb.End(); + sb.Begin(SpriteSortMode.Deferred, + BlendState.AlphaBlend, + SamplerState.LinearClamp, + DepthStencilState.None, + RasterizerState.CullCounterClockwise, + null, + Main.UIScaleMatrix); + + // Use the actual layout widths, not the texture width + const float leftColumnWidth = 106f; // player background column + const float rightAreaWidth = ItemWidth - 22f - leftColumnWidth; // 260 - 12 - 106 = 142 + + float rightAreaLeft = inner.X + leftColumnWidth; + float rightAreaCenterX = rightAreaLeft + rightAreaWidth * 0.5f; + + // Name centered in the right-area + string name = string.IsNullOrEmpty(player.name) ? "Unknown player" : player.name + ""; + float nameScale = 1f; + if (player.name.Length > 16) nameScale = 0.85f; + Vector2 nameSize = FontAssets.MouseText.Value.MeasureString(name) * nameScale; + + Vector2 namePos = new( + rightAreaCenterX - nameSize.X * 0.5f, + inner.Y + ); + + // Draw name + Utils.DrawBorderString(sb,name,namePos,Color.White,nameScale); + + // Draw divider + sb.Draw( + _dividerTexture.Value, + new Vector2(rightAreaLeft-12, inner.Y + 21f), + null, + Color.White, + 0f, + Vector2.Zero, + new Vector2(rightAreaWidth/8+2.2f, 1f), + SpriteEffects.None, + 0f + ); + + // Stat panel settings + float statScale = 0.88f; + float statGap = 5f * statScale; + + // Draw stat panel + float panelWidth = rightAreaWidth+24; + Vector2 panelPos = new(rightAreaLeft-14, inner.Y + 29f); + DrawPanel(sb, panelPos, panelWidth); + + string hpText = $"{player.statLife} HP"; + string mpText = $"{player.statMana} MP"; + + Vector2 hpSize = FontAssets.MouseText.Value.MeasureString(hpText) * statScale; + Vector2 mpSize = FontAssets.MouseText.Value.MeasureString(mpText) * statScale; + + var heart = TextureAssets.Heart; + var mana = TextureAssets.Mana; + + float heartW = heart.Width() * statScale; + float manaW = mana.Width() * statScale; + float hpBlockW = heartW + hpSize.X; + float mpBlockW = manaW + mpSize.X; + float totalWidth = hpBlockW + statGap + mpBlockW; + float startX = panelPos.X + (panelWidth - totalWidth) * 0.5f; + float y = panelPos.Y + 4f; + + // Draw health + sb.Draw(heart.Value, new Vector2(startX, y), null, Color.White, 0f, Vector2.Zero, statScale, SpriteEffects.None, 0f); + startX += heartW; + Utils.DrawBorderString(sb, hpText, new Vector2(startX+1, y + 1f), Color.White, statScale); + startX += hpSize.X; + startX += statGap; + + // Draw mana + sb.Draw(mana.Value, new Vector2(startX, y - 2), null, Color.White, 0f, Vector2.Zero, statScale, SpriteEffects.None, 0f); + startX += manaW; + Utils.DrawBorderString(sb, mpText, new Vector2(startX+1, y + 1f), Color.White, statScale); + + // Set hover teleport tooltip + if (IsMouseHovering) + { + Main.instance.MouseText("Teleport to " + name); + var old = Main.UIScaleMatrix; + + //Main.spriteBatch.End(); + //Main.spriteBatch.Begin(SpriteSortMode.Immediate,BlendState.AlphaBlend,SamplerState.PointClamp,DepthStencilState.None,RasterizerState.CullCounterClockwise,null,Matrix.Identity); + + //DrawHeadOnMap(player); + + //Main.spriteBatch.End(); + //Main.spriteBatch.Begin(SpriteSortMode.Deferred,BlendState.AlphaBlend,SamplerState.PointClamp,DepthStencilState.None,RasterizerState.CullCounterClockwise,null,old); + } + //Main.NewText(Main.mouseY); // 482,435 is spawn + + } + + public override void MouseOver(UIMouseEvent evt) + { + base.MouseOver(evt); + + BackgroundColor = new Color(73, 92, 161); + } + + public override void MouseOut(UIMouseEvent evt) + { + base.MouseOut(evt); + BackgroundColor = new Color(63, 82, 151) * 0.8f; + } + + public override void LeftClick(UIMouseEvent evt) + { + base.LeftClick(evt); + + Player player = Main.player[_playerIndex]; + + Main.LocalPlayer.UnityTeleport(player.position); + + // close map and SSS + Main.mapFullscreen = false; + SpawnSelectorSystem.SetEnabled(false); + } + + private void DrawPanel(SpriteBatch spriteBatch, Vector2 position, float width) + { + spriteBatch.Draw(_innerPanelTexture.Value, position, + new Rectangle(0, 0, 8, _innerPanelTexture.Height()), Color.White); + + spriteBatch.Draw( + _innerPanelTexture.Value, + new Vector2(position.X + 8f, position.Y), + new Rectangle(8, 0, 8, _innerPanelTexture.Height()), + Color.White, + 0f, + Vector2.Zero, + new Vector2((width - 16f) / 8f, 1f), + SpriteEffects.None, + 0f + ); + + spriteBatch.Draw( + _innerPanelTexture.Value, + new Vector2(position.X + width - 8f, position.Y), + new Rectangle(16, 0, 8, _innerPanelTexture.Height()), + Color.White + ); + } + + public static void DrawMapFullscreenBackground(SpriteBatch sb, Rectangle rect, Player player) + { + if (player == null || !player.active) + return; + + var screenPos = Main.screenPosition; + var tile = Main.tile[(int)(player.Center.X / 16f), (int)(player.Center.Y / 16f)]; + if (tile == null) return; + + int wall = tile.wall; + int bgIndex = -1; + Color color = Color.White; + + if (screenPos.Y > (Main.maxTilesY - 232) * 16) + bgIndex = 2; + else if (player.ZoneDungeon) + bgIndex = 4; + else if (wall == 87) + bgIndex = 13; + else if (screenPos.Y > Main.worldSurface * 16.0) + { + bgIndex = wall switch + { + 86 or 108 => 15, + 180 or 184 => 16, + 178 or 183 => 17, + 62 or 263 => 18, + _ => player.ZoneGlowshroom ? 20 : + player.ZoneCorrupt ? player.ZoneDesert ? 39 : player.ZoneSnow ? 33 : 22 : + player.ZoneCrimson ? player.ZoneDesert ? 40 : player.ZoneSnow ? 34 : 23 : + player.ZoneHallow ? player.ZoneDesert ? 41 : player.ZoneSnow ? 35 : 21 : + player.ZoneSnow ? 3 : + player.ZoneJungle ? 12 : + player.ZoneDesert ? 14 : + player.ZoneRockLayerHeight ? 31 : 1 + }; + } + else if (player.ZoneGlowshroom) + bgIndex = 19; + else + { + color = Main.ColorOfTheSkies; + int midTileX = (int)((screenPos.X + Main.screenWidth / 2f) / 16f); + + if (player.ZoneSkyHeight) bgIndex = 32; + else if (player.ZoneCorrupt) bgIndex = player.ZoneDesert ? 36 : 5; + else if (player.ZoneCrimson) bgIndex = player.ZoneDesert ? 37 : 6; + else if (player.ZoneHallow) bgIndex = player.ZoneDesert ? 38 : 7; + else if (screenPos.Y / 16f < Main.worldSurface + 10.0 && (midTileX < 380 || midTileX > Main.maxTilesX - 380)) + bgIndex = 10; + else if (player.ZoneSnow) bgIndex = 11; + else if (player.ZoneJungle) bgIndex = 8; + else if (player.ZoneDesert) bgIndex = 9; + else if (Main.bloodMoon) { bgIndex = 25; color *= 2f; } + else if (player.ZoneGraveyard) bgIndex = 26; + } + + // Vanilla + //var asset = bgIndex >= 0 && bgIndex < TextureAssets.MapBGs.Length? TextureAssets.MapBGs[bgIndex]: TextureAssets.MapBGs[0]; + + // Our textures with rounded corners + int safeIndex = (bgIndex >= 0 && bgIndex < Ass.MapBG.Length) ? bgIndex: 0; + var asset = Ass.MapBG[safeIndex]; + + rect.X += 10; + rect.Y += 10; + rect.Width -= 20; + rect.Height -= 20; + + if (asset == null || asset.Value == null) return; + sb.Draw(asset.Value, rect, color); + } + } +} diff --git a/Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs b/Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs new file mode 100644 index 00000000..96f1184c --- /dev/null +++ b/Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs @@ -0,0 +1,150 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using PvPAdventure.Core.Helpers; +using System.Collections.Generic; +using Terraria; +using Terraria.GameContent.UI.Elements; + +namespace PvPAdventure.Core.Features.SpawnSelector.UI +{ + public class UISpawnSelectorPanel : UIPanel + { + private UIPanel _randomPanel; + private readonly List _playerItems = new(); + + private const float Spacing = 8f; + private const float HorizontalPadding = 16f; + private const float VerticalPadding = 12f; + + public override void OnInitialize() + { + HAlign = 0.5f; + VAlign = 0.0f; + Top.Set(52, 0); + + BackgroundColor = new Color(33, 43, 79) * 0.8f; + SetPadding(0f); + + BuildLayout(); + + Log.Info("UISpawnSelectorPanel.OnInitialize: layout built"); + } + + private void BuildLayout() + { + RemoveAllChildren(); + _playerItems.Clear(); + + var players = new List(); + var local = Main.LocalPlayer; + +#if DEBUG + // If we have debug players, use them instead of scanning teammates + if (_debugPlayers.Count > 0) + { + players.AddRange(_debugPlayers); + } + else +#endif + { + // ADD TEAMMATES + if (local.team != 0) + { + for (int i = 0; i < Main.maxPlayers; i++) + { + Player p = Main.player[i]; + + if (p == null || !p.active) + continue; + + if (p.whoAmI == local.whoAmI || p.team != local.team) + continue; + + players.Add(p); + } + } + } + + int playerCount = players.Count; + + float itemWidth = UISpawnSelectorCharacterListItem.ItemWidth; + float itemHeight = UISpawnSelectorCharacterListItem.ItemHeight; + float randomWidth = itemHeight; // square random panel + + float contentWidth = playerCount * itemWidth + + playerCount * Spacing + + randomWidth; + + float panelWidth = contentWidth + HorizontalPadding * 2f; + float panelHeight = itemHeight + VerticalPadding * 2f; + + Width.Set(panelWidth, 0f); + Height.Set(panelHeight, 0f); + + float startX = HorizontalPadding; + float y = VerticalPadding; + + // Players in a row + for (int i = 0; i < playerCount; i++) + { + float x = startX + i * (itemWidth + Spacing); + + var row = new UISpawnSelectorCharacterListItem(players[i]); + row.Left.Set(x, 0f); + row.Top.Set(y, 0f); + + Append(row); + _playerItems.Add(row); + } + + // Square random panel to the right of the last player + _randomPanel = new UISpawnSelectorRandomPanel( + startX, + itemHeight, + playerCount, + itemWidth, + Spacing, + y + ); + Append(_randomPanel); + + Log.Debug($"UISpawnSelectorPanel.BuildLayout: players={playerCount}, panelWidth={panelWidth}"); + } + + public void Rebuild() + { + BuildLayout(); + Log.Debug("UISpawnSelectorPanel.Rebuild: UI rebuilt"); + } + + public override void Draw(SpriteBatch spriteBatch) + { + base.Draw(spriteBatch); + } + + #region Debug +#if DEBUG + private readonly List _debugPlayers = new(); +#endif + public void DebugAddPlayer() + { +#if DEBUG + _debugPlayers.Add(Main.LocalPlayer); + BuildLayout(); + Log.Debug($"SpawnSelector DebugAddPlayer: debugPlayers={_debugPlayers.Count}"); +#endif + } + + public void DebugClearPlayers() + { +#if DEBUG + _debugPlayers.Clear(); + BuildLayout(); + Log.Debug("SpawnSelector DebugClearPlayers: cleared debug players"); +#endif + } + #endregion + + + } +} diff --git a/Core/Features/SpawnSelector/UI/UISpawnSelectorRandomPanel.cs b/Core/Features/SpawnSelector/UI/UISpawnSelectorRandomPanel.cs new file mode 100644 index 00000000..886a5461 --- /dev/null +++ b/Core/Features/SpawnSelector/UI/UISpawnSelectorRandomPanel.cs @@ -0,0 +1,91 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using PvPAdventure.Core.Features.SpawnSelector.Systems; +using PvPAdventure.Core.Helpers; +using Terraria; +using Terraria.GameContent.UI.Elements; +using Terraria.ID; +using Terraria.UI; + +namespace PvPAdventure.Core.Features.SpawnSelector.UI +{ + internal class UISpawnSelectorRandomPanel : UIPanel + { + public UISpawnSelectorRandomPanel(float startX, float itemHeight, int playerCount, float itemWidth, float Spacing, float y) + { + Width.Set(itemHeight, 0f); + Height.Set(itemHeight, 0f); + Top.Set(y, 0f); + + float randomX = startX + playerCount * (itemWidth + Spacing); + Left.Set(randomX, 0f); + + BackgroundColor = new Color(63, 82, 151) * 0.8f; + BorderColor = Color.Black; + } + + public override void LeftClick(UIMouseEvent evt) + { + base.LeftClick(evt); + + if (Main.netMode == NetmodeID.MultiplayerClient) + { + NetMessage.SendData(MessageID.RequestTeleportationByServer); + } + else + { + Main.LocalPlayer.TeleportationPotion(); + } + + Main.mapFullscreen = false; + SpawnSelectorSystem.SetEnabled(false); + } + + public override void MouseOver(UIMouseEvent evt) + { + base.MouseOver(evt); + BackgroundColor = new Color(73, 92, 161); + + } + + public override void MouseOut(UIMouseEvent evt) + { + base.MouseOut(evt); + BackgroundColor = new Color(63, 82, 151) * 0.8f; + } + + public override void Draw(SpriteBatch sb) + { + base.Draw(sb); + + if (IsMouseHovering) + { + Main.instance.MouseText("Random Teleport"); + } + + // Draw question mark + var d = GetDimensions(); + var tex = Ass.Question_Mark.Value; + var rect = new Rectangle( + (int)(d.X + (d.Width - tex.Width) * 0.5f), + (int)(d.Y + (d.Height - tex.Height) * 0.5f), + tex.Width, + tex.Height + ); + sb.Draw(tex, rect, Color.White); + + // debug + //sb.Draw(TextureAssets.MagicPixel.Value, rect, Color.Red * 0.45f); + + // Draw teleportation potion + Item icon = new(ItemID.TeleportationPotion); + Vector2 pos = new(rect.X + 37, rect.Y + 36); + //ItemSlot.DrawItemIcon(icon, 31, sb, pos, 1.0f, 32f, Color.White); + } + + public override void Update(GameTime gameTime) + { + base.Update(gameTime); + } + } +} diff --git a/Core/Helpers/AssetLoader.cs b/Core/Helpers/AssetLoader.cs new file mode 100644 index 00000000..747b6dd3 --- /dev/null +++ b/Core/Helpers/AssetLoader.cs @@ -0,0 +1,43 @@ +using System.Reflection; +using Microsoft.Xna.Framework.Graphics; +using ReLogic.Content; +using Terraria.ModLoader; + +namespace PvPAdventure.Core.Helpers; + +public static class Ass +{ + public static Asset Question_Mark; + public static Asset[] MapBG; + + public static bool Initialized { get; set; } + + static Ass() + { + // Load MapBG1..MapBG42 + MapBG = new Asset[42]; + for (int i = 1; i <= 42; i++) + { + MapBG[i - 1] = ModContent.Request( + $"PvPAdventure/Assets/SpawnSelector/MapBG{i}", + AssetRequestMode.AsyncLoad); + } + + // Load single texture fields (NOT MapBG array) + foreach (FieldInfo f in typeof(Ass).GetFields()) + { + if (f.FieldType == typeof(Asset)) + { + var asset = ModContent.Request( + $"PvPAdventure/Assets/SpawnSelector/{f.Name}", + AssetRequestMode.AsyncLoad); + f.SetValue(null, asset); + } + } + } +} + +public class LoadAssets : ModSystem +{ + public override void Load() => _ = Ass.Initialized; +} diff --git a/Core/Helpers/Log.cs b/Core/Helpers/Log.cs new file mode 100644 index 00000000..856a1ff0 --- /dev/null +++ b/Core/Helpers/Log.cs @@ -0,0 +1,51 @@ +using System.IO; +using System.Runtime.CompilerServices; +using log4net; +using Terraria.ModLoader; + +namespace PvPAdventure.Core.Helpers; + +/// +/// A static logging helper for PvPAdventure. +/// Example usage: Log.Info("This is an info message."); +/// Example usage: Log.Warn("This is a warning message."); +/// +public static class Log +{ + public static ILog Base + { + get + { + var m = ModContent.GetInstance(); + return (m != null && m.Logger != null) ? m.Logger : LogManager.GetLogger("PvPAdventure"); + } + } + + public static void Info(object message, [CallerFilePath] string file = "") + => Base.Info($"[{Class(file)}] {message}"); + + public static void Debug(object message, [CallerFilePath] string file = "") + => Base.Debug($"[{Class(file)}] {message}"); + + public static void Warn(object message, [CallerFilePath] string file = "") + => Base.Warn($"[{Class(file)}] {message}"); + + public static void Error(object message, [CallerFilePath] string file = "") + => Base.Error($"[{Class(file)}] {message}"); + + public static Prefixed For() => new(Base, typeof(T).Name); + public static Prefixed ForCaller([CallerFilePath] string file = "") => new(Base, Class(file)); + + private static string Class(string file) => Path.GetFileNameWithoutExtension(file); + + public readonly struct Prefixed + { + private readonly ILog _log; + private readonly string _p; + public Prefixed(ILog log, string prefix) { _log = log; _p = prefix; } + public void Info(object m) => _log.Info($"[{_p}] {m}"); + public void Debug(object m) => _log.Debug($"[{_p}] {m}"); + public void Warn(object m) => _log.Warn($"[{_p}] {m}"); + public void Error(object m) => _log.Error($"[{_p}] {m}"); + } +} diff --git a/Localization/en-US.hjson b/Localization/en-US.hjson index 5dbb6eeb..4fee0157 100644 --- a/Localization/en-US.hjson +++ b/Localization/en-US.hjson @@ -14,6 +14,12 @@ Mods: { BountyShop.DisplayName: Bounty Shop AllChat.DisplayName: All Chat Dash.DisplayName: Dash + AdventureMirror.DisplayName: Adventure Mirror + OpenControls.DisplayName: Open Controls + SwitchTeams.DisplayName: Switch Teams + AddPlayerToSpawnSelector.DisplayName: Add Player To Spawn Selector + RemovePlayerFromSpawnSelector.DisplayName: Remove Player From Spawn Selector + ClearPlayersFromSpawnSelector.DisplayName: Clear Players From Spawn Selector } Configs: { @@ -129,6 +135,16 @@ Mods: { Tooltip: "" Label: Minimum Damage Received By Players From Player } + + RTPRecallFrames: { + Label: RTP Recall Frames + Tooltip: "" + } + + AdventureMirrorRecallFrames: { + Label: Adventure Mirror Recall Frames + Tooltip: "" + } } PointsConfig: { @@ -1060,5 +1076,15 @@ Mods: { FatalCarCrash.Label: Fatal Car Crash Part2.Label: Part2 } + Items: { + AdventureMirror: { + DisplayName: Adventure Mirror + Tooltip: + ''' + Gaze in the mirror to go on adventures + Right click to use + ''' + } + } } } diff --git a/Properties/launchSettings.json b/Properties/launchSettings.json index 07e2f8d0..280b6ecf 100644 --- a/Properties/launchSettings.json +++ b/Properties/launchSettings.json @@ -11,6 +11,12 @@ "executablePath": "dotnet", "commandLineArgs": "$(tMLServerPath)", "workingDirectory": "$(tMLSteamPath)" - } + }, + "TerrariaSkipSelect": { + "commandName": "Executable", + "executablePath": "dotnet", + "commandLineArgs": "$(tMLPath) -skipselect", + "workingDirectory": "$(tMLSteamPath)" + }, } } \ No newline at end of file diff --git a/PvPAdventure.csproj b/PvPAdventure.csproj index fed5da73..d01b9a47 100644 --- a/PvPAdventure.csproj +++ b/PvPAdventure.csproj @@ -1,28 +1,32 @@ + - - - PvPAdventure - latest - - - - - - - - - - - - - - lib\Discord.Net.Core.dll - - - lib\Discord.Net.Rest.dll - - - lib\System.Linq.Async.dll - - + + + PvPAdventure + latest + + + + + + + + + + + lib\Discord.Net.Core.dll + + + lib\Discord.Net.Rest.dll + + + lib\System.Linq.Async.dll + + + + + + + + \ No newline at end of file diff --git a/PvPAdventure.csproj.user b/PvPAdventure.csproj.user new file mode 100644 index 00000000..62b33ede --- /dev/null +++ b/PvPAdventure.csproj.user @@ -0,0 +1,9 @@ + + + + ProjectDebugger + + + TerrariaSkipSelect + + \ No newline at end of file diff --git a/System/Client/Keybinds.cs b/System/Client/Keybinds.cs index d72d756f..8d7699b5 100644 --- a/System/Client/Keybinds.cs +++ b/System/Client/Keybinds.cs @@ -9,11 +9,13 @@ public class Keybinds : ModSystem public ModKeybind Scoreboard { get; private set; } public ModKeybind BountyShop { get; private set; } public ModKeybind AllChat { get; private set; } + public ModKeybind AdventureMirrorKeybind { get; private set; } public override void Load() { Scoreboard = KeybindLoader.RegisterKeybind(Mod, "Scoreboard", Keys.OemTilde); BountyShop = KeybindLoader.RegisterKeybind(Mod, "BountyShop", Keys.P); AllChat = KeybindLoader.RegisterKeybind(Mod, "AllChat", Keys.U); + AdventureMirrorKeybind = KeybindLoader.RegisterKeybind(Mod, "AdventureMirror", Keys.M); } } \ No newline at end of file diff --git a/icon_small.png b/icon_small.png new file mode 100644 index 0000000000000000000000000000000000000000..e06b69194deb74c1c306133c9d1b382ca427a528 GIT binary patch literal 942 zcmV;f15x~mP)M6pQy zf>x*!QmGGuAi{>?L#3snh=w8}BBBXc5c{wXf*+s{Qn3%UVL=c|4J4E{+DJ{)TBBx@ zw7c8gnfsT?_QA)UbvGWkFTfV^5}os z&R$^n>;ld$ZpYU*{6JUEeZJCY@Ug3xW{#{*P3inn1k=lYEEZ}zj>?NO$?E_L+R!k| zB?J^WH%qC*L~Y30QoYG9ewfO190fb37;qXCZGnzaYQh$J?*Bs#I$b?L7`MpXA*_%T_0aRrTTh z%^Q67D+f|~VLC;w_LK7i%+IB0UrCa=Z9MZ`lCiMg2Jlo>FKon&+P8jN|Xx@)D_GM{P2!DW6qxYlRW)dHoYa1H~Q$&9z^^OI2yB|BZ<41kv!Hu{iU1#lu3Rs*;93YKyvT3XzD6Q7bC zZ}eTAJ~V2nJ9_=%GYIXh^$Sm3u2%5X><>QXatc;Z!>A0l=6ZmSeLK0#nb{H@yHX>y z^eE-^1(JW4Z5}x}S>(y=O Date: Sat, 15 Nov 2025 21:17:22 -0800 Subject: [PATCH 175/206] Merge branch 'feature/RTP-Spawn-Selector' into feature/missinginmaster --- AdventureClientConfig.cs | 5 + Assets/SpawnSelector/Arrow.png | Bin 0 -> 359 bytes Assets/SpawnSelector/CornerMask4px.png | Bin 268 -> 0 bytes Assets/SpawnSelector/FadeHorizontal.png | Bin 80 -> 0 bytes Content/Items/AdventureMirror.cs | 64 +- Content/Items/AdventureMirrorGlobalItem.cs | 31 - Core/Debug/DebugKeybinds.cs | 30 +- .../SpawnSelector/Hooks/UnityHooks.cs | 45 -- .../Players/AdventureMirrorPlayer.cs | 245 ++++-- ...yerDrawInfo.cs => ModifyDrawInfoPlayer.cs} | 10 +- .../{Hooks => Systems}/ItemSlotHooks.cs | 42 +- .../Systems/SpawnSelectorState.cs | 1 - .../Systems/SpawnSelectorSystem.cs | 7 +- .../SpawnSelector/Systems/UnityHooks.cs | 28 + .../SpawnSelector/UI/PopupTextHelper.cs | 42 + .../UI/UISpawnSelectorCharacterListItem.cs | 91 ++- .../SpawnSelector/UI/UISpawnSelectorPanel.cs | 104 ++- .../UI/UISpawnSelectorRandomPanel.cs | 7 + Core/Helpers/AssetLoader.cs | 1 + Localization/en-US.hjson | 716 ++++++++---------- System/GameManager.cs | 8 +- 21 files changed, 778 insertions(+), 699 deletions(-) create mode 100644 Assets/SpawnSelector/Arrow.png delete mode 100644 Assets/SpawnSelector/CornerMask4px.png delete mode 100644 Assets/SpawnSelector/FadeHorizontal.png delete mode 100644 Content/Items/AdventureMirrorGlobalItem.cs delete mode 100644 Core/Features/SpawnSelector/Hooks/UnityHooks.cs rename Core/Features/SpawnSelector/Players/{ModifyPlayerDrawInfo.cs => ModifyDrawInfoPlayer.cs} (87%) rename Core/Features/SpawnSelector/{Hooks => Systems}/ItemSlotHooks.cs (52%) create mode 100644 Core/Features/SpawnSelector/Systems/UnityHooks.cs create mode 100644 Core/Features/SpawnSelector/UI/PopupTextHelper.cs diff --git a/AdventureClientConfig.cs b/AdventureClientConfig.cs index 9122fef1..ffb84585 100644 --- a/AdventureClientConfig.cs +++ b/AdventureClientConfig.cs @@ -17,6 +17,9 @@ public class AdventureClientConfig : ModConfig public bool IsVanillaDashEnabled { get; set; } [DefaultValue(true)] public bool ShowPauseMessage { get; set; } + [DefaultValue(false)] public bool OpenMapAfterRecall; + [DefaultValue(false)] public bool ShowPopupText; + public class PlayerOutlineConfig { public bool Self { get; set; } = true; @@ -128,6 +131,8 @@ public class PlayerKillMarkerConfig : KillMarkerConfig [DefaultValue(null)] [NullAllowed] public HitMarkerConfig NpcHitMarker { get; set; } [DefaultValue(null)] [NullAllowed] public PlayerHitMarkerConfig PlayerHitMarker { get; set; } [DefaultValue(null)] [NullAllowed] public PlayerKillMarkerConfig PlayerKillMarker { get; set; } + + } public SoundEffectConfig SoundEffect { get; set; } = new(); diff --git a/Assets/SpawnSelector/Arrow.png b/Assets/SpawnSelector/Arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..07067dee08422b61d9afaacb5fa6bef3a04c9058 GIT binary patch literal 359 zcmeAS@N?(olHy`uVBq!ia0vp^(m*W7!3HGnN~S&oQk(@Ik;M!Qd`Cc-ajG^SPz9r; zr;B5VM`!Y%|Nrfo_c93I%}Gi~NN{|1f?HMK>Dl)8Vg{3vCGVskiE`mgIH+c!`-7ux zM(Hhe3+bDQ@Ae+FsI}C-DBjvHn0`a&5PO-}dQ~eIHoe9N%bTAgTe~DWM4f DxbB2V literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/CornerMask4px.png b/Assets/SpawnSelector/CornerMask4px.png deleted file mode 100644 index 8f03f4353fab813910a3a823b9e04bef34e0e43c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 268 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=mpxq^Ln`LHy=};MSV4p(@ZbLb zb3H{lZ)&8@W3iUKarBMIyO`v|bBf=+^Ixzk%l7-{*2%~FKi<2(UvA#1U7O3Nn}4_) z{raKXuV){VbL^V7Ph^O4m`oRZzCJU5@$riP0X5vAp?l?)oZ0{L-P^lQU#_vX7hI@P Tt+JF6FS$$$R;|6k9>*7jZH eLAl2peun<-g8yqaZ{Y?iVeoYIb6Mw<&;$Vdrx$+! diff --git a/Content/Items/AdventureMirror.cs b/Content/Items/AdventureMirror.cs index be84ac39..c30aaa0c 100644 --- a/Content/Items/AdventureMirror.cs +++ b/Content/Items/AdventureMirror.cs @@ -1,7 +1,7 @@ -using Microsoft.Xna.Framework; -using PvPAdventure.Core.Features.SpawnSelector.Players; +using PvPAdventure.Core.Features.SpawnSelector.Players; +using PvPAdventure.Core.Features.SpawnSelector.UI; +using PvPAdventure.System; using Terraria; -using Terraria.Audio; using Terraria.ID; using Terraria.ModLoader; @@ -25,58 +25,54 @@ public override void SetDefaults() public override bool CanUseItem(Player player) { - var adventureMirrorPlayer = player.GetModPlayer(); + var amp = player.GetModPlayer(); + var gm = ModContent.GetInstance(); - if (adventureMirrorPlayer.IsPlayerInSpawnRegion()) + if (gm.CurrentPhase != GameManager.Phase.Playing) { - PopupText.NewText(new AdvancedPopupRequest - { - Color = Color.Crimson, - Text = "Cannot use in spawn!", - Velocity = new(0f, -4f), - DurationInFrames = 60 - }, player.Top); + if (player.whoAmI == Main.myPlayer) + PopupTextHelper.NewText("Cannot use before game has started!"); + return false; + } + if (amp.IsPlayerInSpawnRegion()) + { + if (player.whoAmI == Main.myPlayer) + PopupTextHelper.NewText("Cannot use in spawn region!"); return false; - }; + } - if (adventureMirrorPlayer.CancelIfPlayerMoves()) + if (amp.MirrorActive) return false; - if (adventureMirrorPlayer.MirrorActive) + if (player.whoAmI == Main.myPlayer && player.velocity.LengthSquared() > 0f) + { + //PopupTextHelper.NewText("Cannot use while moving!"); return false; + } return true; } + public override bool AltFunctionUse(Player player) => true; public override bool CanRightClick() => true; public override bool ConsumeItem(Player player) => false; public override void RightClick(Player player) { - var adventureMirrorPlayer = player.GetModPlayer(); - - if (adventureMirrorPlayer.CancelIfPlayerMoves()) + if (!player.GetModPlayer().TryStartMirrorChannel()) return; - - if (adventureMirrorPlayer.MirrorActive) - return; - - var config = ModContent.GetInstance(); - int recallFrames = config.AdventureMirrorRecallFrames + 1; - - SoundEngine.PlaySound(SoundID.Item6); // magic mirror - - adventureMirrorPlayer.StartMirrorUse(recallFrames); } public override bool? UseItem(Player player) { - var config = ModContent.GetInstance(); - int recallFrames = config.AdventureMirrorRecallFrames + 1; - - var mp = player.GetModPlayer(); - mp.StartMirrorUse(recallFrames); - + var amp = player.GetModPlayer(); + amp.TryStartMirrorChannel(); return true; } + + public override void UpdateInventory(Player player) + { + // Force favorite every tick + Item.favorited = true; + } } diff --git a/Content/Items/AdventureMirrorGlobalItem.cs b/Content/Items/AdventureMirrorGlobalItem.cs deleted file mode 100644 index 12d66652..00000000 --- a/Content/Items/AdventureMirrorGlobalItem.cs +++ /dev/null @@ -1,31 +0,0 @@ -using PvPAdventure.Core.Features.SpawnSelector.Players; -using Terraria; -using Terraria.ModLoader; - -namespace PvPAdventure.Content.Items -{ - public class AdventureMirrorGlobalItem : GlobalItem - { - public override bool InstancePerEntity => true; - - // Force the item to always be favorited - public override void UpdateInventory(Item item, Player player) - { - if (item.type == ModContent.ItemType()) - { - item.favorited = true; // Force on every tick - } - } - - public override bool CanPickup(Item item, Player player) - { - // Disallow item pickup while timer is on - if (player.GetModPlayer().MirrorTimer > 0) - { - return false; - } - - return base.CanPickup(item, player); - } - } -} \ No newline at end of file diff --git a/Core/Debug/DebugKeybinds.cs b/Core/Debug/DebugKeybinds.cs index dddcf3e2..8dd6a11f 100644 --- a/Core/Debug/DebugKeybinds.cs +++ b/Core/Debug/DebugKeybinds.cs @@ -1,6 +1,4 @@ -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Input; -using PvPAdventure.Core.Features.SpawnSelector.Systems; +using Microsoft.Xna.Framework.Input; using Terraria; using Terraria.GameInput; using Terraria.ModLoader; @@ -14,15 +12,11 @@ public class DebugKeybinds : ModSystem { public ModKeybind OpenControls { get; private set; } public ModKeybind SwitchTeams { get; private set; } - public ModKeybind AddPlayerToSpawnSelector { get; private set; } - public ModKeybind ClearPlayersFromSpawnSelector { get; private set; } public override void Load() { - OpenControls = KeybindLoader.RegisterKeybind(Mod, "OpenControls", Keys.NumPad0); - SwitchTeams = KeybindLoader.RegisterKeybind(Mod, "SwitchTeams", Keys.NumPad1); - AddPlayerToSpawnSelector = KeybindLoader.RegisterKeybind(Mod, "AddPlayerToSpawnSelector", Keys.NumPad2); - ClearPlayersFromSpawnSelector = KeybindLoader.RegisterKeybind(Mod, "ClearPlayersFromSpawnSelector", Keys.NumPad3); + OpenControls = KeybindLoader.RegisterKeybind(Mod, "[DEBUG] OpenControls", Keys.NumPad0); + SwitchTeams = KeybindLoader.RegisterKeybind(Mod, "[DEBUG] SwitchTeams", Keys.NumPad1); } } @@ -42,23 +36,7 @@ public override void ProcessTriggers(TriggersSet triggersSet) if (key.SwitchTeams.JustPressed) { Player.team = (Player.team + 1) % 6; // Cycle through teams 0-5 - Main.NewText(Player.name + " switched to team: " + (Terraria.Enums.Team)Player.team); - } - - if (key.AddPlayerToSpawnSelector.JustPressed) - { - var sys = ModContent.GetInstance(); - sys.state.spawnSelectorPanel.DebugAddPlayer(); - Main.NewText("Added SpawnSelectorSystem player"); - //sys.state.spawnSelectorPanel.Rebuild(); - } - - if (key.ClearPlayersFromSpawnSelector.JustPressed) - { - var sys = ModContent.GetInstance(); - sys.state.spawnSelectorPanel.DebugClearPlayers(); - Main.NewText("Cleared SpawnSelectorSystem players"); - //sys.state.spawnSelectorPanel.Rebuild(); + Main.NewText("[DEBUG] " + Player.name + " switched to team: " + (Terraria.Enums.Team)Player.team); } } } diff --git a/Core/Features/SpawnSelector/Hooks/UnityHooks.cs b/Core/Features/SpawnSelector/Hooks/UnityHooks.cs deleted file mode 100644 index a6c1052c..00000000 --- a/Core/Features/SpawnSelector/Hooks/UnityHooks.cs +++ /dev/null @@ -1,45 +0,0 @@ -using Microsoft.Xna.Framework; -using PvPAdventure.Core.Features.SpawnSelector.Systems; -using System; -using Terraria; -using Terraria.ModLoader; - -namespace PvPAdventure.Core.Features.SpawnSelector.Hooks; - -/// -/// This allows the player to click on teammates to teleport to them. -/// -public class UnityHooks : ModSystem -{ - public override void Load() - { - Main.QueueMainThreadAction(() => - { - On_Player.HasUnityPotion += OnHasUnityPotion; - On_Player.UnityTeleport += OnUnityTeleport; - }); - } - - public override void Unload() - { - Main.QueueMainThreadAction(() => - { - On_Player.HasUnityPotion -= OnHasUnityPotion; - On_Player.UnityTeleport -= OnUnityTeleport; - }); - } - - private void OnUnityTeleport(On_Player.orig_UnityTeleport orig, Player self, Vector2 telePos) - { - SpawnSelectorSystem.SetEnabled(false); - orig(self, telePos); - } - - private static bool OnHasUnityPotion(On_Player.orig_HasUnityPotion orig, Player self) - { - if (SpawnSelectorSystem.GetEnabled()) - return true; - - return orig(self); - } -} diff --git a/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs b/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs index 9c48d582..00ce866a 100644 --- a/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs +++ b/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs @@ -1,6 +1,7 @@ using Microsoft.Xna.Framework; using PvPAdventure.Content.Items; using PvPAdventure.Core.Features.SpawnSelector.Systems; +using PvPAdventure.Core.Features.SpawnSelector.UI; using PvPAdventure.System; using PvPAdventure.System.Client; using Terraria; @@ -9,22 +10,49 @@ using Terraria.GameInput; using Terraria.ID; using Terraria.ModLoader; -using static PvPAdventure.System.RegionManager; +using static Terraria.ModLoader.BackupIO; namespace PvPAdventure.Core.Features.SpawnSelector.Players; public class AdventureMirrorPlayer : ModPlayer { public int MirrorTimer; // frames left - public bool MirrorActive; - - public void StartMirrorUse(int durationFrames) + public bool MirrorActive; // currently channeling + public int MirrorCountdownLastSecond = -1; + private bool didRebuildOnDeath; + public bool TryStartMirrorChannel() { + if (ModContent.GetInstance().CurrentPhase != GameManager.Phase.Playing) + { + if (Player.whoAmI == Main.myPlayer) + PopupTextHelper.NewText("Cannot use before game has started!"); + return false; + } + + if (IsPlayerInSpawnRegion()) + { + if (Player.whoAmI == Main.myPlayer) + PopupTextHelper.NewText("Cannot use in spawn region!"); + return false; + } + if (MirrorActive) - return; + return false; + + if (Player.whoAmI == Main.myPlayer && IsMoving()) + { + CancelMirrorUse(); + PopupTextHelper.NewText("Cannot use while moving!"); + return false; + } + + SoundEngine.PlaySound(SoundID.Item6); + var config = ModContent.GetInstance(); + int recallFrames = config.AdventureMirrorRecallFrames + 1; MirrorActive = true; - MirrorTimer = durationFrames; + MirrorTimer = recallFrames; + return true; } public bool IsPlayerInSpawnRegion() @@ -40,20 +68,16 @@ public bool IsPlayerInSpawnRegion() return false; } - public bool CancelIfPlayerMoves() - { - if (Player.velocity.LengthSquared() <= 0f) - return false; + private bool IsMoving() => Player.velocity.LengthSquared() > 0f; - // stop the mirror channel - if (MirrorActive) - { - MirrorActive = false; - MirrorTimer = 0; - } + private void CancelMirrorUse() + { + MirrorActive = false; + MirrorTimer = 0; + MirrorCountdownLastSecond = -1; - // stop the actual item use / animation too - if (Player.itemAnimation > 0 && Player.HeldItem.type == ModContent.ItemType()) + if (Player.itemAnimation > 0 && + Player.HeldItem.type == ModContent.ItemType()) { Player.controlUseItem = false; Player.channel = false; @@ -61,34 +85,44 @@ public bool CancelIfPlayerMoves() Player.itemTime = 0; Player.reuseDelay = 0; } + } - PopupText.NewText(new AdvancedPopupRequest - { - Color = Color.Crimson, - Text = "Cannot use while moving!", - Velocity = new(0f, -4f), - DurationInFrames = 60 - }, Player.Top); + public bool CancelIfPlayerMoves() + { + if (Player.whoAmI != Main.myPlayer) + return false; + + if (!IsMoving()) + return false; + CancelMirrorUse(); + PopupTextHelper.NewText("Cannot use while moving!"); return true; } public override void PostUpdate() { - // Open SSS whenever player is in spawn region. - if (IsPlayerInSpawnRegion()) - SpawnSelectorSystem.SetEnabled(true); + if (!Player.dead) + { + didRebuildOnDeath = false; + } + + if (Main.dedServ || Player.whoAmI != Main.myPlayer) + return; - // Closes SSS whenever map is closed. - if (!Main.mapFullscreen) + + if (ModContent.GetInstance().CurrentPhase == GameManager.Phase.Playing && Main.mapFullscreen && IsPlayerInSpawnRegion()) + { + SpawnSelectorSystem.SetEnabled(true); + } + else + { SpawnSelectorSystem.SetEnabled(false); + } if (!MirrorActive) return; - if (Main.dedServ || Player.whoAmI != Main.myPlayer) - return; - if (CancelIfPlayerMoves()) return; @@ -104,43 +138,37 @@ public override void PostUpdate() if (MirrorTimer > 0 && MirrorTimer % 60 == 0) { int secondsLeft = MirrorTimer / 60; - PopupText.NewText(new AdvancedPopupRequest - { - Color = Color.Crimson, - Text = secondsLeft.ToString(), - Velocity = new(0f, -4f), - DurationInFrames = 60 - }, Player.Top); + PopupTextHelper.NewText(secondsLeft.ToString(), Color.LightGreen, showInMultiplayer: true); } - // Teleport to spawn + // Ready to teleport to spawn if (MirrorTimer <= 0) { - // Close player inventory - //Main.playerInventory = false; - - if (!Main.mapFullscreen) + var config = ModContent.GetInstance(); + if (config.OpenMapAfterRecall) { - //SoundEngine.PlaySound(SoundID.MenuOpen); - //Main.mapFullscreen = true; + // Close player inventory + Main.playerInventory = false; + // Open fullscreen map + Main.mapFullscreen = true; + + // center the map float worldCenterX = Main.maxTilesX / 2f; float worldCenterY = Main.maxTilesY / 2f; Main.mapFullscreenPos.X = worldCenterX; Main.mapFullscreenPos.Y = worldCenterY; - - Main.mapFullscreenScale = 0.21f; - - Vector2 spawnPos = new(Main.spawnTileX * 16, Main.spawnTileY * 16 - 48); - //Main.LocalPlayer.Teleport(spawnPos, 0); - CustomTeleportWithoutSound(spawnPos); + Main.mapFullscreenScale = 0.21f; // arbitrary value to zoom out that fits the entire map } + // Teleport to spawn + Vector2 spawnPos = new(Main.spawnTileX * 16, Main.spawnTileY * 16 - 48); + //Main.LocalPlayer.Teleport(spawnPos, 0); + CustomTeleportWithoutSound(spawnPos); + SpawnSelectorSystem.SetEnabled(true); // This is redundant because spawn region already sets it to true ModContent.GetInstance().state.spawnSelectorPanel.Rebuild(); - Player.RemoveAllGrapplingHooks(); - MirrorActive = false; } } @@ -216,58 +244,109 @@ private void CustomTeleportWithoutSound(Vector2 newPos) } } - public override void UpdateDead() + #region Keybind Handling + public override void ProcessTriggers(TriggersSet triggersSet) { - // debug - //Main.NewText(Player.respawnTimer); + var keybinds = ModContent.GetInstance(); - // Keeps the player from respawning until they have selected a spawn. - if (Player.respawnTimer <= 10) + if (keybinds.AdventureMirrorKeybind.JustPressed) { - //Player.respawnTimer = 10; - if (!Main.mapFullscreen) - { - Main.mapFullscreen = true; - SpawnSelectorSystem.SetEnabled(true); - } + TryUseAdventureMirror(); } } - public override void ProcessTriggers(TriggersSet triggersSet) + public void TryUseAdventureMirror() { - var keybinds = ModContent.GetInstance(); + int mirrorIndex = EnsureMirrorInInventory(); - if (keybinds.AdventureMirrorKeybind.JustPressed) + if (mirrorIndex == -1) { - TryUseAdventureMirror(); + PopupTextHelper.NewText("No Adventure Mirror found in inventory or banks!"); + return; } + + if (CancelIfPlayerMoves()) + return; + + Player.selectedItem = mirrorIndex; + Player.controlUseItem = true; + Player.ItemCheck(); } - public void TryUseAdventureMirror() + private int EnsureMirrorInInventory() + { + int mirrorType = ModContent.ItemType(); + + // 1. Look in main inventory first + for (int i = 0; i < Player.inventory.Length; i++) + { + Item item = Player.inventory[i]; + if (!item.IsAir && item.type == mirrorType) + return i; + } + + // 2. Try to pull from personal banks + if (TryPullMirrorFromBank(Player.bank, mirrorType, out int invIndex)) + return invIndex; + + if (TryPullMirrorFromBank(Player.bank2, mirrorType, out invIndex)) + return invIndex; + + if (TryPullMirrorFromBank(Player.bank3, mirrorType, out invIndex)) + return invIndex; + + if (TryPullMirrorFromBank(Player.bank4, mirrorType, out invIndex)) // void vault + return invIndex; + + return -1; + } + + private bool TryPullMirrorFromBank(Chest bank, int mirrorType, out int inventoryIndex) { - // Find a mirror in the player's inventory - int mirrorIndex = -1; + inventoryIndex = -1; + + if (bank == null) + return false; + + // Find the mirror inside this bank + int bankSlot = -1; + for (int i = 0; i < bank.item.Length; i++) + { + Item item = bank.item[i]; + if (!item.IsAir && item.type == mirrorType) + { + bankSlot = i; + break; + } + } + if (bankSlot == -1) + return false; + + // Find a free inventory slot + int freeInvSlot = -1; for (int i = 0; i < Player.inventory.Length; i++) { - if (Player.inventory[i].type == ModContent.ItemType()) + if (Player.inventory[i].IsAir) { - mirrorIndex = i; + freeInvSlot = i; break; } } - if (mirrorIndex == -1) + if (freeInvSlot == -1) { - Main.NewText("You don't have an Adventure Mirror!", Color.Red); - return; + if (Player.whoAmI == Main.myPlayer) + Main.NewText("No free inventory slot for Adventure Mirror!", Color.Red); + return false; } - CancelIfPlayerMoves(); + // Move the item from bank → inventory + Player.inventory[freeInvSlot] = bank.item[bankSlot].Clone(); + bank.item[bankSlot].TurnToAir(); - // Force the player to use the item - Player.selectedItem = mirrorIndex; - Player.controlUseItem = true; - Player.ItemCheck(); + inventoryIndex = freeInvSlot; + return true; } + #endregion } diff --git a/Core/Features/SpawnSelector/Players/ModifyPlayerDrawInfo.cs b/Core/Features/SpawnSelector/Players/ModifyDrawInfoPlayer.cs similarity index 87% rename from Core/Features/SpawnSelector/Players/ModifyPlayerDrawInfo.cs rename to Core/Features/SpawnSelector/Players/ModifyDrawInfoPlayer.cs index 67dd894b..af783918 100644 --- a/Core/Features/SpawnSelector/Players/ModifyPlayerDrawInfo.cs +++ b/Core/Features/SpawnSelector/Players/ModifyDrawInfoPlayer.cs @@ -1,16 +1,20 @@ using Microsoft.Xna.Framework; -using Terraria; using Terraria.DataStructures; -using Terraria.GameContent; using Terraria.ModLoader; namespace PvPAdventure.Core.Features.SpawnSelector.Players; -public class ModifyPlayerDrawInfo : ModPlayer +/// +/// Useful for forcing the player to be drawn with full brightness even when in player is in darkness. +/// +public class ModifyDrawInfoPlayer : ModPlayer { public static bool ForceFullBrightOnce; public override void ModifyDrawInfo(ref PlayerDrawSet drawInfo) { + if (drawInfo.headOnlyRender) + return; + if (!ForceFullBrightOnce) return; diff --git a/Core/Features/SpawnSelector/Hooks/ItemSlotHooks.cs b/Core/Features/SpawnSelector/Systems/ItemSlotHooks.cs similarity index 52% rename from Core/Features/SpawnSelector/Hooks/ItemSlotHooks.cs rename to Core/Features/SpawnSelector/Systems/ItemSlotHooks.cs index dc3f9dbb..d4a974ed 100644 --- a/Core/Features/SpawnSelector/Hooks/ItemSlotHooks.cs +++ b/Core/Features/SpawnSelector/Systems/ItemSlotHooks.cs @@ -2,7 +2,15 @@ using Terraria.ModLoader; using Terraria.UI; using PvPAdventure.Content.Items; +using PvPAdventure.Core.Features.SpawnSelector.UI; +using PvPAdventure.System.Client; +using Microsoft.Xna.Framework.Input; +namespace PvPAdventure.Core.Features.SpawnSelector.Systems; + +/// +/// Prevents the Adventure Mirror from being removed from the player inventory via trashing or selling. +/// public class ItemSlotHooks : ModSystem { public override void Load() @@ -28,6 +36,10 @@ private static bool Hook_LeftClick_SellOrTrash( if (!item.IsAir && item.type == ModContent.ItemType()) { + if (Main.keyState.IsKeyDown(Keys.LeftShift) && Main.mouseLeft && Main.mouseLeftRelease) + { + PopupTextHelper.NewText("Cannot quick trash Adventure Mirror!"); + } //SoundEngine.PlaySound(SoundID.MenuClose); return false; // skip SellOrTrash completely } @@ -35,20 +47,30 @@ private static bool Hook_LeftClick_SellOrTrash( return orig(inv, context, slot); } + private static bool IsAdventureMirror(Item item) + => !item.IsAir && item.type == ModContent.ItemType(); + // DRAGGING ONTO THE TRASH SLOT private static void Hook_LeftClick_ItemArray( On_ItemSlot.orig_LeftClick_ItemArray_int_int orig, Item[] inv, int context, int slot) { + // 1) Hard block: putting mirror into any chest/bank slot + bool isStorageSlot = + context == ItemSlot.Context.ChestItem || + context == ItemSlot.Context.BankItem; // Piggy bank - if (context == ItemSlot.Context.TrashItem - && !Main.mouseItem.IsAir - && Main.mouseItem.type == ModContent.ItemType()) + if (isStorageSlot && + IsAdventureMirror(Main.mouseItem)) // we are dragging the mirror onto this slot { - //SoundEngine.PlaySound(SoundID.MenuClose); - return; + if (Main.mouseLeft && Main.mouseLeftRelease) + PopupTextHelper.NewText("Cannot store Adventure Mirror!"); + + // Do NOT call orig -> cancel the placement + return; } + // Fallback to vanilla behavior orig(inv, context, slot); } @@ -59,12 +81,14 @@ private static bool Hook_SellItem( Item item, int stack) { - if (!item.IsAir && item.type == ModContent.ItemType()) + if (IsAdventureMirror(item)) { - //SoundEngine.PlaySound(SoundID.MenuClose); - return false; + if (Main.mouseLeft && Main.mouseLeftRelease) + PopupTextHelper.NewText("Cannot sell Adventure Mirror!"); + + return false; } return orig(self, item, stack); } -} +} \ No newline at end of file diff --git a/Core/Features/SpawnSelector/Systems/SpawnSelectorState.cs b/Core/Features/SpawnSelector/Systems/SpawnSelectorState.cs index c1d7ae6b..77c71bfa 100644 --- a/Core/Features/SpawnSelector/Systems/SpawnSelectorState.cs +++ b/Core/Features/SpawnSelector/Systems/SpawnSelectorState.cs @@ -17,7 +17,6 @@ public override void OnInitialize() UITextPanel chooseYourSpawnPanel = new("Choose Your Spawn", 0.8f, true); chooseYourSpawnPanel.HAlign = 0.5f; - chooseYourSpawnPanel.VAlign = 0f; chooseYourSpawnPanel.Top.Set(10, 0); chooseYourSpawnPanel.BackgroundColor = new Color(73, 94, 171); Append(chooseYourSpawnPanel); diff --git a/Core/Features/SpawnSelector/Systems/SpawnSelectorSystem.cs b/Core/Features/SpawnSelector/Systems/SpawnSelectorSystem.cs index 4d174412..6dbf5979 100644 --- a/Core/Features/SpawnSelector/Systems/SpawnSelectorSystem.cs +++ b/Core/Features/SpawnSelector/Systems/SpawnSelectorSystem.cs @@ -1,6 +1,5 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; -using PvPAdventure.Core.Features.SpawnSelector.UI; using Terraria; using Terraria.ModLoader; using Terraria.UI; @@ -10,16 +9,14 @@ namespace PvPAdventure.Core.Features.SpawnSelector.Systems; [Autoload(Side = ModSide.Client)] public class SpawnSelectorSystem : ModSystem { - private UserInterface ui; + public UserInterface ui; public SpawnSelectorState state; - private UISpawnSelectorPanel teleportPanel; // Track whether the spawn selector is enabled - private static bool Enabled; // whether the spawn selector is currently showing in the fullscreen map + private static bool Enabled; public static void SetEnabled(bool newValue) => Enabled = newValue; public static bool GetEnabled() => Enabled; - // Load and unload hooks public override void Load() { if (!Main.dedServ) diff --git a/Core/Features/SpawnSelector/Systems/UnityHooks.cs b/Core/Features/SpawnSelector/Systems/UnityHooks.cs new file mode 100644 index 00000000..5952bdc4 --- /dev/null +++ b/Core/Features/SpawnSelector/Systems/UnityHooks.cs @@ -0,0 +1,28 @@ +using Terraria; +using Terraria.ModLoader; + +namespace PvPAdventure.Core.Features.SpawnSelector.Systems; + +/// +/// This allows the player to click on teammates to teleport to them. +/// +public class UnityHooks : ModSystem +{ + public override void Load() + { + On_Player.HasUnityPotion += OnHasUnityPotion; + } + + public override void Unload() + { + On_Player.HasUnityPotion -= OnHasUnityPotion; + } + + private static bool OnHasUnityPotion(On_Player.orig_HasUnityPotion orig, Player self) + { + if (SpawnSelectorSystem.GetEnabled()) + return true; + + return orig(self); + } +} diff --git a/Core/Features/SpawnSelector/UI/PopupTextHelper.cs b/Core/Features/SpawnSelector/UI/PopupTextHelper.cs new file mode 100644 index 00000000..baa755fa --- /dev/null +++ b/Core/Features/SpawnSelector/UI/PopupTextHelper.cs @@ -0,0 +1,42 @@ +using Microsoft.Xna.Framework; +using Terraria; +using Terraria.ModLoader; + +namespace PvPAdventure.Core.Features.SpawnSelector.UI; +public static class PopupTextHelper +{ + public static void NewText(string text, Color color=default, bool showInMultiplayer=false) + { + if (color == default) + color = Color.Crimson; + + var config = ModContent.GetInstance(); + if (!config.ShowPopupText) + { + return; + } + + if (showInMultiplayer) + { + PopupText.NewText(new AdvancedPopupRequest + { + Color = color, + Text = text, + Velocity = new(0f, -4f), + DurationInFrames = 60 + }, Main.LocalPlayer.Top); + return; + } + + if (Main.LocalPlayer.whoAmI == Main.myPlayer) + { + PopupText.NewText(new AdvancedPopupRequest + { + Color = color, + Text = text, + Velocity = new(0f, -4f), + DurationInFrames = 60 + }, Main.LocalPlayer.Top); + } + } +} diff --git a/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs b/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs index 23a90a74..8a539b45 100644 --- a/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs +++ b/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs @@ -4,13 +4,15 @@ using PvPAdventure.Core.Features.SpawnSelector.Systems; using PvPAdventure.Core.Helpers; using ReLogic.Content; +using ReLogic.Graphics; using System; using Terraria; using Terraria.GameContent; using Terraria.GameContent.UI.Elements; +using Terraria.ID; using Terraria.ModLoader; -using Terraria.ModLoader.UI; using Terraria.UI; +using tModPorter; namespace PvPAdventure.Core.Features.SpawnSelector.UI { @@ -27,6 +29,7 @@ internal class UISpawnSelectorCharacterListItem : UIPanel private readonly Asset _playerBGTexture; private readonly int _playerIndex; + public int PlayerIndex => _playerIndex; public UISpawnSelectorCharacterListItem(Player player) { @@ -52,24 +55,61 @@ private void DrawHeadOnMap(Player p) { float scale = Main.mapFullscreenScale; + Vector2 mapPos = new( + (p.position.X + p.width / 2f) / 16f, + (p.position.Y + p.gfxOffY + p.height / 2f) / 16f + ); + Vector2 headPos = new( - ((p.position.X + p.width / 2f) / 16f - Main.mapFullscreenPos.X) * scale - + Main.screenWidth / 2f - 14f * scale+48, + (mapPos.X - Main.mapFullscreenPos.X) * scale + Main.screenWidth / 2f, + (mapPos.Y - Main.mapFullscreenPos.Y) * scale + Main.screenHeight / 2f + ); + headPos += new Vector2(34f, 44f); - ((p.position.Y + p.gfxOffY + p.height / 2f) / 16f - Main.mapFullscreenPos.Y) * scale - + Main.screenHeight / 2f - 14f * scale+58 + CalculatedStyle inner = GetInnerDimensions(); + Rectangle rect = new( + (int)inner.X - 6, + (int)inner.Y - 6, + 100, + 72 ); + Vector2 arrowStart = new(rect.X + rect.Width / 2f, rect.Bottom + 8f); + + Texture2D arrowTex = Ass.Arrow.Value; + Vector2 arrowOrigin = arrowTex.Size() * 0.5f; + + Vector2 dir = headPos - arrowStart; + if (dir.LengthSquared() > 0.001f) + { + dir.Normalize(); + float rotation = dir.ToRotation(); // adjust with +- PiOver2 if your texture points up + Vector2 arrowPos = arrowStart; + + Main.spriteBatch.Draw( + arrowTex, + arrowPos, + null, + Color.White, + rotation, + arrowOrigin, + 1f, + SpriteEffects.None, + 0f + ); + } + Color color = Main.teamColor[p.team]; - //Main.PlayerRenderer.DrawPlayerHead( - // Main.Camera, - // p, - // headPos, - // scale: 1.3f, - // borderColor: color - //); - Utils.DrawBorderString(Main.spriteBatch, p.name, headPos, Color.White); + Main.MapPlayerRenderer.DrawPlayerHead( + Main.Camera, + p, + headPos, + scale: 1.6f, + borderColor: color + ); + + Utils.DrawBorderString(Main.spriteBatch, p.name, headPos + new Vector2(-20f, 20f), Color.White); } private void DrawNineSlice(SpriteBatch sb, int x, int y, int w, int h, Texture2D tex, Color color, int inset, int c = 5) @@ -132,15 +172,16 @@ protected override void DrawSelf(SpriteBatch sb) null, Main.UIScaleMatrix); - ModifyPlayerDrawInfo.ForceFullBrightOnce = true; + ModifyDrawInfoPlayer.ForceFullBrightOnce = true; try { - Vector2 playerDrawPos = pos + Main.screenPosition + new Vector2(32, 8); - - //Main.PlayerRenderer.DrawPlayer(Main.Camera,player,playerDrawPos,player.fullRotation,player.fullRotationOrigin,0f,0.9f); + Vector2 playerDrawPos = pos + Main.screenPosition + new Vector2(34, 9); + Vector2 headDrawPos = pos + new Vector2(38, 28); Color myTeamColor = Main.teamColor[Main.LocalPlayer.team]; - Main.PlayerRenderer.DrawPlayerHead(Main.Camera, player, pos+ new Vector2(40,37), scale: 1.3f, borderColor: Color.Yellow); + + //Main.PlayerRenderer.DrawPlayer(Main.Camera,player,playerDrawPos,player.fullRotation,player.fullRotationOrigin,0f,0.9f); + Main.MapPlayerRenderer.DrawPlayerHead(Main.Camera, player, headDrawPos, scale: 1.0f, borderColor: myTeamColor); } catch (Exception e) { @@ -148,7 +189,7 @@ protected override void DrawSelf(SpriteBatch sb) } finally { - ModifyPlayerDrawInfo.ForceFullBrightOnce = false; + ModifyDrawInfoPlayer.ForceFullBrightOnce = false; } // Switch back to "normal" UI batch @@ -237,15 +278,15 @@ protected override void DrawSelf(SpriteBatch sb) if (IsMouseHovering) { Main.instance.MouseText("Teleport to " + name); - var old = Main.UIScaleMatrix; - //Main.spriteBatch.End(); - //Main.spriteBatch.Begin(SpriteSortMode.Immediate,BlendState.AlphaBlend,SamplerState.PointClamp,DepthStencilState.None,RasterizerState.CullCounterClockwise,null,Matrix.Identity); + Main.spriteBatch.End(); + Main.spriteBatch.Begin(SpriteSortMode.Immediate,BlendState.AlphaBlend,SamplerState.PointClamp,DepthStencilState.None,RasterizerState.CullCounterClockwise,null,Matrix.Identity); - //DrawHeadOnMap(player); + DrawHeadOnMap(player); + //DrawGuideMarkerOnMap(Main.spriteBatch); - //Main.spriteBatch.End(); - //Main.spriteBatch.Begin(SpriteSortMode.Deferred,BlendState.AlphaBlend,SamplerState.PointClamp,DepthStencilState.None,RasterizerState.CullCounterClockwise,null,old); + Main.spriteBatch.End(); + Main.spriteBatch.Begin(SpriteSortMode.Deferred,BlendState.AlphaBlend,SamplerState.PointClamp,DepthStencilState.None,RasterizerState.CullCounterClockwise,null,Main.UIScaleMatrix); } //Main.NewText(Main.mouseY); // 482,435 is spawn diff --git a/Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs b/Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs index 96f1184c..fb802b1c 100644 --- a/Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs +++ b/Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs @@ -38,30 +38,19 @@ private void BuildLayout() var players = new List(); var local = Main.LocalPlayer; -#if DEBUG - // If we have debug players, use them instead of scanning teammates - if (_debugPlayers.Count > 0) + if (local.team != 0) { - players.AddRange(_debugPlayers); - } - else -#endif - { - // ADD TEAMMATES - if (local.team != 0) + for (int i = 0; i < Main.maxPlayers; i++) { - for (int i = 0; i < Main.maxPlayers; i++) - { - Player p = Main.player[i]; + Player p = Main.player[i]; - if (p == null || !p.active) - continue; + if (p == null || !p.active || p.dead || p.statLife <= 0) + continue; - if (p.whoAmI == local.whoAmI || p.team != local.team) - continue; + if (p.whoAmI == local.whoAmI || p.team != local.team) + continue; - players.Add(p); - } + players.Add(p); } } @@ -69,7 +58,7 @@ private void BuildLayout() float itemWidth = UISpawnSelectorCharacterListItem.ItemWidth; float itemHeight = UISpawnSelectorCharacterListItem.ItemHeight; - float randomWidth = itemHeight; // square random panel + float randomWidth = itemHeight; float contentWidth = playerCount * itemWidth + playerCount * Spacing @@ -78,13 +67,18 @@ private void BuildLayout() float panelWidth = contentWidth + HorizontalPadding * 2f; float panelHeight = itemHeight + VerticalPadding * 2f; + if (panelWidth <= 0f) + panelWidth = itemWidth + HorizontalPadding * 2f; + + if (panelHeight <= 0f) + panelHeight = itemHeight + VerticalPadding * 2f; + Width.Set(panelWidth, 0f); Height.Set(panelHeight, 0f); float startX = HorizontalPadding; float y = VerticalPadding; - // Players in a row for (int i = 0; i < playerCount; i++) { float x = startX + i * (itemWidth + Spacing); @@ -97,7 +91,6 @@ private void BuildLayout() _playerItems.Add(row); } - // Square random panel to the right of the last player _randomPanel = new UISpawnSelectorRandomPanel( startX, itemHeight, @@ -108,6 +101,9 @@ private void BuildLayout() ); Append(_randomPanel); + Recalculate(); + RecalculateChildren(); + Log.Debug($"UISpawnSelectorPanel.BuildLayout: players={playerCount}, panelWidth={panelWidth}"); } @@ -117,34 +113,58 @@ public void Rebuild() Log.Debug("UISpawnSelectorPanel.Rebuild: UI rebuilt"); } - public override void Draw(SpriteBatch spriteBatch) + public override void Update(GameTime gameTime) { - base.Draw(spriteBatch); + if (NeedsRebuild()) + { + Rebuild(); + } + + base.Update(gameTime); } - #region Debug -#if DEBUG - private readonly List _debugPlayers = new(); -#endif - public void DebugAddPlayer() + public override void Draw(SpriteBatch spriteBatch) { -#if DEBUG - _debugPlayers.Add(Main.LocalPlayer); - BuildLayout(); - Log.Debug($"SpawnSelector DebugAddPlayer: debugPlayers={_debugPlayers.Count}"); -#endif + base.Draw(spriteBatch); } - public void DebugClearPlayers() + private bool NeedsRebuild() { -#if DEBUG - _debugPlayers.Clear(); - BuildLayout(); - Log.Debug("SpawnSelector DebugClearPlayers: cleared debug players"); -#endif - } - #endregion + var dims = GetDimensions(); + if (dims.Width <= 0f || dims.Height <= 0f) + return true; + + if (_randomPanel == null) + return true; + var randomDims = _randomPanel.GetDimensions(); + if (randomDims.Width <= 0f || randomDims.Height <= 0f) + return true; + + var local = Main.LocalPlayer; + var players = new List(); + for (int i = 0; i < Main.maxPlayers; i++) + { + var p = Main.player[i]; + if (p == null || !p.active || p.dead || p.statLife <= 0) + continue; + if (p.whoAmI == local.whoAmI || p.team != local.team) + continue; + + players.Add(p.whoAmI); + } + + if (players.Count != _playerItems.Count) + return true; + + for (int i = 0; i < players.Count; i++) + { + if (_playerItems[i] == null) return true; + if (_playerItems[i].PlayerIndex != players[i]) return true; + } + + return false; + } } } diff --git a/Core/Features/SpawnSelector/UI/UISpawnSelectorRandomPanel.cs b/Core/Features/SpawnSelector/UI/UISpawnSelectorRandomPanel.cs index 886a5461..237cf2d2 100644 --- a/Core/Features/SpawnSelector/UI/UISpawnSelectorRandomPanel.cs +++ b/Core/Features/SpawnSelector/UI/UISpawnSelectorRandomPanel.cs @@ -2,9 +2,11 @@ using Microsoft.Xna.Framework.Graphics; using PvPAdventure.Core.Features.SpawnSelector.Systems; using PvPAdventure.Core.Helpers; +using PvPAdventure.System; using Terraria; using Terraria.GameContent.UI.Elements; using Terraria.ID; +using Terraria.ModLoader; using Terraria.UI; namespace PvPAdventure.Core.Features.SpawnSelector.UI @@ -28,6 +30,11 @@ public override void LeftClick(UIMouseEvent evt) { base.LeftClick(evt); + // Redundant check, just to be sure we don't allow any shenanigans + var gm = ModContent.GetInstance(); + if (gm.CurrentPhase != GameManager.Phase.Playing) + return; + if (Main.netMode == NetmodeID.MultiplayerClient) { NetMessage.SendData(MessageID.RequestTeleportationByServer); diff --git a/Core/Helpers/AssetLoader.cs b/Core/Helpers/AssetLoader.cs index 747b6dd3..61d92e86 100644 --- a/Core/Helpers/AssetLoader.cs +++ b/Core/Helpers/AssetLoader.cs @@ -9,6 +9,7 @@ public static class Ass { public static Asset Question_Mark; public static Asset[] MapBG; + public static Asset Arrow; public static bool Initialized { get; set; } diff --git a/Localization/en-US.hjson b/Localization/en-US.hjson index 4fee0157..b7012b1e 100644 --- a/Localization/en-US.hjson +++ b/Localization/en-US.hjson @@ -20,6 +20,8 @@ Mods: { AddPlayerToSpawnSelector.DisplayName: Add Player To Spawn Selector RemovePlayerFromSpawnSelector.DisplayName: Remove Player From Spawn Selector ClearPlayersFromSpawnSelector.DisplayName: Clear Players From Spawn Selector + "[DEBUG] OpenControls.DisplayName": "[ D E B U G] Open Controls" + "[DEBUG] SwitchTeams.DisplayName": "[ D E B U G] Switch Teams" } Configs: { @@ -379,7 +381,7 @@ Mods: { } AdventureClientConfig: { - DisplayName: Client + DisplayName: Adventure Client Config PlayerOutline: { Label: Player Outline @@ -392,8 +394,8 @@ Mods: { } ShowPauseMessage: { - Tooltip: "" Label: Show Pause Message + Tooltip: "" } SoundEffect: { @@ -401,143 +403,243 @@ Mods: { Tooltip: "" } - IsVanillaDashEnabled: { - Label: Is Vanilla Dash Enabled - Tooltip: - ''' - On: Dash as usual with double tap - Off: Disables double tap dash. Use keybind instead - ''' + BlightFruit: { + DisplayName: Blight Fruit + Tooltip: Permanently decreases maximum life by 5 } - } - PlayerOutlineConfig: { - Tooltip: "" + OpenMapAfterRecall: { + Label: Open Map After Recall + Tooltip: "" + } - Self: { - Label: Self + ShowPopupText: { + Label: Show Popup Text Tooltip: "" } - Team: { - Label: Team + IsVanillaDashEnabled: { + Label: Is Vanilla Dash Enabled Tooltip: "" } } - CannotModify: You are not permitted to modify this config. + Item: { + Disabled: Cannot be used in this gamemode + NoUndergroundEmpressButterfly: Cannot be released here underground + NoUndergroundQueenSlimeCrystal: Cannot be summoned here underground + } - PlayerDamageBalanceConfig: { - Tooltip: "" + Player.CannotRecall: Cannot recall! + Tiles.LockedLihzahrdChest.MapEntry: Locked Lihzahrd Chest + Sandstorm: "[c/FFC864:Desert winds are picking up...]" + Rain: "[c/6496FF:A storm is brewing overhead...]" - ItemDamageMultipliers: { - Label: Item Damage Multipliers - Tooltip: "" + NPCs: { + Bound: { + Merchant.DisplayName: Bound Merchant + ArmsDealer.DisplayName: Bound Arms Dealer + WitchDoctor.DisplayName: Bound Witch Doctor + Demolitionist.DisplayName: Bound. Demolitionist + + Steampunker: { + DisplayName: Chained Steampunker + Chat: At long last, I'm saved! The strangest people chained me up, they mentioned something about a hardcore challenge... + } + + Truffle: { + DisplayName: Buried Truffle + Chat: You woke me up. Dont eat children. + } + + Cyborg: { + DisplayName: Deactivated Cyborg + Chat: Press F2 to Enter Setup + } + + Chat: At long last, I'm saved! The strangest people tied me up } + } - ProjectileDamageMultipliers: { - Label: Projectile Damage Multipliers - Tooltip: "" + Pause: { + 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! } - ItemFalloff: { - Label: Item Falloff - Tooltip: "" + AncientChiselHotswapBuff: { + DisplayName: THE CURSE OF THE ANCIENT CHISEL + Description: YOU CAN'T USE THAT ACCESSORY SLOT! } - ProjectileFalloff: { - Label: Projectile Falloff - Tooltip: "" + NewIchorPlayerDebuff: { + DisplayName: Ichor + Description: Defense reduced by one third } - DefaultFalloff: { - Tooltip: "" - Label: Default Falloff + BROISACHOJ: { + DisplayName: BRO IS A CHOJ + Description: You are too much of a CHOJ to dash effectively + } + + BuffDescription: { + BeetleMight1: Melee damage and speed increase by 8% + BeetleMight2: Melee damage and speed increase by 8% + BeetleMight3: Melee damage and speed increase by 8% + } + + Anathema: { + DisplayName: Anathema + Description: Enemy attacks can seek you out + } + + BitingEmbrace: { + DisplayName: Summon Tagged + Description: Take 7 more damage from enemies + } + + BrittleBones: { + DisplayName: Summon Tagged + Description: Take 6 more damage from enemies + } + + Hellhex: { + DisplayName: Firecracked + Description: You are going to burst with hellfire at any moment! + } + + Marked: { + DisplayName: Summon Tagged + Description: Take 9 more damage from enemies + } + + PlayerInSpawn: { + DisplayName: Spawn + Description: You're in spawn bro + } + + PressurePoints: { + DisplayName: Summon Tagged + Description: Take 6 more damage from enemies + } + + ShatteredArmor: { + DisplayName: Shattered Armor + Description: You're armor has been shattered by a brutal blow! + } + + Attuning: { + DisplayName: Attuning + Description: Your Spectre armor is attuning to your magic & mind! + } + + UncouthandBoring: { + DisplayName: Uncouth and Boring + Description: You are no longer a charming and mythical philosopher! } } - Falloff: { - Coefficient: { - Tooltip: "" - Label: Coefficient + Items: { + AdventureBag: { + DisplayName: Adventure Bag + Tooltip: Everything you need to start your PvP Adventure! } - Forward: { - Label: Forward + BlightFruit: { Tooltip: "" + DisplayName: Blight Fruit } - Tooltip: "" + AdventureMirror: { + DisplayName: Adventure Mirror + Tooltip: + ''' + Gaze in the mirror to go on adventures + Right click to use + ''' + } } - Statistics: { + PlayerOutlineConfig: { Tooltip: "" - Damage: { - Label: Damage + Self: { + Label: Self Tooltip: "" } - UseTime: { - Label: Use Time + Team: { + Label: Team Tooltip: "" } + } - UseAnimation: { - Label: Use Animation + SoundEffectConfig: { + Tooltip: "" + + NpcHitMarker: { + Label: Npc Hit Marker Tooltip: "" } - ShootSpeed: { - Label: Shoot Speed + PlayerHitMarker: { + Label: Player Hit Marker Tooltip: "" } - Crit: { - Label: Crit + PlayerKillMarker: { + Label: Player Kill Marker Tooltip: "" } + } - Mana: { - Label: Mana + HitMarkerConfig.Tooltip: "" + + Hitsound: { + Tooltip: "" + + OlBetsy: { + Label: Ol Betsy Tooltip: "" } - Scale: { - Label: Scale + Buwee: { + Label: Buwee Tooltip: "" } - Knockback: { - Label: Knockback + Blip: { + Label: Blip Tooltip: "" } - Value: { + Crash: { + Label: Crash Tooltip: "" - Label: Value } - } - - OptionalInt: { - Tooltip: "" - Value: { - Label: Value + Squelchy: { + Label: Squelchy Tooltip: "" } - } - OptionalFloat: { - Tooltip: "" + MarrowMurder: { + Label: Marrow Murder + Tooltip: "" + } - Value: { - Label: Value + Part1: { + Label: Part1 Tooltip: "" } } - HitMarkerConfig: { + MarkerConfig`1: { Sound: { Label: Sound Tooltip: "" @@ -557,172 +659,206 @@ Mods: { Label: Pitch Maximum Tooltip: "" } + } + PlayerHitMarkerConfig: { Tooltip: "" - SoundPath: { + SilenceVanilla: { + Label: Silence Vanilla Tooltip: "" - Label: Sound Path } } - SoundEffectConfig: { + PlayerKillMarkerConfig: { Tooltip: "" - NpcHitMarker: { - Label: Npc Hit Marker + SilenceVanilla: { + Label: Silence Vanilla Tooltip: "" } + } - PlayerHitMarker: { - Label: Player Hit Marker + Killsound: { + Tooltip: "" + + Zacharry: { + Label: Zacharry Tooltip: "" } - PlayerKillMarker: { - Label: Player Kill Marker + Ronaldoz: { + Label: Ronaldoz Tooltip: "" } - } - PlayerHitMarkerConfig: { - Tooltip: "" + Sharkron: { + Label: Sharkron + Tooltip: "" + } - SilenceVanilla: { - Label: Silence Vanilla + Shronker: { + Label: Shronker Tooltip: "" } - } - KillMarkerConfig: { - SoundPath: { + FatalCarCrash: { + Label: Fatal Car Crash Tooltip: "" - Label: Sound Path } - } - PlayerKillMarkerConfig: { - SilenceVanilla: { + Part2: { + Label: Part2 Tooltip: "" - Label: Silence Vanilla } + } + PlayerDamageBalanceConfig: { Tooltip: "" - } - MarkerConfig`1: { - PitchMaximum: { + ItemDamageMultipliers: { + Label: Item Damage Multipliers Tooltip: "" - Label: Pitch Maximum } - PitchMinimum: { + ProjectileDamageMultipliers: { + Label: Projectile Damage Multipliers Tooltip: "" - Label: Pitch Minimum } - Volume: { + ItemFalloff: { + Label: Item Falloff Tooltip: "" - Label: Volume } - Sound: { + ProjectileFalloff: { + Label: Projectile Falloff + Tooltip: "" + } + + DefaultFalloff: { + Label: Default Falloff Tooltip: "" - Label: Sound } } - Killsound: { - Part2: { - Label: Part2 + Falloff: { + Tooltip: "" + + Coefficient: { + Label: Coefficient Tooltip: "" } - FatalCarCrash: { - Label: Fatal Car Crash + Forward: { + Label: Forward Tooltip: "" } + } - Shronker: { - Label: Shronker + TeamLifeConfig: { + Tooltip: "" + + Share: { + Label: Share Tooltip: "" } + } - Sharkron: { - Label: Sharkron + InvasionSizeValue: { + Tooltip: "" + + Value: { + Label: Value Tooltip: "" } + } - Ronaldoz: { - Label: Ronaldoz + Statistics: { + Tooltip: "" + + Damage: { + Label: Damage Tooltip: "" } - Zacharry: { - Label: Zacharry + UseTime: { + Label: Use Time Tooltip: "" } - Tooltip: "" - } + UseAnimation: { + Label: Use Animation + Tooltip: "" + } - Hitsound: { - Part1: { - Label: Part1 + ShootSpeed: { + Label: Shoot Speed Tooltip: "" } - MarrowMurder: { - Label: Marrow Murder + Crit: { + Label: Crit Tooltip: "" } - Squelchy: { - Label: Squelchy + Mana: { + Label: Mana Tooltip: "" } - Crash: { - Label: Crash + Scale: { + Label: Scale Tooltip: "" } - Blip: { - Label: Blip + Knockback: { + Label: Knockback Tooltip: "" } - Buwee: { - Label: BuWEEEEE + Value: { + Label: Value Tooltip: "" } + } - OlBetsy: { - Label: Ol' Betsy + OptionalInt: { + Tooltip: "" + + Value: { + Label: Value Tooltip: "" } + } + OptionalFloat: { Tooltip: "" + + Value: { + Label: Value + Tooltip: "" + } } WorldGenerationConfig: { - LifeFruitMinimumDistanceBetween: { + Tooltip: "" + + LifeFruitChanceDenominator: { + Label: Life Fruit Chance Denominator Tooltip: "" - Label: Life Fruit Minimum Distance Between } LifeFruitExpertChanceDenominator: { - Tooltip: "" Label: Life Fruit Expert Chance Denominator + Tooltip: "" } - LifeFruitChanceDenominator: { + LifeFruitMinimumDistanceBetween: { + Label: Life Fruit Minimum Distance Between Tooltip: "" - Label: Life Fruit Chance Denominator } - Tooltip: "" - PlanteraBulbChanceDenominator: { Label: Plantera Bulb Chance Denominator Tooltip: "" @@ -761,11 +897,6 @@ Mods: { Label: No Mechanical Boss Summon Drops Tooltip: "" } - - NoBiomeKeyDrops: { - Label: No Biome Key Drops - Tooltip: "" - } } FloatStatistic: { @@ -785,305 +916,108 @@ Mods: { Tooltip: "" } } - - InvasionSizeValue: { - Value: { - Tooltip: "" - Label: Value - } - - Tooltip: "" - } - - TeamLifeConfig: { - Tooltip: "" - - Share: { - Label: Share - Tooltip: "" - } - } - - GhostHealMaxDistanceNpc: { - Label: Ghost Heal Max Distance Npc - Tooltip: "" - } - - ProjectileCollisionDamageReduction: { - Label: Projectile Collision Damage Reduction - Tooltip: "" - } - - NoLineOfSightDamageReduction: { - Label: No Line Of Sight Damage Reduction - Tooltip: "" - } - } - - Item: { - Disabled: Cannot be used in this gamemode - NoUndergroundEmpressButterfly: Cannot be released here underground - NoUndergroundQueenSlimeCrystal: Cannot be summoned here underground - } - - Player.CannotRecall: Cannot recall! - Tiles.LockedLihzahrdChest.MapEntry: Locked Lihzahrd Chest - Sandstorm: "[c/FFC864:Desert winds are picking up...]" - Rain: "[c/6496FF:A storm is brewing overhead...]" - - NPCs: { - Bound: { - Merchant.DisplayName: Bound Merchant - ArmsDealer.DisplayName: Bound Arms Dealer - WitchDoctor.DisplayName: Bound Witch Doctor - Demolitionist.DisplayName: Bound. Demolitionist - - Steampunker: { - DisplayName: Chained Steampunker - Chat: At long last, I'm saved! The strangest people chained me up, they mentioned something about a hardcore challenge... - } - - Truffle: { - DisplayName: Buried Truffle - Chat: You woke me up. Dont eat children. - } - - Cyborg: { - DisplayName: Deactivated Cyborg - Chat: Press F2 to Enter Setup - } - - Chat: At long last, I'm saved! The strangest people tied me up - } } - Pause: { - True: "[c/FF0000:The game has been paused.]" - False: "[c/00FF00:The game has been resumed.]" - } + Tiles.LockedLihzahrdChest.MapEntry: Mods.PvPAdventure.Tiles.LockedLihzahrdChest.MapEntry Buffs: { - ShinyStoneHotswap: { - DisplayName: Shiny Stone Hotswap - Description: Shiny Stone is charging up! + Anathema: { + DisplayName: Anathema + Description: Mods.PvPAdventure.Buffs.Anathema.Description } AncientChiselHotswapBuff: { - DisplayName: THE CURSE OF THE ANCIENT CHISEL - Description: YOU CAN'T USE THAT ACCESSORY SLOT! - } - - NewIchorPlayerDebuff: { - DisplayName: Ichor - Description: Defense reduced by one third - } - - BROISACHOJ: { - DisplayName: BRO IS A CHOJ - Description: You are too much of a CHOJ to dash effectively - } - - BuffDescription: { - BeetleMight1: Melee damage and speed increase by 8% - BeetleMight2: Melee damage and speed increase by 8% - BeetleMight3: Melee damage and speed increase by 8% + DisplayName: Ancient Chisel Hotswap Buff + Description: Mods.PvPAdventure.Buffs.AncientChiselHotswapBuff.Description } - Anathema: { - DisplayName: Anathema - Description: Enemy attacks can seek you out + Attuning: { + DisplayName: Attuning + Description: Mods.PvPAdventure.Buffs.Attuning.Description } BitingEmbrace: { - DisplayName: Summon Tagged - Description: Take 7 more damage from enemies + DisplayName: Biting Embrace + Description: Mods.PvPAdventure.Buffs.BitingEmbrace.Description } BrittleBones: { - DisplayName: Summon Tagged - Description: Take 6 more damage from enemies + DisplayName: Brittle Bones + Description: Mods.PvPAdventure.Buffs.BrittleBones.Description + } + + BROISACHOJ: { + DisplayName: B R O I S A C H O J + Description: Mods.PvPAdventure.Buffs.BROISACHOJ.Description } Hellhex: { - DisplayName: Firecracked - Description: You are going to burst with hellfire at any moment! + DisplayName: Hellhex + Description: Mods.PvPAdventure.Buffs.Hellhex.Description } Marked: { - DisplayName: Summon Tagged - Description: Take 9 more damage from enemies + DisplayName: Marked + Description: Mods.PvPAdventure.Buffs.Marked.Description + } + + NewIchorPlayerDebuff: { + DisplayName: New Ichor Player Debuff + Description: Mods.PvPAdventure.Buffs.NewIchorPlayerDebuff.Description } PlayerInSpawn: { - DisplayName: Spawn - Description: You're in spawn bro + DisplayName: Player In Spawn + Description: Mods.PvPAdventure.Buffs.PlayerInSpawn.Description } PressurePoints: { - DisplayName: Summon Tagged - Description: Take 6 more damage from enemies + DisplayName: Pressure Points + Description: Mods.PvPAdventure.Buffs.PressurePoints.Description } ShatteredArmor: { DisplayName: Shattered Armor - Description: You're armor has been shattered by a brutal blow! + Description: Mods.PvPAdventure.Buffs.ShatteredArmor.Description } - Attuning: { - DisplayName: Attuning - Description: Your Spectre armor is attuning to your magic & mind! + ShinyStoneHotswap: { + DisplayName: Shiny Stone Hotswap + Description: Mods.PvPAdventure.Buffs.ShinyStoneHotswap.Description } UncouthandBoring: { - DisplayName: Uncouth and Boring - Description: You are no longer a charming and mythical philosopher! + DisplayName: Uncouthand Boring + Description: Mods.PvPAdventure.Buffs.UncouthandBoring.Description } } Items: { AdventureBag: { DisplayName: Adventure Bag - Tooltip: Everything you need to start your PvP Adventure! - } - - BlightFruit: { - Tooltip: "" - DisplayName: Blight Fruit - } - } - - AdventureClientConfig: { - DisplayName: Adventure Client Config - - PlayerOutline: { - Label: Player Outline - Tooltip: "" - } - - ShiftEnterOpensAllChat: { - Label: Shift Enter Opens All Chat - Tooltip: "" - } - - ShowPauseMessage: { - Label: Show Pause Message - Tooltip: "" - } - - SoundEffect: { - Label: Sound Effect Tooltip: "" } BlightFruit: { DisplayName: Blight Fruit - Tooltip: Permanently decreases maximum life by 5 - } - } - - PlayerOutlineConfig: { - Tooltip: "" - - Self: { - Label: Self - Tooltip: "" - } - - Team: { - Label: Team - Tooltip: "" - } - } - - SoundEffectConfig: { - Tooltip: "" - - NpcHitMarker: { - Label: Npc Hit Marker - Tooltip: "" - } - - PlayerHitMarker: { - Label: Player Hit Marker - Tooltip: "" - } - - PlayerKillMarker: { - Label: Player Kill Marker - Tooltip: "" - } - } - - HitMarkerConfig.Tooltip: "" - - Hitsound: { - Tooltip: "" - OlBetsy.Label: Ol Betsy - Buwee.Label: Buwee - Blip.Label: Blip - Crash.Label: Crash - Squelchy.Label: Squelchy - MarrowMurder.Label: Marrow Murder - Part1.Label: Part1 - } - - MarkerConfig`1: { - Sound: { - Label: Sound - Tooltip: "" - } - - Volume: { - Label: Volume - Tooltip: "" - } - - PitchMinimum: { - Label: Pitch Minimum - Tooltip: "" - } - - PitchMaximum: { - Label: Pitch Maximum - Tooltip: "" - } - } - - PlayerHitMarkerConfig: { - Tooltip: "" - - SilenceVanilla: { - Label: Silence Vanilla Tooltip: "" } - } - PlayerKillMarkerConfig: { - Tooltip: "" - - SilenceVanilla: { - Label: Silence Vanilla + AdventureMirror: { + DisplayName: Adventure Mirror Tooltip: "" } } - Killsound: { - Tooltip: "" - Zacharry.Label: Zacharry - Ronaldoz.Label: Ronaldoz - Sharkron.Label: Sharkron - Shronker.Label: Shronker - FatalCarCrash.Label: Fatal Car Crash - Part2.Label: Part2 - } - Items: { - AdventureMirror: { - DisplayName: Adventure Mirror - Tooltip: - ''' - Gaze in the mirror to go on adventures - Right click to use - ''' + NPCs: { + Bound: { + ArmsDealer.DisplayName: Bound. Arms Dealer + Cyborg.DisplayName: Bound. Cyborg + Demolitionist.DisplayName: Bound. Demolitionist + Merchant.DisplayName: Bound. Merchant + Steampunker.DisplayName: Bound. Steampunker + Truffle.DisplayName: Bound. Truffle + WitchDoctor.DisplayName: Bound. Witch Doctor } } } diff --git a/System/GameManager.cs b/System/GameManager.cs index 06973278..ce8f8d01 100644 --- a/System/GameManager.cs +++ b/System/GameManager.cs @@ -23,7 +23,7 @@ namespace PvPAdventure.System; public class GameManager : ModSystem { public int TimeRemaining { get; set; } - private int? _startGameCountdown = 0; + public int? _startGameCountdown = null; private Phase _currentPhase; private static readonly FieldInfo _bigProgressBarSystemCurrentBarField = @@ -125,7 +125,6 @@ private void OnMainStartRain(On_Main.orig_StartRain orig) orig(); ChatHelper.BroadcastChatMessage(NetworkText.FromKey("Mods.PvPAdventure.Rain"), Color.White); } - public override void PostUpdateTime() { // The Nurse is never allowed to spawn. @@ -148,7 +147,7 @@ public override void PostUpdateTime() else if (_startGameCountdown <= (60 * 3) && _startGameCountdown % 60 == 0) { ChatHelper.BroadcastChatMessage(NetworkText.FromLiteral($"{_startGameCountdown / 60}..."), - Color.Green); + Color.Crimson); } } @@ -157,13 +156,14 @@ public override void PostUpdateTime() case Phase.Playing: { if (--TimeRemaining <= 0) + { CurrentPhase = Phase.Waiting; + } break; } } } - public void StartGame(int time) { CurrentPhase = Phase.Waiting; From 7bbf8da836fd44750e26a0e60f083f01198ef253 Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Sat, 15 Nov 2025 21:18:02 -0800 Subject: [PATCH 176/206] Revert "Merge branch 'feature/RTP-Spawn-Selector' into feature/missinginmaster" This reverts commit fda2e635c132769cae6523a2cbee04bfc2c5eac6. --- AdventureClientConfig.cs | 5 - Assets/SpawnSelector/Arrow.png | Bin 359 -> 0 bytes Assets/SpawnSelector/CornerMask4px.png | Bin 0 -> 268 bytes Assets/SpawnSelector/FadeHorizontal.png | Bin 0 -> 80 bytes Content/Items/AdventureMirror.cs | 64 +- Content/Items/AdventureMirrorGlobalItem.cs | 31 + Core/Debug/DebugKeybinds.cs | 30 +- .../{Systems => Hooks}/ItemSlotHooks.cs | 42 +- .../SpawnSelector/Hooks/UnityHooks.cs | 45 ++ .../Players/AdventureMirrorPlayer.cs | 245 ++---- ...wInfoPlayer.cs => ModifyPlayerDrawInfo.cs} | 10 +- .../Systems/SpawnSelectorState.cs | 1 + .../Systems/SpawnSelectorSystem.cs | 7 +- .../SpawnSelector/Systems/UnityHooks.cs | 28 - .../SpawnSelector/UI/PopupTextHelper.cs | 42 - .../UI/UISpawnSelectorCharacterListItem.cs | 91 +-- .../SpawnSelector/UI/UISpawnSelectorPanel.cs | 104 +-- .../UI/UISpawnSelectorRandomPanel.cs | 7 - Core/Helpers/AssetLoader.cs | 1 - Localization/en-US.hjson | 716 ++++++++++-------- System/GameManager.cs | 8 +- 21 files changed, 699 insertions(+), 778 deletions(-) delete mode 100644 Assets/SpawnSelector/Arrow.png create mode 100644 Assets/SpawnSelector/CornerMask4px.png create mode 100644 Assets/SpawnSelector/FadeHorizontal.png create mode 100644 Content/Items/AdventureMirrorGlobalItem.cs rename Core/Features/SpawnSelector/{Systems => Hooks}/ItemSlotHooks.cs (52%) create mode 100644 Core/Features/SpawnSelector/Hooks/UnityHooks.cs rename Core/Features/SpawnSelector/Players/{ModifyDrawInfoPlayer.cs => ModifyPlayerDrawInfo.cs} (87%) delete mode 100644 Core/Features/SpawnSelector/Systems/UnityHooks.cs delete mode 100644 Core/Features/SpawnSelector/UI/PopupTextHelper.cs diff --git a/AdventureClientConfig.cs b/AdventureClientConfig.cs index ffb84585..9122fef1 100644 --- a/AdventureClientConfig.cs +++ b/AdventureClientConfig.cs @@ -17,9 +17,6 @@ public class AdventureClientConfig : ModConfig public bool IsVanillaDashEnabled { get; set; } [DefaultValue(true)] public bool ShowPauseMessage { get; set; } - [DefaultValue(false)] public bool OpenMapAfterRecall; - [DefaultValue(false)] public bool ShowPopupText; - public class PlayerOutlineConfig { public bool Self { get; set; } = true; @@ -131,8 +128,6 @@ public class PlayerKillMarkerConfig : KillMarkerConfig [DefaultValue(null)] [NullAllowed] public HitMarkerConfig NpcHitMarker { get; set; } [DefaultValue(null)] [NullAllowed] public PlayerHitMarkerConfig PlayerHitMarker { get; set; } [DefaultValue(null)] [NullAllowed] public PlayerKillMarkerConfig PlayerKillMarker { get; set; } - - } public SoundEffectConfig SoundEffect { get; set; } = new(); diff --git a/Assets/SpawnSelector/Arrow.png b/Assets/SpawnSelector/Arrow.png deleted file mode 100644 index 07067dee08422b61d9afaacb5fa6bef3a04c9058..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 359 zcmeAS@N?(olHy`uVBq!ia0vp^(m*W7!3HGnN~S&oQk(@Ik;M!Qd`Cc-ajG^SPz9r; zr;B5VM`!Y%|Nrfo_c93I%}Gi~NN{|1f?HMK>Dl)8Vg{3vCGVskiE`mgIH+c!`-7ux zM(Hhe3+bDQ@Ae+FsI}C-DBjvHn0`a&5PO-}dQ~eIHoe9N%bTAgTe~DWM4f DxbB2V diff --git a/Assets/SpawnSelector/CornerMask4px.png b/Assets/SpawnSelector/CornerMask4px.png new file mode 100644 index 0000000000000000000000000000000000000000..8f03f4353fab813910a3a823b9e04bef34e0e43c GIT binary patch literal 268 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=mpxq^Ln`LHy=};MSV4p(@ZbLb zb3H{lZ)&8@W3iUKarBMIyO`v|bBf=+^Ixzk%l7-{*2%~FKi<2(UvA#1U7O3Nn}4_) z{raKXuV){VbL^V7Ph^O4m`oRZzCJU5@$riP0X5vAp?l?)oZ0{L-P^lQU#_vX7hI@P Tt+JF6FS$$$R;|6k9>*7jZH eLAl2peun<-g8yqaZ{Y?iVeoYIb6Mw<&;$Vdrx$+! literal 0 HcmV?d00001 diff --git a/Content/Items/AdventureMirror.cs b/Content/Items/AdventureMirror.cs index c30aaa0c..be84ac39 100644 --- a/Content/Items/AdventureMirror.cs +++ b/Content/Items/AdventureMirror.cs @@ -1,7 +1,7 @@ -using PvPAdventure.Core.Features.SpawnSelector.Players; -using PvPAdventure.Core.Features.SpawnSelector.UI; -using PvPAdventure.System; +using Microsoft.Xna.Framework; +using PvPAdventure.Core.Features.SpawnSelector.Players; using Terraria; +using Terraria.Audio; using Terraria.ID; using Terraria.ModLoader; @@ -25,54 +25,58 @@ public override void SetDefaults() public override bool CanUseItem(Player player) { - var amp = player.GetModPlayer(); - var gm = ModContent.GetInstance(); + var adventureMirrorPlayer = player.GetModPlayer(); - if (gm.CurrentPhase != GameManager.Phase.Playing) + if (adventureMirrorPlayer.IsPlayerInSpawnRegion()) { - if (player.whoAmI == Main.myPlayer) - PopupTextHelper.NewText("Cannot use before game has started!"); - return false; - } + PopupText.NewText(new AdvancedPopupRequest + { + Color = Color.Crimson, + Text = "Cannot use in spawn!", + Velocity = new(0f, -4f), + DurationInFrames = 60 + }, player.Top); - if (amp.IsPlayerInSpawnRegion()) - { - if (player.whoAmI == Main.myPlayer) - PopupTextHelper.NewText("Cannot use in spawn region!"); return false; - } + }; - if (amp.MirrorActive) + if (adventureMirrorPlayer.CancelIfPlayerMoves()) return false; - if (player.whoAmI == Main.myPlayer && player.velocity.LengthSquared() > 0f) - { - //PopupTextHelper.NewText("Cannot use while moving!"); + if (adventureMirrorPlayer.MirrorActive) return false; - } return true; } - public override bool AltFunctionUse(Player player) => true; public override bool CanRightClick() => true; public override bool ConsumeItem(Player player) => false; public override void RightClick(Player player) { - if (!player.GetModPlayer().TryStartMirrorChannel()) + var adventureMirrorPlayer = player.GetModPlayer(); + + if (adventureMirrorPlayer.CancelIfPlayerMoves()) return; + + if (adventureMirrorPlayer.MirrorActive) + return; + + var config = ModContent.GetInstance(); + int recallFrames = config.AdventureMirrorRecallFrames + 1; + + SoundEngine.PlaySound(SoundID.Item6); // magic mirror + + adventureMirrorPlayer.StartMirrorUse(recallFrames); } public override bool? UseItem(Player player) { - var amp = player.GetModPlayer(); - amp.TryStartMirrorChannel(); - return true; - } + var config = ModContent.GetInstance(); + int recallFrames = config.AdventureMirrorRecallFrames + 1; - public override void UpdateInventory(Player player) - { - // Force favorite every tick - Item.favorited = true; + var mp = player.GetModPlayer(); + mp.StartMirrorUse(recallFrames); + + return true; } } diff --git a/Content/Items/AdventureMirrorGlobalItem.cs b/Content/Items/AdventureMirrorGlobalItem.cs new file mode 100644 index 00000000..12d66652 --- /dev/null +++ b/Content/Items/AdventureMirrorGlobalItem.cs @@ -0,0 +1,31 @@ +using PvPAdventure.Core.Features.SpawnSelector.Players; +using Terraria; +using Terraria.ModLoader; + +namespace PvPAdventure.Content.Items +{ + public class AdventureMirrorGlobalItem : GlobalItem + { + public override bool InstancePerEntity => true; + + // Force the item to always be favorited + public override void UpdateInventory(Item item, Player player) + { + if (item.type == ModContent.ItemType()) + { + item.favorited = true; // Force on every tick + } + } + + public override bool CanPickup(Item item, Player player) + { + // Disallow item pickup while timer is on + if (player.GetModPlayer().MirrorTimer > 0) + { + return false; + } + + return base.CanPickup(item, player); + } + } +} \ No newline at end of file diff --git a/Core/Debug/DebugKeybinds.cs b/Core/Debug/DebugKeybinds.cs index 8dd6a11f..dddcf3e2 100644 --- a/Core/Debug/DebugKeybinds.cs +++ b/Core/Debug/DebugKeybinds.cs @@ -1,4 +1,6 @@ -using Microsoft.Xna.Framework.Input; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Input; +using PvPAdventure.Core.Features.SpawnSelector.Systems; using Terraria; using Terraria.GameInput; using Terraria.ModLoader; @@ -12,11 +14,15 @@ public class DebugKeybinds : ModSystem { public ModKeybind OpenControls { get; private set; } public ModKeybind SwitchTeams { get; private set; } + public ModKeybind AddPlayerToSpawnSelector { get; private set; } + public ModKeybind ClearPlayersFromSpawnSelector { get; private set; } public override void Load() { - OpenControls = KeybindLoader.RegisterKeybind(Mod, "[DEBUG] OpenControls", Keys.NumPad0); - SwitchTeams = KeybindLoader.RegisterKeybind(Mod, "[DEBUG] SwitchTeams", Keys.NumPad1); + OpenControls = KeybindLoader.RegisterKeybind(Mod, "OpenControls", Keys.NumPad0); + SwitchTeams = KeybindLoader.RegisterKeybind(Mod, "SwitchTeams", Keys.NumPad1); + AddPlayerToSpawnSelector = KeybindLoader.RegisterKeybind(Mod, "AddPlayerToSpawnSelector", Keys.NumPad2); + ClearPlayersFromSpawnSelector = KeybindLoader.RegisterKeybind(Mod, "ClearPlayersFromSpawnSelector", Keys.NumPad3); } } @@ -36,7 +42,23 @@ public override void ProcessTriggers(TriggersSet triggersSet) if (key.SwitchTeams.JustPressed) { Player.team = (Player.team + 1) % 6; // Cycle through teams 0-5 - Main.NewText("[DEBUG] " + Player.name + " switched to team: " + (Terraria.Enums.Team)Player.team); + Main.NewText(Player.name + " switched to team: " + (Terraria.Enums.Team)Player.team); + } + + if (key.AddPlayerToSpawnSelector.JustPressed) + { + var sys = ModContent.GetInstance(); + sys.state.spawnSelectorPanel.DebugAddPlayer(); + Main.NewText("Added SpawnSelectorSystem player"); + //sys.state.spawnSelectorPanel.Rebuild(); + } + + if (key.ClearPlayersFromSpawnSelector.JustPressed) + { + var sys = ModContent.GetInstance(); + sys.state.spawnSelectorPanel.DebugClearPlayers(); + Main.NewText("Cleared SpawnSelectorSystem players"); + //sys.state.spawnSelectorPanel.Rebuild(); } } } diff --git a/Core/Features/SpawnSelector/Systems/ItemSlotHooks.cs b/Core/Features/SpawnSelector/Hooks/ItemSlotHooks.cs similarity index 52% rename from Core/Features/SpawnSelector/Systems/ItemSlotHooks.cs rename to Core/Features/SpawnSelector/Hooks/ItemSlotHooks.cs index d4a974ed..dc3f9dbb 100644 --- a/Core/Features/SpawnSelector/Systems/ItemSlotHooks.cs +++ b/Core/Features/SpawnSelector/Hooks/ItemSlotHooks.cs @@ -2,15 +2,7 @@ using Terraria.ModLoader; using Terraria.UI; using PvPAdventure.Content.Items; -using PvPAdventure.Core.Features.SpawnSelector.UI; -using PvPAdventure.System.Client; -using Microsoft.Xna.Framework.Input; -namespace PvPAdventure.Core.Features.SpawnSelector.Systems; - -/// -/// Prevents the Adventure Mirror from being removed from the player inventory via trashing or selling. -/// public class ItemSlotHooks : ModSystem { public override void Load() @@ -36,10 +28,6 @@ private static bool Hook_LeftClick_SellOrTrash( if (!item.IsAir && item.type == ModContent.ItemType()) { - if (Main.keyState.IsKeyDown(Keys.LeftShift) && Main.mouseLeft && Main.mouseLeftRelease) - { - PopupTextHelper.NewText("Cannot quick trash Adventure Mirror!"); - } //SoundEngine.PlaySound(SoundID.MenuClose); return false; // skip SellOrTrash completely } @@ -47,30 +35,20 @@ private static bool Hook_LeftClick_SellOrTrash( return orig(inv, context, slot); } - private static bool IsAdventureMirror(Item item) - => !item.IsAir && item.type == ModContent.ItemType(); - // DRAGGING ONTO THE TRASH SLOT private static void Hook_LeftClick_ItemArray( On_ItemSlot.orig_LeftClick_ItemArray_int_int orig, Item[] inv, int context, int slot) { - // 1) Hard block: putting mirror into any chest/bank slot - bool isStorageSlot = - context == ItemSlot.Context.ChestItem || - context == ItemSlot.Context.BankItem; // Piggy bank - if (isStorageSlot && - IsAdventureMirror(Main.mouseItem)) // we are dragging the mirror onto this slot + if (context == ItemSlot.Context.TrashItem + && !Main.mouseItem.IsAir + && Main.mouseItem.type == ModContent.ItemType()) { - if (Main.mouseLeft && Main.mouseLeftRelease) - PopupTextHelper.NewText("Cannot store Adventure Mirror!"); - - // Do NOT call orig -> cancel the placement - return; + //SoundEngine.PlaySound(SoundID.MenuClose); + return; } - // Fallback to vanilla behavior orig(inv, context, slot); } @@ -81,14 +59,12 @@ private static bool Hook_SellItem( Item item, int stack) { - if (IsAdventureMirror(item)) + if (!item.IsAir && item.type == ModContent.ItemType()) { - if (Main.mouseLeft && Main.mouseLeftRelease) - PopupTextHelper.NewText("Cannot sell Adventure Mirror!"); - - return false; + //SoundEngine.PlaySound(SoundID.MenuClose); + return false; } return orig(self, item, stack); } -} \ No newline at end of file +} diff --git a/Core/Features/SpawnSelector/Hooks/UnityHooks.cs b/Core/Features/SpawnSelector/Hooks/UnityHooks.cs new file mode 100644 index 00000000..a6c1052c --- /dev/null +++ b/Core/Features/SpawnSelector/Hooks/UnityHooks.cs @@ -0,0 +1,45 @@ +using Microsoft.Xna.Framework; +using PvPAdventure.Core.Features.SpawnSelector.Systems; +using System; +using Terraria; +using Terraria.ModLoader; + +namespace PvPAdventure.Core.Features.SpawnSelector.Hooks; + +/// +/// This allows the player to click on teammates to teleport to them. +/// +public class UnityHooks : ModSystem +{ + public override void Load() + { + Main.QueueMainThreadAction(() => + { + On_Player.HasUnityPotion += OnHasUnityPotion; + On_Player.UnityTeleport += OnUnityTeleport; + }); + } + + public override void Unload() + { + Main.QueueMainThreadAction(() => + { + On_Player.HasUnityPotion -= OnHasUnityPotion; + On_Player.UnityTeleport -= OnUnityTeleport; + }); + } + + private void OnUnityTeleport(On_Player.orig_UnityTeleport orig, Player self, Vector2 telePos) + { + SpawnSelectorSystem.SetEnabled(false); + orig(self, telePos); + } + + private static bool OnHasUnityPotion(On_Player.orig_HasUnityPotion orig, Player self) + { + if (SpawnSelectorSystem.GetEnabled()) + return true; + + return orig(self); + } +} diff --git a/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs b/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs index 00ce866a..9c48d582 100644 --- a/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs +++ b/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs @@ -1,7 +1,6 @@ using Microsoft.Xna.Framework; using PvPAdventure.Content.Items; using PvPAdventure.Core.Features.SpawnSelector.Systems; -using PvPAdventure.Core.Features.SpawnSelector.UI; using PvPAdventure.System; using PvPAdventure.System.Client; using Terraria; @@ -10,49 +9,22 @@ using Terraria.GameInput; using Terraria.ID; using Terraria.ModLoader; -using static Terraria.ModLoader.BackupIO; +using static PvPAdventure.System.RegionManager; namespace PvPAdventure.Core.Features.SpawnSelector.Players; public class AdventureMirrorPlayer : ModPlayer { public int MirrorTimer; // frames left - public bool MirrorActive; // currently channeling - public int MirrorCountdownLastSecond = -1; - private bool didRebuildOnDeath; - public bool TryStartMirrorChannel() - { - if (ModContent.GetInstance().CurrentPhase != GameManager.Phase.Playing) - { - if (Player.whoAmI == Main.myPlayer) - PopupTextHelper.NewText("Cannot use before game has started!"); - return false; - } - - if (IsPlayerInSpawnRegion()) - { - if (Player.whoAmI == Main.myPlayer) - PopupTextHelper.NewText("Cannot use in spawn region!"); - return false; - } + public bool MirrorActive; + public void StartMirrorUse(int durationFrames) + { if (MirrorActive) - return false; - - if (Player.whoAmI == Main.myPlayer && IsMoving()) - { - CancelMirrorUse(); - PopupTextHelper.NewText("Cannot use while moving!"); - return false; - } - - SoundEngine.PlaySound(SoundID.Item6); - var config = ModContent.GetInstance(); - int recallFrames = config.AdventureMirrorRecallFrames + 1; + return; MirrorActive = true; - MirrorTimer = recallFrames; - return true; + MirrorTimer = durationFrames; } public bool IsPlayerInSpawnRegion() @@ -68,16 +40,20 @@ public bool IsPlayerInSpawnRegion() return false; } - private bool IsMoving() => Player.velocity.LengthSquared() > 0f; - - private void CancelMirrorUse() + public bool CancelIfPlayerMoves() { - MirrorActive = false; - MirrorTimer = 0; - MirrorCountdownLastSecond = -1; + if (Player.velocity.LengthSquared() <= 0f) + return false; + + // stop the mirror channel + if (MirrorActive) + { + MirrorActive = false; + MirrorTimer = 0; + } - if (Player.itemAnimation > 0 && - Player.HeldItem.type == ModContent.ItemType()) + // stop the actual item use / animation too + if (Player.itemAnimation > 0 && Player.HeldItem.type == ModContent.ItemType()) { Player.controlUseItem = false; Player.channel = false; @@ -85,44 +61,34 @@ private void CancelMirrorUse() Player.itemTime = 0; Player.reuseDelay = 0; } - } - public bool CancelIfPlayerMoves() - { - if (Player.whoAmI != Main.myPlayer) - return false; - - if (!IsMoving()) - return false; + PopupText.NewText(new AdvancedPopupRequest + { + Color = Color.Crimson, + Text = "Cannot use while moving!", + Velocity = new(0f, -4f), + DurationInFrames = 60 + }, Player.Top); - CancelMirrorUse(); - PopupTextHelper.NewText("Cannot use while moving!"); return true; } public override void PostUpdate() { - if (!Player.dead) - { - didRebuildOnDeath = false; - } - - if (Main.dedServ || Player.whoAmI != Main.myPlayer) - return; - - - if (ModContent.GetInstance().CurrentPhase == GameManager.Phase.Playing && Main.mapFullscreen && IsPlayerInSpawnRegion()) - { + // Open SSS whenever player is in spawn region. + if (IsPlayerInSpawnRegion()) SpawnSelectorSystem.SetEnabled(true); - } - else - { + + // Closes SSS whenever map is closed. + if (!Main.mapFullscreen) SpawnSelectorSystem.SetEnabled(false); - } if (!MirrorActive) return; + if (Main.dedServ || Player.whoAmI != Main.myPlayer) + return; + if (CancelIfPlayerMoves()) return; @@ -138,37 +104,43 @@ public override void PostUpdate() if (MirrorTimer > 0 && MirrorTimer % 60 == 0) { int secondsLeft = MirrorTimer / 60; - PopupTextHelper.NewText(secondsLeft.ToString(), Color.LightGreen, showInMultiplayer: true); + PopupText.NewText(new AdvancedPopupRequest + { + Color = Color.Crimson, + Text = secondsLeft.ToString(), + Velocity = new(0f, -4f), + DurationInFrames = 60 + }, Player.Top); } - // Ready to teleport to spawn + // Teleport to spawn if (MirrorTimer <= 0) { - var config = ModContent.GetInstance(); - if (config.OpenMapAfterRecall) - { - // Close player inventory - Main.playerInventory = false; + // Close player inventory + //Main.playerInventory = false; - // Open fullscreen map - Main.mapFullscreen = true; + if (!Main.mapFullscreen) + { + //SoundEngine.PlaySound(SoundID.MenuOpen); + //Main.mapFullscreen = true; - // center the map float worldCenterX = Main.maxTilesX / 2f; float worldCenterY = Main.maxTilesY / 2f; Main.mapFullscreenPos.X = worldCenterX; Main.mapFullscreenPos.Y = worldCenterY; - Main.mapFullscreenScale = 0.21f; // arbitrary value to zoom out that fits the entire map - } - // Teleport to spawn - Vector2 spawnPos = new(Main.spawnTileX * 16, Main.spawnTileY * 16 - 48); - //Main.LocalPlayer.Teleport(spawnPos, 0); - CustomTeleportWithoutSound(spawnPos); + Main.mapFullscreenScale = 0.21f; + + Vector2 spawnPos = new(Main.spawnTileX * 16, Main.spawnTileY * 16 - 48); + //Main.LocalPlayer.Teleport(spawnPos, 0); + CustomTeleportWithoutSound(spawnPos); + } SpawnSelectorSystem.SetEnabled(true); // This is redundant because spawn region already sets it to true ModContent.GetInstance().state.spawnSelectorPanel.Rebuild(); + Player.RemoveAllGrapplingHooks(); + MirrorActive = false; } } @@ -244,109 +216,58 @@ private void CustomTeleportWithoutSound(Vector2 newPos) } } - #region Keybind Handling - public override void ProcessTriggers(TriggersSet triggersSet) - { - var keybinds = ModContent.GetInstance(); - - if (keybinds.AdventureMirrorKeybind.JustPressed) - { - TryUseAdventureMirror(); - } - } - - public void TryUseAdventureMirror() + public override void UpdateDead() { - int mirrorIndex = EnsureMirrorInInventory(); + // debug + //Main.NewText(Player.respawnTimer); - if (mirrorIndex == -1) + // Keeps the player from respawning until they have selected a spawn. + if (Player.respawnTimer <= 10) { - PopupTextHelper.NewText("No Adventure Mirror found in inventory or banks!"); - return; + //Player.respawnTimer = 10; + if (!Main.mapFullscreen) + { + Main.mapFullscreen = true; + SpawnSelectorSystem.SetEnabled(true); + } } - - if (CancelIfPlayerMoves()) - return; - - Player.selectedItem = mirrorIndex; - Player.controlUseItem = true; - Player.ItemCheck(); } - private int EnsureMirrorInInventory() + public override void ProcessTriggers(TriggersSet triggersSet) { - int mirrorType = ModContent.ItemType(); + var keybinds = ModContent.GetInstance(); - // 1. Look in main inventory first - for (int i = 0; i < Player.inventory.Length; i++) + if (keybinds.AdventureMirrorKeybind.JustPressed) { - Item item = Player.inventory[i]; - if (!item.IsAir && item.type == mirrorType) - return i; + TryUseAdventureMirror(); } - - // 2. Try to pull from personal banks - if (TryPullMirrorFromBank(Player.bank, mirrorType, out int invIndex)) - return invIndex; - - if (TryPullMirrorFromBank(Player.bank2, mirrorType, out invIndex)) - return invIndex; - - if (TryPullMirrorFromBank(Player.bank3, mirrorType, out invIndex)) - return invIndex; - - if (TryPullMirrorFromBank(Player.bank4, mirrorType, out invIndex)) // void vault - return invIndex; - - return -1; } - private bool TryPullMirrorFromBank(Chest bank, int mirrorType, out int inventoryIndex) + public void TryUseAdventureMirror() { - inventoryIndex = -1; - - if (bank == null) - return false; - - // Find the mirror inside this bank - int bankSlot = -1; - for (int i = 0; i < bank.item.Length; i++) - { - Item item = bank.item[i]; - if (!item.IsAir && item.type == mirrorType) - { - bankSlot = i; - break; - } - } + // Find a mirror in the player's inventory + int mirrorIndex = -1; - if (bankSlot == -1) - return false; - - // Find a free inventory slot - int freeInvSlot = -1; for (int i = 0; i < Player.inventory.Length; i++) { - if (Player.inventory[i].IsAir) + if (Player.inventory[i].type == ModContent.ItemType()) { - freeInvSlot = i; + mirrorIndex = i; break; } } - if (freeInvSlot == -1) + if (mirrorIndex == -1) { - if (Player.whoAmI == Main.myPlayer) - Main.NewText("No free inventory slot for Adventure Mirror!", Color.Red); - return false; + Main.NewText("You don't have an Adventure Mirror!", Color.Red); + return; } - // Move the item from bank → inventory - Player.inventory[freeInvSlot] = bank.item[bankSlot].Clone(); - bank.item[bankSlot].TurnToAir(); + CancelIfPlayerMoves(); - inventoryIndex = freeInvSlot; - return true; + // Force the player to use the item + Player.selectedItem = mirrorIndex; + Player.controlUseItem = true; + Player.ItemCheck(); } - #endregion } diff --git a/Core/Features/SpawnSelector/Players/ModifyDrawInfoPlayer.cs b/Core/Features/SpawnSelector/Players/ModifyPlayerDrawInfo.cs similarity index 87% rename from Core/Features/SpawnSelector/Players/ModifyDrawInfoPlayer.cs rename to Core/Features/SpawnSelector/Players/ModifyPlayerDrawInfo.cs index af783918..67dd894b 100644 --- a/Core/Features/SpawnSelector/Players/ModifyDrawInfoPlayer.cs +++ b/Core/Features/SpawnSelector/Players/ModifyPlayerDrawInfo.cs @@ -1,20 +1,16 @@ using Microsoft.Xna.Framework; +using Terraria; using Terraria.DataStructures; +using Terraria.GameContent; using Terraria.ModLoader; namespace PvPAdventure.Core.Features.SpawnSelector.Players; -/// -/// Useful for forcing the player to be drawn with full brightness even when in player is in darkness. -/// -public class ModifyDrawInfoPlayer : ModPlayer +public class ModifyPlayerDrawInfo : ModPlayer { public static bool ForceFullBrightOnce; public override void ModifyDrawInfo(ref PlayerDrawSet drawInfo) { - if (drawInfo.headOnlyRender) - return; - if (!ForceFullBrightOnce) return; diff --git a/Core/Features/SpawnSelector/Systems/SpawnSelectorState.cs b/Core/Features/SpawnSelector/Systems/SpawnSelectorState.cs index 77c71bfa..c1d7ae6b 100644 --- a/Core/Features/SpawnSelector/Systems/SpawnSelectorState.cs +++ b/Core/Features/SpawnSelector/Systems/SpawnSelectorState.cs @@ -17,6 +17,7 @@ public override void OnInitialize() UITextPanel chooseYourSpawnPanel = new("Choose Your Spawn", 0.8f, true); chooseYourSpawnPanel.HAlign = 0.5f; + chooseYourSpawnPanel.VAlign = 0f; chooseYourSpawnPanel.Top.Set(10, 0); chooseYourSpawnPanel.BackgroundColor = new Color(73, 94, 171); Append(chooseYourSpawnPanel); diff --git a/Core/Features/SpawnSelector/Systems/SpawnSelectorSystem.cs b/Core/Features/SpawnSelector/Systems/SpawnSelectorSystem.cs index 6dbf5979..4d174412 100644 --- a/Core/Features/SpawnSelector/Systems/SpawnSelectorSystem.cs +++ b/Core/Features/SpawnSelector/Systems/SpawnSelectorSystem.cs @@ -1,5 +1,6 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; +using PvPAdventure.Core.Features.SpawnSelector.UI; using Terraria; using Terraria.ModLoader; using Terraria.UI; @@ -9,14 +10,16 @@ namespace PvPAdventure.Core.Features.SpawnSelector.Systems; [Autoload(Side = ModSide.Client)] public class SpawnSelectorSystem : ModSystem { - public UserInterface ui; + private UserInterface ui; public SpawnSelectorState state; + private UISpawnSelectorPanel teleportPanel; // Track whether the spawn selector is enabled - private static bool Enabled; + private static bool Enabled; // whether the spawn selector is currently showing in the fullscreen map public static void SetEnabled(bool newValue) => Enabled = newValue; public static bool GetEnabled() => Enabled; + // Load and unload hooks public override void Load() { if (!Main.dedServ) diff --git a/Core/Features/SpawnSelector/Systems/UnityHooks.cs b/Core/Features/SpawnSelector/Systems/UnityHooks.cs deleted file mode 100644 index 5952bdc4..00000000 --- a/Core/Features/SpawnSelector/Systems/UnityHooks.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Terraria; -using Terraria.ModLoader; - -namespace PvPAdventure.Core.Features.SpawnSelector.Systems; - -/// -/// This allows the player to click on teammates to teleport to them. -/// -public class UnityHooks : ModSystem -{ - public override void Load() - { - On_Player.HasUnityPotion += OnHasUnityPotion; - } - - public override void Unload() - { - On_Player.HasUnityPotion -= OnHasUnityPotion; - } - - private static bool OnHasUnityPotion(On_Player.orig_HasUnityPotion orig, Player self) - { - if (SpawnSelectorSystem.GetEnabled()) - return true; - - return orig(self); - } -} diff --git a/Core/Features/SpawnSelector/UI/PopupTextHelper.cs b/Core/Features/SpawnSelector/UI/PopupTextHelper.cs deleted file mode 100644 index baa755fa..00000000 --- a/Core/Features/SpawnSelector/UI/PopupTextHelper.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Microsoft.Xna.Framework; -using Terraria; -using Terraria.ModLoader; - -namespace PvPAdventure.Core.Features.SpawnSelector.UI; -public static class PopupTextHelper -{ - public static void NewText(string text, Color color=default, bool showInMultiplayer=false) - { - if (color == default) - color = Color.Crimson; - - var config = ModContent.GetInstance(); - if (!config.ShowPopupText) - { - return; - } - - if (showInMultiplayer) - { - PopupText.NewText(new AdvancedPopupRequest - { - Color = color, - Text = text, - Velocity = new(0f, -4f), - DurationInFrames = 60 - }, Main.LocalPlayer.Top); - return; - } - - if (Main.LocalPlayer.whoAmI == Main.myPlayer) - { - PopupText.NewText(new AdvancedPopupRequest - { - Color = color, - Text = text, - Velocity = new(0f, -4f), - DurationInFrames = 60 - }, Main.LocalPlayer.Top); - } - } -} diff --git a/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs b/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs index 8a539b45..23a90a74 100644 --- a/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs +++ b/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs @@ -4,15 +4,13 @@ using PvPAdventure.Core.Features.SpawnSelector.Systems; using PvPAdventure.Core.Helpers; using ReLogic.Content; -using ReLogic.Graphics; using System; using Terraria; using Terraria.GameContent; using Terraria.GameContent.UI.Elements; -using Terraria.ID; using Terraria.ModLoader; +using Terraria.ModLoader.UI; using Terraria.UI; -using tModPorter; namespace PvPAdventure.Core.Features.SpawnSelector.UI { @@ -29,7 +27,6 @@ internal class UISpawnSelectorCharacterListItem : UIPanel private readonly Asset _playerBGTexture; private readonly int _playerIndex; - public int PlayerIndex => _playerIndex; public UISpawnSelectorCharacterListItem(Player player) { @@ -55,61 +52,24 @@ private void DrawHeadOnMap(Player p) { float scale = Main.mapFullscreenScale; - Vector2 mapPos = new( - (p.position.X + p.width / 2f) / 16f, - (p.position.Y + p.gfxOffY + p.height / 2f) / 16f - ); - Vector2 headPos = new( - (mapPos.X - Main.mapFullscreenPos.X) * scale + Main.screenWidth / 2f, - (mapPos.Y - Main.mapFullscreenPos.Y) * scale + Main.screenHeight / 2f - ); - headPos += new Vector2(34f, 44f); + ((p.position.X + p.width / 2f) / 16f - Main.mapFullscreenPos.X) * scale + + Main.screenWidth / 2f - 14f * scale+48, - CalculatedStyle inner = GetInnerDimensions(); - Rectangle rect = new( - (int)inner.X - 6, - (int)inner.Y - 6, - 100, - 72 + ((p.position.Y + p.gfxOffY + p.height / 2f) / 16f - Main.mapFullscreenPos.Y) * scale + + Main.screenHeight / 2f - 14f * scale+58 ); - Vector2 arrowStart = new(rect.X + rect.Width / 2f, rect.Bottom + 8f); - - Texture2D arrowTex = Ass.Arrow.Value; - Vector2 arrowOrigin = arrowTex.Size() * 0.5f; - - Vector2 dir = headPos - arrowStart; - if (dir.LengthSquared() > 0.001f) - { - dir.Normalize(); - float rotation = dir.ToRotation(); // adjust with +- PiOver2 if your texture points up - Vector2 arrowPos = arrowStart; - - Main.spriteBatch.Draw( - arrowTex, - arrowPos, - null, - Color.White, - rotation, - arrowOrigin, - 1f, - SpriteEffects.None, - 0f - ); - } - Color color = Main.teamColor[p.team]; - Main.MapPlayerRenderer.DrawPlayerHead( - Main.Camera, - p, - headPos, - scale: 1.6f, - borderColor: color - ); - - Utils.DrawBorderString(Main.spriteBatch, p.name, headPos + new Vector2(-20f, 20f), Color.White); + //Main.PlayerRenderer.DrawPlayerHead( + // Main.Camera, + // p, + // headPos, + // scale: 1.3f, + // borderColor: color + //); + Utils.DrawBorderString(Main.spriteBatch, p.name, headPos, Color.White); } private void DrawNineSlice(SpriteBatch sb, int x, int y, int w, int h, Texture2D tex, Color color, int inset, int c = 5) @@ -172,16 +132,15 @@ protected override void DrawSelf(SpriteBatch sb) null, Main.UIScaleMatrix); - ModifyDrawInfoPlayer.ForceFullBrightOnce = true; + ModifyPlayerDrawInfo.ForceFullBrightOnce = true; try { - Vector2 playerDrawPos = pos + Main.screenPosition + new Vector2(34, 9); - Vector2 headDrawPos = pos + new Vector2(38, 28); - - Color myTeamColor = Main.teamColor[Main.LocalPlayer.team]; + Vector2 playerDrawPos = pos + Main.screenPosition + new Vector2(32, 8); //Main.PlayerRenderer.DrawPlayer(Main.Camera,player,playerDrawPos,player.fullRotation,player.fullRotationOrigin,0f,0.9f); - Main.MapPlayerRenderer.DrawPlayerHead(Main.Camera, player, headDrawPos, scale: 1.0f, borderColor: myTeamColor); + + Color myTeamColor = Main.teamColor[Main.LocalPlayer.team]; + Main.PlayerRenderer.DrawPlayerHead(Main.Camera, player, pos+ new Vector2(40,37), scale: 1.3f, borderColor: Color.Yellow); } catch (Exception e) { @@ -189,7 +148,7 @@ protected override void DrawSelf(SpriteBatch sb) } finally { - ModifyDrawInfoPlayer.ForceFullBrightOnce = false; + ModifyPlayerDrawInfo.ForceFullBrightOnce = false; } // Switch back to "normal" UI batch @@ -278,15 +237,15 @@ protected override void DrawSelf(SpriteBatch sb) if (IsMouseHovering) { Main.instance.MouseText("Teleport to " + name); + var old = Main.UIScaleMatrix; - Main.spriteBatch.End(); - Main.spriteBatch.Begin(SpriteSortMode.Immediate,BlendState.AlphaBlend,SamplerState.PointClamp,DepthStencilState.None,RasterizerState.CullCounterClockwise,null,Matrix.Identity); + //Main.spriteBatch.End(); + //Main.spriteBatch.Begin(SpriteSortMode.Immediate,BlendState.AlphaBlend,SamplerState.PointClamp,DepthStencilState.None,RasterizerState.CullCounterClockwise,null,Matrix.Identity); - DrawHeadOnMap(player); - //DrawGuideMarkerOnMap(Main.spriteBatch); + //DrawHeadOnMap(player); - Main.spriteBatch.End(); - Main.spriteBatch.Begin(SpriteSortMode.Deferred,BlendState.AlphaBlend,SamplerState.PointClamp,DepthStencilState.None,RasterizerState.CullCounterClockwise,null,Main.UIScaleMatrix); + //Main.spriteBatch.End(); + //Main.spriteBatch.Begin(SpriteSortMode.Deferred,BlendState.AlphaBlend,SamplerState.PointClamp,DepthStencilState.None,RasterizerState.CullCounterClockwise,null,old); } //Main.NewText(Main.mouseY); // 482,435 is spawn diff --git a/Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs b/Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs index fb802b1c..96f1184c 100644 --- a/Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs +++ b/Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs @@ -38,19 +38,30 @@ private void BuildLayout() var players = new List(); var local = Main.LocalPlayer; - if (local.team != 0) +#if DEBUG + // If we have debug players, use them instead of scanning teammates + if (_debugPlayers.Count > 0) { - for (int i = 0; i < Main.maxPlayers; i++) + players.AddRange(_debugPlayers); + } + else +#endif + { + // ADD TEAMMATES + if (local.team != 0) { - Player p = Main.player[i]; + for (int i = 0; i < Main.maxPlayers; i++) + { + Player p = Main.player[i]; - if (p == null || !p.active || p.dead || p.statLife <= 0) - continue; + if (p == null || !p.active) + continue; - if (p.whoAmI == local.whoAmI || p.team != local.team) - continue; + if (p.whoAmI == local.whoAmI || p.team != local.team) + continue; - players.Add(p); + players.Add(p); + } } } @@ -58,7 +69,7 @@ private void BuildLayout() float itemWidth = UISpawnSelectorCharacterListItem.ItemWidth; float itemHeight = UISpawnSelectorCharacterListItem.ItemHeight; - float randomWidth = itemHeight; + float randomWidth = itemHeight; // square random panel float contentWidth = playerCount * itemWidth + playerCount * Spacing @@ -67,18 +78,13 @@ private void BuildLayout() float panelWidth = contentWidth + HorizontalPadding * 2f; float panelHeight = itemHeight + VerticalPadding * 2f; - if (panelWidth <= 0f) - panelWidth = itemWidth + HorizontalPadding * 2f; - - if (panelHeight <= 0f) - panelHeight = itemHeight + VerticalPadding * 2f; - Width.Set(panelWidth, 0f); Height.Set(panelHeight, 0f); float startX = HorizontalPadding; float y = VerticalPadding; + // Players in a row for (int i = 0; i < playerCount; i++) { float x = startX + i * (itemWidth + Spacing); @@ -91,6 +97,7 @@ private void BuildLayout() _playerItems.Add(row); } + // Square random panel to the right of the last player _randomPanel = new UISpawnSelectorRandomPanel( startX, itemHeight, @@ -101,9 +108,6 @@ private void BuildLayout() ); Append(_randomPanel); - Recalculate(); - RecalculateChildren(); - Log.Debug($"UISpawnSelectorPanel.BuildLayout: players={playerCount}, panelWidth={panelWidth}"); } @@ -113,58 +117,34 @@ public void Rebuild() Log.Debug("UISpawnSelectorPanel.Rebuild: UI rebuilt"); } - public override void Update(GameTime gameTime) - { - if (NeedsRebuild()) - { - Rebuild(); - } - - base.Update(gameTime); - } - public override void Draw(SpriteBatch spriteBatch) { base.Draw(spriteBatch); } - private bool NeedsRebuild() + #region Debug +#if DEBUG + private readonly List _debugPlayers = new(); +#endif + public void DebugAddPlayer() { - var dims = GetDimensions(); - if (dims.Width <= 0f || dims.Height <= 0f) - return true; - - if (_randomPanel == null) - return true; - - var randomDims = _randomPanel.GetDimensions(); - if (randomDims.Width <= 0f || randomDims.Height <= 0f) - return true; - - var local = Main.LocalPlayer; - var players = new List(); - - for (int i = 0; i < Main.maxPlayers; i++) - { - var p = Main.player[i]; - if (p == null || !p.active || p.dead || p.statLife <= 0) - continue; - if (p.whoAmI == local.whoAmI || p.team != local.team) - continue; - - players.Add(p.whoAmI); - } +#if DEBUG + _debugPlayers.Add(Main.LocalPlayer); + BuildLayout(); + Log.Debug($"SpawnSelector DebugAddPlayer: debugPlayers={_debugPlayers.Count}"); +#endif + } - if (players.Count != _playerItems.Count) - return true; + public void DebugClearPlayers() + { +#if DEBUG + _debugPlayers.Clear(); + BuildLayout(); + Log.Debug("SpawnSelector DebugClearPlayers: cleared debug players"); +#endif + } + #endregion - for (int i = 0; i < players.Count; i++) - { - if (_playerItems[i] == null) return true; - if (_playerItems[i].PlayerIndex != players[i]) return true; - } - return false; - } } } diff --git a/Core/Features/SpawnSelector/UI/UISpawnSelectorRandomPanel.cs b/Core/Features/SpawnSelector/UI/UISpawnSelectorRandomPanel.cs index 237cf2d2..886a5461 100644 --- a/Core/Features/SpawnSelector/UI/UISpawnSelectorRandomPanel.cs +++ b/Core/Features/SpawnSelector/UI/UISpawnSelectorRandomPanel.cs @@ -2,11 +2,9 @@ using Microsoft.Xna.Framework.Graphics; using PvPAdventure.Core.Features.SpawnSelector.Systems; using PvPAdventure.Core.Helpers; -using PvPAdventure.System; using Terraria; using Terraria.GameContent.UI.Elements; using Terraria.ID; -using Terraria.ModLoader; using Terraria.UI; namespace PvPAdventure.Core.Features.SpawnSelector.UI @@ -30,11 +28,6 @@ public override void LeftClick(UIMouseEvent evt) { base.LeftClick(evt); - // Redundant check, just to be sure we don't allow any shenanigans - var gm = ModContent.GetInstance(); - if (gm.CurrentPhase != GameManager.Phase.Playing) - return; - if (Main.netMode == NetmodeID.MultiplayerClient) { NetMessage.SendData(MessageID.RequestTeleportationByServer); diff --git a/Core/Helpers/AssetLoader.cs b/Core/Helpers/AssetLoader.cs index 61d92e86..747b6dd3 100644 --- a/Core/Helpers/AssetLoader.cs +++ b/Core/Helpers/AssetLoader.cs @@ -9,7 +9,6 @@ public static class Ass { public static Asset Question_Mark; public static Asset[] MapBG; - public static Asset Arrow; public static bool Initialized { get; set; } diff --git a/Localization/en-US.hjson b/Localization/en-US.hjson index b7012b1e..4fee0157 100644 --- a/Localization/en-US.hjson +++ b/Localization/en-US.hjson @@ -20,8 +20,6 @@ Mods: { AddPlayerToSpawnSelector.DisplayName: Add Player To Spawn Selector RemovePlayerFromSpawnSelector.DisplayName: Remove Player From Spawn Selector ClearPlayersFromSpawnSelector.DisplayName: Clear Players From Spawn Selector - "[DEBUG] OpenControls.DisplayName": "[ D E B U G] Open Controls" - "[DEBUG] SwitchTeams.DisplayName": "[ D E B U G] Switch Teams" } Configs: { @@ -381,7 +379,7 @@ Mods: { } AdventureClientConfig: { - DisplayName: Adventure Client Config + DisplayName: Client PlayerOutline: { Label: Player Outline @@ -394,8 +392,8 @@ Mods: { } ShowPauseMessage: { - Label: Show Pause Message Tooltip: "" + Label: Show Pause Message } SoundEffect: { @@ -403,243 +401,143 @@ Mods: { Tooltip: "" } - BlightFruit: { - DisplayName: Blight Fruit - Tooltip: Permanently decreases maximum life by 5 - } - - OpenMapAfterRecall: { - Label: Open Map After Recall - Tooltip: "" - } - - ShowPopupText: { - Label: Show Popup Text - Tooltip: "" - } - IsVanillaDashEnabled: { Label: Is Vanilla Dash Enabled - Tooltip: "" - } - } - - Item: { - Disabled: Cannot be used in this gamemode - NoUndergroundEmpressButterfly: Cannot be released here underground - NoUndergroundQueenSlimeCrystal: Cannot be summoned here underground - } - - Player.CannotRecall: Cannot recall! - Tiles.LockedLihzahrdChest.MapEntry: Locked Lihzahrd Chest - Sandstorm: "[c/FFC864:Desert winds are picking up...]" - Rain: "[c/6496FF:A storm is brewing overhead...]" - - NPCs: { - Bound: { - Merchant.DisplayName: Bound Merchant - ArmsDealer.DisplayName: Bound Arms Dealer - WitchDoctor.DisplayName: Bound Witch Doctor - Demolitionist.DisplayName: Bound. Demolitionist - - Steampunker: { - DisplayName: Chained Steampunker - Chat: At long last, I'm saved! The strangest people chained me up, they mentioned something about a hardcore challenge... - } - - Truffle: { - DisplayName: Buried Truffle - Chat: You woke me up. Dont eat children. - } - - Cyborg: { - DisplayName: Deactivated Cyborg - Chat: Press F2 to Enter Setup - } - - Chat: At long last, I'm saved! The strangest people tied me up + Tooltip: + ''' + On: Dash as usual with double tap + Off: Disables double tap dash. Use keybind instead + ''' } } - Pause: { - 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! - } - - AncientChiselHotswapBuff: { - DisplayName: THE CURSE OF THE ANCIENT CHISEL - Description: YOU CAN'T USE THAT ACCESSORY SLOT! - } - - NewIchorPlayerDebuff: { - DisplayName: Ichor - Description: Defense reduced by one third - } - - BROISACHOJ: { - DisplayName: BRO IS A CHOJ - Description: You are too much of a CHOJ to dash effectively - } - - BuffDescription: { - BeetleMight1: Melee damage and speed increase by 8% - BeetleMight2: Melee damage and speed increase by 8% - BeetleMight3: Melee damage and speed increase by 8% - } - - Anathema: { - DisplayName: Anathema - Description: Enemy attacks can seek you out - } + PlayerOutlineConfig: { + Tooltip: "" - BitingEmbrace: { - DisplayName: Summon Tagged - Description: Take 7 more damage from enemies + Self: { + Label: Self + Tooltip: "" } - BrittleBones: { - DisplayName: Summon Tagged - Description: Take 6 more damage from enemies + Team: { + Label: Team + Tooltip: "" } + } - Hellhex: { - DisplayName: Firecracked - Description: You are going to burst with hellfire at any moment! - } + CannotModify: You are not permitted to modify this config. - Marked: { - DisplayName: Summon Tagged - Description: Take 9 more damage from enemies - } + PlayerDamageBalanceConfig: { + Tooltip: "" - PlayerInSpawn: { - DisplayName: Spawn - Description: You're in spawn bro + ItemDamageMultipliers: { + Label: Item Damage Multipliers + Tooltip: "" } - PressurePoints: { - DisplayName: Summon Tagged - Description: Take 6 more damage from enemies + ProjectileDamageMultipliers: { + Label: Projectile Damage Multipliers + Tooltip: "" } - ShatteredArmor: { - DisplayName: Shattered Armor - Description: You're armor has been shattered by a brutal blow! + ItemFalloff: { + Label: Item Falloff + Tooltip: "" } - Attuning: { - DisplayName: Attuning - Description: Your Spectre armor is attuning to your magic & mind! + ProjectileFalloff: { + Label: Projectile Falloff + Tooltip: "" } - UncouthandBoring: { - DisplayName: Uncouth and Boring - Description: You are no longer a charming and mythical philosopher! + DefaultFalloff: { + Tooltip: "" + Label: Default Falloff } } - Items: { - AdventureBag: { - DisplayName: Adventure Bag - Tooltip: Everything you need to start your PvP Adventure! + Falloff: { + Coefficient: { + Tooltip: "" + Label: Coefficient } - BlightFruit: { + Forward: { + Label: Forward Tooltip: "" - DisplayName: Blight Fruit } - AdventureMirror: { - DisplayName: Adventure Mirror - Tooltip: - ''' - Gaze in the mirror to go on adventures - Right click to use - ''' - } + Tooltip: "" } - PlayerOutlineConfig: { + Statistics: { Tooltip: "" - Self: { - Label: Self + Damage: { + Label: Damage Tooltip: "" } - Team: { - Label: Team + UseTime: { + Label: Use Time Tooltip: "" } - } - - SoundEffectConfig: { - Tooltip: "" - NpcHitMarker: { - Label: Npc Hit Marker + UseAnimation: { + Label: Use Animation Tooltip: "" } - PlayerHitMarker: { - Label: Player Hit Marker + ShootSpeed: { + Label: Shoot Speed Tooltip: "" } - PlayerKillMarker: { - Label: Player Kill Marker + Crit: { + Label: Crit Tooltip: "" } - } - HitMarkerConfig.Tooltip: "" - - Hitsound: { - Tooltip: "" - - OlBetsy: { - Label: Ol Betsy + Mana: { + Label: Mana Tooltip: "" } - Buwee: { - Label: Buwee + Scale: { + Label: Scale Tooltip: "" } - Blip: { - Label: Blip + Knockback: { + Label: Knockback Tooltip: "" } - Crash: { - Label: Crash + Value: { Tooltip: "" + Label: Value } + } - Squelchy: { - Label: Squelchy - Tooltip: "" - } + OptionalInt: { + Tooltip: "" - MarrowMurder: { - Label: Marrow Murder + Value: { + Label: Value Tooltip: "" } + } - Part1: { - Label: Part1 + OptionalFloat: { + Tooltip: "" + + Value: { + Label: Value Tooltip: "" } } - MarkerConfig`1: { + HitMarkerConfig: { Sound: { Label: Sound Tooltip: "" @@ -659,206 +557,172 @@ Mods: { Label: Pitch Maximum Tooltip: "" } - } - PlayerHitMarkerConfig: { Tooltip: "" - SilenceVanilla: { - Label: Silence Vanilla + SoundPath: { Tooltip: "" + Label: Sound Path } } - PlayerKillMarkerConfig: { + SoundEffectConfig: { Tooltip: "" - SilenceVanilla: { - Label: Silence Vanilla + NpcHitMarker: { + Label: Npc Hit Marker Tooltip: "" } - } - Killsound: { - Tooltip: "" - - Zacharry: { - Label: Zacharry + PlayerHitMarker: { + Label: Player Hit Marker Tooltip: "" } - Ronaldoz: { - Label: Ronaldoz + PlayerKillMarker: { + Label: Player Kill Marker Tooltip: "" } + } - Sharkron: { - Label: Sharkron - Tooltip: "" - } + PlayerHitMarkerConfig: { + Tooltip: "" - Shronker: { - Label: Shronker + SilenceVanilla: { + Label: Silence Vanilla Tooltip: "" } + } - FatalCarCrash: { - Label: Fatal Car Crash + KillMarkerConfig: { + SoundPath: { Tooltip: "" + Label: Sound Path } + } - Part2: { - Label: Part2 + PlayerKillMarkerConfig: { + SilenceVanilla: { Tooltip: "" + Label: Silence Vanilla } - } - PlayerDamageBalanceConfig: { Tooltip: "" + } - ItemDamageMultipliers: { - Label: Item Damage Multipliers - Tooltip: "" - } - - ProjectileDamageMultipliers: { - Label: Projectile Damage Multipliers + MarkerConfig`1: { + PitchMaximum: { Tooltip: "" + Label: Pitch Maximum } - ItemFalloff: { - Label: Item Falloff + PitchMinimum: { Tooltip: "" + Label: Pitch Minimum } - ProjectileFalloff: { - Label: Projectile Falloff + Volume: { Tooltip: "" + Label: Volume } - DefaultFalloff: { - Label: Default Falloff + Sound: { Tooltip: "" + Label: Sound } } - Falloff: { - Tooltip: "" - - Coefficient: { - Label: Coefficient + Killsound: { + Part2: { + Label: Part2 Tooltip: "" } - Forward: { - Label: Forward + FatalCarCrash: { + Label: Fatal Car Crash Tooltip: "" } - } - TeamLifeConfig: { - Tooltip: "" - - Share: { - Label: Share + Shronker: { + Label: Shronker Tooltip: "" } - } - InvasionSizeValue: { - Tooltip: "" - - Value: { - Label: Value + Sharkron: { + Label: Sharkron Tooltip: "" } - } - - Statistics: { - Tooltip: "" - Damage: { - Label: Damage + Ronaldoz: { + Label: Ronaldoz Tooltip: "" } - UseTime: { - Label: Use Time + Zacharry: { + Label: Zacharry Tooltip: "" } - UseAnimation: { - Label: Use Animation - Tooltip: "" - } + Tooltip: "" + } - ShootSpeed: { - Label: Shoot Speed + Hitsound: { + Part1: { + Label: Part1 Tooltip: "" } - Crit: { - Label: Crit + MarrowMurder: { + Label: Marrow Murder Tooltip: "" } - Mana: { - Label: Mana + Squelchy: { + Label: Squelchy Tooltip: "" } - Scale: { - Label: Scale + Crash: { + Label: Crash Tooltip: "" } - Knockback: { - Label: Knockback + Blip: { + Label: Blip Tooltip: "" } - Value: { - Label: Value + Buwee: { + Label: BuWEEEEE Tooltip: "" } - } - - OptionalInt: { - Tooltip: "" - Value: { - Label: Value + OlBetsy: { + Label: Ol' Betsy Tooltip: "" } - } - OptionalFloat: { Tooltip: "" - - Value: { - Label: Value - Tooltip: "" - } } WorldGenerationConfig: { - Tooltip: "" - - LifeFruitChanceDenominator: { - Label: Life Fruit Chance Denominator + LifeFruitMinimumDistanceBetween: { Tooltip: "" + Label: Life Fruit Minimum Distance Between } LifeFruitExpertChanceDenominator: { - Label: Life Fruit Expert Chance Denominator Tooltip: "" + Label: Life Fruit Expert Chance Denominator } - LifeFruitMinimumDistanceBetween: { - Label: Life Fruit Minimum Distance Between + LifeFruitChanceDenominator: { Tooltip: "" + Label: Life Fruit Chance Denominator } + Tooltip: "" + PlanteraBulbChanceDenominator: { Label: Plantera Bulb Chance Denominator Tooltip: "" @@ -897,6 +761,11 @@ Mods: { Label: No Mechanical Boss Summon Drops Tooltip: "" } + + NoBiomeKeyDrops: { + Label: No Biome Key Drops + Tooltip: "" + } } FloatStatistic: { @@ -916,108 +785,305 @@ Mods: { Tooltip: "" } } + + InvasionSizeValue: { + Value: { + Tooltip: "" + Label: Value + } + + Tooltip: "" + } + + TeamLifeConfig: { + Tooltip: "" + + Share: { + Label: Share + Tooltip: "" + } + } + + GhostHealMaxDistanceNpc: { + Label: Ghost Heal Max Distance Npc + Tooltip: "" + } + + ProjectileCollisionDamageReduction: { + Label: Projectile Collision Damage Reduction + Tooltip: "" + } + + NoLineOfSightDamageReduction: { + Label: No Line Of Sight Damage Reduction + Tooltip: "" + } + } + + Item: { + Disabled: Cannot be used in this gamemode + NoUndergroundEmpressButterfly: Cannot be released here underground + NoUndergroundQueenSlimeCrystal: Cannot be summoned here underground + } + + Player.CannotRecall: Cannot recall! + Tiles.LockedLihzahrdChest.MapEntry: Locked Lihzahrd Chest + Sandstorm: "[c/FFC864:Desert winds are picking up...]" + Rain: "[c/6496FF:A storm is brewing overhead...]" + + NPCs: { + Bound: { + Merchant.DisplayName: Bound Merchant + ArmsDealer.DisplayName: Bound Arms Dealer + WitchDoctor.DisplayName: Bound Witch Doctor + Demolitionist.DisplayName: Bound. Demolitionist + + Steampunker: { + DisplayName: Chained Steampunker + Chat: At long last, I'm saved! The strangest people chained me up, they mentioned something about a hardcore challenge... + } + + Truffle: { + DisplayName: Buried Truffle + Chat: You woke me up. Dont eat children. + } + + Cyborg: { + DisplayName: Deactivated Cyborg + Chat: Press F2 to Enter Setup + } + + Chat: At long last, I'm saved! The strangest people tied me up + } } - Tiles.LockedLihzahrdChest.MapEntry: Mods.PvPAdventure.Tiles.LockedLihzahrdChest.MapEntry + Pause: { + True: "[c/FF0000:The game has been paused.]" + False: "[c/00FF00:The game has been resumed.]" + } Buffs: { - Anathema: { - DisplayName: Anathema - Description: Mods.PvPAdventure.Buffs.Anathema.Description + ShinyStoneHotswap: { + DisplayName: Shiny Stone Hotswap + Description: Shiny Stone is charging up! } AncientChiselHotswapBuff: { - DisplayName: Ancient Chisel Hotswap Buff - Description: Mods.PvPAdventure.Buffs.AncientChiselHotswapBuff.Description + DisplayName: THE CURSE OF THE ANCIENT CHISEL + Description: YOU CAN'T USE THAT ACCESSORY SLOT! } - Attuning: { - DisplayName: Attuning - Description: Mods.PvPAdventure.Buffs.Attuning.Description + NewIchorPlayerDebuff: { + DisplayName: Ichor + Description: Defense reduced by one third } - BitingEmbrace: { - DisplayName: Biting Embrace - Description: Mods.PvPAdventure.Buffs.BitingEmbrace.Description + BROISACHOJ: { + DisplayName: BRO IS A CHOJ + Description: You are too much of a CHOJ to dash effectively } - BrittleBones: { - DisplayName: Brittle Bones - Description: Mods.PvPAdventure.Buffs.BrittleBones.Description + BuffDescription: { + BeetleMight1: Melee damage and speed increase by 8% + BeetleMight2: Melee damage and speed increase by 8% + BeetleMight3: Melee damage and speed increase by 8% } - BROISACHOJ: { - DisplayName: B R O I S A C H O J - Description: Mods.PvPAdventure.Buffs.BROISACHOJ.Description + Anathema: { + DisplayName: Anathema + Description: Enemy attacks can seek you out } - Hellhex: { - DisplayName: Hellhex - Description: Mods.PvPAdventure.Buffs.Hellhex.Description + BitingEmbrace: { + DisplayName: Summon Tagged + Description: Take 7 more damage from enemies } - Marked: { - DisplayName: Marked - Description: Mods.PvPAdventure.Buffs.Marked.Description + BrittleBones: { + DisplayName: Summon Tagged + Description: Take 6 more damage from enemies } - NewIchorPlayerDebuff: { - DisplayName: New Ichor Player Debuff - Description: Mods.PvPAdventure.Buffs.NewIchorPlayerDebuff.Description + Hellhex: { + DisplayName: Firecracked + Description: You are going to burst with hellfire at any moment! + } + + Marked: { + DisplayName: Summon Tagged + Description: Take 9 more damage from enemies } PlayerInSpawn: { - DisplayName: Player In Spawn - Description: Mods.PvPAdventure.Buffs.PlayerInSpawn.Description + DisplayName: Spawn + Description: You're in spawn bro } PressurePoints: { - DisplayName: Pressure Points - Description: Mods.PvPAdventure.Buffs.PressurePoints.Description + DisplayName: Summon Tagged + Description: Take 6 more damage from enemies } ShatteredArmor: { DisplayName: Shattered Armor - Description: Mods.PvPAdventure.Buffs.ShatteredArmor.Description + Description: You're armor has been shattered by a brutal blow! } - ShinyStoneHotswap: { - DisplayName: Shiny Stone Hotswap - Description: Mods.PvPAdventure.Buffs.ShinyStoneHotswap.Description + Attuning: { + DisplayName: Attuning + Description: Your Spectre armor is attuning to your magic & mind! } UncouthandBoring: { - DisplayName: Uncouthand Boring - Description: Mods.PvPAdventure.Buffs.UncouthandBoring.Description + DisplayName: Uncouth and Boring + Description: You are no longer a charming and mythical philosopher! } } Items: { AdventureBag: { DisplayName: Adventure Bag + Tooltip: Everything you need to start your PvP Adventure! + } + + BlightFruit: { + Tooltip: "" + DisplayName: Blight Fruit + } + } + + AdventureClientConfig: { + DisplayName: Adventure Client Config + + PlayerOutline: { + Label: Player Outline + Tooltip: "" + } + + ShiftEnterOpensAllChat: { + Label: Shift Enter Opens All Chat + Tooltip: "" + } + + ShowPauseMessage: { + Label: Show Pause Message + Tooltip: "" + } + + SoundEffect: { + Label: Sound Effect Tooltip: "" } BlightFruit: { DisplayName: Blight Fruit + Tooltip: Permanently decreases maximum life by 5 + } + } + + PlayerOutlineConfig: { + Tooltip: "" + + Self: { + Label: Self Tooltip: "" } - AdventureMirror: { - DisplayName: Adventure Mirror + Team: { + Label: Team Tooltip: "" } } - NPCs: { - Bound: { - ArmsDealer.DisplayName: Bound. Arms Dealer - Cyborg.DisplayName: Bound. Cyborg - Demolitionist.DisplayName: Bound. Demolitionist - Merchant.DisplayName: Bound. Merchant - Steampunker.DisplayName: Bound. Steampunker - Truffle.DisplayName: Bound. Truffle - WitchDoctor.DisplayName: Bound. Witch Doctor + SoundEffectConfig: { + Tooltip: "" + + NpcHitMarker: { + Label: Npc Hit Marker + Tooltip: "" + } + + PlayerHitMarker: { + Label: Player Hit Marker + Tooltip: "" + } + + PlayerKillMarker: { + Label: Player Kill Marker + Tooltip: "" + } + } + + HitMarkerConfig.Tooltip: "" + + Hitsound: { + Tooltip: "" + OlBetsy.Label: Ol Betsy + Buwee.Label: Buwee + Blip.Label: Blip + Crash.Label: Crash + Squelchy.Label: Squelchy + MarrowMurder.Label: Marrow Murder + Part1.Label: Part1 + } + + MarkerConfig`1: { + Sound: { + Label: Sound + Tooltip: "" + } + + Volume: { + Label: Volume + Tooltip: "" + } + + PitchMinimum: { + Label: Pitch Minimum + Tooltip: "" + } + + PitchMaximum: { + Label: Pitch Maximum + Tooltip: "" + } + } + + PlayerHitMarkerConfig: { + Tooltip: "" + + SilenceVanilla: { + Label: Silence Vanilla + Tooltip: "" + } + } + + PlayerKillMarkerConfig: { + Tooltip: "" + + SilenceVanilla: { + Label: Silence Vanilla + Tooltip: "" + } + } + + Killsound: { + Tooltip: "" + Zacharry.Label: Zacharry + Ronaldoz.Label: Ronaldoz + Sharkron.Label: Sharkron + Shronker.Label: Shronker + FatalCarCrash.Label: Fatal Car Crash + Part2.Label: Part2 + } + Items: { + AdventureMirror: { + DisplayName: Adventure Mirror + Tooltip: + ''' + Gaze in the mirror to go on adventures + Right click to use + ''' } } } diff --git a/System/GameManager.cs b/System/GameManager.cs index ce8f8d01..06973278 100644 --- a/System/GameManager.cs +++ b/System/GameManager.cs @@ -23,7 +23,7 @@ namespace PvPAdventure.System; public class GameManager : ModSystem { public int TimeRemaining { get; set; } - public int? _startGameCountdown = null; + private int? _startGameCountdown = 0; private Phase _currentPhase; private static readonly FieldInfo _bigProgressBarSystemCurrentBarField = @@ -125,6 +125,7 @@ private void OnMainStartRain(On_Main.orig_StartRain orig) orig(); ChatHelper.BroadcastChatMessage(NetworkText.FromKey("Mods.PvPAdventure.Rain"), Color.White); } + public override void PostUpdateTime() { // The Nurse is never allowed to spawn. @@ -147,7 +148,7 @@ public override void PostUpdateTime() else if (_startGameCountdown <= (60 * 3) && _startGameCountdown % 60 == 0) { ChatHelper.BroadcastChatMessage(NetworkText.FromLiteral($"{_startGameCountdown / 60}..."), - Color.Crimson); + Color.Green); } } @@ -156,14 +157,13 @@ public override void PostUpdateTime() case Phase.Playing: { if (--TimeRemaining <= 0) - { CurrentPhase = Phase.Waiting; - } break; } } } + public void StartGame(int time) { CurrentPhase = Phase.Waiting; From dd4c0a3ec8812ed091fe9f75e65f2a2445991324 Mon Sep 17 00:00:00 2001 From: emyhrberg <121192176+emyhrberg@users.noreply.github.com> Date: Sun, 16 Nov 2025 19:38:07 +0100 Subject: [PATCH 177/206] Fixed minor issues for game tonight disable trashing, cancel mirror use if player gets hit, wip player position indication and arrow, biome too dark, scrunchy text fix with samplerstate reset, minor config updates with headers --- AdventureClientConfig.cs | 8 +- AdventureConfig.cs | 9 +- .../SpawnSelector/CustomPlayerBackground.png | Bin 0 -> 287 bytes .../Players/AdventureMirrorPlayer.cs | 14 ++- .../SpawnSelector/Systems/ItemSlotHooks.cs | 24 ++-- .../SpawnSelector/UI/PopupTextHelper.cs | 2 +- .../UI/UISpawnSelectorCharacterListItem.cs | 106 ++++++++++++------ .../SpawnSelector/UI/UISpawnSelectorPanel.cs | 12 ++ Core/Helpers/AssetLoader.cs | 1 + Localization/en-US.hjson | 22 ++-- 10 files changed, 136 insertions(+), 62 deletions(-) create mode 100644 Assets/SpawnSelector/CustomPlayerBackground.png diff --git a/AdventureClientConfig.cs b/AdventureClientConfig.cs index 434c6ef0..ab9f1fa1 100644 --- a/AdventureClientConfig.cs +++ b/AdventureClientConfig.cs @@ -14,9 +14,6 @@ public class AdventureClientConfig : ModConfig public bool ShiftEnterOpensAllChat { get; set; } [DefaultValue(true)] public bool ShowPauseMessage { get; set; } - [DefaultValue(false)] public bool OpenMapAfterRecall; - [DefaultValue(false)] public bool ShowPopupText; - public class PlayerOutlineConfig { public bool Self { get; set; } = true; @@ -133,4 +130,9 @@ public class PlayerKillMarkerConfig : KillMarkerConfig } public SoundEffectConfig SoundEffect { get; set; } = new(); + + [Header("AdventureMirror")] + [DefaultValue(true)] public bool OpenMapAfterRecall; + [DefaultValue(true)] public bool ShowPopupText; + [DefaultValue(true)] public bool ShowPlayerIndicationWhenWhenHovering; } \ No newline at end of file diff --git a/AdventureConfig.cs b/AdventureConfig.cs index ede84da1..a0051420 100644 --- a/AdventureConfig.cs +++ b/AdventureConfig.cs @@ -66,10 +66,6 @@ public class InvasionSizeValue [DefaultValue(4 * 60)] public int RecallFrames { get; set; } - [Range(0, 60 * 60)] - [DefaultValue(4 * 60)] - public int AdventureMirrorRecallFrames { get; set; } - [Range(0, 30 * 60)] [DefaultValue(1.5 * 60)] public int SpawnImmuneFrames { get; set; } @@ -358,6 +354,11 @@ public class ChestItemReplacement [Range(0, 600)] public int MinimumDamageReceivedByPlayers { get; set; } [Range(0, 600)] public int MinimumDamageReceivedByPlayersFromPlayer { get; set; } + [Header("AdventureMirror")] + [Range(0, 60 * 60)] + [DefaultValue(4 * 60)] + public int AdventureMirrorRecallFrames { get; set; } + public override bool AcceptClientChanges(ModConfig pendingConfig, int whoAmI, ref NetworkText message) { if (pendingConfig is not AdventureConfig pendingAdventureConfig) diff --git a/Assets/SpawnSelector/CustomPlayerBackground.png b/Assets/SpawnSelector/CustomPlayerBackground.png new file mode 100644 index 0000000000000000000000000000000000000000..5115f8ffe3bf7470230478d082e5f8c6896494ac GIT binary patch literal 287 zcmeAS@N?(olHy`uVBq!ia0vp^)EalY;r#aYLEb|K0<0GuIH&2GF#Mg) z%v-QAhB@-2;~@>!in4pD#j<}_7vJ=|Q~tQva{b*Oe+p&ITlc5-yGCdC@7Vi2`i|(7 zpnHYcYtQfae8_ToY~{t9HxKQcrmAZ-TikE!8*?);)wNR3md!bxmY_3rW5}@}N$*sG zjHf-l<#orS?YnkrUfs0MeAy>?My>y^6K`$fk9G}YYdU=S0?_>op00i_>zopr0IVx) As{jB1 literal 0 HcmV?d00001 diff --git a/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs b/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs index 00ce866a..bef3f26e 100644 --- a/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs +++ b/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs @@ -10,7 +10,6 @@ using Terraria.GameInput; using Terraria.ID; using Terraria.ModLoader; -using static Terraria.ModLoader.BackupIO; namespace PvPAdventure.Core.Features.SpawnSelector.Players; @@ -20,6 +19,7 @@ public class AdventureMirrorPlayer : ModPlayer public bool MirrorActive; // currently channeling public int MirrorCountdownLastSecond = -1; private bool didRebuildOnDeath; + public bool TryStartMirrorChannel() { if (ModContent.GetInstance().CurrentPhase != GameManager.Phase.Playing) @@ -55,6 +55,18 @@ public bool TryStartMirrorChannel() return true; } + public override void OnHurt(Terraria.Player.HurtInfo info) + { + // Only care if mirror is currently channeling + if (!MirrorActive) + return; + + // Stop the channel + reset animation + CancelMirrorUse(); + + PopupTextHelper.NewText("Mirror interrupted!", Color.Crimson); + } + public bool IsPlayerInSpawnRegion() { // Force SSS to be enabled when player is within the spawn region. diff --git a/Core/Features/SpawnSelector/Systems/ItemSlotHooks.cs b/Core/Features/SpawnSelector/Systems/ItemSlotHooks.cs index d4a974ed..207cdd24 100644 --- a/Core/Features/SpawnSelector/Systems/ItemSlotHooks.cs +++ b/Core/Features/SpawnSelector/Systems/ItemSlotHooks.cs @@ -48,20 +48,21 @@ private static bool Hook_LeftClick_SellOrTrash( } private static bool IsAdventureMirror(Item item) - => !item.IsAir && item.type == ModContent.ItemType(); + => !item.IsAir && item.type == ModContent.ItemType(); - // DRAGGING ONTO THE TRASH SLOT + // DRAGGING ONTO THE TRASH SLOT / CHESTS / BANKS private static void Hook_LeftClick_ItemArray( On_ItemSlot.orig_LeftClick_ItemArray_int_int orig, Item[] inv, int context, int slot) { - // 1) Hard block: putting mirror into any chest/bank slot + bool isMirrorOnMouse = IsAdventureMirror(Main.mouseItem); + + // 1) Block putting mirror into any storage (chest / banks) bool isStorageSlot = context == ItemSlot.Context.ChestItem || - context == ItemSlot.Context.BankItem; // Piggy bank + context == ItemSlot.Context.BankItem; // Piggy Bank - if (isStorageSlot && - IsAdventureMirror(Main.mouseItem)) // we are dragging the mirror onto this slot + if (isStorageSlot && isMirrorOnMouse) { if (Main.mouseLeft && Main.mouseLeftRelease) PopupTextHelper.NewText("Cannot store Adventure Mirror!"); @@ -70,7 +71,16 @@ private static void Hook_LeftClick_ItemArray( return; } - // Fallback to vanilla behavior + // 2) Block dragging mirror onto trash slot + if (context == ItemSlot.Context.TrashItem && isMirrorOnMouse) + { + if (Main.mouseLeft && Main.mouseLeftRelease) + PopupTextHelper.NewText("Cannot trash Adventure Mirror!"); + + return; // cancel trashing + } + + // Otherwise, normal behavior orig(inv, context, slot); } diff --git a/Core/Features/SpawnSelector/UI/PopupTextHelper.cs b/Core/Features/SpawnSelector/UI/PopupTextHelper.cs index baa755fa..8041d8bb 100644 --- a/Core/Features/SpawnSelector/UI/PopupTextHelper.cs +++ b/Core/Features/SpawnSelector/UI/PopupTextHelper.cs @@ -23,7 +23,7 @@ public static void NewText(string text, Color color=default, bool showInMultipla Color = color, Text = text, Velocity = new(0f, -4f), - DurationInFrames = 60 + DurationInFrames = 30 }, Main.LocalPlayer.Top); return; } diff --git a/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs b/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs index 8a539b45..ba279504 100644 --- a/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs +++ b/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs @@ -4,15 +4,12 @@ using PvPAdventure.Core.Features.SpawnSelector.Systems; using PvPAdventure.Core.Helpers; using ReLogic.Content; -using ReLogic.Graphics; using System; using Terraria; using Terraria.GameContent; using Terraria.GameContent.UI.Elements; -using Terraria.ID; using Terraria.ModLoader; using Terraria.UI; -using tModPorter; namespace PvPAdventure.Core.Features.SpawnSelector.UI { @@ -35,7 +32,8 @@ public UISpawnSelectorCharacterListItem(Player player) { _dividerTexture = Main.Assets.Request("Images/UI/Divider"); _innerPanelTexture = Main.Assets.Request("Images/UI/InnerPanelBackground"); - _playerBGTexture = Main.Assets.Request("Images/UI/PlayerBackground"); + //_playerBGTexture = Main.Assets.Request("Images/UI/PlayerBackground"); + _playerBGTexture = Ass.CustomPlayerBackground; _playerIndex = player.whoAmI; } @@ -51,7 +49,8 @@ public override void OnInitialize() SetPadding(6f); } - private void DrawHeadOnMap(Player p) + + private void DrawArrow(Player p) { float scale = Main.mapFullscreenScale; @@ -74,42 +73,34 @@ private void DrawHeadOnMap(Player p) 72 ); - Vector2 arrowStart = new(rect.X + rect.Width / 2f, rect.Bottom + 8f); - Texture2D arrowTex = Ass.Arrow.Value; + Vector2 arrowCenter = new( + rect.X + rect.Width / 2f -1, + rect.Bottom - 20f + ); + Vector2 arrowOrigin = arrowTex.Size() * 0.5f; - Vector2 dir = headPos - arrowStart; + Vector2 dir = headPos - arrowCenter; + if (dir.LengthSquared() > 0.001f) { dir.Normalize(); - float rotation = dir.ToRotation(); // adjust with +- PiOver2 if your texture points up - Vector2 arrowPos = arrowStart; + + float rotation = dir.ToRotation(); Main.spriteBatch.Draw( arrowTex, - arrowPos, + arrowCenter, // stays the same, no matter angle null, Color.White, rotation, - arrowOrigin, - 1f, + arrowOrigin, // rotate around center + 0.9f, SpriteEffects.None, 0f ); } - - Color color = Main.teamColor[p.team]; - - Main.MapPlayerRenderer.DrawPlayerHead( - Main.Camera, - p, - headPos, - scale: 1.6f, - borderColor: color - ); - - Utils.DrawBorderString(Main.spriteBatch, p.name, headPos + new Vector2(-20f, 20f), Color.White); } private void DrawNineSlice(SpriteBatch sb, int x, int y, int w, int h, Texture2D tex, Color color, int inset, int c = 5) @@ -176,7 +167,7 @@ protected override void DrawSelf(SpriteBatch sb) try { Vector2 playerDrawPos = pos + Main.screenPosition + new Vector2(34, 9); - Vector2 headDrawPos = pos + new Vector2(38, 28); + Vector2 headDrawPos = pos + new Vector2(38, 20); Color myTeamColor = Main.teamColor[Main.LocalPlayer.team]; @@ -273,25 +264,67 @@ protected override void DrawSelf(SpriteBatch sb) sb.Draw(mana.Value, new Vector2(startX, y - 2), null, Color.White, 0f, Vector2.Zero, statScale, SpriteEffects.None, 0f); startX += manaW; Utils.DrawBorderString(sb, mpText, new Vector2(startX+1, y + 1f), Color.White, statScale); - + + // Draw arrow + //DrawArrow(player); + + // Draw player head if hovering + DrawPlayerHeadOnMap(player); + } + + private void DrawPlayerHeadOnMap(Player p) + { + if (p == null || !p.active) + return; + // Set hover teleport tooltip - if (IsMouseHovering) + var config = ModContent.GetInstance(); + if (IsMouseHovering && config.ShowPlayerIndicationWhenWhenHovering) { - Main.instance.MouseText("Teleport to " + name); + Main.instance.MouseText("Teleport to " + p.name); Main.spriteBatch.End(); - Main.spriteBatch.Begin(SpriteSortMode.Immediate,BlendState.AlphaBlend,SamplerState.PointClamp,DepthStencilState.None,RasterizerState.CullCounterClockwise,null,Matrix.Identity); + Main.spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.PointClamp, DepthStencilState.None, RasterizerState.CullCounterClockwise, null, Matrix.Identity); + + float mapScale = Main.mapFullscreenScale; + + // World center in tile coordinates + Vector2 tilePos = p.Center / 16f; + + // Fullscreen map's visual center in screen pixels + Vector2 mapScreenCenter = new( + Main.screenWidth / 2f, + Main.screenHeight / 2f + ); + + // Screen coordinates of the player on the fullscreen map + Vector2 headPos = (tilePos - Main.mapFullscreenPos) * mapScale + mapScreenCenter; - DrawHeadOnMap(player); - //DrawGuideMarkerOnMap(Main.spriteBatch); + headPos += new Vector2(80, 40); + Color c = Main.teamColor[p.team]; + + // Draw on the fullscreen map + Main.MapPlayerRenderer.DrawPlayerHead(Main.Camera,p,headPos,scale: 1.8f,borderColor: c); + + // Draw text centered below the player head + string name = p.name + "" ?? string.Empty; + float textScale = 1f; + Vector2 nameSize = FontAssets.MouseText.Value.MeasureString(name) * textScale; + Vector2 namePos = new( + headPos.X - nameSize.X * 0.5f + 5, + headPos.Y + 30f + ); + Utils.DrawBorderString(Main.spriteBatch, name, namePos, Color.White, textScale); + + // Restart sb Main.spriteBatch.End(); - Main.spriteBatch.Begin(SpriteSortMode.Deferred,BlendState.AlphaBlend,SamplerState.PointClamp,DepthStencilState.None,RasterizerState.CullCounterClockwise,null,Main.UIScaleMatrix); - } - //Main.NewText(Main.mouseY); // 482,435 is spawn + Main.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.None, RasterizerState.CullCounterClockwise, null, Main.UIScaleMatrix); + } } + public override void MouseOver(UIMouseEvent evt) { base.MouseOver(evt); @@ -384,7 +417,8 @@ public static void DrawMapFullscreenBackground(SpriteBatch sb, Rectangle rect, P bgIndex = 19; else { - color = Main.ColorOfTheSkies; + //color = Main.ColorOfTheSkies; + color = Color.White; int midTileX = (int)((screenPos.X + Main.screenWidth / 2f) / 16f); if (player.ZoneSkyHeight) bgIndex = 32; diff --git a/Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs b/Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs index fb802b1c..f4259a58 100644 --- a/Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs +++ b/Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs @@ -54,6 +54,12 @@ private void BuildLayout() } } + // DEBUG: ADD LOCAL PLAYER + if (players.Count == 0 && local != null && local.active && !local.dead && local.statLife > 0) + { + players.Add(local); + } + int playerCount = players.Count; float itemWidth = UISpawnSelectorCharacterListItem.ItemWidth; @@ -155,6 +161,11 @@ private bool NeedsRebuild() players.Add(p.whoAmI); } + if (players.Count == 0 && local != null && local.active && !local.dead && local.statLife > 0) + { + players.Add(local.whoAmI); + } + if (players.Count != _playerItems.Count) return true; @@ -166,5 +177,6 @@ private bool NeedsRebuild() return false; } + } } diff --git a/Core/Helpers/AssetLoader.cs b/Core/Helpers/AssetLoader.cs index 61d92e86..9b18acee 100644 --- a/Core/Helpers/AssetLoader.cs +++ b/Core/Helpers/AssetLoader.cs @@ -10,6 +10,7 @@ public static class Ass public static Asset Question_Mark; public static Asset[] MapBG; public static Asset Arrow; + public static Asset CustomPlayerBackground; public static bool Initialized { get; set; } diff --git a/Localization/en-US.hjson b/Localization/en-US.hjson index 3d32fd4a..4bcf91d6 100644 --- a/Localization/en-US.hjson +++ b/Localization/en-US.hjson @@ -16,9 +16,6 @@ Mods: { AdventureMirror.DisplayName: Adventure Mirror OpenControls.DisplayName: Open Controls SwitchTeams.DisplayName: Switch Teams - AddPlayerToSpawnSelector.DisplayName: Add Player To Spawn Selector - RemovePlayerFromSpawnSelector.DisplayName: Remove Player From Spawn Selector - ClearPlayersFromSpawnSelector.DisplayName: Clear Players From Spawn Selector "[DEBUG] OpenControls.DisplayName": "[ D E B U G] Open Controls" "[DEBUG] SwitchTeams.DisplayName": "[ D E B U G] Switch Teams" } @@ -144,8 +141,10 @@ Mods: { AdventureMirrorRecallFrames: { Label: Adventure Mirror Recall Frames - Tooltip: "" + Tooltip: The number of frames it takes to use the item until it executes its action } + + Headers.AdventureMirror: Adventure Mirror } PointsConfig: { @@ -376,7 +375,14 @@ Mods: { ShowPopupText: { Label: Show Popup Text - Tooltip: "" + Tooltip: Shows popup text related to item + } + + Headers.AdventureMirror: Adventure Mirror + + ShowPlayerIndicationWhenWhenHovering: { + Label: Show Player Indication When When Hovering + Tooltip: Shows arrow and player head on the fullscreen map when hovering the teleport option above a player } } @@ -801,11 +807,7 @@ Mods: { Items: { AdventureMirror: { DisplayName: Adventure Mirror - Tooltip: - ''' - Gaze in the mirror to go on adventures - Right click to use - ''' + Tooltip: Gaze in the mirror to go on adventures } } } From 19776d264124740778627001ca9e04ad425f8ecf Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Sun, 16 Nov 2025 10:50:43 -0800 Subject: [PATCH 178/206] nerfed the amount of beewax qb gives --- AdventureDropDatabase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AdventureDropDatabase.cs b/AdventureDropDatabase.cs index b33fe0dc..0ed715b3 100644 --- a/AdventureDropDatabase.cs +++ b/AdventureDropDatabase.cs @@ -304,7 +304,7 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) break; case NPCID.QueenBee: - npcLoot.Add(ItemDropRule.Common(ItemID.BeeWax, 1, 70, 200)); + npcLoot.Add(ItemDropRule.Common(ItemID.BeeWax, 1, 51, 87)); npcLoot.Add(ItemDropRule.Common(ItemID.HoneyComb, 1, 1, 2)); npcLoot.Add(ItemDropRule.Common(ItemID.GoldCoin, 1, 10, 15)); npcLoot.Add(ItemDropRule.Common(ItemID.Beenade, 1, 22, 32)); From e816cdb6b064532900b33d92ac0af734adcfe442 Mon Sep 17 00:00:00 2001 From: emyhrberg <121192176+emyhrberg@users.noreply.github.com> Date: Sun, 16 Nov 2025 19:53:26 +0100 Subject: [PATCH 179/206] Fixed most uiscales --- .../Systems/SpawnSelectorSystem.cs | 8 ++- .../UI/UISpawnSelectorCharacterListItem.cs | 67 ++++++++----------- 2 files changed, 36 insertions(+), 39 deletions(-) diff --git a/Core/Features/SpawnSelector/Systems/SpawnSelectorSystem.cs b/Core/Features/SpawnSelector/Systems/SpawnSelectorSystem.cs index 6dbf5979..737a732d 100644 --- a/Core/Features/SpawnSelector/Systems/SpawnSelectorSystem.cs +++ b/Core/Features/SpawnSelector/Systems/SpawnSelectorSystem.cs @@ -78,7 +78,13 @@ private void DrawOverFullscreenMap(Vector2 _mapPos, float _mapScale) try { - sb.Begin(SpriteSortMode.Deferred,BlendState.AlphaBlend,SamplerState.LinearClamp,DepthStencilState.None,RasterizerState.CullCounterClockwise,null,Main.UIScaleMatrix); + sb.Begin(SpriteSortMode.Deferred, + BlendState.AlphaBlend, + SamplerState.LinearClamp, + DepthStencilState.None, + RasterizerState.CullCounterClockwise + ,null, + Main.UIScaleMatrix); began = true; ui.Draw(sb, Main._drawInterfaceGameTime); } diff --git a/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs b/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs index ba279504..9cf2304e 100644 --- a/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs +++ b/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs @@ -167,7 +167,7 @@ protected override void DrawSelf(SpriteBatch sb) try { Vector2 playerDrawPos = pos + Main.screenPosition + new Vector2(34, 9); - Vector2 headDrawPos = pos + new Vector2(38, 20); + Vector2 headDrawPos = pos + new Vector2(38, 30); Color myTeamColor = Main.teamColor[Main.LocalPlayer.team]; @@ -277,54 +277,45 @@ private void DrawPlayerHeadOnMap(Player p) if (p == null || !p.active) return; - // Set hover teleport tooltip var config = ModContent.GetInstance(); - if (IsMouseHovering && config.ShowPlayerIndicationWhenWhenHovering) - { - Main.instance.MouseText("Teleport to " + p.name); - - Main.spriteBatch.End(); - Main.spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.PointClamp, DepthStencilState.None, RasterizerState.CullCounterClockwise, null, Matrix.Identity); - - float mapScale = Main.mapFullscreenScale; - - // World center in tile coordinates - Vector2 tilePos = p.Center / 16f; + if (!IsMouseHovering || !config.ShowPlayerIndicationWhenWhenHovering) + return; - // Fullscreen map's visual center in screen pixels - Vector2 mapScreenCenter = new( - Main.screenWidth / 2f, - Main.screenHeight / 2f - ); + Main.instance.MouseText("Teleport to " + p.name); - // Screen coordinates of the player on the fullscreen map - Vector2 headPos = (tilePos - Main.mapFullscreenPos) * mapScale + mapScreenCenter; + float mapScale = Main.mapFullscreenScale; - headPos += new Vector2(80, 40); + // Player in tile coords + Vector2 tilePos = p.Center / 16f; - Color c = Main.teamColor[p.team]; + // Screen-space position on the fullscreen map (pixels) + Vector2 mapScreenCenter = new( + Main.screenWidth / 2f, + Main.screenHeight / 2f + ); + Vector2 headPosScreen = (tilePos - Main.mapFullscreenPos) * mapScale + mapScreenCenter; + //headPosScreen += new Vector2(80, 40); // your offset + headPosScreen *= Main.UIScale; - // Draw on the fullscreen map - Main.MapPlayerRenderer.DrawPlayerHead(Main.Camera,p,headPos,scale: 1.8f,borderColor: c); + Matrix invUi = Matrix.Invert(Main.UIScaleMatrix); + Vector2 headPosUI = Vector2.Transform(headPosScreen, invUi); - // Draw text centered below the player head - string name = p.name + "" ?? string.Empty; - float textScale = 1f; - Vector2 nameSize = FontAssets.MouseText.Value.MeasureString(name) * textScale; - Vector2 namePos = new( - headPos.X - nameSize.X * 0.5f + 5, - headPos.Y + 30f - ); - Utils.DrawBorderString(Main.spriteBatch, name, namePos, Color.White, textScale); + Color c = Main.teamColor[p.team]; - // Restart sb - Main.spriteBatch.End(); - Main.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.None, RasterizerState.CullCounterClockwise, null, Main.UIScaleMatrix); + // Draw head in UI-space + Main.MapPlayerRenderer.DrawPlayerHead(Main.Camera, p, headPosUI, scale: 1.8f, borderColor: c); - } + // Text centered below head, also in UI-space + string name = p.name ?? string.Empty; + float textScale = 1f; + Vector2 nameSize = FontAssets.MouseText.Value.MeasureString(name) * textScale; + Vector2 namePos = new( + headPosUI.X - nameSize.X * 0.5f, + headPosUI.Y + 30f + ); + Utils.DrawBorderString(Main.spriteBatch, name, namePos, Color.White, textScale); } - public override void MouseOver(UIMouseEvent evt) { base.MouseOver(evt); From 02e097698eb3b315f12d554aac81b25897b22bad Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Tue, 18 Nov 2025 22:00:03 -0800 Subject: [PATCH 180/206] Update AdventurePlayer.cs Fixed the virus --- AdventurePlayer.cs | 93 +++++++++------------------------------------- 1 file changed, 17 insertions(+), 76 deletions(-) diff --git a/AdventurePlayer.cs b/AdventurePlayer.cs index ffd0bdd2..d227c10c 100644 --- a/AdventurePlayer.cs +++ b/AdventurePlayer.cs @@ -1327,9 +1327,6 @@ public override void PostUpdateEquips() } } } -// Add this to each ModPlayer class that handles a debuff - -// For BitingEmbracePlayer: public class BitingEmbracePlayer : ModPlayer { public int bitingEmbraceApplierIndex = -1; @@ -1430,7 +1427,6 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) { if (Player.HasBuff()) { - // Check if the current attacker is the same player who applied the debuff bool isDebuffApplier = modifiers.DamageSource.SourcePlayerIndex == bitingEmbraceApplierIndex; bool isSummon = false; @@ -1455,12 +1451,9 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) } } - // Only apply bonus if NOT from summon/whip AND NOT from the debuff applier if (!isSummon && !isDebuffApplier) { - modifiers.ModifyHurtInfo += (ref Player.HurtInfo info) => { - info.Damage += 6; - }; + modifiers.SourceDamage.Flat += 6; } } } @@ -1564,7 +1557,6 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) { if (Player.HasBuff()) { - // Check if the current attacker is the same player who applied the debuff bool isDebuffApplier = modifiers.DamageSource.SourcePlayerIndex == pressurePointsApplierIndex; bool isSummon = false; @@ -1590,12 +1582,9 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) } } - // Only apply bonus if NOT from summon/whip AND NOT from the debuff applier if (!isSummon && !isDebuffApplier) { - modifiers.ModifyHurtInfo += (ref Player.HurtInfo info) => { - info.Damage += 6; - }; + modifiers.SourceDamage.Flat += 6; } } } @@ -1699,7 +1688,6 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) { if (Player.HasBuff()) { - // Check if the current attacker is the same player who applied the debuff bool isDebuffApplier = modifiers.DamageSource.SourcePlayerIndex == brittleBonesApplierIndex; bool isSummon = false; @@ -1725,12 +1713,9 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) } } - // Only apply bonus if NOT from summon/whip AND NOT from the debuff applier if (!isSummon && !isDebuffApplier) { - modifiers.ModifyHurtInfo += (ref Player.HurtInfo info) => { - info.Damage += 7; - }; + modifiers.SourceDamage.Flat += 7; } } } @@ -1834,7 +1819,6 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) { if (Player.HasBuff()) { - // Check if the current attacker is the same player who applied the debuff bool isDebuffApplier = modifiers.DamageSource.SourcePlayerIndex == markedApplierIndex; bool isSummon = false; @@ -1860,12 +1844,9 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) } } - // Only apply bonus if NOT from summon/whip AND NOT from the debuff applier if (!isSummon && !isDebuffApplier) { - modifiers.ModifyHurtInfo += (ref Player.HurtInfo info) => { - info.Damage += 9; - }; + modifiers.SourceDamage.Flat += 9; } } } @@ -1964,7 +1945,6 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) { if (Player.HasBuff()) { - // Check if the current attacker is the same player who applied the debuff bool isDebuffApplier = modifiers.DamageSource.SourcePlayerIndex == anathemaApplierIndex; bool isSummon = false; @@ -1990,12 +1970,9 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) } } - // Only apply bonus if NOT from summon/whip AND NOT from the debuff applier if (!isSummon && !isDebuffApplier) { - modifiers.ModifyHurtInfo += (ref Player.HurtInfo info) => { - info.Damage += 20; - }; + modifiers.SourceDamage.Flat += 20; modifiers.FinalDamage *= 1.1f; } } @@ -2072,7 +2049,6 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) { if (Player.HasBuff()) { - // Check if the current attacker is the same player who applied the debuff bool isDebuffApplier = modifiers.DamageSource.SourcePlayerIndex == shatteredArmorApplierIndex; bool isSummon = false; @@ -2098,28 +2074,24 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) } } - // Only apply bonus if NOT from summon/whip AND NOT from the debuff applier if (!isSummon && !isDebuffApplier) { - modifiers.ModifyHurtInfo += (ref Player.HurtInfo info) => { - info.Damage += 8; - }; + modifiers.SourceDamage.Flat += 8; modifiers.FinalDamage *= 1.12f; } } } } + public class HellhexPlayer : ModPlayer { public bool hellhexTriggered = false; private int storedDamage = 0; - public int hellhexApplierIndex = -1; // Track who applied the Hellhex debuff - private bool explosionSpawned = false; // Prevent duplicate explosions + public int hellhexApplierIndex = -1; + private bool explosionSpawned = false; - // Helper method to check if damage source is from summon/whip (for HurtInfo) private bool IsSummonOrWhipDamage(Player.HurtInfo info) { - // Check projectile instance if (info.DamageSource.SourceProjectileLocalIndex >= 0) { Projectile proj = Main.projectile[info.DamageSource.SourceProjectileLocalIndex]; @@ -2129,7 +2101,6 @@ private bool IsSummonOrWhipDamage(Player.HurtInfo info) } } - // Check projectile type for whips if (info.DamageSource.SourceProjectileType > 0) { int projType = info.DamageSource.SourceProjectileType; @@ -2146,10 +2117,8 @@ private bool IsSummonOrWhipDamage(Player.HurtInfo info) return false; } - // Helper method to check if damage source is from summon/whip (for HurtModifiers) private bool IsSummonOrWhipDamage(ref Player.HurtModifiers modifiers) { - // Check projectile instance if (modifiers.DamageSource.SourceProjectileLocalIndex >= 0) { Projectile proj = Main.projectile[modifiers.DamageSource.SourceProjectileLocalIndex]; @@ -2159,7 +2128,6 @@ private bool IsSummonOrWhipDamage(ref Player.HurtModifiers modifiers) } } - // Check projectile type for whips if (modifiers.DamageSource.SourceProjectileType > 0) { int projType = modifiers.DamageSource.SourceProjectileType; @@ -2176,10 +2144,8 @@ private bool IsSummonOrWhipDamage(ref Player.HurtModifiers modifiers) return false; } - // Helper method to check if death reason is from summon/whip (for PlayerDeathReason) private bool IsSummonOrWhipDeath(PlayerDeathReason damageSource) { - // Check projectile instance if (damageSource.SourceProjectileLocalIndex >= 0) { Projectile proj = Main.projectile[damageSource.SourceProjectileLocalIndex]; @@ -2189,7 +2155,6 @@ private bool IsSummonOrWhipDeath(PlayerDeathReason damageSource) } } - // Check projectile type for whips if (damageSource.SourceProjectileType > 0) { int projType = damageSource.SourceProjectileType; @@ -2208,20 +2173,17 @@ private bool IsSummonOrWhipDeath(PlayerDeathReason damageSource) public override bool PreKill(double damage, int hitDirection, bool pvp, ref bool playSound, ref bool genGore, ref PlayerDeathReason damageSource) { - // If player has Hellhex when they die from non-summon damage, spawn explosion if (Player.HasBuff()) { bool isSummon = IsSummonOrWhipDeath(damageSource); - // Check if killed by the debuff applier bool isDebuffApplier = damageSource.SourcePlayerIndex == hellhexApplierIndex; - // Only spawn explosion if NOT from summon/whip AND NOT from the debuff applier - if (!isSummon && !isDebuffApplier && damage >= 30) + if (!isSummon && !isDebuffApplier && damage >= 30 && !explosionSpawned) { - // Only spawn on server or singleplayer + explosionSpawned = true; + if (Main.netMode != NetmodeID.MultiplayerClient) { - float scale = (float)damage / 100f; int owner = hellhexApplierIndex >= 0 && hellhexApplierIndex < Main.maxPlayers ? hellhexApplierIndex : -1; int explosionDamage = (int)(damage * 2.75f); @@ -2234,14 +2196,11 @@ public override bool PreKill(double damage, int hitDirection, bool pvp, ref bool 0f, owner, 0f, - scale + 0f ); if (proj >= 0 && proj < Main.maxProjectiles) { - Main.projectile[proj].scale = scale; - - // Sync projectile to all clients if (Main.netMode == NetmodeID.Server) { NetMessage.SendData(MessageID.SyncProjectile, -1, -1, null, proj); @@ -2256,7 +2215,6 @@ public override bool PreKill(double damage, int hitDirection, bool pvp, ref bool public override void PostHurt(Player.HurtInfo info) { - // Apply Hellhex when hit by FireWhip if (info.DamageSource.SourceProjectileType == ProjectileID.FireWhip) { int duration = 450; @@ -2280,11 +2238,10 @@ public override void PostHurt(Player.HurtInfo info) hellhexApplierIndex = applierIndex; Player.AddBuff(ModContent.BuffType(), duration); - // Sync the applier index to all clients if (Main.netMode == NetmodeID.Server) { ModPacket packet = Mod.GetPacket(); - packet.Write((byte)0); // Message type for Hellhex application + packet.Write((byte)0); packet.Write((byte)Player.whoAmI); packet.Write((byte)applierIndex); packet.Send(); @@ -2293,36 +2250,29 @@ public override void PostHurt(Player.HurtInfo info) return; } - // Only check for removal if player already has Hellhex and explosion hasn't spawned yet if (Player.HasBuff() && !explosionSpawned) { bool isSummon = IsSummonOrWhipDamage(info); - // Check if hit by the debuff applier bool isDebuffApplier = info.DamageSource.SourcePlayerIndex == hellhexApplierIndex; - // Only trigger if damage >= 30 and NOT summon/whip AND NOT from the debuff applier if (!isSummon && !isDebuffApplier && info.Damage >= 30) { - explosionSpawned = true; // Mark that explosion is being spawned + explosionSpawned = true; - // Remove the buff immediately on all sides int buffIndex = Player.FindBuffIndex(ModContent.BuffType()); if (buffIndex >= 0) { Player.buffTime[buffIndex] = 0; } - // Calculate explosion parameters Vector2 spawnPos = Player.Center; float scale = info.Damage / 100f; int owner = hellhexApplierIndex >= 0 && hellhexApplierIndex < Main.maxPlayers ? hellhexApplierIndex : -1; int explosionDamage = (int)(info.Damage * 2.75f); - // On attacker's client or server: spawn the explosion immediately if (Main.netMode == NetmodeID.SinglePlayer || (info.DamageSource.SourcePlayerIndex >= 0 && Main.myPlayer == info.DamageSource.SourcePlayerIndex)) { - // Attacker's client - spawn locally int proj = Projectile.NewProjectile( Player.GetSource_Buff(buffIndex), spawnPos, @@ -2338,11 +2288,10 @@ public override void PostHurt(Player.HurtInfo info) Main.projectile[proj].scale = scale; } - // If this is multiplayer, send a packet to server to spawn for everyone else if (Main.netMode == NetmodeID.MultiplayerClient) { ModPacket packet = Mod.GetPacket(); - packet.Write((byte)1); // Message type for Hellhex explosion + packet.Write((byte)1); packet.Write((byte)Player.whoAmI); packet.Write(spawnPos.X); packet.Write(spawnPos.Y); @@ -2352,7 +2301,6 @@ public override void PostHurt(Player.HurtInfo info) packet.Send(); } } - // On server: spawn and sync to all clients else if (Main.netMode == NetmodeID.Server) { int proj = Projectile.NewProjectile( @@ -2371,8 +2319,6 @@ public override void PostHurt(Player.HurtInfo info) NetMessage.SendData(MessageID.SyncProjectile, -1, -1, null, proj); } } - // Victim's client (not attacker): don't spawn, wait for server sync - // This prevents double spawning } } } @@ -2383,20 +2329,15 @@ public override void ModifyHurt(ref Player.HurtModifiers modifiers) { bool isSummon = IsSummonOrWhipDamage(ref modifiers); - // Track that Hellhex triggered for UI/effects purposes if (!isSummon) { - modifiers.ModifyHurtInfo += (ref Player.HurtInfo info) => { - storedDamage = info.Damage; - hellhexTriggered = true; - }; + hellhexTriggered = true; } } } public override void PostUpdateBuffs() { - // Check if applier died - remove buff if so if (Player.HasBuff() && hellhexApplierIndex >= 0 && hellhexApplierIndex < Main.maxPlayers) { Player applier = Main.player[hellhexApplierIndex]; From e5983af805a8c886c3669def84194b01a66b87ba Mon Sep 17 00:00:00 2001 From: emyhrberg <121192176+emyhrberg@users.noreply.github.com> Date: Wed, 19 Nov 2025 23:44:09 +0100 Subject: [PATCH 181/206] Added pause button --- Assets/SpawnSelector/Pause.png | Bin 0 -> 205 bytes Common/Integrations/HerosModIntegration.cs | 58 ++++++++++++++++++ .../UI/UISpawnSelectorCharacterListItem.cs | 2 +- Core/Helpers/AssetLoader.cs | 1 + System/PauseManager.cs | 12 ++++ 5 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 Assets/SpawnSelector/Pause.png create mode 100644 Common/Integrations/HerosModIntegration.cs diff --git a/Assets/SpawnSelector/Pause.png b/Assets/SpawnSelector/Pause.png new file mode 100644 index 0000000000000000000000000000000000000000..9b324008b780a5a2e0ed858711b4bc760332aaee GIT binary patch literal 205 zcmeAS@N?(olHy`uVBq!ia0vp^av;pX1|+Qw)-3{3oCO|{#S9GG!XV7ZFl&wkP_W+9 z#WBRAGx^W||MrI+7?v?^EWPq5u)BTfQJoeM1FMMSvoHSh%cQEf$%#w+aXdR?-Jt_B z);VpnxhWPbEs(o$oi2Yf5a0Zi677>~@JUB)Mt|Y~=Tnm!f#9LgVb)DgE*?C={fcq( xjEMoWvu{kj%2Mm2ZSYCx`ii5A#V+$OFysm;ZdaE(^&aRH22WQ%mvv4FO#q`DN^}4K literal 0 HcmV?d00001 diff --git a/Common/Integrations/HerosModIntegration.cs b/Common/Integrations/HerosModIntegration.cs new file mode 100644 index 00000000..565c4b1b --- /dev/null +++ b/Common/Integrations/HerosModIntegration.cs @@ -0,0 +1,58 @@ +using PvPAdventure.Core.Helpers; +using PvPAdventure.System; +using System; +using Terraria.ModLoader; + +namespace PvPAdventure.Common.Integrations; + +[JITWhenModsEnabled("HEROsMod")] +public sealed class HerosModIntegration : ModSystem +{ + private const string PauseGamePermissionKey = "PauseGame"; + + public override void PostSetupContent() + { + if (ModLoader.TryGetMod("HEROsMod", out Mod herosMod)) + { + AddButtons(herosMod); + } + } + + private void AddButtons(Mod herosMod) + { + herosMod.Call("AddSimpleButton", + PauseGamePermissionKey, + Ass.Pause, + (Action)(() => + { + var mgr = ModContent.GetInstance(); + if (mgr != null) + mgr.PauseGame(); + else + Log.Info("PauseManager not loaded yet."); + }), + (Action)(hasPerm => PermissionChanged(hasPerm, PauseGamePermissionKey)), + (Func)(() => + { + var mgr = ModContent.GetInstance(); + return (mgr != null && mgr.IsPaused) + ? "Continue game" + : "Play game"; + }) + ); + } + + private static void PermissionChanged(bool hasPerm, string permissionName) + { + if (!hasPerm) + { + //Main.NewText($"⛔ You lost permission to use the {permissionName} button!", ColorHelper.CalamityRed); + Log.Info($"You lost permission for {permissionName} button. You cannot use it anymore."); + } + else + { + //Main.NewText($"✅ You regained permission to use the {permissionName} button!", OutlineColor.LightGreen); + Log.Info($"You regained permission for {permissionName} button. You can use it again."); + } + } +} \ No newline at end of file diff --git a/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs b/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs index 9cf2304e..03f10a47 100644 --- a/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs +++ b/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs @@ -303,7 +303,7 @@ private void DrawPlayerHeadOnMap(Player p) Color c = Main.teamColor[p.team]; // Draw head in UI-space - Main.MapPlayerRenderer.DrawPlayerHead(Main.Camera, p, headPosUI, scale: 1.8f, borderColor: c); + Main.MapPlayerRenderer.DrawPlayerHead(Main.Camera, p, headPosUI, scale: 1.6f, borderColor: c); // Text centered below head, also in UI-space string name = p.name ?? string.Empty; diff --git a/Core/Helpers/AssetLoader.cs b/Core/Helpers/AssetLoader.cs index 9b18acee..470a13c3 100644 --- a/Core/Helpers/AssetLoader.cs +++ b/Core/Helpers/AssetLoader.cs @@ -11,6 +11,7 @@ public static class Ass public static Asset[] MapBG; public static Asset Arrow; public static Asset CustomPlayerBackground; + public static Asset Pause; public static bool Initialized { get; set; } diff --git a/System/PauseManager.cs b/System/PauseManager.cs index 286b895e..61b1cb3f 100644 --- a/System/PauseManager.cs +++ b/System/PauseManager.cs @@ -15,6 +15,7 @@ namespace PvPAdventure.System; public class PauseManager : ModSystem { private bool _paused; + public bool IsPaused => _paused; private Interface _interface; public override void Load() @@ -104,4 +105,15 @@ public override void Action(CommandCaller caller, string input, string[] args) public override string Command => "pause"; public override CommandType Type => CommandType.Console; } + + public void PauseGame() + { + var pause = ModContent.GetInstance(); + pause._paused = !pause._paused; + + ChatHelper.BroadcastChatMessage(NetworkText.FromKey($"Mods.PvPAdventure.Pause.{pause._paused}"), + Color.White); + + NetMessage.SendData(MessageID.WorldData); + } } \ No newline at end of file From b894268157a333583f5b45985b636bbc592289bb Mon Sep 17 00:00:00 2001 From: emyhrberg <121192176+emyhrberg@users.noreply.github.com> Date: Fri, 21 Nov 2025 00:01:20 +0100 Subject: [PATCH 182/206] I think all bugs are fixed with AM now Rewrote most of it in AdventureMirror instead of AdventureMirrorPlayer --- Content/Items/AdventureMirror.cs | 133 +++++++++++--- Core/Debug/DebugKeybinds.cs | 10 ++ .../Players/AdventureMirrorPlayer.cs | 165 +++--------------- .../SpawnSelector/Systems/ItemSlotHooks.cs | 19 +- .../SpawnSelector/UI/PopupTextHelper.cs | 38 ++-- .../UI/UISpawnSelectorCharacterListItem.cs | 2 +- Localization/en-US.hjson | 1 + System/GameManager.cs | 4 +- 8 files changed, 163 insertions(+), 209 deletions(-) diff --git a/Content/Items/AdventureMirror.cs b/Content/Items/AdventureMirror.cs index c30aaa0c..046243d6 100644 --- a/Content/Items/AdventureMirror.cs +++ b/Content/Items/AdventureMirror.cs @@ -1,4 +1,5 @@ -using PvPAdventure.Core.Features.SpawnSelector.Players; +using Microsoft.Xna.Framework; +using PvPAdventure.Core.Features.SpawnSelector.Players; using PvPAdventure.Core.Features.SpawnSelector.UI; using PvPAdventure.System; using Terraria; @@ -11,11 +12,13 @@ internal class AdventureMirror : ModItem { public override void SetDefaults() { + //Item.CloneDefaults(ItemID.MagicMirror); + var config = ModContent.GetInstance(); int recallFrames = config.AdventureMirrorRecallFrames; // 5 seconds = 60 * 5 - Item.useTime = recallFrames; - Item.useAnimation = recallFrames; + Item.useTime = recallFrames + 1; + Item.useAnimation = recallFrames + 1; Item.useStyle = ItemUseStyleID.HoldUp; Item.UseSound = SoundID.Item6; Item.rare = ItemRarityID.Blue; @@ -23,50 +26,128 @@ public override void SetDefaults() Item.noUseGraphic = false; } - public override bool CanUseItem(Player player) + //public override bool AltFunctionUse(Player player) => true; + //public override bool CanRightClick() => true; + public override bool ConsumeItem(Player player) => false; + //public override void RightClick(Player player) + //{ + // if (!player.GetModPlayer().TryStartMirrorChannel()) + // return; + //} + + private void CancelItemUse(Player player) { - var amp = player.GetModPlayer(); - var gm = ModContent.GetInstance(); + player.controlUseItem = false; + player.channel = false; + player.itemAnimation = 0; + player.itemTime = 0; + player.reuseDelay = 0; + } - if (gm.CurrentPhase != GameManager.Phase.Playing) + public bool IsPlayerInSpawnRegion(Player player) + { + // Is player in resin's spawn region? + var regionManager = ModContent.GetInstance(); + Point tilePos = player.Center.ToTileCoordinates(); + var region = regionManager.GetRegionContaining(tilePos); + if (region != null) { - if (player.whoAmI == Main.myPlayer) - PopupTextHelper.NewText("Cannot use before game has started!"); - return false; + return true; } - if (amp.IsPlayerInSpawnRegion()) + // Is player in bed spawn region? + Vector2 bedSpawnPoint = new(player.SpawnX, player.SpawnY); + float distanceToBedSpawn = Vector2.Distance(bedSpawnPoint * 16f, player.Center); + if (distanceToBedSpawn <= 25 * 16f) + { + return true; + } + + return false; + } + + public override void UseStyle(Player player, Rectangle heldItemFrame) + { + base.UseStyle(player, heldItemFrame); + + if (IsPlayerInSpawnRegion(player)) + { + //PopupTextHelper.NewText("cannot use in spawn!", player); + //CancelItemUse(player); + //return; + } + + // If this player moves, cancel their use + if (player.velocity.LengthSquared() > 0) { if (player.whoAmI == Main.myPlayer) - PopupTextHelper.NewText("Cannot use in spawn region!"); - return false; + PopupTextHelper.NewText("stay still!", player); + CancelItemUse(player); + return; } - if (amp.MirrorActive) - return false; + // Spawn dust for all to see + if (Main.rand.NextBool()) + Dust.NewDust(player.position, player.width, player.height,DustID.MagicMirror, player.velocity.X * 0.5f,player.velocity.Y * 0.5f,150,default,1.5f); - if (player.whoAmI == Main.myPlayer && player.velocity.LengthSquared() > 0f) + // Show countdown for all to see + int secondsLeft = (player.itemTime + 59) / 60; + if (player.itemTime % 60 == 0 && secondsLeft > 0) { - //PopupTextHelper.NewText("Cannot use while moving!"); - return false; + PopupTextHelper.NewText(secondsLeft.ToString(), player, Color.GreenYellow); } - return true; + // Teleport the player who used the item to their spawn and open their map + if (player.whoAmI == Main.myPlayer && player.itemTime == 1) + { + TeleportToSpawn(player); + OpenFullscreenMap(); + } } - public override bool AltFunctionUse(Player player) => true; - public override bool CanRightClick() => true; - public override bool ConsumeItem(Player player) => false; - public override void RightClick(Player player) + private void TeleportToSpawn(Player player) { - if (!player.GetModPlayer().TryStartMirrorChannel()) + // Get player spawn pos + int twoTilesAbove = 2 * 16; + Vector2 playerSpawnPos = new Vector2(player.SpawnX * 16, player.SpawnY * 16 - twoTilesAbove); + if (player.SpawnX == -1 && player.SpawnY == -1) + { + playerSpawnPos = new(Main.spawnTileX * 16, Main.spawnTileY * 16 - 48); + } + + player.Teleport(playerSpawnPos); + } + + private void OpenFullscreenMap() + { + // Do nothing if config value is false + var config = ModContent.GetInstance(); + if (!config.OpenMapAfterRecall) return; + + // First we must close inventory, otherwise map is not allowed to open + Main.playerInventory = false; + + // Open fullscreen map + Main.mapFullscreen = true; + + // Center the map + float worldCenterX = Main.maxTilesX / 2f; + float worldCenterY = Main.maxTilesY / 2f; + Main.mapFullscreenPos.X = worldCenterX; + Main.mapFullscreenPos.Y = worldCenterY; + + // Zoom out a bit to see the whole map + Main.mapFullscreenScale = 0.01f; + } + + public override void UseAnimation(Player player) + { + base.UseAnimation(player); } public override bool? UseItem(Player player) { - var amp = player.GetModPlayer(); - amp.TryStartMirrorChannel(); return true; } diff --git a/Core/Debug/DebugKeybinds.cs b/Core/Debug/DebugKeybinds.cs index 8dd6a11f..30a348fe 100644 --- a/Core/Debug/DebugKeybinds.cs +++ b/Core/Debug/DebugKeybinds.cs @@ -1,4 +1,5 @@ using Microsoft.Xna.Framework.Input; +using PvPAdventure.System; using Terraria; using Terraria.GameInput; using Terraria.ModLoader; @@ -12,11 +13,13 @@ public class DebugKeybinds : ModSystem { public ModKeybind OpenControls { get; private set; } public ModKeybind SwitchTeams { get; private set; } + public ModKeybind StartGame { get; private set; } public override void Load() { OpenControls = KeybindLoader.RegisterKeybind(Mod, "[DEBUG] OpenControls", Keys.NumPad0); SwitchTeams = KeybindLoader.RegisterKeybind(Mod, "[DEBUG] SwitchTeams", Keys.NumPad1); + StartGame = KeybindLoader.RegisterKeybind(Mod, "[DEBUG] StartGame", Keys.NumPad2); } } @@ -38,6 +41,13 @@ public override void ProcessTriggers(TriggersSet triggersSet) Player.team = (Player.team + 1) % 6; // Cycle through teams 0-5 Main.NewText("[DEBUG] " + Player.name + " switched to team: " + (Terraria.Enums.Team)Player.team); } + + // Start game + if (key.StartGame.JustPressed) + { + var gm = ModContent.GetInstance(); + gm.StartGame(60000, 1); + } } } diff --git a/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs b/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs index bef3f26e..7ab290b7 100644 --- a/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs +++ b/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs @@ -15,61 +15,16 @@ namespace PvPAdventure.Core.Features.SpawnSelector.Players; public class AdventureMirrorPlayer : ModPlayer { - public int MirrorTimer; // frames left - public bool MirrorActive; // currently channeling - public int MirrorCountdownLastSecond = -1; - private bool didRebuildOnDeath; - - public bool TryStartMirrorChannel() + public override void OnHurt(Player.HurtInfo info) { - if (ModContent.GetInstance().CurrentPhase != GameManager.Phase.Playing) - { - if (Player.whoAmI == Main.myPlayer) - PopupTextHelper.NewText("Cannot use before game has started!"); - return false; - } - - if (IsPlayerInSpawnRegion()) - { - if (Player.whoAmI == Main.myPlayer) - PopupTextHelper.NewText("Cannot use in spawn region!"); - return false; - } - - if (MirrorActive) - return false; - - if (Player.whoAmI == Main.myPlayer && IsMoving()) - { - CancelMirrorUse(); - PopupTextHelper.NewText("Cannot use while moving!"); - return false; - } - - SoundEngine.PlaySound(SoundID.Item6); - var config = ModContent.GetInstance(); - int recallFrames = config.AdventureMirrorRecallFrames + 1; - - MirrorActive = true; - MirrorTimer = recallFrames; - return true; - } - - public override void OnHurt(Terraria.Player.HurtInfo info) - { - // Only care if mirror is currently channeling - if (!MirrorActive) - return; - - // Stop the channel + reset animation - CancelMirrorUse(); - - PopupTextHelper.NewText("Mirror interrupted!", Color.Crimson); + base.OnHurt(info); + // TODO Stop the channel + reset animation + //PopupTextHelper.NewText("Mirror interrupted!", Color.Crimson); } public bool IsPlayerInSpawnRegion() { - // Force SSS to be enabled when player is within the spawn region. + // Is player in spawn region? var regionManager = ModContent.GetInstance(); Point tilePos = Player.Center.ToTileCoordinates(); var region = regionManager.GetRegionContaining(tilePos); @@ -77,52 +32,29 @@ public bool IsPlayerInSpawnRegion() { return true; } - return false; - } - - private bool IsMoving() => Player.velocity.LengthSquared() > 0f; - - private void CancelMirrorUse() - { - MirrorActive = false; - MirrorTimer = 0; - MirrorCountdownLastSecond = -1; - if (Player.itemAnimation > 0 && - Player.HeldItem.type == ModContent.ItemType()) + // Is player in bed spawn region? + Vector2 bedSpawnPoint = new(Player.SpawnX, Player.SpawnY); + float distanceToBedSpawn = Vector2.Distance(bedSpawnPoint * 16f, Player.Center); + if (distanceToBedSpawn <= 25 * 16f) { - Player.controlUseItem = false; - Player.channel = false; - Player.itemAnimation = 0; - Player.itemTime = 0; - Player.reuseDelay = 0; + return true; } - } - - public bool CancelIfPlayerMoves() - { - if (Player.whoAmI != Main.myPlayer) - return false; - - if (!IsMoving()) - return false; - CancelMirrorUse(); - PopupTextHelper.NewText("Cannot use while moving!"); - return true; + return false; } public override void PostUpdate() { - if (!Player.dead) - { - didRebuildOnDeath = false; - } - - if (Main.dedServ || Player.whoAmI != Main.myPlayer) + // Only run on clients + if (Main.dedServ) return; + // Only run on this client + if (Player.whoAmI != Main.myPlayer) + return; + // Update spawn selector UI state every frame if (ModContent.GetInstance().CurrentPhase == GameManager.Phase.Playing && Main.mapFullscreen && IsPlayerInSpawnRegion()) { SpawnSelectorSystem.SetEnabled(true); @@ -131,61 +63,9 @@ public override void PostUpdate() { SpawnSelectorSystem.SetEnabled(false); } - - if (!MirrorActive) - return; - - if (CancelIfPlayerMoves()) - return; - - // spawn dust - if (Main.rand.NextBool()) - Dust.NewDust(Player.position, Player.width, Player.height,DustID.MagicMirror, Player.velocity.X * 0.5f,Player.velocity.Y * 0.5f,150,default,1.5f); - - // countdown tick - MirrorTimer--; - //Main.NewText(MirrorTimer); - - // Show countdown every full second - if (MirrorTimer > 0 && MirrorTimer % 60 == 0) - { - int secondsLeft = MirrorTimer / 60; - PopupTextHelper.NewText(secondsLeft.ToString(), Color.LightGreen, showInMultiplayer: true); - } - - // Ready to teleport to spawn - if (MirrorTimer <= 0) - { - var config = ModContent.GetInstance(); - if (config.OpenMapAfterRecall) - { - // Close player inventory - Main.playerInventory = false; - - // Open fullscreen map - Main.mapFullscreen = true; - - // center the map - float worldCenterX = Main.maxTilesX / 2f; - float worldCenterY = Main.maxTilesY / 2f; - Main.mapFullscreenPos.X = worldCenterX; - Main.mapFullscreenPos.Y = worldCenterY; - Main.mapFullscreenScale = 0.21f; // arbitrary value to zoom out that fits the entire map - } - - // Teleport to spawn - Vector2 spawnPos = new(Main.spawnTileX * 16, Main.spawnTileY * 16 - 48); - //Main.LocalPlayer.Teleport(spawnPos, 0); - CustomTeleportWithoutSound(spawnPos); - - SpawnSelectorSystem.SetEnabled(true); // This is redundant because spawn region already sets it to true - ModContent.GetInstance().state.spawnSelectorPanel.Rebuild(); - Player.RemoveAllGrapplingHooks(); - MirrorActive = false; - } } - private void CustomTeleportWithoutSound(Vector2 newPos) + public void CustomTeleportWithoutSound(Vector2 newPos) { try { @@ -263,23 +143,20 @@ public override void ProcessTriggers(TriggersSet triggersSet) if (keybinds.AdventureMirrorKeybind.JustPressed) { - TryUseAdventureMirror(); + TryUseAdventureMirrorKeybind(); } } - public void TryUseAdventureMirror() + public void TryUseAdventureMirrorKeybind() { int mirrorIndex = EnsureMirrorInInventory(); if (mirrorIndex == -1) { - PopupTextHelper.NewText("No Adventure Mirror found in inventory or banks!"); + PopupTextHelper.NewText("No Adventure Mirror found in inventory or banks!", Player); return; } - if (CancelIfPlayerMoves()) - return; - Player.selectedItem = mirrorIndex; Player.controlUseItem = true; Player.ItemCheck(); diff --git a/Core/Features/SpawnSelector/Systems/ItemSlotHooks.cs b/Core/Features/SpawnSelector/Systems/ItemSlotHooks.cs index 207cdd24..99c02636 100644 --- a/Core/Features/SpawnSelector/Systems/ItemSlotHooks.cs +++ b/Core/Features/SpawnSelector/Systems/ItemSlotHooks.cs @@ -36,10 +36,9 @@ private static bool Hook_LeftClick_SellOrTrash( if (!item.IsAir && item.type == ModContent.ItemType()) { - if (Main.keyState.IsKeyDown(Keys.LeftShift) && Main.mouseLeft && Main.mouseLeftRelease) - { - PopupTextHelper.NewText("Cannot quick trash Adventure Mirror!"); - } + //if (Main.keyState.IsKeyDown(Keys.LeftShift) && Main.mouseLeft && Main.mouseLeftRelease) + //PopupTextHelper.NewText("Cannot quick trash Adventure Mirror!"); + //SoundEngine.PlaySound(SoundID.MenuClose); return false; // skip SellOrTrash completely } @@ -64,8 +63,8 @@ private static void Hook_LeftClick_ItemArray( if (isStorageSlot && isMirrorOnMouse) { - if (Main.mouseLeft && Main.mouseLeftRelease) - PopupTextHelper.NewText("Cannot store Adventure Mirror!"); + //if (Main.mouseLeft && Main.mouseLeftRelease) + //PopupTextHelper.NewText("Cannot store Adventure Mirror!"); // Do NOT call orig -> cancel the placement return; @@ -74,8 +73,8 @@ private static void Hook_LeftClick_ItemArray( // 2) Block dragging mirror onto trash slot if (context == ItemSlot.Context.TrashItem && isMirrorOnMouse) { - if (Main.mouseLeft && Main.mouseLeftRelease) - PopupTextHelper.NewText("Cannot trash Adventure Mirror!"); + //if (Main.mouseLeft && Main.mouseLeftRelease) + //PopupTextHelper.NewText("Cannot trash Adventure Mirror!"); return; // cancel trashing } @@ -93,8 +92,8 @@ private static bool Hook_SellItem( { if (IsAdventureMirror(item)) { - if (Main.mouseLeft && Main.mouseLeftRelease) - PopupTextHelper.NewText("Cannot sell Adventure Mirror!"); + //if (Main.mouseLeft && Main.mouseLeftRelease) + //PopupTextHelper.NewText("Cannot sell Adventure Mirror!", self); return false; } diff --git a/Core/Features/SpawnSelector/UI/PopupTextHelper.cs b/Core/Features/SpawnSelector/UI/PopupTextHelper.cs index 8041d8bb..370de859 100644 --- a/Core/Features/SpawnSelector/UI/PopupTextHelper.cs +++ b/Core/Features/SpawnSelector/UI/PopupTextHelper.cs @@ -5,38 +5,24 @@ namespace PvPAdventure.Core.Features.SpawnSelector.UI; public static class PopupTextHelper { - public static void NewText(string text, Color color=default, bool showInMultiplayer=false) + public static void NewText(string text, Player player, Color color=default) { - if (color == default) - color = Color.Crimson; - + // Check if the config allows popup text var config = ModContent.GetInstance(); if (!config.ShowPopupText) - { return; - } - if (showInMultiplayer) - { - PopupText.NewText(new AdvancedPopupRequest - { - Color = color, - Text = text, - Velocity = new(0f, -4f), - DurationInFrames = 30 - }, Main.LocalPlayer.Top); - return; - } + // Default color to Crimson if none is provided + if (color == default) + color = Color.Crimson; - if (Main.LocalPlayer.whoAmI == Main.myPlayer) + // Create and display the popup text + PopupText.NewText(new AdvancedPopupRequest { - PopupText.NewText(new AdvancedPopupRequest - { - Color = color, - Text = text, - Velocity = new(0f, -4f), - DurationInFrames = 60 - }, Main.LocalPlayer.Top); - } + Color = color, + Text = text, + Velocity = new(0f, -4f), + DurationInFrames = 60 + }, player.Top + new Vector2(0,-12)); } } diff --git a/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs b/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs index 9cf2304e..03f10a47 100644 --- a/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs +++ b/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs @@ -303,7 +303,7 @@ private void DrawPlayerHeadOnMap(Player p) Color c = Main.teamColor[p.team]; // Draw head in UI-space - Main.MapPlayerRenderer.DrawPlayerHead(Main.Camera, p, headPosUI, scale: 1.8f, borderColor: c); + Main.MapPlayerRenderer.DrawPlayerHead(Main.Camera, p, headPosUI, scale: 1.6f, borderColor: c); // Text centered below head, also in UI-space string name = p.name ?? string.Empty; diff --git a/Localization/en-US.hjson b/Localization/en-US.hjson index 4bcf91d6..353a7109 100644 --- a/Localization/en-US.hjson +++ b/Localization/en-US.hjson @@ -18,6 +18,7 @@ Mods: { SwitchTeams.DisplayName: Switch Teams "[DEBUG] OpenControls.DisplayName": "[ D E B U G] Open Controls" "[DEBUG] SwitchTeams.DisplayName": "[ D E B U G] Switch Teams" + "[DEBUG] StartGame.DisplayName": "[ D E B U G] Start Game" } Configs: { diff --git a/System/GameManager.cs b/System/GameManager.cs index aa925483..421ba167 100644 --- a/System/GameManager.cs +++ b/System/GameManager.cs @@ -159,11 +159,11 @@ public override void PostUpdateTime() } } } - public void StartGame(int time) + public void StartGame(int time, int countdownTimeInSeconds = 10) { CurrentPhase = Phase.Waiting; TimeRemaining = time; - _startGameCountdown = 60 * 10; + _startGameCountdown = 60 * countdownTimeInSeconds; ChatHelper.BroadcastChatMessage( NetworkText.FromLiteral($"The game will begin in {_startGameCountdown / 60} seconds."), Color.Green); From 64f46d590acfce6eb3acaf4d02c2ce51426bcb2f Mon Sep 17 00:00:00 2001 From: emyhrberg <121192176+emyhrberg@users.noreply.github.com> Date: Fri, 21 Nov 2025 01:36:07 +0100 Subject: [PATCH 183/206] Starting to implement team beds Also cleaning up AM. Sending packets. Drawing them on IMapLayer. Not MP tested yet. --- AdventurePacketIdentifier.cs | 3 +- Content/Items/AdventureMirror.cs | 66 +++++++++-- .../Players/AdventureMirrorPlayer.cs | 18 ++- .../Players/ModifyDrawInfoPlayer.cs | 1 + .../SpawnSelector/Systems/ItemSlotHooks.cs | 3 - .../Systems/SpawnSelectorState.cs | 6 +- .../SpawnSelector/UI/DrawBedsOnMapHook.cs | 110 ++++++++++++++++++ .../SpawnSelector/UI/PopupTextHelper.cs | 6 +- ...ctorPanel.cs => SpawnSelectorBasePanel.cs} | 12 +- ...rListItem.cs => SpawnSelectorCharacter.cs} | 65 +---------- ...mPanel.cs => SpawnSelectorQuestionMark.cs} | 4 +- PvPAdventure.cs | 24 ++++ PvPAdventure.csproj | 2 - 13 files changed, 228 insertions(+), 92 deletions(-) create mode 100644 Core/Features/SpawnSelector/UI/DrawBedsOnMapHook.cs rename Core/Features/SpawnSelector/UI/{UISpawnSelectorPanel.cs => SpawnSelectorBasePanel.cs} (92%) rename Core/Features/SpawnSelector/UI/{UISpawnSelectorCharacterListItem.cs => SpawnSelectorCharacter.cs} (89%) rename Core/Features/SpawnSelector/UI/{UISpawnSelectorRandomPanel.cs => SpawnSelectorQuestionMark.cs} (93%) diff --git a/AdventurePacketIdentifier.cs b/AdventurePacketIdentifier.cs index 3a814bd5..b6940a8d 100644 --- a/AdventurePacketIdentifier.cs +++ b/AdventurePacketIdentifier.cs @@ -6,5 +6,6 @@ public enum AdventurePacketIdentifier : byte PlayerStatistics, PingPong, PlayerItemPickup, - PlayerTeam + PlayerTeam, + PlayerBed } \ No newline at end of file diff --git a/Content/Items/AdventureMirror.cs b/Content/Items/AdventureMirror.cs index 046243d6..5baff499 100644 --- a/Content/Items/AdventureMirror.cs +++ b/Content/Items/AdventureMirror.cs @@ -1,5 +1,4 @@ using Microsoft.Xna.Framework; -using PvPAdventure.Core.Features.SpawnSelector.Players; using PvPAdventure.Core.Features.SpawnSelector.UI; using PvPAdventure.System; using Terraria; @@ -25,15 +24,57 @@ public override void SetDefaults() Item.value = Item.buyPrice(gold: 5); Item.noUseGraphic = false; } - - //public override bool AltFunctionUse(Player player) => true; - //public override bool CanRightClick() => true; public override bool ConsumeItem(Player player) => false; - //public override void RightClick(Player player) - //{ - // if (!player.GetModPlayer().TryStartMirrorChannel()) - // return; - //} + + #region Right click use + public override bool AltFunctionUse(Player player) => true; + public override bool CanRightClick() => true; + + public override void RightClick(Player player) + { + // Find this item in the player's inventory + int index = -1; + for (int i = 0; i < player.inventory.Length; i++) + { + if (player.inventory[i] == Item) // 'Item' is this ModItem's backing Item + { + index = i; + break; + } + } + + if (index == -1) + return; + + // Make it the selected hotbar item + player.selectedItem = index; + + // Simulate pressing the use button so vanilla + your UseStyle/UseItem run + player.controlUseItem = true; + player.ItemCheck(); // runs use logic, respects useTime/useAnimation + } + #endregion + public override bool CanUseItem(Player player) + { + // If this player moves, cancel their use + if (player.velocity.LengthSquared() > 0) + { + //if (player.whoAmI == Main.myPlayer) + //PopupTextHelper.NewText("stay still!", player); + return false; + } + + // Redundant check, just to be sure we don't allow any shenanigans + var gm = ModContent.GetInstance(); + if (gm.CurrentPhase != GameManager.Phase.Playing) + { + if (player.whoAmI == Main.myPlayer) + PopupTextHelper.NewText("wait until game starts!", player); + return false; + } + + return true; + } private void CancelItemUse(Player player) { @@ -66,6 +107,9 @@ public bool IsPlayerInSpawnRegion(Player player) return false; } + /// + /// Main logic for using the Adventure Mirror + /// public override void UseStyle(Player player, Rectangle heldItemFrame) { base.UseStyle(player, heldItemFrame); @@ -80,8 +124,8 @@ public override void UseStyle(Player player, Rectangle heldItemFrame) // If this player moves, cancel their use if (player.velocity.LengthSquared() > 0) { - if (player.whoAmI == Main.myPlayer) - PopupTextHelper.NewText("stay still!", player); + //if (player.whoAmI == Main.myPlayer) + //PopupTextHelper.NewText("stay still!", player); CancelItemUse(player); return; } diff --git a/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs b/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs index 7ab290b7..199ad84a 100644 --- a/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs +++ b/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs @@ -5,10 +5,8 @@ using PvPAdventure.System; using PvPAdventure.System.Client; using Terraria; -using Terraria.Audio; using Terraria.GameContent; using Terraria.GameInput; -using Terraria.ID; using Terraria.ModLoader; namespace PvPAdventure.Core.Features.SpawnSelector.Players; @@ -44,6 +42,7 @@ public bool IsPlayerInSpawnRegion() return false; } + private int _timer; // temp debug todo public override void PostUpdate() { // Only run on clients @@ -63,6 +62,21 @@ public override void PostUpdate() { SpawnSelectorSystem.SetEnabled(false); } + + // Run every 3 seconds (60 ticks * 3) + //_timer++; + //if (_timer < 60 * 3) + // return; + + //_timer = 0; + + //foreach (var player in Main.player) + //{ + // if (player == null || !player.active) + // continue; + + // Main.NewText($"Player {player.whoAmI} ({player.name}) - SpawnX:{player.SpawnX}, SpawnY:{player.SpawnY}")); + //} } public void CustomTeleportWithoutSound(Vector2 newPos) diff --git a/Core/Features/SpawnSelector/Players/ModifyDrawInfoPlayer.cs b/Core/Features/SpawnSelector/Players/ModifyDrawInfoPlayer.cs index af783918..c83a99df 100644 --- a/Core/Features/SpawnSelector/Players/ModifyDrawInfoPlayer.cs +++ b/Core/Features/SpawnSelector/Players/ModifyDrawInfoPlayer.cs @@ -6,6 +6,7 @@ namespace PvPAdventure.Core.Features.SpawnSelector.Players; /// /// Useful for forcing the player to be drawn with full brightness even when in player is in darkness. +/// DONT DELETE, its still used /// public class ModifyDrawInfoPlayer : ModPlayer { diff --git a/Core/Features/SpawnSelector/Systems/ItemSlotHooks.cs b/Core/Features/SpawnSelector/Systems/ItemSlotHooks.cs index 99c02636..f6751443 100644 --- a/Core/Features/SpawnSelector/Systems/ItemSlotHooks.cs +++ b/Core/Features/SpawnSelector/Systems/ItemSlotHooks.cs @@ -2,9 +2,6 @@ using Terraria.ModLoader; using Terraria.UI; using PvPAdventure.Content.Items; -using PvPAdventure.Core.Features.SpawnSelector.UI; -using PvPAdventure.System.Client; -using Microsoft.Xna.Framework.Input; namespace PvPAdventure.Core.Features.SpawnSelector.Systems; diff --git a/Core/Features/SpawnSelector/Systems/SpawnSelectorState.cs b/Core/Features/SpawnSelector/Systems/SpawnSelectorState.cs index 77c71bfa..44798c8e 100644 --- a/Core/Features/SpawnSelector/Systems/SpawnSelectorState.cs +++ b/Core/Features/SpawnSelector/Systems/SpawnSelectorState.cs @@ -9,7 +9,7 @@ namespace PvPAdventure.Core.Features.SpawnSelector.Systems; public class SpawnSelectorState : UIState { - public UISpawnSelectorPanel spawnSelectorPanel; + public SpawnSelectorBasePanel spawnSelectorPanel; public override void OnInitialize() { spawnSelectorPanel = new(); @@ -25,10 +25,10 @@ public override void OnInitialize() public override void OnActivate() { base.OnActivate(); - UISpawnSelectorPanel panel = null; + SpawnSelectorBasePanel panel = null; foreach (var element in Elements) { - panel = element as UISpawnSelectorPanel; + panel = element as SpawnSelectorBasePanel; if (panel != null) break; } diff --git a/Core/Features/SpawnSelector/UI/DrawBedsOnMapHook.cs b/Core/Features/SpawnSelector/UI/DrawBedsOnMapHook.cs new file mode 100644 index 00000000..c204c382 --- /dev/null +++ b/Core/Features/SpawnSelector/UI/DrawBedsOnMapHook.cs @@ -0,0 +1,110 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using PvPAdventure.Core.Features.SpawnSelector.Systems; +using Terraria; +using Terraria.DataStructures; +using Terraria.GameContent; +using Terraria.ID; +using Terraria.Map; +using Terraria.ModLoader; +using Terraria.UI; + +namespace PvPAdventure.Core.Features.SpawnSelector.UI; + +internal class DrawBedsOnMapHook : ModSystem +{ + public override void Load() + { + On_Player.ChangeSpawn += OnPlayerChangeSpawn; + On_SpawnMapLayer.Draw += OnSpawnMapLayer; + } + + public override void Unload() + { + On_Player.ChangeSpawn -= OnPlayerChangeSpawn; + On_SpawnMapLayer.Draw -= OnSpawnMapLayer; + } + + private void OnPlayerChangeSpawn(On_Player.orig_ChangeSpawn orig, Player self, int x, int y) + { + orig(self, x, y); + + // Send packet to server, notifying the server of a updated player spawn position for a player. + if (Main.netMode == NetmodeID.MultiplayerClient) + { + var packet = Mod.GetPacket(); + packet.Write((byte)AdventurePacketIdentifier.PlayerBed); + packet.Write((byte)self.whoAmI); + packet.Write(x); + packet.Write(y); + packet.Send(); + } + } + + private void OnSpawnMapLayer(On_SpawnMapLayer.orig_Draw orig, + SpawnMapLayer self, + ref MapOverlayDrawContext context, + ref string text) + { + // Let vanilla draw spawn point + local bed first + orig(self, ref context, ref text); + + // If spawn selector state is not active, skip + if (!SpawnSelectorSystem.GetEnabled()) + return; + + Texture2D bedTex = TextureAssets.SpawnBed.Value; + + for (int i = 0; i < Main.maxPlayers; i++) + { + Player p = Main.player[i]; + if (p == null || !p.active) + continue; + + if (p.team != Main.LocalPlayer.team) + continue; + + //Main.NewText(p.SpawnX); + + // No bed set for this player + if (p.SpawnX == -1 || p.SpawnY == -1) + continue; + + Vector2 bedTilePos = new Vector2(p.SpawnX, p.SpawnY); + + var hoverCheck = context.Draw( + texture: bedTex, + position: bedTilePos, + color: Color.White, + frame: new SpriteFrame(1, 1), + scaleIfNotSelected: 1.0f, + scaleIfSelected: 1.8f, + alignment: Alignment.Bottom, + spriteEffects: SpriteEffects.None + ); + + if (!hoverCheck.IsMouseOver) + continue; + + // Hover text + text = $"Teleport to {p.name}'s Bed"; + + if (Main.mouseLeft && Main.mouseLeftRelease) + { + if (Main.netMode == NetmodeID.MultiplayerClient) + { + // Ask server to teleport this player to their spawn position + NetMessage.SendData(MessageID.TeleportEntity, number: Main.myPlayer); + } + else + { + // Singleplayer: teleport directly to bed spawn + Vector2 spawn = new Vector2(p.SpawnX * 16, p.SpawnY * 16 - 48); + p.Teleport(spawn); + } + + Main.mapFullscreen = false; + } + } + } +} diff --git a/Core/Features/SpawnSelector/UI/PopupTextHelper.cs b/Core/Features/SpawnSelector/UI/PopupTextHelper.cs index 370de859..93295be2 100644 --- a/Core/Features/SpawnSelector/UI/PopupTextHelper.cs +++ b/Core/Features/SpawnSelector/UI/PopupTextHelper.cs @@ -21,8 +21,8 @@ public static void NewText(string text, Player player, Color color=default) { Color = color, Text = text, - Velocity = new(0f, -4f), - DurationInFrames = 60 - }, player.Top + new Vector2(0,-12)); + Velocity = new(0f, -4), + DurationInFrames = 120 + }, player.Top + new Vector2(0,-4)); } } diff --git a/Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs b/Core/Features/SpawnSelector/UI/SpawnSelectorBasePanel.cs similarity index 92% rename from Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs rename to Core/Features/SpawnSelector/UI/SpawnSelectorBasePanel.cs index f4259a58..1d493a98 100644 --- a/Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs +++ b/Core/Features/SpawnSelector/UI/SpawnSelectorBasePanel.cs @@ -7,10 +7,10 @@ namespace PvPAdventure.Core.Features.SpawnSelector.UI { - public class UISpawnSelectorPanel : UIPanel + public class SpawnSelectorBasePanel : UIPanel { private UIPanel _randomPanel; - private readonly List _playerItems = new(); + private readonly List _playerItems = new(); private const float Spacing = 8f; private const float HorizontalPadding = 16f; @@ -62,8 +62,8 @@ private void BuildLayout() int playerCount = players.Count; - float itemWidth = UISpawnSelectorCharacterListItem.ItemWidth; - float itemHeight = UISpawnSelectorCharacterListItem.ItemHeight; + float itemWidth = SpawnSelectorCharacter.ItemWidth; + float itemHeight = SpawnSelectorCharacter.ItemHeight; float randomWidth = itemHeight; float contentWidth = playerCount * itemWidth @@ -89,7 +89,7 @@ private void BuildLayout() { float x = startX + i * (itemWidth + Spacing); - var row = new UISpawnSelectorCharacterListItem(players[i]); + var row = new SpawnSelectorCharacter(players[i]); row.Left.Set(x, 0f); row.Top.Set(y, 0f); @@ -97,7 +97,7 @@ private void BuildLayout() _playerItems.Add(row); } - _randomPanel = new UISpawnSelectorRandomPanel( + _randomPanel = new SpawnSelectorQuestionMark( startX, itemHeight, playerCount, diff --git a/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs b/Core/Features/SpawnSelector/UI/SpawnSelectorCharacter.cs similarity index 89% rename from Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs rename to Core/Features/SpawnSelector/UI/SpawnSelectorCharacter.cs index 03f10a47..7f3a1539 100644 --- a/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs +++ b/Core/Features/SpawnSelector/UI/SpawnSelectorCharacter.cs @@ -16,7 +16,7 @@ namespace PvPAdventure.Core.Features.SpawnSelector.UI /// /// Vanilla-like character row. /// - internal class UISpawnSelectorCharacterListItem : UIPanel + internal class SpawnSelectorCharacter : UIPanel { internal const float ItemWidth = 260f; internal const float ItemHeight = 72f; @@ -28,7 +28,7 @@ internal class UISpawnSelectorCharacterListItem : UIPanel private readonly int _playerIndex; public int PlayerIndex => _playerIndex; - public UISpawnSelectorCharacterListItem(Player player) + public SpawnSelectorCharacter(Player player) { _dividerTexture = Main.Assets.Request("Images/UI/Divider"); _innerPanelTexture = Main.Assets.Request("Images/UI/InnerPanelBackground"); @@ -49,60 +49,6 @@ public override void OnInitialize() SetPadding(6f); } - - private void DrawArrow(Player p) - { - float scale = Main.mapFullscreenScale; - - Vector2 mapPos = new( - (p.position.X + p.width / 2f) / 16f, - (p.position.Y + p.gfxOffY + p.height / 2f) / 16f - ); - - Vector2 headPos = new( - (mapPos.X - Main.mapFullscreenPos.X) * scale + Main.screenWidth / 2f, - (mapPos.Y - Main.mapFullscreenPos.Y) * scale + Main.screenHeight / 2f - ); - headPos += new Vector2(34f, 44f); - - CalculatedStyle inner = GetInnerDimensions(); - Rectangle rect = new( - (int)inner.X - 6, - (int)inner.Y - 6, - 100, - 72 - ); - - Texture2D arrowTex = Ass.Arrow.Value; - Vector2 arrowCenter = new( - rect.X + rect.Width / 2f -1, - rect.Bottom - 20f - ); - - Vector2 arrowOrigin = arrowTex.Size() * 0.5f; - - Vector2 dir = headPos - arrowCenter; - - if (dir.LengthSquared() > 0.001f) - { - dir.Normalize(); - - float rotation = dir.ToRotation(); - - Main.spriteBatch.Draw( - arrowTex, - arrowCenter, // stays the same, no matter angle - null, - Color.White, - rotation, - arrowOrigin, // rotate around center - 0.9f, - SpriteEffects.None, - 0f - ); - } - } - private void DrawNineSlice(SpriteBatch sb, int x, int y, int w, int h, Texture2D tex, Color color, int inset, int c = 5) { x += inset; y += inset; w -= inset * 2; h -= inset * 2; @@ -319,7 +265,6 @@ private void DrawPlayerHeadOnMap(Player p) public override void MouseOver(UIMouseEvent evt) { base.MouseOver(evt); - BackgroundColor = new Color(73, 92, 161); } @@ -337,9 +282,8 @@ public override void LeftClick(UIMouseEvent evt) Main.LocalPlayer.UnityTeleport(player.position); - // close map and SSS + // close map Main.mapFullscreen = false; - SpawnSelectorSystem.SetEnabled(false); } private void DrawPanel(SpriteBatch spriteBatch, Vector2 position, float width) @@ -367,6 +311,9 @@ private void DrawPanel(SpriteBatch spriteBatch, Vector2 position, float width) ); } + /// + /// Draws a biome-looking BG behind the player + /// public static void DrawMapFullscreenBackground(SpriteBatch sb, Rectangle rect, Player player) { if (player == null || !player.active) diff --git a/Core/Features/SpawnSelector/UI/UISpawnSelectorRandomPanel.cs b/Core/Features/SpawnSelector/UI/SpawnSelectorQuestionMark.cs similarity index 93% rename from Core/Features/SpawnSelector/UI/UISpawnSelectorRandomPanel.cs rename to Core/Features/SpawnSelector/UI/SpawnSelectorQuestionMark.cs index 237cf2d2..647fc665 100644 --- a/Core/Features/SpawnSelector/UI/UISpawnSelectorRandomPanel.cs +++ b/Core/Features/SpawnSelector/UI/SpawnSelectorQuestionMark.cs @@ -11,9 +11,9 @@ namespace PvPAdventure.Core.Features.SpawnSelector.UI { - internal class UISpawnSelectorRandomPanel : UIPanel + internal class SpawnSelectorQuestionMark : UIPanel { - public UISpawnSelectorRandomPanel(float startX, float itemHeight, int playerCount, float itemWidth, float Spacing, float y) + public SpawnSelectorQuestionMark(float startX, float itemHeight, int playerCount, float itemWidth, float Spacing, float y) { Width.Set(itemHeight, 0f); Height.Set(itemHeight, 0f); diff --git a/PvPAdventure.cs b/PvPAdventure.cs index 37cd443c..d4b674ab 100644 --- a/PvPAdventure.cs +++ b/PvPAdventure.cs @@ -51,6 +51,30 @@ public override void HandlePacket(BinaryReader reader, int whoAmI) switch (id) { + case AdventurePacketIdentifier.PlayerBed: + { + byte playerId = reader.ReadByte(); + int spawnX = reader.ReadInt32(); + int spawnY = reader.ReadInt32(); + + Player p = Main.player[playerId]; + p.SpawnX = spawnX; + p.SpawnY = spawnY; + + if (Main.dedServ) + { + // Re-broadcast to all clients except the original sender (whoAmI) + var packet = GetPacket(); + packet.Write((byte)AdventurePacketIdentifier.PlayerBed); + packet.Write(playerId); + packet.Write(spawnX); + packet.Write(spawnY); + packet.Send(-1, whoAmI); + } + + break; + } + case AdventurePacketIdentifier.BountyTransaction: { var bountyTransaction = BountyManager.Transaction.Deserialize(reader); diff --git a/PvPAdventure.csproj b/PvPAdventure.csproj index 05bbc501..27248e3c 100644 --- a/PvPAdventure.csproj +++ b/PvPAdventure.csproj @@ -4,8 +4,6 @@ PvPAdventure latest - - From 589343a2f6892ddff922efe283ab0204c9c74f54 Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Fri, 21 Nov 2025 23:44:04 -0800 Subject: [PATCH 184/206] A fistful of shit Removed ancient chizzy hotswap debuff Fixed the virus Removed profanity from code Removed banners (thanks playering for the suggestion) Small tweaks to worldgen (WIP) --- AdventurePlayer.cs | 164 ++-------------- AdventureProjectile.cs | 2 - Dogshit.cs | 417 ++++++++++++++++++++++++++++++++++++----- 3 files changed, 392 insertions(+), 191 deletions(-) diff --git a/AdventurePlayer.cs b/AdventurePlayer.cs index d227c10c..178e0ce8 100644 --- a/AdventurePlayer.cs +++ b/AdventurePlayer.cs @@ -33,6 +33,8 @@ public class AdventurePlayer : ModPlayer public int Kills { get; private set; } public int Deaths { get; private set; } + private bool deathProcessedThisLife = false; + private readonly int[] _playerMeleeInvincibleTime = new int[Main.maxPlayers]; public HashSet ItemPickups { get; private set; } = new(); @@ -616,126 +618,6 @@ public override bool PreKill(double damage, int hitDirection, bool pvp, ref bool } private bool hadShinyStoneLastFrame; - public class AncientChiselHotswap : ModPlayer - { - private bool hadAncientChiselLastFrame; - private int ancientChiselSlot = -1; - private int disabledSlot = -1; // Track which slot is currently disabled - private Item[] lastFrameArmor = new Item[10]; - private int periodicBuffTimer = 0; // Timer for periodic buff application - - public override void PostUpdateEquips() - { - if (lastFrameArmor[3] == null) - { - for (int i = 0; i < 10; i++) - { - lastFrameArmor[i] = new Item(); - } - } - - int currentChiselSlot = GetAncientChiselSlot(); - bool hasAncientChisel = currentChiselSlot != -1; - - // Check if Ancient Chisel was just equipped (wasn't equipped last frame, but is now) - if (!hadAncientChiselLastFrame && hasAncientChisel) - { - Player.AddBuff(ModContent.BuffType(), 15 * 60 * 60); - disabledSlot = currentChiselSlot; - periodicBuffTimer = 0; // Reset timer when first equipped - } - - // Check if Ancient Chisel was just removed - if (hadAncientChiselLastFrame && !hasAncientChisel) - { - Player.AddBuff(ModContent.BuffType(), 15 * 60 * 60); - disabledSlot = ancientChiselSlot; - periodicBuffTimer = 0; // Reset timer when removed - } - - // Handle periodic buff application while equipped - if (hasAncientChisel) - { - periodicBuffTimer++; - - // Apply buff every 59 seconds (59 * 60 ticks) - if (periodicBuffTimer >= 59 * 60) - { - Player.AddBuff(ModContent.BuffType(), 15 * 60 * 60); - disabledSlot = currentChiselSlot; - periodicBuffTimer = 0; // Reset timer - } - - ancientChiselSlot = currentChiselSlot; - hadAncientChiselLastFrame = true; - } - else - { - hadAncientChiselLastFrame = false; - periodicBuffTimer = 0; // Reset timer when not equipped - } - - if (Player.HasBuff(ModContent.BuffType()) && disabledSlot != -1) - { - PreventSlotPlacement(disabledSlot); - } - else if (!Player.HasBuff(ModContent.BuffType())) - { - disabledSlot = -1; - } - - for (int i = 3; i < 10; i++) - { - lastFrameArmor[i] = Player.armor[i].Clone(); - } - } - - private void PreventSlotPlacement(int slotIndex) - { - if (slotIndex >= 3 && slotIndex < 10) - { - Item currentItem = Player.armor[slotIndex]; - Item lastFrameItem = lastFrameArmor[slotIndex]; - bool slotChanged = currentItem.type != lastFrameItem.type || currentItem.stack != lastFrameItem.stack; - bool isNotAncientChisel = currentItem.type != ItemID.AncientChisel; - bool wasEmpty = lastFrameItem.IsAir; - bool nowHasItem = !currentItem.IsAir; - - if (slotChanged && isNotAncientChisel && (wasEmpty && nowHasItem)) - { - Item rejectedItem = currentItem.Clone(); - Player.armor[slotIndex] = lastFrameItem.Clone(); // Restore previous state - - if (Main.netMode != NetmodeID.Server) // Only on client/singleplayer - { - Item leftoverItem = Player.GetItem(Player.whoAmI, rejectedItem, GetItemSettings.InventoryEntityToPlayerInventorySettings); - } - } - } - } - - private int GetAncientChiselSlot() - { - for (int i = 3; i < 10; i++) // Check all accessory slots - { - if (Player.armor[i].type == ItemID.AncientChisel && - (i < 7 || !Player.hideVisibleAccessory[i - 3])) - { - return i; - } - } - return -1; - } - - // Method to check if a slot is disabled (can be used by other systems) - public bool IsSlotDisabled(int slotIndex) - { - return Player.HasBuff(ModContent.BuffType()) && - disabledSlot == slotIndex; - } - } - - private int lastSpectreHead = 0; private bool hadSpectreSetLastFrame; @@ -840,25 +722,20 @@ public override void Kill(double damage, int hitDirection, bool pvp, PlayerDeath // Only play kill markers on clients that we hurt that aren't ourselves if (!Main.dedServ && pvp && damageSource.SourcePlayerIndex == Main.myPlayer && Player.whoAmI != Main.myPlayer) PlayKillMarker((int)damage); - // Only for non-suicide PvP deaths, apply Beetle Might as needed to the attacker. if (pvp && damageSource.SourcePlayerIndex != Player.whoAmI) { var attacker = Main.player[damageSource.SourcePlayerIndex]; - if (attacker.beetleOffense && attacker.beetleOrbs < 3) { // First, make sure to clear any previous buff if applicable. if (attacker.beetleOrbs > 0) attacker.ClearBuff(BuffID.BeetleMight1 + attacker.beetleOrbs - 1); - attacker.AddBuff(BuffID.BeetleMight1 + attacker.beetleOrbs, 5); } } - if (Main.netMode == NetmodeID.MultiplayerClient) return; - // Remove the Dungeon Guardian when it kills a player. if (damageSource.SourceNPCIndex != -1) { @@ -874,31 +751,35 @@ public override void Kill(double damage, int hitDirection, bool pvp, PlayerDeath try { - Player killer = null; + if (deathProcessedThisLife) + { + Mod.Logger.Warn($"Death already processed for {Player.name} this life, skipping duplicate K/D increment"); + return; + } + deathProcessedThisLife = true; - // If you killed yourself, we should delegate to the recent damage. + Player killer = null; if (pvp && damageSource.SourcePlayerIndex != -1 && damageSource.SourcePlayerIndex != Player.whoAmI) { killer = Main.player[damageSource.SourcePlayerIndex]; } else { - // We checked this earlier, but let's check again for logging purposes. if (pvp && damageSource.SourcePlayerIndex == -1) Mod.Logger.Warn($"PvP kill without a valid SourcePlayerIndex ({this} killed)"); - if (RecentDamageFromPlayer != null) killer = Main.player[RecentDamageFromPlayer.Who]; } - // Nothing should happen for suicide if (killer == null || !killer.active || killer.whoAmI == Player.whoAmI) return; ModContent.GetInstance().AwardPlayerKillToTeam(killer, Player); - killer.GetModPlayer().Kills += 1; - killer.GetModPlayer().SyncStatistics(); + // Increment and sync + var killerAdventurePlayer = killer.GetModPlayer(); + killerAdventurePlayer.Kills += 1; + killerAdventurePlayer.SyncStatistics(); Deaths += 1; SyncStatistics(); @@ -909,7 +790,6 @@ public override void Kill(double damage, int hitDirection, bool pvp, PlayerDeath { // PvP or not, reset whom we last took damage from. RecentDamageFromPlayer = null; - // Remove recent damage for ALL players we've attacked after we die. // These are indirect post-mortem kills, which we don't want. // FIXME: We would still like to attribute this to the next recent damager, which would require a stack of @@ -923,6 +803,11 @@ public override void Kill(double damage, int hitDirection, bool pvp, PlayerDeath } } + public override void OnRespawn() + { + deathProcessedThisLife = false; + } + public override void ProcessTriggers(TriggersSet triggersSet) { var pointsManager = ModContent.GetInstance(); @@ -2571,19 +2456,6 @@ public override void SetStaticDefaults() Main.buffNoTimeDisplay[Type] = false; } } -public class AncientChiselHotswapBuff : ModBuff -{ - public override string Texture => $"PvPAdventure/Assets/Buff/AncientChiselHotswapBuff"; - - public override void SetStaticDefaults() - { - Main.debuff[Type] = true; - Main.buffNoSave[Type] = false; - Main.buffNoTimeDisplay[Type] = false; - Main.persistentBuff[Type] = true; - } -} - public class NewIchorPlayerDebuff : ModBuff { public override string Texture => $"PvPAdventure/Assets/Buff/NewIchorPlayerDebuff"; diff --git a/AdventureProjectile.cs b/AdventureProjectile.cs index b3f3cdb6..60976ea4 100644 --- a/AdventureProjectile.cs +++ b/AdventureProjectile.cs @@ -961,8 +961,6 @@ public override void ReceiveExtraAI(Projectile projectile, BitReader bitReader, attachOffset.Y = binaryReader.ReadSingle(); } } - - // GlobalItem even though in adventureprojectile because FUCK YOU public class PiranhaGunItem : GlobalItem { public override bool AppliesToEntity(Item entity, bool lateInstantiation) diff --git a/Dogshit.cs b/Dogshit.cs index f7c7c875..aea436ef 100644 --- a/Dogshit.cs +++ b/Dogshit.cs @@ -14,6 +14,9 @@ using Terraria.GameContent.Generation; using Terraria.IO; using Terraria.WorldBuilding; +using System.IO; +using Terraria.DataStructures; +using Terraria.GameContent.Biomes; namespace PvPAdventure { public class IncreasedRainSystem : ModSystem @@ -386,83 +389,411 @@ private static void RemoveTownNPCCheck(ILContext il) } } } - // public class ExtraWorldGen : ModSystem + internal class RemoveBanners : GlobalItem + { + public override void OnSpawn(Item item, IEntitySource source) + { + if (item.createTile == TileID.Banners) + { + item.active = false; + item.TurnToAir(); + } + } + + public override void UpdateInventory(Item item, Player player) + { + if (item.createTile == TileID.Banners) + { + item.TurnToAir(); + } + } + } + //public class ExtraWorldGen : ModSystem + //{ + // public override void ModifyWorldGenTasks(List tasks, ref double totalWeight) // { - // public override void ModifyWorldGenTasks(List tasks, ref double totalWeight) + // // We need to run AFTER most worldgen, so let's find later passes to insert after + // int shiniesIndex = tasks.FindIndex(genpass => genpass.Name.Equals("Shinies")); + // int finalCleanupIndex = tasks.FindIndex(genpass => genpass.Name.Equals("Final Cleanup")); + + // // If we can't find those, use a safe default (near the end) + // int insertIndex = finalCleanupIndex != -1 ? finalCleanupIndex : tasks.Count - 1; + + // // Add all our extra generation as a single pass that runs late + // tasks.Insert(insertIndex, new PassLegacy("Extra Structures Late Pass", delegate (GenerationProgress progress, GameConfiguration passConfig) // { - // // Find the original passes to insert after them - // int lifeCrystalIndex = tasks.FindIndex(genpass => genpass.Name.Equals("Life Crystals")); - // int minecartIndex = tasks.FindIndex(genpass => genpass.Name.Equals("Minecart Tracks")); - // int undergroundChestIndex = tasks.FindIndex(genpass => genpass.Name.Equals("Buried Chests")); + // progress.Message = "Adding extra structures..."; + + // // Add extra pyramids + // progress.Set(0.1); + // int extraPyramids = WorldGen.genRand.Next(1, 1); + // for (int i = 0; i < extraPyramids; i++) + // { + // int attempts = 0; + // bool placed = false; + // while (!placed && attempts < 1000) + // { + // int x = WorldGen.genRand.Next(300, Main.maxTilesX - 300); + // int y = (int)Main.worldSurface - 10; + // if (WorldGen.InWorld(x, y) && Main.tile[x, y].TileType == TileID.Sand) + // { + // placed = WorldGen.Pyramid(x, y); + // } + // attempts++; + // } + // } + + // // Add extra pyramids + // progress.Set(0.2); + // int extraPatches = WorldGen.genRand.Next(3, 7); + + // for (int i = 0; i < extraPatches; i++) + // { + // progress.Set((double)i / extraPatches); + // int attempts = 0; + // bool placed = false; + + // while (!placed && attempts < 1000) + // { + // int x = WorldGen.genRand.Next((int)(Main.maxTilesX * 0.2), (int)(Main.maxTilesX * 0.8)); + // int y = WorldGen.genRand.Next((int)Main.rockLayer + 50, Main.maxTilesY - 300); + + // if (WorldGen.InWorld(x, y)) + // { + // WorldGen.ShroomPatch(x, y); + // placed = true; + // } + // attempts++; + // } + // } - // // Add extra life crystals (2x more) - // if (lifeCrystalIndex != -1) + // // Add extra rich mahogany trees using the proper biome system + // progress.Set(0.3); + // try // { - // tasks.Insert(lifeCrystalIndex + 1, new PassLegacy("Extra Life Crystals", delegate (GenerationProgress progress, GameConfiguration passConfig) + // var mahoganyTreeBiome = GenVars.configuration.CreateBiome(); + // int extraMahoganyTrees = WorldGen.genRand.Next(4, 6); + // int mahoganyPlaced = 0; + // int mahoganyAttempts = 0; + + // while (mahoganyPlaced < extraMahoganyTrees && mahoganyAttempts < 20000) // { - // progress.Message = "Adding extra life crystals..."; + // Point point = WorldGen.RandomWorldPoint((int)Main.worldSurface + 50, 50, 500, 50); + // if (mahoganyTreeBiome.Place(point, GenVars.structures)) + // { + // mahoganyPlaced++; + // } + // mahoganyAttempts++; + // } + // } + // catch + // { + // // Fallback if MahoganyTreeBiome isn't available + // ModContent.GetInstance().Logger.Info("MahoganyTreeBiome not available, skipping extra mahogany trees"); + // } - // double num = (double)(Main.maxTilesX * Main.maxTilesY) * 2E-05; // Same formula as vanilla but e5 for now + // // Add extra minecart tracks using TrackGenerator + // progress.Set(0.5); + // try + // { + // var trackGenerator = new TrackGenerator(); + + // // Add long tracks + // int extraLongTracks = WorldGen.genRand.Next(15, 20); + // int longTrackPlaced = 0; + // int longTrackAttempts = 0; - // for (int i = 0; i < (int)num; i++) + // while (longTrackPlaced < extraLongTracks && longTrackAttempts < Main.maxTilesX) + // { + // Point point = WorldGen.RandomWorldPoint((int)Main.worldSurface, 10, 200, 10); + // if (trackGenerator.Place(point, 300, 2000)) // Long track length range // { - // progress.Set((double)i / num); + // longTrackPlaced++; + // longTrackAttempts = 0; + // } + // else + // { + // longTrackAttempts++; + // } + // } + + // // Add standard tracks + // int extraStandardTracks = WorldGen.genRand.Next(15, 22); + // int standardTrackPlaced = 0; + // int standardTrackAttempts = 0; + + // while (standardTrackPlaced < extraStandardTracks && standardTrackAttempts < Main.maxTilesX) + // { + // Point point = WorldGen.RandomWorldPoint((int)Main.worldSurface, 10, 200, 10); + // if (trackGenerator.Place(point, 100, 300)) // Standard track length range + // { + // standardTrackPlaced++; + // standardTrackAttempts = 0; + // } + // else + // { + // standardTrackAttempts++; + // } + // } + // } + // catch + // { + // // Fallback if TrackGenerator isn't available + // ModContent.GetInstance().Logger.Info("TrackGenerator not available, using alternative minecart track generation"); + + // // Alternative minecart track generation + // int extraTracks = WorldGen.genRand.Next(10, 18); + // for (int i = 0; i < extraTracks; i++) + // { + // int attempts = 0; + // bool placed = false; + // while (!placed && attempts < 500) + // { + // int x = WorldGen.genRand.Next(200, Main.maxTilesX - 200); + // int y = WorldGen.genRand.Next((int)Main.worldSurface + 50, (int)Main.rockLayer + 100); + + // if (WorldGen.InWorld(x, y)) + // { + // // Create underground tunnel with minecart tracks + // WorldGen.TileRunner(x, y, (double)WorldGen.genRand.Next(8, 15), WorldGen.genRand.Next(50, 100), + // -1, false, 0f, 0f, true, true); - // bool placed = false; - // int attempts = 0; + // // Place minecart tracks in the tunnel + // for (int trackX = x - 5; trackX <= x + 5; trackX++) + // { + // if (WorldGen.InWorld(trackX, y) && !Main.tile[trackX, y].HasTile) + // { + // WorldGen.PlaceTile(trackX, y, TileID.MinecartTrack, true, false); + // } + // } + + // placed = true; + // } + // attempts++; + // } + // } + // } + + // // Add extra hives using HiveBiome + // progress.Set(0.6); + // try + // { + // var hiveBiome = GenVars.configuration.CreateBiome(); + // var honeyPatchBiome = GenVars.configuration.CreateBiome(); + // double hiveNum = (double)Main.maxTilesX / 4200.0; + // int extraHives = WorldGen.genRand.Next((int)(7.0 * hiveNum), (int)(11.0 * hiveNum)); - // while (!placed && attempts < 10000) + // for (int i = 0; i < extraHives; i++) + // { + // int attempts = 0; + // bool placed = false; + // while (!placed && attempts < 1000) + // { + // Point point = WorldGen.RandomWorldPoint((int)(Main.worldSurface + Main.rockLayer) >> 1, 20, 300, 20); + // if (hiveBiome.Place(point, GenVars.structures)) // { - // int x = WorldGen.genRand.Next(Main.offLimitBorderTiles, Main.maxTilesX - Main.offLimitBorderTiles); - // int y = WorldGen.genRand.Next((int)(Main.worldSurface * 2.0 + Main.rockLayer) / 3, Main.maxTilesY - 300); + // placed = true; + // int honeyPatches = WorldGen.genRand.Next(3); + // int honeyPlaced = 0; + // int honeyAttempts = 0; - // if (WorldGen.getGoodWorldGen) //for the worthy + // while (honeyPlaced < honeyPatches && honeyAttempts < 100) // { - // y = WorldGen.genRand.Next((int)Main.worldSurface, Main.maxTilesY - 400); + // double distance = WorldGen.genRand.NextDouble() * 60.0 + 30.0; + // double angle = WorldGen.genRand.NextDouble() * 6.2831854820251465; + // int honeyX = (int)(Math.Cos(angle) * distance) + point.X; + // int honeyY = (int)(Math.Sin(angle) * distance) + point.Y; + // honeyAttempts++; + + // if (honeyPatchBiome.Place(new Point(honeyX, honeyY), GenVars.structures)) + // { + // honeyPlaced++; + // } // } + // } + // attempts++; + // } + // } + // } + // catch + // { + // // Fallback if HiveBiome isn't available + // ModContent.GetInstance().Logger.Info("HiveBiome not available, using alternative hive generation"); - // if (WorldGen.AddLifeCrystal(x, y)) + // // Alternative hive generation + // int extraHives = WorldGen.genRand.Next(4, 8); + // for (int i = 0; i < extraHives; i++) + // { + // int attempts = 0; + // bool placed = false; + // while (!placed && attempts < 500) + // { + // int x = WorldGen.genRand.Next(200, Main.maxTilesX - 200); + // int y = WorldGen.genRand.Next((int)((Main.worldSurface + Main.rockLayer) / 2), (int)Main.rockLayer + 200); + + // // Check if we're in jungle (mud blocks) + // if (Main.tile[x, y].TileType == TileID.Mud || Main.tile[x, y].TileType == TileID.JungleGrass) + // { + // // Create a hive using TileRunner with Hive block (225) + // int hiveSize = WorldGen.genRand.Next(30, 60); + // WorldGen.TileRunner(x, y, (double)hiveSize, 1, TileID.Hive, false, 0f, 0f, true, true); + + // // Carve out the interior + // WorldGen.TileRunner(x, y, (double)(hiveSize - 10), 1, -1, false, 0f, 0f, true, true); + + // // Add some honey + // if (WorldGen.genRand.NextBool(3)) // { - // placed = true; + // WorldGen.TileRunner(x, y, (double)WorldGen.genRand.Next(5, 15), 1, TileID.HoneyBlock, false, 0f, 0f, true, true); // } - // attempts++; + + // placed = true; // } + // attempts++; // } - // })); + // } // } - // // Add extra underground chests (2x more) - // if (undergroundChestIndex != -1) + + // // Add extra sky islands with houses + // progress.Set(0.8); + // int extraIslands = WorldGen.genRand.Next(2, 4); + // for (int i = 0; i < extraIslands; i++) // { - // tasks.Insert(undergroundChestIndex + 1, new PassLegacy("Extra Underground Chests", delegate (GenerationProgress progress, GameConfiguration passConfig) + // int attempts = 0; + // bool placed = false; + // while (!placed && attempts < 1000) // { - // progress.Message = "Adding extra underground chests..."; + // int x = WorldGen.genRand.Next((int)(Main.maxTilesX * 0.1), (int)(Main.maxTilesX * 0.9)); + // int y = WorldGen.genRand.Next(90, (int)Main.worldSurface - 150); + + // if (x > Main.maxTilesX / 2 - 150 && x < Main.maxTilesX / 2 + 150) + // { + // attempts++; + // continue; + // } + + // if (WorldGen.InWorld(x, y)) + // { + // WorldGen.CloudIsland(x, y); - // // Vanilla formula is roughly maxTilesX / 34 - // int extraChests = Main.maxTilesX / 34; + // int islandStyle = 0; + // if (WorldGen.remixWorldGen && WorldGen.drunkWorldGen) + // { + // bool flag = (GenVars.crimsonLeft && x < Main.maxTilesX / 2) || (!GenVars.crimsonLeft && x > Main.maxTilesX / 2); + // islandStyle = flag ? 5 : 4; + // } + // else if (WorldGen.getGoodWorldGen || WorldGen.remixWorldGen) + // { + // islandStyle = WorldGen.crimson ? 5 : 4; + // } + // else if (Main.tenthAnniversaryWorld) + // { + // islandStyle = 6; + // } + + // WorldGen.IslandHouse(x, y, islandStyle); + // placed = true; + // } + // attempts++; + // } + // } - // for (int i = 0; i < extraChests; i++) + // // Add extra mine houses with buried chests + // progress.Set(0.9); + // int extraHouses = WorldGen.genRand.Next(40, 80); + // for (int i = 0; i < extraHouses; i++) + // { + // int attempts = 0; + // bool placed = false; + // while (!placed && attempts < 1000) + // { + // int x = WorldGen.genRand.Next(100, Main.maxTilesX - 100); + // int y = WorldGen.genRand.Next((int)Main.worldSurface + 100, (int)Main.rockLayer + 200); + + // if (WorldGen.InWorld(x, y) && !Main.tile[x, y].HasTile && Main.tile[x, y].WallType == 0) // { - // progress.Set((double)i / extraChests); + // // Generate the mine house + // WorldGen.MineHouse(x, y); - // bool placed = false; - // int attempts = 0; + // // Now try to place a buried chest inside the mine house + // bool chestPlaced = false; + // int chestAttempts = 0; - // while (!placed && attempts < 1000) + // // Search for a suitable spot inside the mine house area for the chest + // while (!chestPlaced && chestAttempts < 100) // { - // int x = WorldGen.genRand.Next(Main.offLimitBorderTiles, Main.maxTilesX - Main.offLimitBorderTiles); - // int y = WorldGen.genRand.Next((int)Main.worldSurface + 50, Main.maxTilesY - 350); + // // Look within a 15 tile radius of the original placement point + // int chestX = x + WorldGen.genRand.Next(-10, 11); + // int chestY = y + WorldGen.genRand.Next(-5, 6); - // if (WorldGen.AddBuriedChest(x, y, 0, false, 1)) + // if (WorldGen.InWorld(chestX, chestY)) // { - // placed = true; + // // Check if this position is inside the mine house structure + // // Mine houses typically have wooden walls (wall ID 27) and wood/stone tiles + // if (Main.tile[chestX, chestY].WallType == 27 || + // (Main.tile[chestX, chestY].HasTile && + // (Main.tile[chestX, chestY].TileType == TileID.WoodBlock || + // Main.tile[chestX, chestY].TileType == TileID.Stone))) + // { + // // Try to place a buried chest with random style + // int chestStyle = WorldGen.genRand.Next(1, 11); // Regular underground chest styles + // if (WorldGen.AddBuriedChest(chestX, chestY, 0, false, 1)) + // { + // chestPlaced = true; + // ModContent.GetInstance().Logger.Info($"Placed buried chest at {chestX}, {chestY} in mine house"); + // } + // } // } - // attempts++; + // chestAttempts++; // } + + // placed = true; // } - // })); + // attempts++; + // } // } - // ModContent.GetInstance().Logger.Info("Added extra worldgen passes for life crystals, and underground chests"); - // } + // // Add extra life crystals and underground chests + // progress.Set(0.95); + // int extraLifeCrystals = Main.maxTilesX / 15; + // for (int i = 0; i < extraLifeCrystals; i++) + // { + // int attempts = 0; + // bool placed = false; + // while (!placed && attempts < 1000) + // { + // int x = WorldGen.genRand.Next(Main.offLimitBorderTiles, Main.maxTilesX - Main.offLimitBorderTiles); + // int y = WorldGen.genRand.Next((int)(Main.worldSurface * 2.0 + Main.rockLayer) / 3, Main.maxTilesY - 300); + // if (WorldGen.AddLifeCrystal(x, y)) + // { + // placed = true; + // } + // attempts++; + // } + // } + + // int extraChests = Main.maxTilesX / 30; + // for (int i = 0; i < extraChests; i++) + // { + // int attempts = 0; + // bool placed = false; + // while (!placed && attempts < 1000) + // { + // int x = WorldGen.genRand.Next(Main.offLimitBorderTiles, Main.maxTilesX - Main.offLimitBorderTiles); + // int y = WorldGen.genRand.Next((int)Main.worldSurface + 50, Main.maxTilesY - 350); + // if (WorldGen.AddBuriedChest(x, y, 0, false, 1)) + // { + // placed = true; + // } + // attempts++; + // } + // } + + // progress.Set(1.0); + + // })); + + // ModContent.GetInstance().Logger.Info("Added extra worldgen pass for multiple structures"); // } + //} } \ No newline at end of file From ab72906b04329d0ee42669c0cb73221fda13a4f4 Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Sun, 23 Nov 2025 20:42:53 -0800 Subject: [PATCH 185/206] cahnged many drop drates --- AdventureDropDatabase.cs | 86 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 1 deletion(-) diff --git a/AdventureDropDatabase.cs b/AdventureDropDatabase.cs index 0ed715b3..9cf90b92 100644 --- a/AdventureDropDatabase.cs +++ b/AdventureDropDatabase.cs @@ -98,9 +98,10 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) foreach (var drop in drops) { ModifyDropRate(drop, ItemID.Stinger, 1, 1); - ModifyDropRate(drop, ItemID.TatteredBeeWing, 1, 33); + ModifyDropRate(drop, ItemID.TatteredBeeWing, 1, 1); } break; + case NPCID.GiantTortoise: foreach (var drop in drops) ModifyDropRate(drop, ItemID.TurtleShell, 1, 3); @@ -209,7 +210,11 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) case NPCID.Mothron: foreach (var drop in drops) + { ModifyDropRate(drop, ItemID.BrokenHeroSword, 1, 2); + ModifyDropRate(drop, ItemID.TheEyeOfCthulhu, 1, 2); + ModifyDropRate(drop, ItemID.MothronWings, 1, 6); + } break; case NPCID.SkeletonArcher: @@ -234,6 +239,85 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) ModifyDropRate(drop, ItemID.LihzahrdPowerCell, 1, 75); break; + case NPCID.MartianEngineer: + case NPCID.MartianOfficer: + case NPCID.BrainScrambler: + case NPCID.MartianWalker: + case NPCID.GrayGrunt: + case NPCID.GigaZapper: + case NPCID.RayGunner: + foreach (var drop in drops) + { + ModifyDropRate(drop, ItemID.ChargedBlasterCannon, 1, 300); + ModifyDropRate(drop, ItemID.LaserDrill, 1, 300); + } + break; + + case NPCID.AngryNimbus: + foreach (var drop in drops) + { + ModifyDropRate(drop, ItemID.NimbusRod, 1, 6); + } + break; + + case NPCID.AngryTrapper: + foreach (var drop in drops) + { + ModifyDropRate(drop, ItemID.Vine, 1, 1); + } + break; + + case NPCID.Hornet: + foreach (var drop in drops) + { + ModifyDropRate(drop, ItemID.Stinger, 1, 1); + } + break; + + case NPCID.Nailhead: + foreach (var drop in drops) + { + ModifyDropRate(drop, ItemID.NailGun, 1, 6); + } + break; + + case NPCID.Reaper: + foreach (var drop in drops) + { + ModifyDropRate(drop, ItemID.DeathSickle, 1, 20); + } + break; + + case NPCID.DeadlySphere: + foreach (var drop in drops) + { + ModifyDropRate(drop, ItemID.DeadlySphereStaff, 1, 10); + } + break; + + case NPCID.DrManFly: + foreach (var drop in drops) + { + ModifyDropRate(drop, ItemID.ToxicFlask, 1, 6); + } + break; + + case NPCID.PirateCaptain: + npcLoot.Add(ItemDropRule.OneFromOptions(1, + ItemID.CoinGun, + ItemID.LuckyCoin, + ItemID.DiscountCard, + ItemID.PirateStaff + ) + ); + foreach (var drop in drops) + { + + ModifyDropRate(drop, ItemID.Cutlass, 1, 10); + ModifyDropRate(drop, ItemID.GoldRing, 1, 10); + } + break; + case NPCID.EyeofCthulhu: foreach (var drop in drops) ModifyDropRate(drop, ItemID.Binoculars, 1, 1); From f4a44fc17e3854421d7dde96671a2534e105fd71 Mon Sep 17 00:00:00 2001 From: emyhrberg <121192176+emyhrberg@users.noreply.github.com> Date: Tue, 25 Nov 2025 00:39:29 +0100 Subject: [PATCH 186/206] WiP fixing teleport position for beds --- AdventurePacketIdentifier.cs | 3 +- Content/Items/AdventureMirror.cs | 50 +++++++++------ .../SpawnSelector/UI/DrawBedsOnMapHook.cs | 4 ++ Localization/en-US.hjson | 4 +- PvPAdventure.cs | 61 +++++++++++++++++-- PvPAdventure.csproj.user | 2 +- 6 files changed, 99 insertions(+), 25 deletions(-) diff --git a/AdventurePacketIdentifier.cs b/AdventurePacketIdentifier.cs index b6940a8d..4a7af571 100644 --- a/AdventurePacketIdentifier.cs +++ b/AdventurePacketIdentifier.cs @@ -7,5 +7,6 @@ public enum AdventurePacketIdentifier : byte PingPong, PlayerItemPickup, PlayerTeam, - PlayerBed + PlayerBed, + AdventureMirrorRightClickUse } \ No newline at end of file diff --git a/Content/Items/AdventureMirror.cs b/Content/Items/AdventureMirror.cs index 5baff499..778e4eaf 100644 --- a/Content/Items/AdventureMirror.cs +++ b/Content/Items/AdventureMirror.cs @@ -27,33 +27,52 @@ public override void SetDefaults() public override bool ConsumeItem(Player player) => false; #region Right click use - public override bool AltFunctionUse(Player player) => true; + public override bool AltFunctionUse(Player player) => true; public override bool CanRightClick() => true; public override void RightClick(Player player) { - // Find this item in the player's inventory + if (player.whoAmI != Main.myPlayer) + return; + + // Find the slot of this item int index = -1; for (int i = 0; i < player.inventory.Length; i++) { - if (player.inventory[i] == Item) // 'Item' is this ModItem's backing Item + if (player.inventory[i] == Item) { index = i; break; } } - if (index == -1) return; - // Make it the selected hotbar item - player.selectedItem = index; + if (player.CCed || player.itemAnimation > 0 || player.reuseDelay > 0) + return; - // Simulate pressing the use button so vanilla + your UseStyle/UseItem run - player.controlUseItem = true; - player.ItemCheck(); // runs use logic, respects useTime/useAnimation + if (Main.netMode == NetmodeID.SinglePlayer) + { + player.selectedItem = index; + player.controlUseItem = true; + player.releaseUseItem = true; + player.ItemCheck(); + player.controlUseItem = false; + player.releaseUseItem = false; + return; + } + + if (Main.netMode == NetmodeID.MultiplayerClient) + { + ModPacket p = Mod.GetPacket(); + p.Write((byte)AdventurePacketIdentifier.AdventureMirrorRightClickUse); + p.Write((byte)player.whoAmI); + p.Write((byte)index); + p.Send(); // to server + } } #endregion + public override bool CanUseItem(Player player) { // If this player moves, cancel their use @@ -107,9 +126,6 @@ public bool IsPlayerInSpawnRegion(Player player) return false; } - /// - /// Main logic for using the Adventure Mirror - /// public override void UseStyle(Player player, Rectangle heldItemFrame) { base.UseStyle(player, heldItemFrame); @@ -153,11 +169,11 @@ private void TeleportToSpawn(Player player) { // Get player spawn pos int twoTilesAbove = 2 * 16; - Vector2 playerSpawnPos = new Vector2(player.SpawnX * 16, player.SpawnY * 16 - twoTilesAbove); - if (player.SpawnX == -1 && player.SpawnY == -1) - { - playerSpawnPos = new(Main.spawnTileX * 16, Main.spawnTileY * 16 - 48); - } + //Vector2 playerSpawnPos = new Vector2(player.SpawnX * 16, player.SpawnY * 16 - twoTilesAbove); + //if (player.SpawnX == -1 && player.SpawnY == -1) + //{ + Vector2 playerSpawnPos = new(Main.spawnTileX * 16, Main.spawnTileY * 16 - twoTilesAbove); + //} player.Teleport(playerSpawnPos); } diff --git a/Core/Features/SpawnSelector/UI/DrawBedsOnMapHook.cs b/Core/Features/SpawnSelector/UI/DrawBedsOnMapHook.cs index c204c382..076502a7 100644 --- a/Core/Features/SpawnSelector/UI/DrawBedsOnMapHook.cs +++ b/Core/Features/SpawnSelector/UI/DrawBedsOnMapHook.cs @@ -93,6 +93,10 @@ private void OnSpawnMapLayer(On_SpawnMapLayer.orig_Draw orig, { if (Main.netMode == NetmodeID.MultiplayerClient) { + // Singleplayer: teleport directly to bed spawn + Vector2 spawn = new Vector2(p.SpawnX * 16, p.SpawnY * 16 - 48); + p.Teleport(spawn); + // Ask server to teleport this player to their spawn position NetMessage.SendData(MessageID.TeleportEntity, number: Main.myPlayer); } diff --git a/Localization/en-US.hjson b/Localization/en-US.hjson index 353a7109..c2688b3d 100644 --- a/Localization/en-US.hjson +++ b/Localization/en-US.hjson @@ -370,12 +370,12 @@ Mods: { } OpenMapAfterRecall: { - Label: Open Map After Recall + Label: "[i:2435] Open Map After Recall" Tooltip: Opens the map instantly after the mirror has finished channeling } ShowPopupText: { - Label: Show Popup Text + Label: "[i:159] Show Popup Text" Tooltip: Shows popup text related to item } diff --git a/PvPAdventure.cs b/PvPAdventure.cs index d4b674ab..76eb34ea 100644 --- a/PvPAdventure.cs +++ b/PvPAdventure.cs @@ -1,8 +1,9 @@ -using System.IO; -using System.Linq; -using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework; using MonoMod.Cil; +using PvPAdventure.Content.Items; using PvPAdventure.System; +using System.IO; +using System.Linq; using Terraria; using Terraria.Enums; using Terraria.ID; @@ -51,6 +52,59 @@ public override void HandlePacket(BinaryReader reader, int whoAmI) switch (id) { + case AdventurePacketIdentifier.AdventureMirrorRightClickUse: + { + byte playerId = reader.ReadByte(); + byte slot = reader.ReadByte(); + + if (Main.netMode == NetmodeID.Server) + { + if (playerId != whoAmI) + return; + + if (playerId < 0 || playerId >= Main.maxPlayers) + return; + + Player player = Main.player[playerId]; + if (player is null || !player.active) + return; + + if (slot < 0 || slot >= player.inventory.Length) + return; + + Item item = player.inventory[slot]; + if (item?.ModItem is not AdventureMirror) + return; + + ModPacket p = GetPacket(); + p.Write((byte)AdventurePacketIdentifier.AdventureMirrorRightClickUse); + p.Write(playerId); + p.Write(slot); + p.Send(); + } + else if (Main.netMode == NetmodeID.MultiplayerClient) + { + Player player = Main.player[playerId]; + if (player is null || !player.active) + return; + + if (slot < 0 || slot >= player.inventory.Length) + return; + + Item item = player.inventory[slot]; + if (item?.ModItem is not AdventureMirror) + return; + + // Visual state only + player.selectedItem = slot; + player.itemAnimation = item.useAnimation; + player.itemAnimationMax = item.useAnimation; + player.itemTime = item.useTime; + player.itemTimeMax = item.useTime; + } + + break; + } case AdventurePacketIdentifier.PlayerBed: { byte playerId = reader.ReadByte(); @@ -63,7 +117,6 @@ public override void HandlePacket(BinaryReader reader, int whoAmI) if (Main.dedServ) { - // Re-broadcast to all clients except the original sender (whoAmI) var packet = GetPacket(); packet.Write((byte)AdventurePacketIdentifier.PlayerBed); packet.Write(playerId); diff --git a/PvPAdventure.csproj.user b/PvPAdventure.csproj.user index 62b33ede..bccdcde8 100644 --- a/PvPAdventure.csproj.user +++ b/PvPAdventure.csproj.user @@ -4,6 +4,6 @@ ProjectDebugger - TerrariaSkipSelect + Terraria \ No newline at end of file From d665706f128762084d155ae94628eac212195a26 Mon Sep 17 00:00:00 2001 From: emyhrberg <121192176+emyhrberg@users.noreply.github.com> Date: Tue, 25 Nov 2025 05:46:57 +0100 Subject: [PATCH 187/206] Really good progress on everything 1. Added so teammate player beds always show in the map 2. Added respawn timer to players in spawn selector screen 3. Improved background BG biome drawing code 4. Added spawn box --- Content/Items/AdventureMirror.cs | 5 +- .../Players/AdventureMirrorPlayer.cs | 16 -- .../SpawnSelector/UI/DrawBedsOnMapHook.cs | 73 +++++- .../UI/SpawnSelectorBasePanel.cs | 20 +- .../UI/SpawnSelectorCharacter.cs | 224 +++++++++++++++--- System/RegionManager.cs | 82 ++++++- 6 files changed, 336 insertions(+), 84 deletions(-) diff --git a/Content/Items/AdventureMirror.cs b/Content/Items/AdventureMirror.cs index 778e4eaf..dc5746ac 100644 --- a/Content/Items/AdventureMirror.cs +++ b/Content/Items/AdventureMirror.cs @@ -27,8 +27,11 @@ public override void SetDefaults() public override bool ConsumeItem(Player player) => false; #region Right click use - public override bool AltFunctionUse(Player player) => true; public override bool CanRightClick() => true; + public override bool AltFunctionUse(Player player) + { + return false; + } public override void RightClick(Player player) { diff --git a/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs b/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs index 199ad84a..e3f84863 100644 --- a/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs +++ b/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs @@ -42,7 +42,6 @@ public bool IsPlayerInSpawnRegion() return false; } - private int _timer; // temp debug todo public override void PostUpdate() { // Only run on clients @@ -62,21 +61,6 @@ public override void PostUpdate() { SpawnSelectorSystem.SetEnabled(false); } - - // Run every 3 seconds (60 ticks * 3) - //_timer++; - //if (_timer < 60 * 3) - // return; - - //_timer = 0; - - //foreach (var player in Main.player) - //{ - // if (player == null || !player.active) - // continue; - - // Main.NewText($"Player {player.whoAmI} ({player.name}) - SpawnX:{player.SpawnX}, SpawnY:{player.SpawnY}")); - //} } public void CustomTeleportWithoutSound(Vector2 newPos) diff --git a/Core/Features/SpawnSelector/UI/DrawBedsOnMapHook.cs b/Core/Features/SpawnSelector/UI/DrawBedsOnMapHook.cs index 076502a7..4a6bcd83 100644 --- a/Core/Features/SpawnSelector/UI/DrawBedsOnMapHook.cs +++ b/Core/Features/SpawnSelector/UI/DrawBedsOnMapHook.cs @@ -16,12 +16,14 @@ internal class DrawBedsOnMapHook : ModSystem public override void Load() { On_Player.ChangeSpawn += OnPlayerChangeSpawn; + On_Player.RemoveSpawn += OnPlayerRemoveSpawn; On_SpawnMapLayer.Draw += OnSpawnMapLayer; } public override void Unload() { On_Player.ChangeSpawn -= OnPlayerChangeSpawn; + On_Player.RemoveSpawn -= OnPlayerRemoveSpawn; On_SpawnMapLayer.Draw -= OnSpawnMapLayer; } @@ -41,18 +43,27 @@ private void OnPlayerChangeSpawn(On_Player.orig_ChangeSpawn orig, Player self, i } } - private void OnSpawnMapLayer(On_SpawnMapLayer.orig_Draw orig, - SpawnMapLayer self, - ref MapOverlayDrawContext context, - ref string text) + private void OnPlayerRemoveSpawn(On_Player.orig_RemoveSpawn orig, Player self) + { + orig(self); + + // Send packet to server, notifying the server of a removed player spawn position for a player. + if (Main.netMode == NetmodeID.MultiplayerClient) + { + var packet = Mod.GetPacket(); + packet.Write((byte)AdventurePacketIdentifier.PlayerBed); + packet.Write((byte)self.whoAmI); + packet.Write(-1); + packet.Write(-1); + packet.Send(); + } + } + + private void OnSpawnMapLayer(On_SpawnMapLayer.orig_Draw orig,SpawnMapLayer self,ref MapOverlayDrawContext context, ref string text) { // Let vanilla draw spawn point + local bed first orig(self, ref context, ref text); - // If spawn selector state is not active, skip - if (!SpawnSelectorSystem.GetEnabled()) - return; - Texture2D bedTex = TextureAssets.SpawnBed.Value; for (int i = 0; i < Main.maxPlayers; i++) @@ -66,8 +77,10 @@ private void OnSpawnMapLayer(On_SpawnMapLayer.orig_Draw orig, //Main.NewText(p.SpawnX); - // No bed set for this player - if (p.SpawnX == -1 || p.SpawnY == -1) + bool selectorEnabled = SpawnSelectorSystem.GetEnabled(); + + // No bed set for this player + if (p.SpawnX == -1 || p.SpawnY == -1) continue; Vector2 bedTilePos = new Vector2(p.SpawnX, p.SpawnY); @@ -83,6 +96,15 @@ private void OnSpawnMapLayer(On_SpawnMapLayer.orig_Draw orig, spriteEffects: SpriteEffects.None ); + if (!selectorEnabled) + { + if (hoverCheck.IsMouseOver) + { + text = $"{p.name}'s Bed"; + } + continue; + } + if (!hoverCheck.IsMouseOver) continue; @@ -109,6 +131,37 @@ private void OnSpawnMapLayer(On_SpawnMapLayer.orig_Draw orig, Main.mapFullscreen = false; } + } + DrawSpawnBoxOnMap(ref context); + } + + private void DrawSpawnBoxOnMap(ref MapOverlayDrawContext context) + { + if (!Main.mapFullscreen) return; + + if (Main.mapFullscreenScale < 0.5) return; + + // spawn region in tiles (same as RegionManager) + Rectangle area = new(Main.spawnTileX - 25, Main.spawnTileY - 25, 50, 50); + + // tile → map screen + Vector2 topLeft = (new Vector2(area.X, area.Y) - context.MapPosition) * context.MapScale + context.MapOffset; + Vector2 size = new(area.Width * context.MapScale, area.Height * context.MapScale); + + Texture2D pix = TextureAssets.MagicPixel.Value; + Color col = Color.Black * 0.7f; + int t = 10; + + int x = (int)topLeft.X; + int y = (int)topLeft.Y; + int w = (int)size.X; + int h = (int)size.Y; + + // top, bottom, left, right + Main.spriteBatch.Draw(pix, new Rectangle(x, y, w, t), col); + Main.spriteBatch.Draw(pix, new Rectangle(x, y + h - t, w, t), col); + Main.spriteBatch.Draw(pix, new Rectangle(x, y, t, h), col); + Main.spriteBatch.Draw(pix, new Rectangle(x + w - t, y, t, h), col); } } diff --git a/Core/Features/SpawnSelector/UI/SpawnSelectorBasePanel.cs b/Core/Features/SpawnSelector/UI/SpawnSelectorBasePanel.cs index 1d493a98..44ec96ae 100644 --- a/Core/Features/SpawnSelector/UI/SpawnSelectorBasePanel.cs +++ b/Core/Features/SpawnSelector/UI/SpawnSelectorBasePanel.cs @@ -26,8 +26,6 @@ public override void OnInitialize() SetPadding(0f); BuildLayout(); - - Log.Info("UISpawnSelectorPanel.OnInitialize: layout built"); } private void BuildLayout() @@ -44,7 +42,7 @@ private void BuildLayout() { Player p = Main.player[i]; - if (p == null || !p.active || p.dead || p.statLife <= 0) + if (p == null) continue; if (p.whoAmI == local.whoAmI || p.team != local.team) @@ -54,12 +52,6 @@ private void BuildLayout() } } - // DEBUG: ADD LOCAL PLAYER - if (players.Count == 0 && local != null && local.active && !local.dead && local.statLife > 0) - { - players.Add(local); - } - int playerCount = players.Count; float itemWidth = SpawnSelectorCharacter.ItemWidth; @@ -110,13 +102,12 @@ private void BuildLayout() Recalculate(); RecalculateChildren(); - Log.Debug($"UISpawnSelectorPanel.BuildLayout: players={playerCount}, panelWidth={panelWidth}"); + Log.Debug($"UISpawnSelectorPanel.BuildLayout: players={playerCount}"); } public void Rebuild() { BuildLayout(); - Log.Debug("UISpawnSelectorPanel.Rebuild: UI rebuilt"); } public override void Update(GameTime gameTime) @@ -153,7 +144,7 @@ private bool NeedsRebuild() for (int i = 0; i < Main.maxPlayers; i++) { var p = Main.player[i]; - if (p == null || !p.active || p.dead || p.statLife <= 0) + if (p == null) continue; if (p.whoAmI == local.whoAmI || p.team != local.team) continue; @@ -161,11 +152,6 @@ private bool NeedsRebuild() players.Add(p.whoAmI); } - if (players.Count == 0 && local != null && local.active && !local.dead && local.statLife > 0) - { - players.Add(local.whoAmI); - } - if (players.Count != _playerItems.Count) return true; diff --git a/Core/Features/SpawnSelector/UI/SpawnSelectorCharacter.cs b/Core/Features/SpawnSelector/UI/SpawnSelectorCharacter.cs index 7f3a1539..680d0364 100644 --- a/Core/Features/SpawnSelector/UI/SpawnSelectorCharacter.cs +++ b/Core/Features/SpawnSelector/UI/SpawnSelectorCharacter.cs @@ -1,15 +1,16 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using PvPAdventure.Core.Features.SpawnSelector.Players; -using PvPAdventure.Core.Features.SpawnSelector.Systems; using PvPAdventure.Core.Helpers; using ReLogic.Content; using System; using Terraria; using Terraria.GameContent; using Terraria.GameContent.UI.Elements; +using Terraria.ID; using Terraria.ModLoader; using Terraria.UI; +using Terraria.UI.Chat; namespace PvPAdventure.Core.Features.SpawnSelector.UI { @@ -81,7 +82,7 @@ protected override void DrawSelf(SpriteBatch sb) { var rect2 = dims.ToRectangle(); - Utils.DrawBorderString(sb, "Unable to find player :(", rect2.Location.ToVector2() + new Vector2(50, 0), Color.White); + Utils.DrawBorderString(sb, "Unable to find p :(", rect2.Location.ToVector2() + new Vector2(50, 0), Color.White); return; } @@ -122,7 +123,7 @@ protected override void DrawSelf(SpriteBatch sb) } catch (Exception e) { - Log.Error("Failed to draw player: " + e); + Log.Error("Failed to draw p: " + e); } finally { @@ -147,7 +148,7 @@ protected override void DrawSelf(SpriteBatch sb) float rightAreaCenterX = rightAreaLeft + rightAreaWidth * 0.5f; // Name centered in the right-area - string name = string.IsNullOrEmpty(player.name) ? "Unknown player" : player.name + ""; + string name = string.IsNullOrEmpty(player.name) ? "Unknown p" : player.name + ""; float nameScale = 1f; if (player.name.Length > 16) nameScale = 0.85f; Vector2 nameSize = FontAssets.MouseText.Value.MeasureString(name) * nameScale; @@ -216,11 +217,18 @@ protected override void DrawSelf(SpriteBatch sb) // Draw player head if hovering DrawPlayerHeadOnMap(player); + + // Draw player respawn timer if it exists + string respawnTimeInSeconds = ((player.respawnTimer / 60) + 1).ToString(); + if (player.respawnTimer != 0) + { + Utils.DrawBorderStringBig(sb, respawnTimeInSeconds, pos + new Vector2(31, 4), Color.Gray, scale: 1f); + } } private void DrawPlayerHeadOnMap(Player p) { - if (p == null || !p.active) + if (p == null || !p.active || p.dead) return; var config = ModContent.GetInstance(); @@ -234,13 +242,13 @@ private void DrawPlayerHeadOnMap(Player p) // Player in tile coords Vector2 tilePos = p.Center / 16f; - // Screen-space position on the fullscreen map (pixels) + // Screen-space position on the fullscreen map (pixels) Vector2 mapScreenCenter = new( Main.screenWidth / 2f, Main.screenHeight / 2f ); Vector2 headPosScreen = (tilePos - Main.mapFullscreenPos) * mapScale + mapScreenCenter; - //headPosScreen += new Vector2(80, 40); // your offset + //headPosScreen += new Vector2(80, 40); // offset headPosScreen *= Main.UIScale; Matrix invUi = Matrix.Invert(Main.UIScaleMatrix); @@ -249,7 +257,7 @@ private void DrawPlayerHeadOnMap(Player p) Color c = Main.teamColor[p.team]; // Draw head in UI-space - Main.MapPlayerRenderer.DrawPlayerHead(Main.Camera, p, headPosUI, scale: 1.6f, borderColor: c); + Main.MapPlayerRenderer.DrawPlayerHead(Main.Camera, p, headPosUI, scale: 1.3f, borderColor: c); // Text centered below head, also in UI-space string name = p.name ?? string.Empty; @@ -259,18 +267,27 @@ private void DrawPlayerHeadOnMap(Player p) headPosUI.X - nameSize.X * 0.5f, headPosUI.Y + 30f ); - Utils.DrawBorderString(Main.spriteBatch, name, namePos, Color.White, textScale); + Utils.DrawBorderString(Main.spriteBatch, "Teleport to " + name, namePos, Color.White, textScale); } public override void MouseOver(UIMouseEvent evt) { base.MouseOver(evt); + + Player p = Main.player[_playerIndex]; + if (p == null || !p.active || p.dead) + return; BackgroundColor = new Color(73, 92, 161); } public override void MouseOut(UIMouseEvent evt) { base.MouseOut(evt); + + Player p = Main.player[_playerIndex]; + if (p == null || !p.active || p.dead) + return; + BackgroundColor = new Color(63, 82, 151) * 0.8f; } @@ -278,8 +295,16 @@ public override void LeftClick(UIMouseEvent evt) { base.LeftClick(evt); + // Get the target player to teleport to Player player = Main.player[_playerIndex]; + if (player.dead) + { + // DONT allow teleporting to a dead player + return; + } + + // Teleport to the target player Main.LocalPlayer.UnityTeleport(player.position); // close map @@ -311,29 +336,130 @@ private void DrawPanel(SpriteBatch spriteBatch, Vector2 position, float width) ); } - /// - /// Draws a biome-looking BG behind the player - /// + + public static void DrawMapFullscreenBackground_BadMP(SpriteBatch sb, Rectangle rect, Player player) + { + if (player == null || !player.active) + return; + + int tx = (int)(player.Center.X / 16f); + int ty = (int)(player.Center.Y / 16f); + + if (!WorldGen.InWorld(tx, ty, 5)) + return; + + Tile tile = Framing.GetTileSafely(tx, ty); + ushort type = tile.TileType; + int wall = tile.WallType; + + float py = player.Center.Y / 16f; + Log.Debug(player.name + ", y: " + py); + + bool inUnderworld = py >= Main.maxTilesY - 230; + bool inCavern = py >= Main.rockLayer && py < Main.maxTilesY - 230; + bool inUnderground = py >= Main.worldSurface && py < Main.rockLayer; + bool inSurface = py < Main.worldSurface; + + bool isJungle = TileID.Sets.JungleBiome[type] > 0; + bool isMushroom = TileID.Sets.MushroomBiome[type] > 0; + bool isDesert = TileID.Sets.SandBiome[type] > 0; + bool isSnow = TileID.Sets.SnowBiome[type] > 0; + bool isCorrupt = TileID.Sets.Corrupt[type]; + bool isCrimson = TileID.Sets.Crimson[type]; + bool isHallow = TileID.Sets.Hallow[type]; + bool isDungeon = TileID.Sets.DungeonBiome[type] > 0; + + Color color = Color.White; + if (player.dead) + color = new Color(100, 100, 100); + + int bgIndex = 1; + + if (inUnderworld) + { + bgIndex = 2; + } + else if (isDungeon) + { + bgIndex = 4; + } + else if (isMushroom) + { + bgIndex = inUnderground ? 20 : 19; + } + else if (inUnderground) + { + if (isCorrupt) bgIndex = 22; + else if (isCrimson) bgIndex = 23; + else if (isHallow) bgIndex = 21; + else if (isSnow) bgIndex = 3; + else if (isJungle) bgIndex = 12; + else if (isDesert) bgIndex = 14; + else if (inCavern) bgIndex = 31; + else bgIndex = 1; + } + else if (inSurface) + { + if (player.ZoneSkyHeight) bgIndex = 32; + else if (isCorrupt) bgIndex = 5; + else if (isCrimson) bgIndex = 6; + else if (isHallow) bgIndex = 7; + else if (isSnow) bgIndex = 11; + else if (isJungle) bgIndex = 8; + else if (isDesert) bgIndex = 9; + else if (player.ZoneGraveyard) bgIndex = 26; + else if (Main.bloodMoon) { bgIndex = 25; color *= 2f; } + else bgIndex = 1; + } + + // Draw + int safeIndex = (bgIndex >= 0 && bgIndex < Ass.MapBG.Length) ? bgIndex : 0; + var asset = Ass.MapBG[safeIndex]; + if (asset?.Value == null) + return; + + rect = new Rectangle(rect.X + 10, rect.Y + 10, rect.Width - 20, rect.Height - 20); + sb.Draw(asset.Value, rect, color); + } + public static void DrawMapFullscreenBackground(SpriteBatch sb, Rectangle rect, Player player) { if (player == null || !player.active) return; - var screenPos = Main.screenPosition; - var tile = Main.tile[(int)(player.Center.X / 16f), (int)(player.Center.Y / 16f)]; - if (tile == null) return; + // Player tile coordinates + int tileX = (int)(player.Center.X / 16f); + int tileY = (int)(player.Center.Y / 16f); + + Tile tile = Main.tile[tileX, tileY]; + if (tile == null) + return; - int wall = tile.wall; + int wall = tile.wall; // or tile.WallType in 1.4.4 tModLoader int bgIndex = -1; Color color = Color.White; - if (screenPos.Y > (Main.maxTilesY - 232) * 16) + // Use *player depth* instead of screenPos + float playerYWorld = player.Center.Y; + float playerYTiles = playerYWorld / 16f; + + // Hell layer + if (playerYWorld > (Main.maxTilesY - 232) * 16) + { bgIndex = 2; + } + // Dungeon else if (player.ZoneDungeon) + { bgIndex = 4; + } + // Spider cave (?) wall else if (wall == 87) + { bgIndex = 13; - else if (screenPos.Y > Main.worldSurface * 16.0) + } + // Underground / cavern backgrounds + else if (playerYWorld > Main.worldSurface * 16.0) { bgIndex = wall switch { @@ -342,41 +468,58 @@ public static void DrawMapFullscreenBackground(SpriteBatch sb, Rectangle rect, P 178 or 183 => 17, 62 or 263 => 18, _ => player.ZoneGlowshroom ? 20 : - player.ZoneCorrupt ? player.ZoneDesert ? 39 : player.ZoneSnow ? 33 : 22 : - player.ZoneCrimson ? player.ZoneDesert ? 40 : player.ZoneSnow ? 34 : 23 : - player.ZoneHallow ? player.ZoneDesert ? 41 : player.ZoneSnow ? 35 : 21 : + player.ZoneCorrupt ? (player.ZoneDesert ? 39 : (player.ZoneSnow ? 33 : 22)) : + player.ZoneCrimson ? (player.ZoneDesert ? 40 : (player.ZoneSnow ? 34 : 23)) : + player.ZoneHallow ? (player.ZoneDesert ? 41 : (player.ZoneSnow ? 35 : 21)) : player.ZoneSnow ? 3 : player.ZoneJungle ? 12 : player.ZoneDesert ? 14 : player.ZoneRockLayerHeight ? 31 : 1 }; } + // Surface mushroom biome else if (player.ZoneGlowshroom) + { bgIndex = 19; + } else { - //color = Main.ColorOfTheSkies; color = Color.White; - int midTileX = (int)((screenPos.X + Main.screenWidth / 2f) / 16f); - if (player.ZoneSkyHeight) bgIndex = 32; - else if (player.ZoneCorrupt) bgIndex = player.ZoneDesert ? 36 : 5; - else if (player.ZoneCrimson) bgIndex = player.ZoneDesert ? 37 : 6; - else if (player.ZoneHallow) bgIndex = player.ZoneDesert ? 38 : 7; - else if (screenPos.Y / 16f < Main.worldSurface + 10.0 && (midTileX < 380 || midTileX > Main.maxTilesX - 380)) + if (player.dead) + color = new Color(100, 100, 100, 255); + + // Use the *player’s* X position instead of camera center + int midTileX = tileX; + + if (player.ZoneSkyHeight) + bgIndex = 32; + else if (player.ZoneCorrupt) + bgIndex = player.ZoneDesert ? 36 : 5; + else if (player.ZoneCrimson) + bgIndex = player.ZoneDesert ? 37 : 6; + else if (player.ZoneHallow) + bgIndex = player.ZoneDesert ? 38 : 7; + // "Ocean" style edges: use player’s tileY + tileX instead of screenPos + else if (playerYTiles < Main.worldSurface + 10.0 && + (midTileX < 380 || midTileX > Main.maxTilesX - 380)) bgIndex = 10; - else if (player.ZoneSnow) bgIndex = 11; - else if (player.ZoneJungle) bgIndex = 8; - else if (player.ZoneDesert) bgIndex = 9; - else if (Main.bloodMoon) { bgIndex = 25; color *= 2f; } - else if (player.ZoneGraveyard) bgIndex = 26; + else if (player.ZoneSnow) + bgIndex = 11; + else if (player.ZoneJungle) + bgIndex = 8; + else if (player.ZoneDesert) + bgIndex = 9; + else if (Main.bloodMoon) + { + bgIndex = 25; + color *= 2f; + } + else if (player.ZoneGraveyard) + bgIndex = 26; } - // Vanilla - //var asset = bgIndex >= 0 && bgIndex < TextureAssets.MapBGs.Length? TextureAssets.MapBGs[bgIndex]: TextureAssets.MapBGs[0]; - - // Our textures with rounded corners - int safeIndex = (bgIndex >= 0 && bgIndex < Ass.MapBG.Length) ? bgIndex: 0; + int safeIndex = (bgIndex >= 0 && bgIndex < Ass.MapBG.Length) ? bgIndex : 0; var asset = Ass.MapBG[safeIndex]; rect.X += 10; @@ -384,8 +527,11 @@ public static void DrawMapFullscreenBackground(SpriteBatch sb, Rectangle rect, P rect.Width -= 20; rect.Height -= 20; - if (asset == null || asset.Value == null) return; + if (asset == null || asset.Value == null) + return; + sb.Draw(asset.Value, rect, color); } + } } diff --git a/System/RegionManager.cs b/System/RegionManager.cs index bbdfa37a..81c29f75 100644 --- a/System/RegionManager.cs +++ b/System/RegionManager.cs @@ -1,10 +1,15 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using PvPAdventure.Core.Helpers; +using ReLogic.Content; using System.Collections.Generic; using System.IO; using System.Linq; -using Microsoft.Xna.Framework; using Terraria; +using Terraria.GameContent; using Terraria.ID; using Terraria.ModLoader; +using static PvPAdventure.System.RegionManager; namespace PvPAdventure.System; @@ -31,6 +36,81 @@ public class Region public override void Load() { On_Collision.TileCollision += OnCollisionTileCollision; + + if (!Main.dedServ) + _playerBGTexture = Ass.CustomPlayerBackground; + } + + private Asset _playerBGTexture; + + public override void PostDrawInterface(SpriteBatch spriteBatch) + { + // COMMENT THIS LINE OUT TO SKIP DRAWING THE SPAWN BOX + //return; + + if (_regions.Count == 0 || _playerBGTexture == null) + return; + + var region = _regions[0]; + var area = region.Area; + + Rectangle screenRect = new( + (int)(area.X * 16 - Main.screenPosition.X), + (int)(area.Y * 16 - Main.screenPosition.Y), + area.Width * 16, + area.Height * 16 + ); + + DrawNineSliceBorder( + spriteBatch, + screenRect.X, + screenRect.Y, + screenRect.Width, + screenRect.Height, + _playerBGTexture.Value, + Color.Black, + inset: -16, + c: 10 + ); + } + + private void DrawNineSliceBorder(SpriteBatch sb, int x, int y, int w, int h, Texture2D tex, Color color, int inset, int c = 5) + { + x += inset; y += inset; w -= inset * 2 -16; h -= inset * 2; + int ew = tex.Width - c * 2; + int eh = tex.Height - c * 2; + + // corners + edges, NO center + sb.Draw(tex, new Rectangle(x, y, c, c), new Rectangle(0, 0, c, c), color); + sb.Draw(tex, new Rectangle(x + c, y, w - c * 2, c), new Rectangle(c, 0, ew, c), color); + sb.Draw(tex, new Rectangle(x + w - c, y, c, c), new Rectangle(tex.Width - c, 0, c, c), color); + + sb.Draw(tex, new Rectangle(x, y + c, c, h - c * 2), new Rectangle(0, c, c, eh), color); + // center row skipped here + sb.Draw(tex, new Rectangle(x + w - c, y + c, c, h - c * 2), new Rectangle(tex.Width - c, c, c, eh), color); + + sb.Draw(tex, new Rectangle(x, y + h - c, c, c), new Rectangle(0, tex.Height - c, c, c), color); + sb.Draw(tex, new Rectangle(x + c, y + h - c, w - c * 2, c), new Rectangle(c, tex.Height - c, ew, c), color); + sb.Draw(tex, new Rectangle(x + w - c, y + h - c, c, c), new Rectangle(tex.Width - c, tex.Height - c, c, c), color); + } + + private void DrawNineSlice(SpriteBatch sb, int x, int y, int w, int h, Texture2D tex, Color color, int inset, int c = 5) + { + x += inset; y += inset; w -= inset * 2; h -= inset * 2; + int ew = tex.Width - c * 2; + int eh = tex.Height - c * 2; + + sb.Draw(tex, new Rectangle(x, y, c, c), new Rectangle(0, 0, c, c), color); + sb.Draw(tex, new Rectangle(x + c, y, w - c * 2, c), new Rectangle(c, 0, ew, c), color); + sb.Draw(tex, new Rectangle(x + w - c, y, c, c), new Rectangle(tex.Width - c, 0, c, c), color); + + sb.Draw(tex, new Rectangle(x, y + c, c, h - c * 2), new Rectangle(0, c, c, eh), color); + sb.Draw(tex, new Rectangle(x + c, y + c, w - c * 2, h - c * 2), new Rectangle(c, c, ew, eh), color); + sb.Draw(tex, new Rectangle(x + w - c, y + c, c, h - c * 2), new Rectangle(tex.Width - c, c, c, eh), color); + + sb.Draw(tex, new Rectangle(x, y + h - c, c, c), new Rectangle(0, tex.Height - c, c, c), color); + sb.Draw(tex, new Rectangle(x + c, y + h - c, w - c * 2, c), new Rectangle(c, tex.Height - c, ew, c), color); + sb.Draw(tex, new Rectangle(x + w - c, y + h - c, c, c), new Rectangle(tex.Width - c, tex.Height - c, c, c), color); } private Vector2 OnCollisionTileCollision(On_Collision.orig_TileCollision orig, Vector2 position, Vector2 velocity, From 1cbcdb974f948bb44e6820d50c2a8756527d4b37 Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Wed, 26 Nov 2025 09:20:59 -0800 Subject: [PATCH 188/206] Update en-US.hjson --- Localization/en-US.hjson | 1 + 1 file changed, 1 insertion(+) diff --git a/Localization/en-US.hjson b/Localization/en-US.hjson index 28420c52..afefef51 100644 --- a/Localization/en-US.hjson +++ b/Localization/en-US.hjson @@ -1110,3 +1110,4 @@ Mods: { } } } +} \ No newline at end of file From be9faf28c0e9bb6d0538b0e955f04385b8c5ba9f Mon Sep 17 00:00:00 2001 From: emyhrberg <121192176+emyhrberg@users.noreply.github.com> Date: Wed, 26 Nov 2025 19:16:37 +0100 Subject: [PATCH 189/206] Fixed spawnbox to fit all UIScales --- System/RegionManager.cs | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/System/RegionManager.cs b/System/RegionManager.cs index 81c29f75..ed956b24 100644 --- a/System/RegionManager.cs +++ b/System/RegionManager.cs @@ -49,16 +49,31 @@ public override void PostDrawInterface(SpriteBatch spriteBatch) //return; if (_regions.Count == 0 || _playerBGTexture == null) + { return; + } + + Region region = _regions[0]; + Rectangle area = region.Area; + + // World (tiles) -> world pixels + Vector2 worldTopLeft = new Vector2(area.X * 16, area.Y * 16); + Vector2 worldSize = new Vector2(area.Width * 16, area.Height * 16); - var region = _regions[0]; - var area = region.Area; + // Convert to screen pixel coords + Vector2 screenTopLeft = worldTopLeft - Main.screenPosition; - Rectangle screenRect = new( - (int)(area.X * 16 - Main.screenPosition.X), - (int)(area.Y * 16 - Main.screenPosition.Y), - area.Width * 16, - area.Height * 16 + float uiScale = Main.UIScale; + + // Compensate for UI scaling (PostDrawInterface uses Main.UIScaleMatrix) + screenTopLeft /= uiScale; + worldSize /= uiScale; + + Rectangle screenRect = new Rectangle( + (int)screenTopLeft.X, + (int)screenTopLeft.Y, + (int)worldSize.X, + (int)worldSize.Y ); DrawNineSliceBorder( @@ -74,6 +89,7 @@ public override void PostDrawInterface(SpriteBatch spriteBatch) ); } + private void DrawNineSliceBorder(SpriteBatch sb, int x, int y, int w, int h, Texture2D tex, Color color, int inset, int c = 5) { x += inset; y += inset; w -= inset * 2 -16; h -= inset * 2; From f7fbb4a0ca8511538deb52188881c4b9e9bde4bf Mon Sep 17 00:00:00 2001 From: emyhrberg <121192176+emyhrberg@users.noreply.github.com> Date: Thu, 27 Nov 2025 03:57:29 +0100 Subject: [PATCH 190/206] Bug fixes to bed teleport system - Big rework of bed teleport by sending a packet since SpawnMapLayer isn't run on the server - Reworking spawn box to make it look cleaner in map, minimap and in-world. - Added OnHurt cancel mirror use (to fix issue where knockback immunity would be too OP) - Added some debug options - Started using a MultDebug proj for faster MP testing & hot reload --- AdventurePacketIdentifier.cs | 3 +- Content/Items/AdventureMirror.cs | 35 ++- Core/Debug/DebugCommands.cs | 118 +++++++++ Core/Debug/DebugKeybinds.cs | 108 ++++---- .../Players/AdventureMirrorPlayer.cs | 239 ------------------ .../Players/ModifyDrawInfoPlayer.cs | 52 ---- .../SpawnSelector/UI/DrawBedsOnMapHook.cs | 167 ------------ .../SpawnSelector/UI/PopupTextHelper.cs | 28 -- .../Players/AdventureMirrorPlayer.cs | 148 +++++++++++ .../SpawnSelector/Systems/ItemSlotHooks.cs | 28 +- .../Systems/SpawnSelectorState.cs | 4 +- .../Systems/SpawnSelectorSystem.cs | 2 +- .../SpawnSelector/Systems/UnityHooks.cs | 2 +- Core/SpawnSelector/UI/BedsOnMap.cs | 163 ++++++++++++ .../UI/SpawnSelectorBasePanel.cs | 11 +- .../UI/SpawnSelectorCharacter.cs | 24 +- .../UI/SpawnSelectorQuestionMark.cs | 7 +- Core/Spawnbox/SpawnboxMap.cs | 83 ++++++ Core/Spawnbox/SpawnboxWorld.cs | 192 ++++++++++++++ PvPAdventure.cs | 207 +++++++++++---- PvPAdventure.csproj.user | 2 +- System/RegionManager.cs | 91 ------- 22 files changed, 1001 insertions(+), 713 deletions(-) create mode 100644 Core/Debug/DebugCommands.cs delete mode 100644 Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs delete mode 100644 Core/Features/SpawnSelector/Players/ModifyDrawInfoPlayer.cs delete mode 100644 Core/Features/SpawnSelector/UI/DrawBedsOnMapHook.cs delete mode 100644 Core/Features/SpawnSelector/UI/PopupTextHelper.cs create mode 100644 Core/SpawnSelector/Players/AdventureMirrorPlayer.cs rename Core/{Features => }/SpawnSelector/Systems/ItemSlotHooks.cs (76%) rename Core/{Features => }/SpawnSelector/Systems/SpawnSelectorState.cs (91%) rename Core/{Features => }/SpawnSelector/Systems/SpawnSelectorSystem.cs (97%) rename Core/{Features => }/SpawnSelector/Systems/UnityHooks.cs (90%) create mode 100644 Core/SpawnSelector/UI/BedsOnMap.cs rename Core/{Features => }/SpawnSelector/UI/SpawnSelectorBasePanel.cs (94%) rename Core/{Features => }/SpawnSelector/UI/SpawnSelectorCharacter.cs (95%) rename Core/{Features => }/SpawnSelector/UI/SpawnSelectorQuestionMark.cs (94%) create mode 100644 Core/Spawnbox/SpawnboxMap.cs create mode 100644 Core/Spawnbox/SpawnboxWorld.cs diff --git a/AdventurePacketIdentifier.cs b/AdventurePacketIdentifier.cs index 4a7af571..400620d7 100644 --- a/AdventurePacketIdentifier.cs +++ b/AdventurePacketIdentifier.cs @@ -8,5 +8,6 @@ public enum AdventurePacketIdentifier : byte PlayerItemPickup, PlayerTeam, PlayerBed, - AdventureMirrorRightClickUse + AdventureMirrorRightClickUse, + BedTeleport, } \ No newline at end of file diff --git a/Content/Items/AdventureMirror.cs b/Content/Items/AdventureMirror.cs index dc5746ac..f13c0b90 100644 --- a/Content/Items/AdventureMirror.cs +++ b/Content/Items/AdventureMirror.cs @@ -1,9 +1,10 @@ using Microsoft.Xna.Framework; -using PvPAdventure.Core.Features.SpawnSelector.UI; +using PvPAdventure.Core.SpawnSelector.UI; using PvPAdventure.System; using Terraria; using Terraria.ID; using Terraria.ModLoader; +using static System.Net.Mime.MediaTypeNames; namespace PvPAdventure.Content.Items; @@ -90,15 +91,26 @@ public override bool CanUseItem(Player player) var gm = ModContent.GetInstance(); if (gm.CurrentPhase != GameManager.Phase.Playing) { - if (player.whoAmI == Main.myPlayer) - PopupTextHelper.NewText("wait until game starts!", player); + // Check if the config allows popup text + var config = ModContent.GetInstance(); + if (!config.ShowPopupText) + return false; + + // Create and display the popup text + PopupText.NewText(new AdvancedPopupRequest + { + Color = Color.Crimson, + Text = "wait until game starts!", + Velocity = new(0f, -4), + DurationInFrames = 120 + }, player.Top + new Vector2(0, -4)); return false; } return true; } - private void CancelItemUse(Player player) + internal void CancelItemUse(Player player) { player.controlUseItem = false; player.channel = false; @@ -157,7 +169,20 @@ public override void UseStyle(Player player, Rectangle heldItemFrame) int secondsLeft = (player.itemTime + 59) / 60; if (player.itemTime % 60 == 0 && secondsLeft > 0) { - PopupTextHelper.NewText(secondsLeft.ToString(), player, Color.GreenYellow); + // Check if the config allows popup text + var config = ModContent.GetInstance(); + if (!config.ShowPopupText) + return; + + // Create and display the popup text + PopupText.NewText(new AdvancedPopupRequest + { + Color = Color.GreenYellow, + Text = secondsLeft.ToString(), + Velocity = new(0f, -4), + DurationInFrames = 120 + }, player.Top + new Vector2(0, -4)); + return; } // Teleport the player who used the item to their spawn and open their map diff --git a/Core/Debug/DebugCommands.cs b/Core/Debug/DebugCommands.cs new file mode 100644 index 00000000..d7feb49b --- /dev/null +++ b/Core/Debug/DebugCommands.cs @@ -0,0 +1,118 @@ +using Microsoft.Xna.Framework; +using PvPAdventure.System; +using Terraria; +using Terraria.Enums; +using Terraria.ID; +using Terraria.ModLoader; + +namespace PvPAdventure.Core.Debug; + +// Only run in debug builds. +#if DEBUG +public class DBStartCommand : ModCommand +{ + public override string Command => "dbstart"; + public override CommandType Type => CommandType.World | CommandType.Server; + + public override void Action(CommandCaller caller, string input, string[] args) + { + var gm = ModContent.GetInstance(); + gm.StartGame(time: 60000, countdownTimeInSeconds: 0); + } +} + +public class DBTeamCommand : ModCommand +{ + public override string Command => "dbteam"; + + public override CommandType Type => CommandType.World | CommandType.Server; + + public override void Action(CommandCaller caller, string input, string[] args) + { + // Must be a player + if (caller.Player is null) + { + caller.Reply("Must be used by a player.", Color.Red); + return; + } + + // Only run on server / singleplayer world context + if (Main.netMode == NetmodeID.MultiplayerClient) + return; + + var player = caller.Player; + + // No args -> cycle teams 0–5 + if (args.Length == 0) + { + player.team = (player.team + 1) % 6; // 0 = None, 1–5 = colors + } + // One arg -> parse team name + else if (args.Length == 1) + { + string arg = args[0].ToLowerInvariant(); + Team newTeam; + + switch (arg) + { + case "none": + case "n": + case "0": + newTeam = Team.None; + break; + case "red": + case "r": + case "1": + newTeam = Team.Red; + break; + case "green": + case "g": + case "2": + newTeam = Team.Green; + break; + case "blue": + case "b": + case "3": + newTeam = Team.Blue; + break; + case "yellow": + case "y": + case "4": + newTeam = Team.Yellow; + break; + case "pink": + case "p": + case "5": + newTeam = Team.Pink; + break; + + default: + caller.Reply( + "Error: invalid team. Use none, red, green, blue, yellow, or pink.", + Color.Red + ); + return; + } + + player.team = (int)newTeam; + } + else + { + caller.Reply( + "Usage: /dbteam [none|red|green|blue|yellow|pink]", + Color.Red + ); + return; + } + + // Sync team to all clients + NetMessage.SendData(MessageID.PlayerTeam, -1, -1, null, player.whoAmI); + + caller.Reply( + $"Switched team to {(Team)player.team}.", + Color.Green + ); + } +} + +#endif \ No newline at end of file diff --git a/Core/Debug/DebugKeybinds.cs b/Core/Debug/DebugKeybinds.cs index 30a348fe..1f50de17 100644 --- a/Core/Debug/DebugKeybinds.cs +++ b/Core/Debug/DebugKeybinds.cs @@ -1,54 +1,54 @@ -using Microsoft.Xna.Framework.Input; -using PvPAdventure.System; -using Terraria; -using Terraria.GameInput; -using Terraria.ModLoader; -using Terraria.UI; - -namespace PvPAdventure.Core.Debug; - -#if DEBUG -[Autoload(Side = ModSide.Client)] -public class DebugKeybinds : ModSystem -{ - public ModKeybind OpenControls { get; private set; } - public ModKeybind SwitchTeams { get; private set; } - public ModKeybind StartGame { get; private set; } - - public override void Load() - { - OpenControls = KeybindLoader.RegisterKeybind(Mod, "[DEBUG] OpenControls", Keys.NumPad0); - SwitchTeams = KeybindLoader.RegisterKeybind(Mod, "[DEBUG] SwitchTeams", Keys.NumPad1); - StartGame = KeybindLoader.RegisterKeybind(Mod, "[DEBUG] StartGame", Keys.NumPad2); - } -} - -public class DebugKeybindsPlayer : ModPlayer -{ - public override void ProcessTriggers(TriggersSet triggersSet) - { - var key = ModContent.GetInstance(); - - // Open controls - if (key.OpenControls.JustPressed) - { - IngameFancyUI.OpenKeybinds(); - } - - // Switch teams - if (key.SwitchTeams.JustPressed) - { - Player.team = (Player.team + 1) % 6; // Cycle through teams 0-5 - Main.NewText("[DEBUG] " + Player.name + " switched to team: " + (Terraria.Enums.Team)Player.team); - } - - // Start game - if (key.StartGame.JustPressed) - { - var gm = ModContent.GetInstance(); - gm.StartGame(60000, 1); - } - } -} - -#endif \ No newline at end of file +//using Ionic.Zlib; +//using Microsoft.Xna.Framework.Input; +//using PvPAdventure.System; +//using Terraria; +//using Terraria.GameInput; +//using Terraria.ID; +//using Terraria.Localization; +//using Terraria.ModLoader; +//using Terraria.UI; + +//namespace PvPAdventure.Core.Debug; + +//#if DEBUG +//[Autoload(Side = ModSide.Client)] +//public class DebugKeybinds : ModSystem +//{ +// //public ModKeybind OpenControls { get; private set; } + +// public override void Load() +// { +// //OpenControls = KeybindLoader.RegisterKeybind(Mod, "[DEBUG] OpenControls", Keys.NumPad0); +// } +//} + +//public class DebugKeybindsPlayer : ModPlayer +//{ +// public override void ProcessTriggers(TriggersSet triggersSet) +// { +// var key = ModContent.GetInstance(); + +// // NOTE: DOESN'T WORK BELOW + +// //// Start game via /dbstart +// //if (key.StartGame.JustPressed) +// //{ +// // if (Main.netMode == NetmodeID.MultiplayerClient) +// // { +// // // Send a chat packet to the server as if we typed "/dbstart" +// // NetMessage.SendData( +// // MessageID.ChatText, +// // number: Player.whoAmI, +// // text: NetworkText.FromLiteral("/dbstart") +// // ); +// // } +// // else +// // { +// // // Singleplayer: just call directly +// // ModContent.GetInstance().StartGame(60000, 0); +// // } +// //} +// } +//} + +//#endif \ No newline at end of file diff --git a/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs b/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs deleted file mode 100644 index e3f84863..00000000 --- a/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs +++ /dev/null @@ -1,239 +0,0 @@ -using Microsoft.Xna.Framework; -using PvPAdventure.Content.Items; -using PvPAdventure.Core.Features.SpawnSelector.Systems; -using PvPAdventure.Core.Features.SpawnSelector.UI; -using PvPAdventure.System; -using PvPAdventure.System.Client; -using Terraria; -using Terraria.GameContent; -using Terraria.GameInput; -using Terraria.ModLoader; - -namespace PvPAdventure.Core.Features.SpawnSelector.Players; - -public class AdventureMirrorPlayer : ModPlayer -{ - public override void OnHurt(Player.HurtInfo info) - { - base.OnHurt(info); - // TODO Stop the channel + reset animation - //PopupTextHelper.NewText("Mirror interrupted!", Color.Crimson); - } - - public bool IsPlayerInSpawnRegion() - { - // Is player in spawn region? - var regionManager = ModContent.GetInstance(); - Point tilePos = Player.Center.ToTileCoordinates(); - var region = regionManager.GetRegionContaining(tilePos); - if (region != null) - { - return true; - } - - // Is player in bed spawn region? - Vector2 bedSpawnPoint = new(Player.SpawnX, Player.SpawnY); - float distanceToBedSpawn = Vector2.Distance(bedSpawnPoint * 16f, Player.Center); - if (distanceToBedSpawn <= 25 * 16f) - { - return true; - } - - return false; - } - - public override void PostUpdate() - { - // Only run on clients - if (Main.dedServ) - return; - - // Only run on this client - if (Player.whoAmI != Main.myPlayer) - return; - - // Update spawn selector UI state every frame - if (ModContent.GetInstance().CurrentPhase == GameManager.Phase.Playing && Main.mapFullscreen && IsPlayerInSpawnRegion()) - { - SpawnSelectorSystem.SetEnabled(true); - } - else - { - SpawnSelectorSystem.SetEnabled(false); - } - } - - public void CustomTeleportWithoutSound(Vector2 newPos) - { - try - { - Player._funkytownAchievementCheckCooldown = 100; - Player.environmentBuffImmunityTimer = 4; - Player.RemoveAllGrapplingHooks(); - Player.StopVanityActions(); - if (Player.shimmering || Player.shimmerWet) - { - Player.shimmering = false; - Player.shimmerWet = false; - Player.wet = false; - Player.ClearBuff(353); - } - int extraInfo2 = 0; - - float num = MathHelper.Clamp(1f - Player.teleportTime * 0.99f, 0.01f, 1f); - Vector2 otherPosition = Player.position; - //Main.TeleportEffect(Player.getRect(), 0, extraInfo2, num, TeleportationSide.Entry, newPos); - float num2 = Vector2.Distance(Player.position, newPos); - PressurePlateHelper.UpdatePlayerPosition(Player); - Player.position = newPos; - Player.fallStart = (int)(Player.position.Y / 16f); - if (Player.whoAmI == Main.myPlayer) - { - bool flag = false; - if (num2 < new Vector2(Main.screenWidth, Main.screenHeight).Length() / 2f + 100f) - { - int time = 0; - Main.SetCameraLerp(0.1f, time); - flag = true; - } - else - { - NPC.ResetNetOffsets(); - Main.BlackFadeIn = 255; - Lighting.Clear(); - Main.screenLastPosition = Main.screenPosition; - Main.screenPosition.X = Player.position.X + (float)(Player.width / 2) - (float)(Main.screenWidth / 2); - Main.screenPosition.Y = Player.position.Y + (float)(Player.height / 2) - (float)(Main.screenHeight / 2); - Main.instantBGTransitionCounter = 10; - Player.ForceUpdateBiomes(); - } - //if (num > 0.1f || !flag || Style != 0) - //{ - // if (Main.mapTime < 5) - // { - // Main.mapTime = 5; - // } - // Main.maxQ = true; - // Main.renderNow = true; - //} - } - - PressurePlateHelper.UpdatePlayerPosition(Player); - Player.ResetAdvancedShadows(); - for (int i = 0; i < 3; i++) - { - Player.UpdateSocialShadow(); - } - Player.oldPosition = Player.position + Player.BlehOldPositionFixer; - //Main.TeleportEffect(Player.getRect(), 0, extraInfo2, num, TeleportationSide.Exit, otherPosition); - Player.teleportTime = 1f; - Player.teleportStyle = 0; - } - catch - { - } - } - - #region Keybind Handling - public override void ProcessTriggers(TriggersSet triggersSet) - { - var keybinds = ModContent.GetInstance(); - - if (keybinds.AdventureMirrorKeybind.JustPressed) - { - TryUseAdventureMirrorKeybind(); - } - } - - public void TryUseAdventureMirrorKeybind() - { - int mirrorIndex = EnsureMirrorInInventory(); - - if (mirrorIndex == -1) - { - PopupTextHelper.NewText("No Adventure Mirror found in inventory or banks!", Player); - return; - } - - Player.selectedItem = mirrorIndex; - Player.controlUseItem = true; - Player.ItemCheck(); - } - - private int EnsureMirrorInInventory() - { - int mirrorType = ModContent.ItemType(); - - // 1. Look in main inventory first - for (int i = 0; i < Player.inventory.Length; i++) - { - Item item = Player.inventory[i]; - if (!item.IsAir && item.type == mirrorType) - return i; - } - - // 2. Try to pull from personal banks - if (TryPullMirrorFromBank(Player.bank, mirrorType, out int invIndex)) - return invIndex; - - if (TryPullMirrorFromBank(Player.bank2, mirrorType, out invIndex)) - return invIndex; - - if (TryPullMirrorFromBank(Player.bank3, mirrorType, out invIndex)) - return invIndex; - - if (TryPullMirrorFromBank(Player.bank4, mirrorType, out invIndex)) // void vault - return invIndex; - - return -1; - } - - private bool TryPullMirrorFromBank(Chest bank, int mirrorType, out int inventoryIndex) - { - inventoryIndex = -1; - - if (bank == null) - return false; - - // Find the mirror inside this bank - int bankSlot = -1; - for (int i = 0; i < bank.item.Length; i++) - { - Item item = bank.item[i]; - if (!item.IsAir && item.type == mirrorType) - { - bankSlot = i; - break; - } - } - - if (bankSlot == -1) - return false; - - // Find a free inventory slot - int freeInvSlot = -1; - for (int i = 0; i < Player.inventory.Length; i++) - { - if (Player.inventory[i].IsAir) - { - freeInvSlot = i; - break; - } - } - - if (freeInvSlot == -1) - { - if (Player.whoAmI == Main.myPlayer) - Main.NewText("No free inventory slot for Adventure Mirror!", Color.Red); - return false; - } - - // Move the item from bank → inventory - Player.inventory[freeInvSlot] = bank.item[bankSlot].Clone(); - bank.item[bankSlot].TurnToAir(); - - inventoryIndex = freeInvSlot; - return true; - } - #endregion -} diff --git a/Core/Features/SpawnSelector/Players/ModifyDrawInfoPlayer.cs b/Core/Features/SpawnSelector/Players/ModifyDrawInfoPlayer.cs deleted file mode 100644 index c83a99df..00000000 --- a/Core/Features/SpawnSelector/Players/ModifyDrawInfoPlayer.cs +++ /dev/null @@ -1,52 +0,0 @@ -using Microsoft.Xna.Framework; -using Terraria.DataStructures; -using Terraria.ModLoader; - -namespace PvPAdventure.Core.Features.SpawnSelector.Players; - -/// -/// Useful for forcing the player to be drawn with full brightness even when in player is in darkness. -/// DONT DELETE, its still used -/// -public class ModifyDrawInfoPlayer : ModPlayer -{ - public static bool ForceFullBrightOnce; - public override void ModifyDrawInfo(ref PlayerDrawSet drawInfo) - { - if (drawInfo.headOnlyRender) - return; - - if (!ForceFullBrightOnce) - return; - - drawInfo.shadow = 0f; - drawInfo.stealth = 1f; - - var p = drawInfo.drawPlayer; - p.socialIgnoreLight = true; - - drawInfo.colorEyeWhites = Color.White; - drawInfo.colorEyes = p.eyeColor; - drawInfo.colorHair = p.GetHairColor(useLighting: false); - drawInfo.colorHead = p.skinColor; - drawInfo.colorBodySkin = p.skinColor; - drawInfo.colorLegs = p.skinColor; - - drawInfo.colorShirt = p.shirtColor; - drawInfo.colorUnderShirt = p.underShirtColor; - drawInfo.colorPants = p.pantsColor; - drawInfo.colorShoes = p.shoeColor; - - drawInfo.colorArmorHead = Color.White; - drawInfo.colorArmorBody = Color.White; - drawInfo.colorArmorLegs = Color.White; - drawInfo.colorMount = Color.White; - - drawInfo.colorDisplayDollSkin = PlayerDrawHelper.DISPLAY_DOLL_DEFAULT_SKIN_COLOR; - - drawInfo.headGlowColor = new Color(drawInfo.headGlowColor.R, drawInfo.headGlowColor.G, drawInfo.headGlowColor.B, 0); - drawInfo.bodyGlowColor = new Color(drawInfo.bodyGlowColor.R, drawInfo.bodyGlowColor.G, drawInfo.bodyGlowColor.B, 0); - drawInfo.armGlowColor = new Color(drawInfo.armGlowColor.R, drawInfo.armGlowColor.G, drawInfo.armGlowColor.B, 0); - drawInfo.legsGlowColor = new Color(drawInfo.legsGlowColor.R, drawInfo.legsGlowColor.G, drawInfo.legsGlowColor.B, 0); - } -} \ No newline at end of file diff --git a/Core/Features/SpawnSelector/UI/DrawBedsOnMapHook.cs b/Core/Features/SpawnSelector/UI/DrawBedsOnMapHook.cs deleted file mode 100644 index 4a6bcd83..00000000 --- a/Core/Features/SpawnSelector/UI/DrawBedsOnMapHook.cs +++ /dev/null @@ -1,167 +0,0 @@ -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Graphics; -using PvPAdventure.Core.Features.SpawnSelector.Systems; -using Terraria; -using Terraria.DataStructures; -using Terraria.GameContent; -using Terraria.ID; -using Terraria.Map; -using Terraria.ModLoader; -using Terraria.UI; - -namespace PvPAdventure.Core.Features.SpawnSelector.UI; - -internal class DrawBedsOnMapHook : ModSystem -{ - public override void Load() - { - On_Player.ChangeSpawn += OnPlayerChangeSpawn; - On_Player.RemoveSpawn += OnPlayerRemoveSpawn; - On_SpawnMapLayer.Draw += OnSpawnMapLayer; - } - - public override void Unload() - { - On_Player.ChangeSpawn -= OnPlayerChangeSpawn; - On_Player.RemoveSpawn -= OnPlayerRemoveSpawn; - On_SpawnMapLayer.Draw -= OnSpawnMapLayer; - } - - private void OnPlayerChangeSpawn(On_Player.orig_ChangeSpawn orig, Player self, int x, int y) - { - orig(self, x, y); - - // Send packet to server, notifying the server of a updated player spawn position for a player. - if (Main.netMode == NetmodeID.MultiplayerClient) - { - var packet = Mod.GetPacket(); - packet.Write((byte)AdventurePacketIdentifier.PlayerBed); - packet.Write((byte)self.whoAmI); - packet.Write(x); - packet.Write(y); - packet.Send(); - } - } - - private void OnPlayerRemoveSpawn(On_Player.orig_RemoveSpawn orig, Player self) - { - orig(self); - - // Send packet to server, notifying the server of a removed player spawn position for a player. - if (Main.netMode == NetmodeID.MultiplayerClient) - { - var packet = Mod.GetPacket(); - packet.Write((byte)AdventurePacketIdentifier.PlayerBed); - packet.Write((byte)self.whoAmI); - packet.Write(-1); - packet.Write(-1); - packet.Send(); - } - } - - private void OnSpawnMapLayer(On_SpawnMapLayer.orig_Draw orig,SpawnMapLayer self,ref MapOverlayDrawContext context, ref string text) - { - // Let vanilla draw spawn point + local bed first - orig(self, ref context, ref text); - - Texture2D bedTex = TextureAssets.SpawnBed.Value; - - for (int i = 0; i < Main.maxPlayers; i++) - { - Player p = Main.player[i]; - if (p == null || !p.active) - continue; - - if (p.team != Main.LocalPlayer.team) - continue; - - //Main.NewText(p.SpawnX); - - bool selectorEnabled = SpawnSelectorSystem.GetEnabled(); - - // No bed set for this player - if (p.SpawnX == -1 || p.SpawnY == -1) - continue; - - Vector2 bedTilePos = new Vector2(p.SpawnX, p.SpawnY); - - var hoverCheck = context.Draw( - texture: bedTex, - position: bedTilePos, - color: Color.White, - frame: new SpriteFrame(1, 1), - scaleIfNotSelected: 1.0f, - scaleIfSelected: 1.8f, - alignment: Alignment.Bottom, - spriteEffects: SpriteEffects.None - ); - - if (!selectorEnabled) - { - if (hoverCheck.IsMouseOver) - { - text = $"{p.name}'s Bed"; - } - continue; - } - - if (!hoverCheck.IsMouseOver) - continue; - - // Hover text - text = $"Teleport to {p.name}'s Bed"; - - if (Main.mouseLeft && Main.mouseLeftRelease) - { - if (Main.netMode == NetmodeID.MultiplayerClient) - { - // Singleplayer: teleport directly to bed spawn - Vector2 spawn = new Vector2(p.SpawnX * 16, p.SpawnY * 16 - 48); - p.Teleport(spawn); - - // Ask server to teleport this player to their spawn position - NetMessage.SendData(MessageID.TeleportEntity, number: Main.myPlayer); - } - else - { - // Singleplayer: teleport directly to bed spawn - Vector2 spawn = new Vector2(p.SpawnX * 16, p.SpawnY * 16 - 48); - p.Teleport(spawn); - } - - Main.mapFullscreen = false; - } - - } - DrawSpawnBoxOnMap(ref context); - } - - private void DrawSpawnBoxOnMap(ref MapOverlayDrawContext context) - { - if (!Main.mapFullscreen) return; - - if (Main.mapFullscreenScale < 0.5) return; - - // spawn region in tiles (same as RegionManager) - Rectangle area = new(Main.spawnTileX - 25, Main.spawnTileY - 25, 50, 50); - - // tile → map screen - Vector2 topLeft = (new Vector2(area.X, area.Y) - context.MapPosition) * context.MapScale + context.MapOffset; - Vector2 size = new(area.Width * context.MapScale, area.Height * context.MapScale); - - Texture2D pix = TextureAssets.MagicPixel.Value; - Color col = Color.Black * 0.7f; - int t = 10; - - int x = (int)topLeft.X; - int y = (int)topLeft.Y; - int w = (int)size.X; - int h = (int)size.Y; - - // top, bottom, left, right - Main.spriteBatch.Draw(pix, new Rectangle(x, y, w, t), col); - Main.spriteBatch.Draw(pix, new Rectangle(x, y + h - t, w, t), col); - Main.spriteBatch.Draw(pix, new Rectangle(x, y, t, h), col); - Main.spriteBatch.Draw(pix, new Rectangle(x + w - t, y, t, h), col); - } -} diff --git a/Core/Features/SpawnSelector/UI/PopupTextHelper.cs b/Core/Features/SpawnSelector/UI/PopupTextHelper.cs deleted file mode 100644 index 93295be2..00000000 --- a/Core/Features/SpawnSelector/UI/PopupTextHelper.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Microsoft.Xna.Framework; -using Terraria; -using Terraria.ModLoader; - -namespace PvPAdventure.Core.Features.SpawnSelector.UI; -public static class PopupTextHelper -{ - public static void NewText(string text, Player player, Color color=default) - { - // Check if the config allows popup text - var config = ModContent.GetInstance(); - if (!config.ShowPopupText) - return; - - // Default color to Crimson if none is provided - if (color == default) - color = Color.Crimson; - - // Create and display the popup text - PopupText.NewText(new AdvancedPopupRequest - { - Color = color, - Text = text, - Velocity = new(0f, -4), - DurationInFrames = 120 - }, player.Top + new Vector2(0,-4)); - } -} diff --git a/Core/SpawnSelector/Players/AdventureMirrorPlayer.cs b/Core/SpawnSelector/Players/AdventureMirrorPlayer.cs new file mode 100644 index 00000000..d7eb5fa7 --- /dev/null +++ b/Core/SpawnSelector/Players/AdventureMirrorPlayer.cs @@ -0,0 +1,148 @@ +using Microsoft.Xna.Framework; +using PvPAdventure.Content.Items; +using PvPAdventure.Core.SpawnSelector.Systems; +using PvPAdventure.System; +using Terraria; +using Terraria.DataStructures; +using Terraria.ID; +using Terraria.ModLoader; + +namespace PvPAdventure.Core.SpawnSelector.Players; + +public class AdventureMirrorPlayer : ModPlayer +{ + // Variables + private Point _lastSpawn = new(-1, -1); + + public override void OnHurt(Player.HurtInfo info) + { + base.OnHurt(info); + + // Only care if the player is currently using the AdventureMirror + if (Player.itemTime > 0 && + Player.HeldItem?.type == ModContent.ItemType()) + { + if (Player.HeldItem.ModItem is AdventureMirror mirror) + { + mirror.CancelItemUse(Player); + } + + // Show text only for the local player + if (Player.whoAmI == Main.myPlayer) + { + //PopupTextHelper.NewText("Mirror interrupted!", Player, Color.Crimson); + } + } + } + + public bool IsPlayerInSpawnRegion(int extraTileOffset=0) + { + // Is player in spawn region? + var regionManager = ModContent.GetInstance(); + Point tilePos = Player.Center.ToTileCoordinates(); + var region = regionManager.GetRegionContaining(tilePos); + if (region != null) + { + return true; + } + + // Is player in bed spawn region? + Vector2 bedSpawnPoint = new(Player.SpawnX, Player.SpawnY); + float distanceToBedSpawn = Vector2.Distance(bedSpawnPoint * 16f, Player.Center); + if (distanceToBedSpawn <= 25 * 16f) + { + return true; + } + + return false; + } + + public override void PostUpdate() + { + if (Main.dedServ) + return; + + if (Player.whoAmI != Main.myPlayer) + return; + + if (ModContent.GetInstance().CurrentPhase == GameManager.Phase.Playing && + Main.mapFullscreen && IsPlayerInSpawnRegion()) + { + SpawnSelectorSystem.SetEnabled(true); + } + else + { + SpawnSelectorSystem.SetEnabled(false); + } + + if (Main.netMode != NetmodeID.MultiplayerClient) + return; + + UpdatePlayerSpawnpoint(); + } + + // Update the player's bed spawnpoint to the server + private void UpdatePlayerSpawnpoint() + { + Point current = new(Player.SpawnX, Player.SpawnY); + + if (current == _lastSpawn) + return; // nothing changed + + // Spawn changed (bed set, removed, bed mined, room invalid, etc.) + _lastSpawn = current; + + var packet = Mod.GetPacket(); + packet.Write((byte)AdventurePacketIdentifier.PlayerBed); + packet.Write((byte)Player.whoAmI); + packet.Write(current.X); + packet.Write(current.Y); + packet.Send(); + +#if DEBUG + Main.NewText($"[DEBUG/MODPLAYER] Sync spawn for {Player.name}: ({current.X}, {current.Y})"); +#endif + } + + #region Fullbright + public static bool ForceFullBrightOnce; + public override void ModifyDrawInfo(ref PlayerDrawSet drawInfo) + { + if (drawInfo.headOnlyRender) + return; + + if (!ForceFullBrightOnce) + return; + + drawInfo.shadow = 0f; + drawInfo.stealth = 1f; + + var p = drawInfo.drawPlayer; + p.socialIgnoreLight = true; + + drawInfo.colorEyeWhites = Color.White; + drawInfo.colorEyes = p.eyeColor; + drawInfo.colorHair = p.GetHairColor(useLighting: false); + drawInfo.colorHead = p.skinColor; + drawInfo.colorBodySkin = p.skinColor; + drawInfo.colorLegs = p.skinColor; + + drawInfo.colorShirt = p.shirtColor; + drawInfo.colorUnderShirt = p.underShirtColor; + drawInfo.colorPants = p.pantsColor; + drawInfo.colorShoes = p.shoeColor; + + drawInfo.colorArmorHead = Color.White; + drawInfo.colorArmorBody = Color.White; + drawInfo.colorArmorLegs = Color.White; + drawInfo.colorMount = Color.White; + + drawInfo.colorDisplayDollSkin = PlayerDrawHelper.DISPLAY_DOLL_DEFAULT_SKIN_COLOR; + + drawInfo.headGlowColor = new Color(drawInfo.headGlowColor.R, drawInfo.headGlowColor.G, drawInfo.headGlowColor.B, 0); + drawInfo.bodyGlowColor = new Color(drawInfo.bodyGlowColor.R, drawInfo.bodyGlowColor.G, drawInfo.bodyGlowColor.B, 0); + drawInfo.armGlowColor = new Color(drawInfo.armGlowColor.R, drawInfo.armGlowColor.G, drawInfo.armGlowColor.B, 0); + drawInfo.legsGlowColor = new Color(drawInfo.legsGlowColor.R, drawInfo.legsGlowColor.G, drawInfo.legsGlowColor.B, 0); + } + #endregion +} diff --git a/Core/Features/SpawnSelector/Systems/ItemSlotHooks.cs b/Core/SpawnSelector/Systems/ItemSlotHooks.cs similarity index 76% rename from Core/Features/SpawnSelector/Systems/ItemSlotHooks.cs rename to Core/SpawnSelector/Systems/ItemSlotHooks.cs index f6751443..fb710765 100644 --- a/Core/Features/SpawnSelector/Systems/ItemSlotHooks.cs +++ b/Core/SpawnSelector/Systems/ItemSlotHooks.cs @@ -3,7 +3,7 @@ using Terraria.UI; using PvPAdventure.Content.Items; -namespace PvPAdventure.Core.Features.SpawnSelector.Systems; +namespace PvPAdventure.Core.SpawnSelector.Systems; /// /// Prevents the Adventure Mirror from being removed from the player inventory via trashing or selling. @@ -15,6 +15,8 @@ public override void Load() On_ItemSlot.LeftClick_SellOrTrash += Hook_LeftClick_SellOrTrash; On_ItemSlot.LeftClick_ItemArray_int_int += Hook_LeftClick_ItemArray; On_Player.SellItem += Hook_SellItem; + On_Player.DropSelectedItem += Hook_DropSelectedItem; + On_Player.dropItemCheck += Hook_DropItemCheck; } public override void Unload() @@ -22,6 +24,29 @@ public override void Unload() On_ItemSlot.LeftClick_SellOrTrash -= Hook_LeftClick_SellOrTrash; On_ItemSlot.LeftClick_ItemArray_int_int -= Hook_LeftClick_ItemArray; On_Player.SellItem -= Hook_SellItem; + On_Player.DropSelectedItem -= Hook_DropSelectedItem; + On_Player.dropItemCheck -= Hook_DropItemCheck; + } + + private void Hook_DropItemCheck(On_Player.orig_dropItemCheck orig, Player self) + { + // If the mouse is holding the Adventure Mirror, just block the drop. + if (IsAdventureMirror(Main.mouseItem)) + { + return; + } + orig(self); + } + + private void Hook_DropSelectedItem(On_Player.orig_DropSelectedItem orig,Player self) + { + // If the selected item is the Adventure Mirror, block the drop. + Item selectedItem = self.inventory[self.selectedItem]; + if (IsAdventureMirror(selectedItem)) + { + return; + } + orig(self); } // QUICK TRASH / QUICK SELL (Shift + click) @@ -43,6 +68,7 @@ private static bool Hook_LeftClick_SellOrTrash( return orig(inv, context, slot); } + // Helper method to identify Adventure Mirror private static bool IsAdventureMirror(Item item) => !item.IsAir && item.type == ModContent.ItemType(); diff --git a/Core/Features/SpawnSelector/Systems/SpawnSelectorState.cs b/Core/SpawnSelector/Systems/SpawnSelectorState.cs similarity index 91% rename from Core/Features/SpawnSelector/Systems/SpawnSelectorState.cs rename to Core/SpawnSelector/Systems/SpawnSelectorState.cs index 44798c8e..7c742f5a 100644 --- a/Core/Features/SpawnSelector/Systems/SpawnSelectorState.cs +++ b/Core/SpawnSelector/Systems/SpawnSelectorState.cs @@ -1,11 +1,11 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; -using PvPAdventure.Core.Features.SpawnSelector.UI; using PvPAdventure.Core.Helpers; +using PvPAdventure.Core.SpawnSelector.UI; using Terraria.GameContent.UI.Elements; using Terraria.UI; -namespace PvPAdventure.Core.Features.SpawnSelector.Systems; +namespace PvPAdventure.Core.SpawnSelector.Systems; public class SpawnSelectorState : UIState { diff --git a/Core/Features/SpawnSelector/Systems/SpawnSelectorSystem.cs b/Core/SpawnSelector/Systems/SpawnSelectorSystem.cs similarity index 97% rename from Core/Features/SpawnSelector/Systems/SpawnSelectorSystem.cs rename to Core/SpawnSelector/Systems/SpawnSelectorSystem.cs index 737a732d..2f62726f 100644 --- a/Core/Features/SpawnSelector/Systems/SpawnSelectorSystem.cs +++ b/Core/SpawnSelector/Systems/SpawnSelectorSystem.cs @@ -4,7 +4,7 @@ using Terraria.ModLoader; using Terraria.UI; -namespace PvPAdventure.Core.Features.SpawnSelector.Systems; +namespace PvPAdventure.Core.SpawnSelector.Systems; [Autoload(Side = ModSide.Client)] public class SpawnSelectorSystem : ModSystem diff --git a/Core/Features/SpawnSelector/Systems/UnityHooks.cs b/Core/SpawnSelector/Systems/UnityHooks.cs similarity index 90% rename from Core/Features/SpawnSelector/Systems/UnityHooks.cs rename to Core/SpawnSelector/Systems/UnityHooks.cs index 5952bdc4..49ceed72 100644 --- a/Core/Features/SpawnSelector/Systems/UnityHooks.cs +++ b/Core/SpawnSelector/Systems/UnityHooks.cs @@ -1,7 +1,7 @@ using Terraria; using Terraria.ModLoader; -namespace PvPAdventure.Core.Features.SpawnSelector.Systems; +namespace PvPAdventure.Core.SpawnSelector.Systems; /// /// This allows the player to click on teammates to teleport to them. diff --git a/Core/SpawnSelector/UI/BedsOnMap.cs b/Core/SpawnSelector/UI/BedsOnMap.cs new file mode 100644 index 00000000..ac8feb52 --- /dev/null +++ b/Core/SpawnSelector/UI/BedsOnMap.cs @@ -0,0 +1,163 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using PvPAdventure.Core.SpawnSelector.Systems; +using ReLogic.Content; +using Terraria; +using Terraria.DataStructures; +using Terraria.GameContent; +using Terraria.ID; +using Terraria.Map; +using Terraria.ModLoader; +using Terraria.UI; + +namespace PvPAdventure.Core.SpawnSelector.UI; + +internal class BedsOnMap : ModSystem +{ + private Asset spawnBedTexture; + + public override void Load() + { + On_SpawnMapLayer.Draw += OnSpawnMapLayer; + + } + + public override void Unload() + { + On_SpawnMapLayer.Draw -= OnSpawnMapLayer; + } + + public override void PostSetupContent() + { + if (!Main.dedServ) + { + spawnBedTexture = TextureAssets.SpawnBed; + } + } + + private void OnSpawnMapLayer(On_SpawnMapLayer.orig_Draw orig,SpawnMapLayer self,ref MapOverlayDrawContext context, ref string text) + { + // Let vanilla draw spawn point + local bed first + orig(self, ref context, ref text); + + for (int i = 0; i < Main.maxPlayers; i++) + { + Player player = Main.player[i]; + if (player == null || !player.active || player.team != Main.LocalPlayer.team) + continue; + + + // No bed set for this player -> don't draw anything + if (player.SpawnX == -1 || player.SpawnY == -1) + continue; + + Vector2 bedTilePos = new(player.SpawnX, player.SpawnY); + +#if DEBUG + DrawBedSpawnDebugRect(player, bedTilePos); +#endif + + // Safety check and load texture if needed + spawnBedTexture ??= TextureAssets.SpawnBed; + + bool selectorEnabled = SpawnSelectorSystem.GetEnabled(); + + var hoverCheck = context.Draw( + texture: spawnBedTexture.Value, + position: bedTilePos, + color: Color.White, + frame: new SpriteFrame(1, 1), + scaleIfNotSelected: 1.0f, + scaleIfSelected: selectorEnabled ? 1.8f : 1.0f, // scale up if selector is enabled + alignment: Alignment.Bottom, + spriteEffects: SpriteEffects.None + ); + + if (hoverCheck.IsMouseOver) + { + text = $"{player.name}'s Bed"; + + // Handle hover + click + if (selectorEnabled) + { + // Hover text + text = $"Teleport to {player.name}'s Bed"; + + // Handle click + if (Main.mouseLeft && Main.mouseLeftRelease) + { + if (Main.netMode == NetmodeID.SinglePlayer) + { + // teleport LOCAL player to the clicked bed + Vector2 spawn = new(player.SpawnX * 16, player.SpawnY * 16 - 48); + Main.LocalPlayer.Teleport(spawn); + Main.mapFullscreen = false; + return; + } + + if (Main.netMode == NetmodeID.MultiplayerClient) + { + ModPacket p = Mod.GetPacket(); + p.Write((byte)AdventurePacketIdentifier.BedTeleport); + p.Write((byte)Main.myPlayer); // send the player to teleport (the player who clicked) + p.Write((short)player.SpawnX); // to the target bed position X + p.Write((short)player.SpawnY); // to the target bed position Y + + p.Send(); + + // Close the map afterwards + Main.mapFullscreen = false; + +#if DEBUG + Main.NewText($"[DEBUG/SYSTEM] Sent packet to send player {player.name} to pos: ({player.SpawnX}, {player.SpawnY})"); +#endif + } + } + + } + } + + } + } + +#if DEBUG + private static void DrawBedSpawnDebugRect(Player player, Vector2 bedTilePos) + { + if (!Main.mapFullscreen) + { + return; + } + + // World-space center of the bed (pixels) + Vector2 bedWorld = bedTilePos * 16f; + + // Convert world -> fullscreen map screen coordinates + Vector2 screenCenter = new(Main.screenWidth / 2f, Main.screenHeight / 2f); + Vector2 bedOnMap = (bedWorld - Main.mapFullscreenPos) * Main.mapFullscreenScale + screenCenter; + + float radiusWorld = 25 * 16f; // 25 tiles in world space + float radiusOnMap = radiusWorld * Main.mapFullscreenScale; + + Texture2D pixel = TextureAssets.MagicPixel.Value; + float thickness = 2f; + + Rectangle rect = new( + (int)(bedOnMap.X - radiusOnMap), + (int)(bedOnMap.Y - radiusOnMap), + (int)(radiusOnMap * 2f), + (int)(radiusOnMap * 2f) + ); + + Color color = Main.teamColor[player.team] * 0.75f; + + // Top + Main.spriteBatch.Draw(pixel, new Rectangle(rect.Left, rect.Top, rect.Width, (int)thickness), color); + // Bottom + Main.spriteBatch.Draw(pixel, new Rectangle(rect.Left, rect.Bottom - (int)thickness, rect.Width, (int)thickness), color); + // Left + Main.spriteBatch.Draw(pixel, new Rectangle(rect.Left, rect.Top, (int)thickness, rect.Height), color); + // Right + Main.spriteBatch.Draw(pixel, new Rectangle(rect.Right - (int)thickness, rect.Top, (int)thickness, rect.Height), color); + } +#endif +} diff --git a/Core/Features/SpawnSelector/UI/SpawnSelectorBasePanel.cs b/Core/SpawnSelector/UI/SpawnSelectorBasePanel.cs similarity index 94% rename from Core/Features/SpawnSelector/UI/SpawnSelectorBasePanel.cs rename to Core/SpawnSelector/UI/SpawnSelectorBasePanel.cs index 44ec96ae..2a61a817 100644 --- a/Core/Features/SpawnSelector/UI/SpawnSelectorBasePanel.cs +++ b/Core/SpawnSelector/UI/SpawnSelectorBasePanel.cs @@ -5,7 +5,7 @@ using Terraria; using Terraria.GameContent.UI.Elements; -namespace PvPAdventure.Core.Features.SpawnSelector.UI +namespace PvPAdventure.Core.SpawnSelector.UI { public class SpawnSelectorBasePanel : UIPanel { @@ -52,6 +52,11 @@ private void BuildLayout() } } +#if DEBUG + players.Add(Main.LocalPlayer); + Main.NewText($"[DEBUG] Added local player '{Main.LocalPlayer.name}' to SpawnSelectorBasePanel"); +#endif + int playerCount = players.Count; float itemWidth = SpawnSelectorCharacter.ItemWidth; @@ -152,6 +157,10 @@ private bool NeedsRebuild() players.Add(p.whoAmI); } +#if DEBUG + players.Add(local.whoAmI); +#endif + if (players.Count != _playerItems.Count) return true; diff --git a/Core/Features/SpawnSelector/UI/SpawnSelectorCharacter.cs b/Core/SpawnSelector/UI/SpawnSelectorCharacter.cs similarity index 95% rename from Core/Features/SpawnSelector/UI/SpawnSelectorCharacter.cs rename to Core/SpawnSelector/UI/SpawnSelectorCharacter.cs index 680d0364..5427db31 100644 --- a/Core/Features/SpawnSelector/UI/SpawnSelectorCharacter.cs +++ b/Core/SpawnSelector/UI/SpawnSelectorCharacter.cs @@ -1,7 +1,7 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; -using PvPAdventure.Core.Features.SpawnSelector.Players; using PvPAdventure.Core.Helpers; +using PvPAdventure.Core.SpawnSelector.Players; using ReLogic.Content; using System; using Terraria; @@ -12,7 +12,7 @@ using Terraria.UI; using Terraria.UI.Chat; -namespace PvPAdventure.Core.Features.SpawnSelector.UI +namespace PvPAdventure.Core.SpawnSelector.UI { /// /// Vanilla-like character row. @@ -82,7 +82,7 @@ protected override void DrawSelf(SpriteBatch sb) { var rect2 = dims.ToRectangle(); - Utils.DrawBorderString(sb, "Unable to find p :(", rect2.Location.ToVector2() + new Vector2(50, 0), Color.White); + Utils.DrawBorderString(sb, "Unable to find player :(", rect2.Location.ToVector2() + new Vector2(50, 0), Color.White); return; } @@ -110,7 +110,7 @@ protected override void DrawSelf(SpriteBatch sb) null, Main.UIScaleMatrix); - ModifyDrawInfoPlayer.ForceFullBrightOnce = true; + AdventureMirrorPlayer.ForceFullBrightOnce = true; try { Vector2 playerDrawPos = pos + Main.screenPosition + new Vector2(34, 9); @@ -127,7 +127,7 @@ protected override void DrawSelf(SpriteBatch sb) } finally { - ModifyDrawInfoPlayer.ForceFullBrightOnce = false; + AdventureMirrorPlayer.ForceFullBrightOnce = false; } // Switch back to "normal" UI batch @@ -219,7 +219,7 @@ protected override void DrawSelf(SpriteBatch sb) DrawPlayerHeadOnMap(player); // Draw player respawn timer if it exists - string respawnTimeInSeconds = ((player.respawnTimer / 60) + 1).ToString(); + string respawnTimeInSeconds = (player.respawnTimer / 60 + 1).ToString(); if (player.respawnTimer != 0) { Utils.DrawBorderStringBig(sb, respawnTimeInSeconds, pos + new Vector2(31, 4), Color.Gray, scale: 1f); @@ -277,7 +277,7 @@ public override void MouseOver(UIMouseEvent evt) Player p = Main.player[_playerIndex]; if (p == null || !p.active || p.dead) return; - BackgroundColor = new Color(73, 92, 161); + BackgroundColor = new Color(73, 92, 161, 150); } public override void MouseOut(UIMouseEvent evt) @@ -413,7 +413,7 @@ public static void DrawMapFullscreenBackground_BadMP(SpriteBatch sb, Rectangle r } // Draw - int safeIndex = (bgIndex >= 0 && bgIndex < Ass.MapBG.Length) ? bgIndex : 0; + int safeIndex = bgIndex >= 0 && bgIndex < Ass.MapBG.Length ? bgIndex : 0; var asset = Ass.MapBG[safeIndex]; if (asset?.Value == null) return; @@ -468,9 +468,9 @@ public static void DrawMapFullscreenBackground(SpriteBatch sb, Rectangle rect, P 178 or 183 => 17, 62 or 263 => 18, _ => player.ZoneGlowshroom ? 20 : - player.ZoneCorrupt ? (player.ZoneDesert ? 39 : (player.ZoneSnow ? 33 : 22)) : - player.ZoneCrimson ? (player.ZoneDesert ? 40 : (player.ZoneSnow ? 34 : 23)) : - player.ZoneHallow ? (player.ZoneDesert ? 41 : (player.ZoneSnow ? 35 : 21)) : + player.ZoneCorrupt ? player.ZoneDesert ? 39 : player.ZoneSnow ? 33 : 22 : + player.ZoneCrimson ? player.ZoneDesert ? 40 : player.ZoneSnow ? 34 : 23 : + player.ZoneHallow ? player.ZoneDesert ? 41 : player.ZoneSnow ? 35 : 21 : player.ZoneSnow ? 3 : player.ZoneJungle ? 12 : player.ZoneDesert ? 14 : @@ -519,7 +519,7 @@ public static void DrawMapFullscreenBackground(SpriteBatch sb, Rectangle rect, P bgIndex = 26; } - int safeIndex = (bgIndex >= 0 && bgIndex < Ass.MapBG.Length) ? bgIndex : 0; + int safeIndex = bgIndex >= 0 && bgIndex < Ass.MapBG.Length ? bgIndex : 0; var asset = Ass.MapBG[safeIndex]; rect.X += 10; diff --git a/Core/Features/SpawnSelector/UI/SpawnSelectorQuestionMark.cs b/Core/SpawnSelector/UI/SpawnSelectorQuestionMark.cs similarity index 94% rename from Core/Features/SpawnSelector/UI/SpawnSelectorQuestionMark.cs rename to Core/SpawnSelector/UI/SpawnSelectorQuestionMark.cs index 647fc665..a8ad019a 100644 --- a/Core/Features/SpawnSelector/UI/SpawnSelectorQuestionMark.cs +++ b/Core/SpawnSelector/UI/SpawnSelectorQuestionMark.cs @@ -1,7 +1,7 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; -using PvPAdventure.Core.Features.SpawnSelector.Systems; using PvPAdventure.Core.Helpers; +using PvPAdventure.Core.SpawnSelector.Systems; using PvPAdventure.System; using Terraria; using Terraria.GameContent.UI.Elements; @@ -9,7 +9,7 @@ using Terraria.ModLoader; using Terraria.UI; -namespace PvPAdventure.Core.Features.SpawnSelector.UI +namespace PvPAdventure.Core.SpawnSelector.UI { internal class SpawnSelectorQuestionMark : UIPanel { @@ -51,8 +51,7 @@ public override void LeftClick(UIMouseEvent evt) public override void MouseOver(UIMouseEvent evt) { base.MouseOver(evt); - BackgroundColor = new Color(73, 92, 161); - + BackgroundColor = new Color(73, 92, 161, 150); } public override void MouseOut(UIMouseEvent evt) diff --git a/Core/Spawnbox/SpawnboxMap.cs b/Core/Spawnbox/SpawnboxMap.cs new file mode 100644 index 00000000..bf791302 --- /dev/null +++ b/Core/Spawnbox/SpawnboxMap.cs @@ -0,0 +1,83 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using PvPAdventure.System; +using Terraria; +using Terraria.GameContent; +using Terraria.Map; +using Terraria.ModLoader; +using static PvPAdventure.System.RegionManager; + +namespace PvPAdventure.Core.Spawnbox; + +public class SpawnboxMap : ModMapLayer +{ + public override void Draw(ref MapOverlayDrawContext context, ref string text) + { + var rm = ModContent.GetInstance(); + if (rm.Regions.Count == 0) + return; + + DrawSpawnBoxOnFullscreenMap(ref context); + } + + private static void DrawSpawnBoxOnFullscreenMap(ref MapOverlayDrawContext context) + { + + if (Main.mapFullscreenScale < 0.5) return; + + // spawn region in tiles + //Rectangle area = new(Main.spawnTileX - 25, Main.spawnTileY - 25, 50, 50); + + // Get the spawn region from RegionManager + var rm = ModContent.GetInstance(); + var bgTexture = ModContent.GetInstance()._playerBGTexture; + if (rm.Regions.Count == 0 || bgTexture == null) + return; + + Region region = rm.Regions[0]; + Rectangle area = region.Area; + + // Convert from tiles to map screen + Vector2 topLeft = (new Vector2(area.X, area.Y) - context.MapPosition) * context.MapScale + context.MapOffset; + Vector2 size = new(area.Width * context.MapScale, area.Height * context.MapScale); + + int x = (int)topLeft.X; + int y = (int)topLeft.Y; + int w = (int)size.X; + int h = (int)size.Y; + + // Create rectangle for spawn area + Rectangle spawnRect = new(x, y, w, h); + + // For minimap only: clip to minimap bounds + if (!Main.mapFullscreen && Main.mapStyle == 1) + { + Rectangle minimapRect = new(Main.miniMapX, Main.miniMapY, Main.miniMapWidth, Main.miniMapHeight); + + spawnRect = Rectangle.Intersect(spawnRect, minimapRect); + + // If completely outside, don't draw at all + if (spawnRect.Width <= 0 || spawnRect.Height <= 0) + return; + + x = spawnRect.X; + y = spawnRect.Y; + w = spawnRect.Width; + h = spawnRect.Height; + } + + // now draw using the (possibly clipped) rect + Texture2D pix = TextureAssets.MagicPixel.Value; + Color col = Color.Black * 0.7f; + int thickness = 2; + + if (Main.mapFullscreen) + thickness = (int)(1 * Main.mapFullscreenScale); // match 1 pixel at scale 1 + + // top, bottom, left, right + Main.spriteBatch.Draw(pix, new Rectangle(x, y, w, thickness), col); + Main.spriteBatch.Draw(pix, new Rectangle(x, y + h - thickness, w, thickness), col); + Main.spriteBatch.Draw(pix, new Rectangle(x, y, thickness, h), col); + Main.spriteBatch.Draw(pix, new Rectangle(x + w - thickness, y, thickness, h), col); + } +} diff --git a/Core/Spawnbox/SpawnboxWorld.cs b/Core/Spawnbox/SpawnboxWorld.cs new file mode 100644 index 00000000..db6d988d --- /dev/null +++ b/Core/Spawnbox/SpawnboxWorld.cs @@ -0,0 +1,192 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using PvPAdventure.Core.Helpers; +using PvPAdventure.Core.SpawnSelector.Players; +using PvPAdventure.System; +using ReLogic.Content; +using System; +using System.Collections.Generic; +using Terraria; +using Terraria.ModLoader; +using Terraria.UI; +using static PvPAdventure.System.RegionManager; +using static Terraria.ModLoader.BackupIO; + +namespace PvPAdventure.Core.Spawnbox; + +[Autoload(Side = ModSide.Client)] +public class SpawnBoxWorld : ModSystem +{ + // Initialize the interface layer. + private readonly SpawnBoxInterfaceLayer _randomTeleportGameInterfaceLayer = new(); + public Asset _playerBGTexture; + + // Load the texture. + public override void Load() + { + if (!Main.dedServ) + _playerBGTexture = Ass.CustomPlayerBackground; + } + + // Add the layer. + public override void ModifyInterfaceLayers(List layers) + { + if (!layers.Contains(_randomTeleportGameInterfaceLayer)) + { + // add at the bottom interface layer + // https://github.com/tModLoader/tModLoader/wiki/Vanilla-Interface-layers-values + var layerIndex = layers.FindIndex(layer => layer.Name == "Vanilla: Interface Logic 1"); + + if (layerIndex != -1) + layers.Insert(layerIndex + 1, _randomTeleportGameInterfaceLayer); + } + } + + private class SpawnBoxInterfaceLayer() : GameInterfaceLayer("PvPAdventure: Spawn Box", InterfaceScaleType.UI) + { + protected override bool DrawSelf() + { + //var hitbox = Main.LocalPlayer.Hitbox; + //var tileHitbox = new Rectangle(hitbox.X / 16, hitbox.Y / 16, hitbox.Width / 16, hitbox.Height / 16); + DrawSpawnBox(Main.spriteBatch); + + return base.DrawSelf(); + } + + private static void DrawSpawnBox(SpriteBatch sb) + { + var rm = ModContent.GetInstance(); + var bgTexture = ModContent.GetInstance()._playerBGTexture; + if (rm.Regions.Count == 0 || bgTexture == null) + return; + + Region region = rm.Regions[0]; + Rectangle area = region.Area; + + Vector2 worldTopLeft = new(area.X * 16, area.Y * 16); + Vector2 worldSize = new(area.Width * 16, area.Height * 16); + + Vector2 screenTopLeft = worldTopLeft - Main.screenPosition; + + float uiScale = Main.UIScale; + screenTopLeft /= uiScale; + worldSize /= uiScale; + + Rectangle r = new( + (int)screenTopLeft.X, + (int)screenTopLeft.Y, + (int)worldSize.X, + (int)worldSize.Y + ); + + // Adjust to fit player inside the box (slightly) better + int fullTile = (int) (16f / Main.UIScale); + int halfTile = (int)(fullTile * 0.5f); + r.X -= halfTile; + r.Y -= fullTile; + r.Height += halfTile; + r.Width += halfTile; + + int thickness = (int)Math.Max(1f, 16f / uiScale); // 1 tile wide in world + + float opacity = 1.0f; + + // If we're playing and outside the ring, we can't move outside + var gm = ModContent.GetInstance(); + if (gm.CurrentPhase == GameManager.Phase.Playing) + { + opacity = 0.7f; + + var am = Main.LocalPlayer.GetModPlayer(); + if (!am.IsPlayerInSpawnRegion()) + { + opacity = 1f; + } + } + + DrawOutline(sb, r, thickness, Color.Black * opacity); + } + + private static void DrawOutline(SpriteBatch sb, Rectangle r, int t, Color col) + { + Texture2D pix = Terraria.GameContent.TextureAssets.MagicPixel.Value; + + // top + sb.Draw(pix, new Rectangle(r.X, r.Y, r.Width, t), col); + // bottom + sb.Draw(pix, new Rectangle(r.X, r.Y + r.Height - t, r.Width, t), col); + // left + sb.Draw(pix, new Rectangle(r.X, r.Y, t, r.Height), col); + // right + sb.Draw(pix, new Rectangle(r.X + r.Width - t, r.Y, t, r.Height), col); + } + + + private void DrawSpawnBoxPretty(SpriteBatch sb) + { + var rm = ModContent.GetInstance(); + var bgTexture = ModContent.GetInstance()._playerBGTexture; + + if (rm.Regions.Count == 0 || bgTexture == null) + { + return; + } + + // Get the area + Region region = rm.Regions[0]; + Rectangle area = region.Area; + + Vector2 topLeft = new(area.X * 16, area.Y * 16); + Vector2 areaSize = new(area.Width * 16, area.Height * 16); + + // Convert to screen pixel coords + Vector2 screenTopLeft = topLeft - Main.screenPosition; + + // Compensate for UI scaling (PostDrawInterface uses Main.UIScaleMatrix) + float uiScale = Main.UIScale; + screenTopLeft /= uiScale; + areaSize /= uiScale; + + Rectangle screenRect = new Rectangle( + (int)screenTopLeft.X, + (int)screenTopLeft.Y, + (int)areaSize.X, + (int)areaSize.Y + ); + + // Draw the nine-slice border + DrawNineSliceBorder( + sb, + screenRect.X, + screenRect.Y, + screenRect.Width, + screenRect.Height, + bgTexture.Value, + Color.Black, + inset: -16, + c: 10 + ); + } + + private static void DrawNineSliceBorder(SpriteBatch sb, int x, int y, int w, int h, Texture2D tex, Color color, int inset, int c = 5) + { + c = 12; + x += inset; y += inset; w -= inset * 2 - 16; h -= inset * 2; + int ew = tex.Width - c * 2; + int eh = tex.Height - c * 2; + + // corners + edges, NO center + sb.Draw(tex, new Rectangle(x, y, c, c), new Rectangle(0, 0, c, c), color); + sb.Draw(tex, new Rectangle(x + c, y, w - c * 2, c), new Rectangle(c, 0, ew, c), color); + sb.Draw(tex, new Rectangle(x + w - c, y, c, c), new Rectangle(tex.Width - c, 0, c, c), color); + + sb.Draw(tex, new Rectangle(x, y + c, c, h - c * 2), new Rectangle(0, c, c, eh), color); + // center row skipped here + sb.Draw(tex, new Rectangle(x + w - c, y + c, c, h - c * 2), new Rectangle(tex.Width - c, c, c, eh), color); + + sb.Draw(tex, new Rectangle(x, y + h - c, c, c), new Rectangle(0, tex.Height - c, c, c), color); + sb.Draw(tex, new Rectangle(x + c, y + h - c, w - c * 2, c), new Rectangle(c, tex.Height - c, ew, c), color); + sb.Draw(tex, new Rectangle(x + w - c, y + h - c, c, c), new Rectangle(tex.Width - c, tex.Height - c, c, c), color); + } + } +} diff --git a/PvPAdventure.cs b/PvPAdventure.cs index 76eb34ea..3e3edcb1 100644 --- a/PvPAdventure.cs +++ b/PvPAdventure.cs @@ -1,14 +1,20 @@ using Microsoft.Xna.Framework; using MonoMod.Cil; using PvPAdventure.Content.Items; +using PvPAdventure.Core.Helpers; using PvPAdventure.System; +using System; +using System.Collections.Generic; using System.IO; using System.Linq; using Terraria; +using Terraria.Chat; using Terraria.Enums; using Terraria.ID; +using Terraria.Localization; using Terraria.Map; using Terraria.ModLoader; +using Terraria.UI.Chat; namespace PvPAdventure; @@ -46,63 +52,153 @@ private void EditMainDrawBuffIcon(ILContext il) cursor.RemoveRange(5); } + public override void PostSetupContent() + { + if (File == null) return; + + var names = File.GetFileNames(); + var entries = names + .Select(n => new { Name = n, Bytes = File.GetBytes(n) }) + .OrderByDescending(e => e.Bytes?.Length ?? 0) + .ToList(); + + // Added aggregate stats + if (entries.Count == 0) + { + Log.Info("[ModSize] No files found in mod."); + return; + } + + long totalBytes = entries.Sum(e => (long)(e.Bytes?.Length ?? 0)); + int totalFiles = entries.Count; + double totalMB = totalBytes / 1024f / 1024f; + double avgBytes = totalFiles > 0 ? (double)totalBytes / totalFiles : 0; + double avgKB = avgBytes / 1024.0; + var sizeArray = entries.Select(e => (long)(e.Bytes?.Length ?? 0)).OrderBy(x => x).ToArray(); + double medianBytes = sizeArray.Length % 2 == 1 + ? sizeArray[sizeArray.Length / 2] + : (sizeArray[sizeArray.Length / 2 - 1] + sizeArray[sizeArray.Length / 2]) / 2.0; + double medianKB = medianBytes / 1024.0; + int uniqueExtCount = entries.Select(e => Path.GetExtension(e.Name).ToLowerInvariant()).Distinct().Count(); + + Log.Info($"[ModSize] Total files: {totalFiles}"); + Log.Info($"[ModSize] Total size : {totalMB:0.00} MB"); + Log.Info($"[ModSize] Avg size : {avgKB:0.0} KB Median: {medianKB:0.0} KB"); + Log.Info($"[ModSize] Unique extensions: {uniqueExtCount}"); + var largest = entries[0]; + Log.Info($"[ModSize] Largest file: {largest.Name} ({largest.Bytes.Length / 1024f / 1024f:0.00} MB)"); + + Log.Info("[ModSize] Top 10 biggest files inside mod:"); + foreach (var e in entries.Take(10)) + Log.Info($"[ModSize] {e.Bytes.Length / 1024f / 1024f:0.00} MB {e.Name}"); + + var byExt = entries.GroupBy(e => Path.GetExtension(e.Name).ToLowerInvariant()) + .Select(g => new { Ext = g.Key, MB = g.Sum(x => x.Bytes?.Length ?? 0) / 1024f / 1024f }) + .OrderByDescending(x => x.MB); + + Log.Info("[ModSize] Totals by extension:"); + foreach (var g in byExt) + Log.Info($"[ModSize] {g.Ext,-6} {g.MB:0.00} MB"); + } + public override void HandlePacket(BinaryReader reader, int whoAmI) { var id = (AdventurePacketIdentifier)reader.ReadByte(); switch (id) { - case AdventurePacketIdentifier.AdventureMirrorRightClickUse: - { - byte playerId = reader.ReadByte(); - byte slot = reader.ReadByte(); + case AdventurePacketIdentifier.BedTeleport: + { + byte playerId = reader.ReadByte(); + short bedX = reader.ReadInt16(); + short bedY = reader.ReadInt16(); - if (Main.netMode == NetmodeID.Server) - { - if (playerId != whoAmI) - return; + if (Main.netMode != NetmodeID.Server) + break; - if (playerId < 0 || playerId >= Main.maxPlayers) - return; + // optional anti-cheat: ensure bedX/bedY matches what server knows for this player + if (playerId != whoAmI) + return; - Player player = Main.player[playerId]; - if (player is null || !player.active) - return; + Player player = Main.player[playerId]; + if (player is null || !player.active) + return; - if (slot < 0 || slot >= player.inventory.Length) - return; + // If you trust bedX/bedY, use those: + Vector2 spawnWorld = new Vector2(bedX, bedY - 3).ToWorldCoordinates(); - Item item = player.inventory[slot]; - if (item?.ModItem is not AdventureMirror) - return; + player.Teleport(spawnWorld, TeleportationStyleID.RecallPotion); - ModPacket p = GetPacket(); - p.Write((byte)AdventurePacketIdentifier.AdventureMirrorRightClickUse); - p.Write(playerId); - p.Write(slot); - p.Send(); - } - else if (Main.netMode == NetmodeID.MultiplayerClient) - { - Player player = Main.player[playerId]; - if (player is null || !player.active) - return; - - if (slot < 0 || slot >= player.inventory.Length) - return; - - Item item = player.inventory[slot]; - if (item?.ModItem is not AdventureMirror) - return; - - // Visual state only - player.selectedItem = slot; - player.itemAnimation = item.useAnimation; - player.itemAnimationMax = item.useAnimation; - player.itemTime = item.useTime; - player.itemTimeMax = item.useTime; - } + NetMessage.SendData( + MessageID.TeleportEntity, + -1, -1, null, + number: 0, + number2: player.whoAmI, + number3: spawnWorld.X, + number4: spawnWorld.Y, + number5: TeleportationStyleID.RecallPotion + ); + +#if DEBUG + ChatHelper.BroadcastChatMessage( + NetworkText.FromLiteral($"[DEBUG/SERVER] Player {player.name} teleported to bed ({bedX}, {bedY})."), + Color.Green + ); +#endif + + break; + } + + case AdventurePacketIdentifier.AdventureMirrorRightClickUse: + { + byte playerId = reader.ReadByte(); + byte slot = reader.ReadByte(); + + if (Main.netMode == NetmodeID.Server) + { + if (playerId != whoAmI) + return; + + if (playerId < 0 || playerId >= Main.maxPlayers) + return; + + Player player = Main.player[playerId]; + if (player is null || !player.active) + return; + + if (slot < 0 || slot >= player.inventory.Length) + return; + Item item = player.inventory[slot]; + if (item?.ModItem is not AdventureMirror) + return; + + ModPacket p = GetPacket(); + p.Write((byte)AdventurePacketIdentifier.AdventureMirrorRightClickUse); + p.Write(playerId); + p.Write(slot); + p.Send(); + } + else if (Main.netMode == NetmodeID.MultiplayerClient) + { + Player player = Main.player[playerId]; + if (player is null || !player.active) + return; + + if (slot < 0 || slot >= player.inventory.Length) + return; + + Item item = player.inventory[slot]; + if (item?.ModItem is not AdventureMirror) + return; + + // Visual state only + player.selectedItem = slot; + player.itemAnimation = item.useAnimation; + player.itemAnimationMax = item.useAnimation; + player.itemTime = item.useTime; + player.itemTimeMax = item.useTime; + } break; } case AdventurePacketIdentifier.PlayerBed: @@ -115,15 +211,20 @@ public override void HandlePacket(BinaryReader reader, int whoAmI) p.SpawnX = spawnX; p.SpawnY = spawnY; - if (Main.dedServ) - { - var packet = GetPacket(); - packet.Write((byte)AdventurePacketIdentifier.PlayerBed); - packet.Write(playerId); - packet.Write(spawnX); - packet.Write(spawnY); - packet.Send(-1, whoAmI); - } + if (Main.dedServ) + { + var packet = GetPacket(); + packet.Write((byte)AdventurePacketIdentifier.PlayerBed); + packet.Write(playerId); + packet.Write(spawnX); + packet.Write(spawnY); + packet.Send(-1, whoAmI); + +#if DEBUG + ChatHelper.BroadcastChatMessage( + NetworkText.FromLiteral($"[DEBUG/SERVER] Player {p.name} set spawn to ({spawnX}, {spawnY})"), Color.Green); +#endif + } break; } diff --git a/PvPAdventure.csproj.user b/PvPAdventure.csproj.user index bccdcde8..e9e561e2 100644 --- a/PvPAdventure.csproj.user +++ b/PvPAdventure.csproj.user @@ -4,6 +4,6 @@ ProjectDebugger - Terraria + TerrariaServer \ No newline at end of file diff --git a/System/RegionManager.cs b/System/RegionManager.cs index ed956b24..03da8121 100644 --- a/System/RegionManager.cs +++ b/System/RegionManager.cs @@ -36,97 +36,6 @@ public class Region public override void Load() { On_Collision.TileCollision += OnCollisionTileCollision; - - if (!Main.dedServ) - _playerBGTexture = Ass.CustomPlayerBackground; - } - - private Asset _playerBGTexture; - - public override void PostDrawInterface(SpriteBatch spriteBatch) - { - // COMMENT THIS LINE OUT TO SKIP DRAWING THE SPAWN BOX - //return; - - if (_regions.Count == 0 || _playerBGTexture == null) - { - return; - } - - Region region = _regions[0]; - Rectangle area = region.Area; - - // World (tiles) -> world pixels - Vector2 worldTopLeft = new Vector2(area.X * 16, area.Y * 16); - Vector2 worldSize = new Vector2(area.Width * 16, area.Height * 16); - - // Convert to screen pixel coords - Vector2 screenTopLeft = worldTopLeft - Main.screenPosition; - - float uiScale = Main.UIScale; - - // Compensate for UI scaling (PostDrawInterface uses Main.UIScaleMatrix) - screenTopLeft /= uiScale; - worldSize /= uiScale; - - Rectangle screenRect = new Rectangle( - (int)screenTopLeft.X, - (int)screenTopLeft.Y, - (int)worldSize.X, - (int)worldSize.Y - ); - - DrawNineSliceBorder( - spriteBatch, - screenRect.X, - screenRect.Y, - screenRect.Width, - screenRect.Height, - _playerBGTexture.Value, - Color.Black, - inset: -16, - c: 10 - ); - } - - - private void DrawNineSliceBorder(SpriteBatch sb, int x, int y, int w, int h, Texture2D tex, Color color, int inset, int c = 5) - { - x += inset; y += inset; w -= inset * 2 -16; h -= inset * 2; - int ew = tex.Width - c * 2; - int eh = tex.Height - c * 2; - - // corners + edges, NO center - sb.Draw(tex, new Rectangle(x, y, c, c), new Rectangle(0, 0, c, c), color); - sb.Draw(tex, new Rectangle(x + c, y, w - c * 2, c), new Rectangle(c, 0, ew, c), color); - sb.Draw(tex, new Rectangle(x + w - c, y, c, c), new Rectangle(tex.Width - c, 0, c, c), color); - - sb.Draw(tex, new Rectangle(x, y + c, c, h - c * 2), new Rectangle(0, c, c, eh), color); - // center row skipped here - sb.Draw(tex, new Rectangle(x + w - c, y + c, c, h - c * 2), new Rectangle(tex.Width - c, c, c, eh), color); - - sb.Draw(tex, new Rectangle(x, y + h - c, c, c), new Rectangle(0, tex.Height - c, c, c), color); - sb.Draw(tex, new Rectangle(x + c, y + h - c, w - c * 2, c), new Rectangle(c, tex.Height - c, ew, c), color); - sb.Draw(tex, new Rectangle(x + w - c, y + h - c, c, c), new Rectangle(tex.Width - c, tex.Height - c, c, c), color); - } - - private void DrawNineSlice(SpriteBatch sb, int x, int y, int w, int h, Texture2D tex, Color color, int inset, int c = 5) - { - x += inset; y += inset; w -= inset * 2; h -= inset * 2; - int ew = tex.Width - c * 2; - int eh = tex.Height - c * 2; - - sb.Draw(tex, new Rectangle(x, y, c, c), new Rectangle(0, 0, c, c), color); - sb.Draw(tex, new Rectangle(x + c, y, w - c * 2, c), new Rectangle(c, 0, ew, c), color); - sb.Draw(tex, new Rectangle(x + w - c, y, c, c), new Rectangle(tex.Width - c, 0, c, c), color); - - sb.Draw(tex, new Rectangle(x, y + c, c, h - c * 2), new Rectangle(0, c, c, eh), color); - sb.Draw(tex, new Rectangle(x + c, y + c, w - c * 2, h - c * 2), new Rectangle(c, c, ew, eh), color); - sb.Draw(tex, new Rectangle(x + w - c, y + c, c, h - c * 2), new Rectangle(tex.Width - c, c, c, eh), color); - - sb.Draw(tex, new Rectangle(x, y + h - c, c, c), new Rectangle(0, tex.Height - c, c, c), color); - sb.Draw(tex, new Rectangle(x + c, y + h - c, w - c * 2, c), new Rectangle(c, tex.Height - c, ew, c), color); - sb.Draw(tex, new Rectangle(x + w - c, y + h - c, c, c), new Rectangle(tex.Width - c, tex.Height - c, c, c), color); } private Vector2 OnCollisionTileCollision(On_Collision.orig_TileCollision orig, Vector2 position, Vector2 velocity, From d22ef423c4ee82a1596c36174357180e23b5d0ee Mon Sep 17 00:00:00 2001 From: emyhrberg <121192176+emyhrberg@users.noreply.github.com> Date: Thu, 27 Nov 2025 22:28:15 +0100 Subject: [PATCH 191/206] Fixed most bugs after thursday game --- Assets/SpawnSelector/Spawnbox.png | Bin 0 -> 198 bytes Content/Items/AdventureMirror.cs | 41 +++- Content/WorldGen/Spawnbox.shstruct | Bin 0 -> 502 bytes Content/WorldGen/WorldGenTasks.cs | 75 ++++++++ Core/Debug/DebugChat.cs | 43 +++++ Core/Debug/DebugCommands.cs | 87 ++++++++- Core/Helpers/AssetLoader.cs | 1 + Core/SpawnSelector/Systems/ItemSlotHooks.cs | 5 +- .../UI/SpawnSelectorBasePanel.cs | 14 +- Core/Spawnbox/SpawnboxWorld.cs | 180 +++++++----------- Localization/en-US.hjson | 6 +- PvPAdventure.cs | 50 +---- PvPAdventure.csproj | 5 + PvPAdventure.csproj.user | 2 +- RectangleExtensions.cs | 20 +- System/GameManager.cs | 2 +- System/RegionManager.cs | 29 ++- build.txt | 2 +- lib/StructureHelper.dll | Bin 0 -> 105984 bytes 19 files changed, 378 insertions(+), 184 deletions(-) create mode 100644 Assets/SpawnSelector/Spawnbox.png create mode 100644 Content/WorldGen/Spawnbox.shstruct create mode 100644 Content/WorldGen/WorldGenTasks.cs create mode 100644 Core/Debug/DebugChat.cs create mode 100644 lib/StructureHelper.dll diff --git a/Assets/SpawnSelector/Spawnbox.png b/Assets/SpawnSelector/Spawnbox.png new file mode 100644 index 0000000000000000000000000000000000000000..671c228bc79d7a8d19edabd509c79d8d103ecdb9 GIT binary patch literal 198 zcmeAS@N?(olHy`uVBq!ia0vp^azHH0!3HGvF1f=4q&N#aB8wRqxP?KOkzv*x37}ww zr;B5VN9WsXmV6BcJT8GY-}ir35OBOvm@#4b!TmlDm+QFpJP|YAT=~&iMR(moso1kF zrn_eGvd)qWShzS*cDkN(y!>=6lQmpMnpZaHywHe0ylKJW8s5`~{wJu_-+Se8YiF|R uxzoG)qZ&Ua?yz2W(); + if (gm.CurrentPhase != GameManager.Phase.Playing) + { + // Check if the config allows popup text + var config = ModContent.GetInstance(); + if (!config.ShowPopupText) + return; + + // Create and display the popup text (locally) + if (player.whoAmI == Main.myPlayer) + { + PopupText.NewText(new AdvancedPopupRequest + { + Color = Color.Crimson, + Text = "wait until game starts!", + Velocity = new(0f, -4), + DurationInFrames = 120 + }, player.Top + new Vector2(0, -4)); + } + return; + } + if (player.whoAmI != Main.myPlayer) return; @@ -96,15 +119,19 @@ public override bool CanUseItem(Player player) if (!config.ShowPopupText) return false; - // Create and display the popup text - PopupText.NewText(new AdvancedPopupRequest + // Create and display the popup text (locally) + if (player.whoAmI == Main.myPlayer) { - Color = Color.Crimson, - Text = "wait until game starts!", - Velocity = new(0f, -4), - DurationInFrames = 120 - }, player.Top + new Vector2(0, -4)); + PopupText.NewText(new AdvancedPopupRequest + { + Color = Color.Crimson, + Text = "wait until game starts!", + Velocity = new(0f, -4), + DurationInFrames = 120 + }, player.Top + new Vector2(0, -4)); + } return false; + } return true; diff --git a/Content/WorldGen/Spawnbox.shstruct b/Content/WorldGen/Spawnbox.shstruct new file mode 100644 index 0000000000000000000000000000000000000000..301f7f2e34414e2e6adef6c740a2e6a173d7b56f GIT binary patch literal 502 zcmb2|=3oE=uD5s2dml=WIsS1yJAdp{J=sIfC7o}?EBd?)CUDHr>Ah_|a9Ul$^DR(X#7|XIa|3#-Ed(KAU#U(EXdK^L75m6?JWV5a%Cw z6`F2blKcJ3n|CwjGeg9#rN6&zy6#_mNqXn*dXM&t86}oAh05ixlcx9m-E;Ri+f+sd zh9CXg>U)3w((BxnIm1tH{)*U{Th}Bm4c;uhI%1{SelzXV(~qv(Z`ZGyfByIHA8&p7 z>b0wXd|e%%emii@9=?t7!99nbmR8K4r>+qe$9|5Vw^H_nywoSF0A$t`=go3o_<6q+ z>pnq3P_Coy6=&|BG2DM+KqMSNxRn9iUoSY>U3ap-4kFa;`K=euZv~QY m1m&`uz7G8OUHNoe@&64;@AqGuaZmrT@DqV~mzpOtFaQAiUi*Ro literal 0 HcmV?d00001 diff --git a/Content/WorldGen/WorldGenTasks.cs b/Content/WorldGen/WorldGenTasks.cs new file mode 100644 index 00000000..1f8cc6c1 --- /dev/null +++ b/Content/WorldGen/WorldGenTasks.cs @@ -0,0 +1,75 @@ +//using PvPAdventure.Core.Helpers; +//using System.Collections.Generic; +//using Terraria; +//using Terraria.DataStructures; +//using Terraria.GameContent.Generation; +//using Terraria.ID; +//using Terraria.IO; +//using Terraria.ModLoader; +//using Terraria.WorldBuilding; + +//namespace PvPAdventure.Content.WorldGen; + +//public sealed class WorldGenTasks : ModSystem +//{ +// public override void ModifyWorldGenTasks(List tasks, ref double totalWeight) +// { +// // Here, we can modify which task we want to insert our pass after. +// // https://github.com/tModLoader/tModLoader/wiki/Vanilla-World-Generation-Steps +// int index = tasks.FindIndex(gp => gp.Name == "Final Cleanup"); + +// // Null check +// if (index == -1) +// { +// Log.Error("Failed to find 'Final Cleanup' worldgen task."); +// return; +// } + +// // Insert a new pass after the found index. +// tasks.Insert(index + 1, +// new PassLegacy( +// name: $"{Mod.Name}: Two Sunflower Trees", +// method: (progress, config) => PlaceTwoSunflowerTrees(progress))); +// } + +// private static void PlaceTwoSunflowerTrees(GenerationProgress progress) +// { +// // Set progress message +// progress.Message = "Planting two sunflower trees..."; + +// // Find starting X +// int startX = Main.spawnTileX - 25; + +// // Find ground Y by scanning downwards from spawn point +// int y = Main.spawnTileY; +// while (y < Main.maxTilesY - 10) +// { +// //&& Main.tile[startX, y].TileType == TileID.Grass +// // ^^ This condition was removed to allow placement on any solid tile +// if (Main.tile[startX, y].HasTile) +// break; +// y++; +// } + +// var mod = ModContent.GetInstance(); +// string structurePath = "Content/WorldGen/Spawnbox"; + +// // Set structure size +// Point16 size = StructureHelper.API.Generator.GetStructureDimensions(structurePath, mod); +// int placeX = startX; +// int placeY = y - size.Y; + +// // TEMP REPLACE WITH -25 +// placeX = Main.spawnTileX - 25; +// placeY = Main.spawnTileY - 25; + +// // Generate the structure at the calculated position +// StructureHelper.API.Generator.GenerateStructure( +// path: structurePath, +// pos: new Point16(placeX, placeY), +// mod: mod +// ); + +// Log.Info($"Placed {structurePath} at: ({placeX}, {placeY}) with size: {size.X}x{size.Y}"); +// } +//} diff --git a/Core/Debug/DebugChat.cs b/Core/Debug/DebugChat.cs new file mode 100644 index 00000000..07c99398 --- /dev/null +++ b/Core/Debug/DebugChat.cs @@ -0,0 +1,43 @@ +using Microsoft.Xna.Framework; +using System.Collections.Generic; +using System.Reflection; +using Terraria.GameContent.UI.Chat; +using Terraria.ModLoader; +using Terraria.UI.Chat; + +namespace PvPAdventure.Core.Debug; + +internal class DebugChat : ModSystem +{ + public override void Load() + { + On_RemadeChatMonitor.AddNewMessage += OnAddNewChatMessage; + } + + public override void Unload() + { + On_RemadeChatMonitor.AddNewMessage -= OnAddNewChatMessage; + } + + private void OnAddNewChatMessage(On_RemadeChatMonitor.orig_AddNewMessage orig, RemadeChatMonitor self, string text, Color color, int widthLimitInPixels) + { + orig(self, text, color, widthLimitInPixels); + + // Increase chat visible lines to 20 + var showCountField = typeof(RemadeChatMonitor).GetField("_showCount", BindingFlags.NonPublic | BindingFlags.Instance); + showCountField?.SetValue(self, 20); + + // Access _messages + var messagesField = typeof(RemadeChatMonitor).GetField("_messages", BindingFlags.NonPublic | BindingFlags.Instance); + var messages = (List)messagesField.GetValue(self); + + // Null check + if (messages == null || messages.Count == 0) + return; + + // Extend message lifetime to 60 seconds + var msg = messages[0]; + var timeLeftField = typeof(ChatMessageContainer).GetField("_timeLeft", BindingFlags.NonPublic | BindingFlags.Instance); + timeLeftField?.SetValue(msg, 60 * 60); + } +} diff --git a/Core/Debug/DebugCommands.cs b/Core/Debug/DebugCommands.cs index d7feb49b..639a1732 100644 --- a/Core/Debug/DebugCommands.cs +++ b/Core/Debug/DebugCommands.cs @@ -1,14 +1,84 @@ using Microsoft.Xna.Framework; using PvPAdventure.System; +using System.Collections.Generic; +using System.Reflection; using Terraria; +using Terraria.Chat; using Terraria.Enums; +using Terraria.GameContent.UI.Chat; using Terraria.ID; +using Terraria.Localization; using Terraria.ModLoader; +using Terraria.UI.Chat; namespace PvPAdventure.Core.Debug; -// Only run in debug builds. +// This is only run in debug builds. #if DEBUG + +public class ClearChatCommand : ModCommand +{ + public override string Command => "clear"; + public override CommandType Type => CommandType.World | CommandType.Server; + + public override void Action(CommandCaller caller, string input, string[] args) + { + // Clear Main.chatMonitor messages + var clearMethod = Main.chatMonitor.GetType().GetMethod("Clear", BindingFlags.Instance | BindingFlags.Public); + + // Try to clear in 3 different ways but only 30 empty messages works lol. + if (clearMethod != null) + { + (Main.chatMonitor as RemadeChatMonitor)?.Clear(); + clearMethod?.Invoke(Main.chatMonitor, null); + for (int i=0;i<30;i++) + { + ChatHelper.BroadcastChatMessage(NetworkText.FromLiteral(string.Empty), Color.White); + } + ChatHelper.BroadcastChatMessage(NetworkText.FromLiteral("[DEBUG/SERVER] Chat cleared!!"), Color.White); + } + } +} + +public class ChatTimeCommand : ModCommand +{ + public override string Command => "chattime"; + public override CommandType Type => CommandType.World | CommandType.Server; + + public override void Action(CommandCaller caller, string input, string[] args) + { + if (args.Length != 1 || !int.TryParse(args[0], out int seconds)) + { + caller.Reply("Usage: /chattime ", Color.Red); + return; + } + + var monitor = Main.chatMonitor as RemadeChatMonitor; + if (monitor == null) + return; + + // Access _messages + var messagesField = typeof(RemadeChatMonitor) + .GetField("_messages", BindingFlags.NonPublic | BindingFlags.Instance); + + var messages = (List)messagesField.GetValue(monitor); + if (messages == null) + return; + + // Access ChatMessageContainer._timeLeft + var timeLeftField = typeof(ChatMessageContainer) + .GetField("_timeLeft", BindingFlags.NonPublic | BindingFlags.Instance); + + int frames = seconds * 60; + + // Apply to all messages + foreach (var msg in messages) + timeLeftField.SetValue(msg, frames); + + caller.Reply($"Chat message lifetime set to {seconds} seconds.", Color.Green); + } +} + public class DBStartCommand : ModCommand { public override string Command => "dbstart"; @@ -18,6 +88,21 @@ public override void Action(CommandCaller caller, string input, string[] args) { var gm = ModContent.GetInstance(); gm.StartGame(time: 60000, countdownTimeInSeconds: 0); + ChatHelper.BroadcastChatMessage(NetworkText.FromLiteral("[DEBUG/SERVER] Game started!"), Color.White); + } +} + +public class DBEndCommand : ModCommand +{ + public override string Command => "dbend"; // ends the game + public override CommandType Type => CommandType.World | CommandType.Server; + + public override void Action(CommandCaller caller, string input, string[] args) + { + var gm = ModContent.GetInstance(); + gm._startGameCountdown = null; + gm.TimeRemaining = 0; + gm.CurrentPhase = GameManager.Phase.Waiting; } } diff --git a/Core/Helpers/AssetLoader.cs b/Core/Helpers/AssetLoader.cs index 9b18acee..2f51f592 100644 --- a/Core/Helpers/AssetLoader.cs +++ b/Core/Helpers/AssetLoader.cs @@ -11,6 +11,7 @@ public static class Ass public static Asset[] MapBG; public static Asset Arrow; public static Asset CustomPlayerBackground; + public static Asset Spawnbox; public static bool Initialized { get; set; } diff --git a/Core/SpawnSelector/Systems/ItemSlotHooks.cs b/Core/SpawnSelector/Systems/ItemSlotHooks.cs index fb710765..92cd76be 100644 --- a/Core/SpawnSelector/Systems/ItemSlotHooks.cs +++ b/Core/SpawnSelector/Systems/ItemSlotHooks.cs @@ -33,7 +33,8 @@ private void Hook_DropItemCheck(On_Player.orig_dropItemCheck orig, Player self) // If the mouse is holding the Adventure Mirror, just block the drop. if (IsAdventureMirror(Main.mouseItem)) { - return; + // Note, this makes the item unusable out of the inventory + //return; } orig(self); } @@ -44,7 +45,7 @@ private void Hook_DropSelectedItem(On_Player.orig_DropSelectedItem orig,Player s Item selectedItem = self.inventory[self.selectedItem]; if (IsAdventureMirror(selectedItem)) { - return; + return; } orig(self); } diff --git a/Core/SpawnSelector/UI/SpawnSelectorBasePanel.cs b/Core/SpawnSelector/UI/SpawnSelectorBasePanel.cs index 2a61a817..9d2d4a08 100644 --- a/Core/SpawnSelector/UI/SpawnSelectorBasePanel.cs +++ b/Core/SpawnSelector/UI/SpawnSelectorBasePanel.cs @@ -52,10 +52,10 @@ private void BuildLayout() } } -#if DEBUG - players.Add(Main.LocalPlayer); - Main.NewText($"[DEBUG] Added local player '{Main.LocalPlayer.name}' to SpawnSelectorBasePanel"); -#endif +//#if DEBUG +// players.Add(Main.LocalPlayer); +// Main.NewText($"[DEBUG] Added local player '{Main.LocalPlayer.name}' to SpawnSelectorBasePanel"); +//#endif int playerCount = players.Count; @@ -157,9 +157,9 @@ private bool NeedsRebuild() players.Add(p.whoAmI); } -#if DEBUG - players.Add(local.whoAmI); -#endif +//#if DEBUG +// players.Add(local.whoAmI); +//#endif if (players.Count != _playerItems.Count) return true; diff --git a/Core/Spawnbox/SpawnboxWorld.cs b/Core/Spawnbox/SpawnboxWorld.cs index db6d988d..b2757d5c 100644 --- a/Core/Spawnbox/SpawnboxWorld.cs +++ b/Core/Spawnbox/SpawnboxWorld.cs @@ -7,10 +7,10 @@ using System; using System.Collections.Generic; using Terraria; +using Terraria.GameContent; using Terraria.ModLoader; using Terraria.UI; using static PvPAdventure.System.RegionManager; -using static Terraria.ModLoader.BackupIO; namespace PvPAdventure.Core.Spawnbox; @@ -18,7 +18,7 @@ namespace PvPAdventure.Core.Spawnbox; public class SpawnBoxWorld : ModSystem { // Initialize the interface layer. - private readonly SpawnBoxInterfaceLayer _randomTeleportGameInterfaceLayer = new(); + private readonly SpawnBoxInterfaceLayer _spawnBoxInterfaceLayer = new(); public Asset _playerBGTexture; // Load the texture. @@ -31,14 +31,14 @@ public override void Load() // Add the layer. public override void ModifyInterfaceLayers(List layers) { - if (!layers.Contains(_randomTeleportGameInterfaceLayer)) + if (!layers.Contains(_spawnBoxInterfaceLayer)) { // add at the bottom interface layer // https://github.com/tModLoader/tModLoader/wiki/Vanilla-Interface-layers-values var layerIndex = layers.FindIndex(layer => layer.Name == "Vanilla: Interface Logic 1"); if (layerIndex != -1) - layers.Insert(layerIndex + 1, _randomTeleportGameInterfaceLayer); + layers.Insert(layerIndex + 1, _spawnBoxInterfaceLayer); } } @@ -46,147 +46,113 @@ private class SpawnBoxInterfaceLayer() : GameInterfaceLayer("PvPAdventure: Spawn { protected override bool DrawSelf() { - //var hitbox = Main.LocalPlayer.Hitbox; - //var tileHitbox = new Rectangle(hitbox.X / 16, hitbox.Y / 16, hitbox.Width / 16, hitbox.Height / 16); - DrawSpawnBox(Main.spriteBatch); + // To see how to draw coordinates properly, see the wiki on Coordinates. + // https://github.com/tModLoader/tModLoader/wiki/Coordinates + // Draw the spawn box. + DrawSpawnBox(Main.spriteBatch); return base.DrawSelf(); } - private static void DrawSpawnBox(SpriteBatch sb) + private void DrawSpawnBox(SpriteBatch sb) { var rm = ModContent.GetInstance(); - var bgTexture = ModContent.GetInstance()._playerBGTexture; - if (rm.Regions.Count == 0 || bgTexture == null) + if (rm.Regions.Count == 0) return; Region region = rm.Regions[0]; - Rectangle area = region.Area; - Vector2 worldTopLeft = new(area.X * 16, area.Y * 16); - Vector2 worldSize = new(area.Width * 16, area.Height * 16); + // 🔹 this is the “solid ring” bounds in TILE space + Rectangle ring = region.CollisionRingBounds; - Vector2 screenTopLeft = worldTopLeft - Main.screenPosition; - - float uiScale = Main.UIScale; - screenTopLeft /= uiScale; - worldSize /= uiScale; + int leftTile = ring.X; + int rightTile = ring.X + ring.Width; // exclusive + int topTile = ring.Y; + int bottomTile = ring.Y + ring.Height; // exclusive - Rectangle r = new( - (int)screenTopLeft.X, - (int)screenTopLeft.Y, - (int)worldSize.X, - (int)worldSize.Y - ); + // Tile -> world + float leftWorld = leftTile * 16f; + float rightWorld = rightTile * 16f; + float topWorld = topTile * 16f; + float bottomWorld = bottomTile * 16f; - // Adjust to fit player inside the box (slightly) better - int fullTile = (int) (16f / Main.UIScale); - int halfTile = (int)(fullTile * 0.5f); - r.X -= halfTile; - r.Y -= fullTile; - r.Height += halfTile; - r.Width += halfTile; + // World -> screen + float uiScale = Main.UIScale; - int thickness = (int)Math.Max(1f, 16f / uiScale); // 1 tile wide in world + float leftScreen = (leftWorld - Main.screenPosition.X) / uiScale; + float rightScreen = (rightWorld - Main.screenPosition.X) / uiScale; + float topScreen = (topWorld - Main.screenPosition.Y) / uiScale; + float bottomScreen = (bottomWorld - Main.screenPosition.Y) / uiScale; - float opacity = 1.0f; - // If we're playing and outside the ring, we can't move outside var gm = ModContent.GetInstance(); - if (gm.CurrentPhase == GameManager.Phase.Playing) - { - opacity = 0.7f; - - var am = Main.LocalPlayer.GetModPlayer(); - if (!am.IsPlayerInSpawnRegion()) - { - opacity = 1f; - } - } - - DrawOutline(sb, r, thickness, Color.Black * opacity); - } + var am = Main.LocalPlayer.GetModPlayer(); - private static void DrawOutline(SpriteBatch sb, Rectangle r, int t, Color col) - { - Texture2D pix = Terraria.GameContent.TextureAssets.MagicPixel.Value; + float solidOpacity = 1.0f; + float lightOpacity = 0.5f; - // top - sb.Draw(pix, new Rectangle(r.X, r.Y, r.Width, t), col); - // bottom - sb.Draw(pix, new Rectangle(r.X, r.Y + r.Height - t, r.Width, t), col); - // left - sb.Draw(pix, new Rectangle(r.X, r.Y, t, r.Height), col); - // right - sb.Draw(pix, new Rectangle(r.X + r.Width - t, r.Y, t, r.Height), col); - } + float opacity = gm.CurrentPhase == GameManager.Phase.Playing + ? (am.IsPlayerInSpawnRegion() ? lightOpacity : solidOpacity) + : solidOpacity; + int l = (int)leftScreen; + int r = (int)rightScreen; + int t = (int)topScreen; + int b = (int)bottomScreen; - private void DrawSpawnBoxPretty(SpriteBatch sb) - { - var rm = ModContent.GetInstance(); - var bgTexture = ModContent.GetInstance()._playerBGTexture; + int thickness = (int)Math.Max(1f, 16f / uiScale); + //Texture2D pix = TextureAssets.MagicPixel.Value; + //Color col = Color.Gray * 0.7f; - if (rm.Regions.Count == 0 || bgTexture == null) - { - return; - } + // vanilla borders (top,left,bottom,right) + //sb.Draw(pix, new Rectangle(l, t, r - l, thickness), col); + //sb.Draw(pix, new Rectangle(l, b - thickness, r - l, thickness), col); + //sb.Draw(pix, new Rectangle(l, t, thickness, b - t), col); + //sb.Draw(pix, new Rectangle(r - thickness, t, thickness, b - t), col); - // Get the area - Region region = rm.Regions[0]; - Rectangle area = region.Area; + Rectangle screenRect = new(l,t,r - l, b - t); + DrawNineSliceBorder(sb, screenRect, Color.White * opacity); + } - Vector2 topLeft = new(area.X * 16, area.Y * 16); - Vector2 areaSize = new(area.Width * 16, area.Height * 16); + private void DrawNineSliceBorder(SpriteBatch sb, Rectangle rect, Color color) + { + Texture2D tex = ModContent.GetInstance()._playerBGTexture.Value; - // Convert to screen pixel coords - Vector2 screenTopLeft = topLeft - Main.screenPosition; - // Compensate for UI scaling (PostDrawInterface uses Main.UIScaleMatrix) - float uiScale = Main.UIScale; - screenTopLeft /= uiScale; - areaSize /= uiScale; - - Rectangle screenRect = new Rectangle( - (int)screenTopLeft.X, - (int)screenTopLeft.Y, - (int)areaSize.X, - (int)areaSize.Y - ); - - // Draw the nine-slice border - DrawNineSliceBorder( - sb, - screenRect.X, - screenRect.Y, - screenRect.Width, - screenRect.Height, - bgTexture.Value, - Color.Black, - inset: -16, - c: 10 - ); - } + tex = Ass.Spawnbox.Value; + + int c = 16; // corner size + int x = rect.X; + int y = rect.Y; + int w = rect.Width; + int h = rect.Height; - private static void DrawNineSliceBorder(SpriteBatch sb, int x, int y, int w, int h, Texture2D tex, Color color, int inset, int c = 5) - { - c = 12; - x += inset; y += inset; w -= inset * 2 - 16; h -= inset * 2; int ew = tex.Width - c * 2; int eh = tex.Height - c * 2; - // corners + edges, NO center + // top-left sb.Draw(tex, new Rectangle(x, y, c, c), new Rectangle(0, 0, c, c), color); + + // top sb.Draw(tex, new Rectangle(x + c, y, w - c * 2, c), new Rectangle(c, 0, ew, c), color); + + // top-right sb.Draw(tex, new Rectangle(x + w - c, y, c, c), new Rectangle(tex.Width - c, 0, c, c), color); + // left sb.Draw(tex, new Rectangle(x, y + c, c, h - c * 2), new Rectangle(0, c, c, eh), color); - // center row skipped here + + // right sb.Draw(tex, new Rectangle(x + w - c, y + c, c, h - c * 2), new Rectangle(tex.Width - c, c, c, eh), color); + // bottom-left sb.Draw(tex, new Rectangle(x, y + h - c, c, c), new Rectangle(0, tex.Height - c, c, c), color); - sb.Draw(tex, new Rectangle(x + c, y + h - c, w - c * 2, c), new Rectangle(c, tex.Height - c, ew, c), color); - sb.Draw(tex, new Rectangle(x + w - c, y + h - c, c, c), new Rectangle(tex.Width - c, tex.Height - c, c, c), color); + + // bottom + sb.Draw(tex, new Rectangle(x + c, y + h - c, w - c * 2, c),new Rectangle(c, tex.Height - c, ew, c), color); + + // bottom-right + sb.Draw(tex, new Rectangle(x + w - c, y + h - c, c, c),new Rectangle(tex.Width - c, tex.Height - c, c, c), color); } } } diff --git a/Localization/en-US.hjson b/Localization/en-US.hjson index c2688b3d..08ed8a84 100644 --- a/Localization/en-US.hjson +++ b/Localization/en-US.hjson @@ -808,7 +808,11 @@ Mods: { Items: { AdventureMirror: { DisplayName: Adventure Mirror - Tooltip: Gaze in the mirror to go on adventures + Tooltip: + ''' + Gaze in the mirror to go on adventures + Right click to use + ''' } } } diff --git a/PvPAdventure.cs b/PvPAdventure.cs index 3e3edcb1..b49100a5 100644 --- a/PvPAdventure.cs +++ b/PvPAdventure.cs @@ -54,51 +54,7 @@ private void EditMainDrawBuffIcon(ILContext il) public override void PostSetupContent() { - if (File == null) return; - - var names = File.GetFileNames(); - var entries = names - .Select(n => new { Name = n, Bytes = File.GetBytes(n) }) - .OrderByDescending(e => e.Bytes?.Length ?? 0) - .ToList(); - - // Added aggregate stats - if (entries.Count == 0) - { - Log.Info("[ModSize] No files found in mod."); - return; - } - - long totalBytes = entries.Sum(e => (long)(e.Bytes?.Length ?? 0)); - int totalFiles = entries.Count; - double totalMB = totalBytes / 1024f / 1024f; - double avgBytes = totalFiles > 0 ? (double)totalBytes / totalFiles : 0; - double avgKB = avgBytes / 1024.0; - var sizeArray = entries.Select(e => (long)(e.Bytes?.Length ?? 0)).OrderBy(x => x).ToArray(); - double medianBytes = sizeArray.Length % 2 == 1 - ? sizeArray[sizeArray.Length / 2] - : (sizeArray[sizeArray.Length / 2 - 1] + sizeArray[sizeArray.Length / 2]) / 2.0; - double medianKB = medianBytes / 1024.0; - int uniqueExtCount = entries.Select(e => Path.GetExtension(e.Name).ToLowerInvariant()).Distinct().Count(); - - Log.Info($"[ModSize] Total files: {totalFiles}"); - Log.Info($"[ModSize] Total size : {totalMB:0.00} MB"); - Log.Info($"[ModSize] Avg size : {avgKB:0.0} KB Median: {medianKB:0.0} KB"); - Log.Info($"[ModSize] Unique extensions: {uniqueExtCount}"); - var largest = entries[0]; - Log.Info($"[ModSize] Largest file: {largest.Name} ({largest.Bytes.Length / 1024f / 1024f:0.00} MB)"); - - Log.Info("[ModSize] Top 10 biggest files inside mod:"); - foreach (var e in entries.Take(10)) - Log.Info($"[ModSize] {e.Bytes.Length / 1024f / 1024f:0.00} MB {e.Name}"); - - var byExt = entries.GroupBy(e => Path.GetExtension(e.Name).ToLowerInvariant()) - .Select(g => new { Ext = g.Key, MB = g.Sum(x => x.Bytes?.Length ?? 0) / 1024f / 1024f }) - .OrderByDescending(x => x.MB); - - Log.Info("[ModSize] Totals by extension:"); - foreach (var g in byExt) - Log.Info($"[ModSize] {g.Ext,-6} {g.MB:0.00} MB"); + base.PostSetupContent(); } public override void HandlePacket(BinaryReader reader, int whoAmI) @@ -142,7 +98,7 @@ public override void HandlePacket(BinaryReader reader, int whoAmI) #if DEBUG ChatHelper.BroadcastChatMessage( NetworkText.FromLiteral($"[DEBUG/SERVER] Player {player.name} teleported to bed ({bedX}, {bedY})."), - Color.Green + Color.White ); #endif @@ -222,7 +178,7 @@ public override void HandlePacket(BinaryReader reader, int whoAmI) #if DEBUG ChatHelper.BroadcastChatMessage( - NetworkText.FromLiteral($"[DEBUG/SERVER] Player {p.name} set spawn to ({spawnX}, {spawnY})"), Color.Green); + NetworkText.FromLiteral($"[DEBUG/SERVER] Player {p.name} set spawn to ({spawnX}, {spawnY})"), Color.White); #endif } diff --git a/PvPAdventure.csproj b/PvPAdventure.csproj index 27248e3c..77432301 100644 --- a/PvPAdventure.csproj +++ b/PvPAdventure.csproj @@ -19,6 +19,11 @@ lib\System.Linq.Async.dll + + + + lib\StructureHelper.dll + diff --git a/PvPAdventure.csproj.user b/PvPAdventure.csproj.user index e9e561e2..bccdcde8 100644 --- a/PvPAdventure.csproj.user +++ b/PvPAdventure.csproj.user @@ -4,6 +4,6 @@ ProjectDebugger - TerrariaServer + Terraria \ No newline at end of file diff --git a/RectangleExtensions.cs b/RectangleExtensions.cs index caa06576..965e40f7 100644 --- a/RectangleExtensions.cs +++ b/RectangleExtensions.cs @@ -4,10 +4,18 @@ namespace PvPAdventure; public static class RectangleExtensions { - public static Rectangle ToTileRectangle(this Rectangle rectangle) => new( - rectangle.X / 16, - rectangle.Y / 16, - rectangle.Width / 16, - rectangle.Height / 16 - ); + public static Rectangle ToTileRectangle(this Rectangle r) + { + int leftTile = r.Left / 16; + int topTile = r.Top / 16; + int rightTile = (r.Right - 1) / 16; + int bottomTile = (r.Bottom - 1) / 16; + + return new Rectangle( + leftTile, + topTile, + rightTile - leftTile + 1, + bottomTile - topTile + 1 + ); + } } \ No newline at end of file diff --git a/System/GameManager.cs b/System/GameManager.cs index 421ba167..d80b87a3 100644 --- a/System/GameManager.cs +++ b/System/GameManager.cs @@ -27,7 +27,7 @@ public class GameManager : ModSystem public Phase CurrentPhase { get => _currentPhase; - private set + set { if (_currentPhase == value) return; diff --git a/System/RegionManager.cs b/System/RegionManager.cs index 03da8121..66e41c78 100644 --- a/System/RegionManager.cs +++ b/System/RegionManager.cs @@ -1,4 +1,4 @@ -using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using PvPAdventure.Core.Helpers; using ReLogic.Content; @@ -31,6 +31,8 @@ public class Region public bool CanRecall { get; set; } public bool CanEnter { get; set; } public bool CanExit { get; set; } + public Rectangle CollisionRingBounds => + new(Area.X - 1, Area.Y - 1, Area.Width + 2, Area.Height + 2); } public override void Load() @@ -39,7 +41,7 @@ public override void Load() } private Vector2 OnCollisionTileCollision(On_Collision.orig_TileCollision orig, Vector2 position, Vector2 velocity, - int width, int height, bool fallthrough, bool fall2, int gravdir) + int width, int height, bool fallthrough, bool fall2, int gravdir) { // Always call to the original to ensure we set Collision.up and Collision.down, and collide with real tiles // as expected. @@ -61,6 +63,27 @@ private Vector2 OnCollisionTileCollision(On_Collision.orig_TileCollision orig, V if (ShouldPrevent(sourceIntersections, GetRegionsIntersecting(verticalDestinationHitbox).ToHashSet())) collisionVelocity.Y = 0.0f; + // extra tightening from inside: stop 1 tile earlier than the outer ring + var destHitboxX = new Rectangle((int)(position.X + collisionVelocity.X), (int)position.Y, width, height) + .ToTileRectangle(); + var destHitboxY = new Rectangle((int)position.X, (int)(position.Y + collisionVelocity.Y), width, height) + .ToTileRectangle(); + + foreach (var region in sourceIntersections) + { + if (!region.CanExit) + { + var innerBounds = region.CollisionRingBounds; + innerBounds.Inflate(-1, -1); // shrink 1 tile on all sides + + if (innerBounds.Contains(sourceHitbox) && !innerBounds.Contains(destHitboxX)) + collisionVelocity.X = 0.0f; + + if (innerBounds.Contains(sourceHitbox) && !innerBounds.Contains(destHitboxY)) + collisionVelocity.Y = 0.0f; + } + } + return collisionVelocity; bool ShouldPrevent(HashSet source, HashSet destination) @@ -164,7 +187,7 @@ public IEnumerable GetRegionsContaining(Point point) => _regions.Where(region => region.Area.Contains(point)); public IEnumerable GetRegionsIntersecting(Rectangle rectangle) => - _regions.Where(region => region.Area.Intersects(rectangle)); + _regions.Where(region => region.CollisionRingBounds.Intersects(rectangle)); public override void ClearWorld() { diff --git a/build.txt b/build.txt index dea6b050..6fb1b8b0 100644 --- a/build.txt +++ b/build.txt @@ -3,4 +3,4 @@ author = James Puleo version = 1.1.0 hideCode = true homepage = https://tpvpa.terraria.sh -dllReferences = Discord.Net.Rest, Discord.Net.Core, System.Linq.Async +dllReferences = Discord.Net.Rest, Discord.Net.Core, System.Linq.Async, StructureHelper diff --git a/lib/StructureHelper.dll b/lib/StructureHelper.dll new file mode 100644 index 0000000000000000000000000000000000000000..82be0872453cfce6b65f7b7d1bd5b526d23c1eb1 GIT binary patch literal 105984 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�%(wkrsMVKd8h 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 Date: Thu, 27 Nov 2025 13:32:49 -0800 Subject: [PATCH 192/206] Update AdventureDropDatabase.cs --- AdventureDropDatabase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AdventureDropDatabase.cs b/AdventureDropDatabase.cs index 9cf90b92..2b42cb82 100644 --- a/AdventureDropDatabase.cs +++ b/AdventureDropDatabase.cs @@ -98,7 +98,7 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) foreach (var drop in drops) { ModifyDropRate(drop, ItemID.Stinger, 1, 1); - ModifyDropRate(drop, ItemID.TatteredBeeWing, 1, 1); + ModifyDropRate(drop, ItemID.TatteredBeeWing, 1, 15); } break; From 3326f239839d7b30b3799a58a6ac6a96795c5b60 Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Sat, 29 Nov 2025 03:50:14 -0800 Subject: [PATCH 193/206] crazy shit --- Dogshit.cs | 1326 +++++++++++++++++++++++++++----------- Localization/en-US.hjson | 42 +- LockedLihzahrdChest.cs | 158 ++++- 3 files changed, 1122 insertions(+), 404 deletions(-) diff --git a/Dogshit.cs b/Dogshit.cs index aea436ef..87a30bae 100644 --- a/Dogshit.cs +++ b/Dogshit.cs @@ -17,6 +17,7 @@ using System.IO; using Terraria.DataStructures; using Terraria.GameContent.Biomes; +using Terraria.GameContent.Personalities; namespace PvPAdventure { public class IncreasedRainSystem : ModSystem @@ -408,392 +409,939 @@ public override void UpdateInventory(Item item, Player player) } } } - //public class ExtraWorldGen : ModSystem - //{ - // public override void ModifyWorldGenTasks(List tasks, ref double totalWeight) - // { - // // We need to run AFTER most worldgen, so let's find later passes to insert after - // int shiniesIndex = tasks.FindIndex(genpass => genpass.Name.Equals("Shinies")); - // int finalCleanupIndex = tasks.FindIndex(genpass => genpass.Name.Equals("Final Cleanup")); - - // // If we can't find those, use a safe default (near the end) - // int insertIndex = finalCleanupIndex != -1 ? finalCleanupIndex : tasks.Count - 1; - - // // Add all our extra generation as a single pass that runs late - // tasks.Insert(insertIndex, new PassLegacy("Extra Structures Late Pass", delegate (GenerationProgress progress, GameConfiguration passConfig) - // { - // progress.Message = "Adding extra structures..."; - - // // Add extra pyramids - // progress.Set(0.1); - // int extraPyramids = WorldGen.genRand.Next(1, 1); - // for (int i = 0; i < extraPyramids; i++) - // { - // int attempts = 0; - // bool placed = false; - // while (!placed && attempts < 1000) - // { - // int x = WorldGen.genRand.Next(300, Main.maxTilesX - 300); - // int y = (int)Main.worldSurface - 10; - // if (WorldGen.InWorld(x, y) && Main.tile[x, y].TileType == TileID.Sand) - // { - // placed = WorldGen.Pyramid(x, y); - // } - // attempts++; - // } - // } - - // // Add extra pyramids - // progress.Set(0.2); - // int extraPatches = WorldGen.genRand.Next(3, 7); - - // for (int i = 0; i < extraPatches; i++) - // { - // progress.Set((double)i / extraPatches); - // int attempts = 0; - // bool placed = false; - - // while (!placed && attempts < 1000) - // { - // int x = WorldGen.genRand.Next((int)(Main.maxTilesX * 0.2), (int)(Main.maxTilesX * 0.8)); - // int y = WorldGen.genRand.Next((int)Main.rockLayer + 50, Main.maxTilesY - 300); - - // if (WorldGen.InWorld(x, y)) - // { - // WorldGen.ShroomPatch(x, y); - // placed = true; - // } - // attempts++; - // } - // } - - // // Add extra rich mahogany trees using the proper biome system - // progress.Set(0.3); - // try - // { - // var mahoganyTreeBiome = GenVars.configuration.CreateBiome(); - // int extraMahoganyTrees = WorldGen.genRand.Next(4, 6); - // int mahoganyPlaced = 0; - // int mahoganyAttempts = 0; - - // while (mahoganyPlaced < extraMahoganyTrees && mahoganyAttempts < 20000) - // { - // Point point = WorldGen.RandomWorldPoint((int)Main.worldSurface + 50, 50, 500, 50); - // if (mahoganyTreeBiome.Place(point, GenVars.structures)) - // { - // mahoganyPlaced++; - // } - // mahoganyAttempts++; - // } - // } - // catch - // { - // // Fallback if MahoganyTreeBiome isn't available - // ModContent.GetInstance().Logger.Info("MahoganyTreeBiome not available, skipping extra mahogany trees"); - // } - - // // Add extra minecart tracks using TrackGenerator - // progress.Set(0.5); - // try - // { - // var trackGenerator = new TrackGenerator(); - - // // Add long tracks - // int extraLongTracks = WorldGen.genRand.Next(15, 20); - // int longTrackPlaced = 0; - // int longTrackAttempts = 0; - - // while (longTrackPlaced < extraLongTracks && longTrackAttempts < Main.maxTilesX) - // { - // Point point = WorldGen.RandomWorldPoint((int)Main.worldSurface, 10, 200, 10); - // if (trackGenerator.Place(point, 300, 2000)) // Long track length range - // { - // longTrackPlaced++; - // longTrackAttempts = 0; - // } - // else - // { - // longTrackAttempts++; - // } - // } - - // // Add standard tracks - // int extraStandardTracks = WorldGen.genRand.Next(15, 22); - // int standardTrackPlaced = 0; - // int standardTrackAttempts = 0; - - // while (standardTrackPlaced < extraStandardTracks && standardTrackAttempts < Main.maxTilesX) - // { - // Point point = WorldGen.RandomWorldPoint((int)Main.worldSurface, 10, 200, 10); - // if (trackGenerator.Place(point, 100, 300)) // Standard track length range - // { - // standardTrackPlaced++; - // standardTrackAttempts = 0; - // } - // else - // { - // standardTrackAttempts++; - // } - // } - // } - // catch - // { - // // Fallback if TrackGenerator isn't available - // ModContent.GetInstance().Logger.Info("TrackGenerator not available, using alternative minecart track generation"); - - // // Alternative minecart track generation - // int extraTracks = WorldGen.genRand.Next(10, 18); - // for (int i = 0; i < extraTracks; i++) - // { - // int attempts = 0; - // bool placed = false; - // while (!placed && attempts < 500) - // { - // int x = WorldGen.genRand.Next(200, Main.maxTilesX - 200); - // int y = WorldGen.genRand.Next((int)Main.worldSurface + 50, (int)Main.rockLayer + 100); - - // if (WorldGen.InWorld(x, y)) - // { - // // Create underground tunnel with minecart tracks - // WorldGen.TileRunner(x, y, (double)WorldGen.genRand.Next(8, 15), WorldGen.genRand.Next(50, 100), - // -1, false, 0f, 0f, true, true); - - // // Place minecart tracks in the tunnel - // for (int trackX = x - 5; trackX <= x + 5; trackX++) - // { - // if (WorldGen.InWorld(trackX, y) && !Main.tile[trackX, y].HasTile) - // { - // WorldGen.PlaceTile(trackX, y, TileID.MinecartTrack, true, false); - // } - // } - - // placed = true; - // } - // attempts++; - // } - // } - // } - - // // Add extra hives using HiveBiome - // progress.Set(0.6); - // try - // { - // var hiveBiome = GenVars.configuration.CreateBiome(); - // var honeyPatchBiome = GenVars.configuration.CreateBiome(); - // double hiveNum = (double)Main.maxTilesX / 4200.0; - // int extraHives = WorldGen.genRand.Next((int)(7.0 * hiveNum), (int)(11.0 * hiveNum)); - - // for (int i = 0; i < extraHives; i++) - // { - // int attempts = 0; - // bool placed = false; - // while (!placed && attempts < 1000) - // { - // Point point = WorldGen.RandomWorldPoint((int)(Main.worldSurface + Main.rockLayer) >> 1, 20, 300, 20); - // if (hiveBiome.Place(point, GenVars.structures)) - // { - // placed = true; - // int honeyPatches = WorldGen.genRand.Next(3); - // int honeyPlaced = 0; - // int honeyAttempts = 0; - - // while (honeyPlaced < honeyPatches && honeyAttempts < 100) - // { - // double distance = WorldGen.genRand.NextDouble() * 60.0 + 30.0; - // double angle = WorldGen.genRand.NextDouble() * 6.2831854820251465; - // int honeyX = (int)(Math.Cos(angle) * distance) + point.X; - // int honeyY = (int)(Math.Sin(angle) * distance) + point.Y; - // honeyAttempts++; - - // if (honeyPatchBiome.Place(new Point(honeyX, honeyY), GenVars.structures)) - // { - // honeyPlaced++; - // } - // } - // } - // attempts++; - // } - // } - // } - // catch - // { - // // Fallback if HiveBiome isn't available - // ModContent.GetInstance().Logger.Info("HiveBiome not available, using alternative hive generation"); - - // // Alternative hive generation - // int extraHives = WorldGen.genRand.Next(4, 8); - // for (int i = 0; i < extraHives; i++) - // { - // int attempts = 0; - // bool placed = false; - // while (!placed && attempts < 500) - // { - // int x = WorldGen.genRand.Next(200, Main.maxTilesX - 200); - // int y = WorldGen.genRand.Next((int)((Main.worldSurface + Main.rockLayer) / 2), (int)Main.rockLayer + 200); - - // // Check if we're in jungle (mud blocks) - // if (Main.tile[x, y].TileType == TileID.Mud || Main.tile[x, y].TileType == TileID.JungleGrass) - // { - // // Create a hive using TileRunner with Hive block (225) - // int hiveSize = WorldGen.genRand.Next(30, 60); - // WorldGen.TileRunner(x, y, (double)hiveSize, 1, TileID.Hive, false, 0f, 0f, true, true); - - // // Carve out the interior - // WorldGen.TileRunner(x, y, (double)(hiveSize - 10), 1, -1, false, 0f, 0f, true, true); - - // // Add some honey - // if (WorldGen.genRand.NextBool(3)) - // { - // WorldGen.TileRunner(x, y, (double)WorldGen.genRand.Next(5, 15), 1, TileID.HoneyBlock, false, 0f, 0f, true, true); - // } - - // placed = true; - // } - // attempts++; - // } - // } - // } - - // // Add extra sky islands with houses - // progress.Set(0.8); - // int extraIslands = WorldGen.genRand.Next(2, 4); - // for (int i = 0; i < extraIslands; i++) - // { - // int attempts = 0; - // bool placed = false; - // while (!placed && attempts < 1000) - // { - // int x = WorldGen.genRand.Next((int)(Main.maxTilesX * 0.1), (int)(Main.maxTilesX * 0.9)); - // int y = WorldGen.genRand.Next(90, (int)Main.worldSurface - 150); - - // if (x > Main.maxTilesX / 2 - 150 && x < Main.maxTilesX / 2 + 150) - // { - // attempts++; - // continue; - // } - - // if (WorldGen.InWorld(x, y)) - // { - // WorldGen.CloudIsland(x, y); - - // int islandStyle = 0; - // if (WorldGen.remixWorldGen && WorldGen.drunkWorldGen) - // { - // bool flag = (GenVars.crimsonLeft && x < Main.maxTilesX / 2) || (!GenVars.crimsonLeft && x > Main.maxTilesX / 2); - // islandStyle = flag ? 5 : 4; - // } - // else if (WorldGen.getGoodWorldGen || WorldGen.remixWorldGen) - // { - // islandStyle = WorldGen.crimson ? 5 : 4; - // } - // else if (Main.tenthAnniversaryWorld) - // { - // islandStyle = 6; - // } - - // WorldGen.IslandHouse(x, y, islandStyle); - // placed = true; - // } - // attempts++; - // } - // } - - // // Add extra mine houses with buried chests - // progress.Set(0.9); - // int extraHouses = WorldGen.genRand.Next(40, 80); - // for (int i = 0; i < extraHouses; i++) - // { - // int attempts = 0; - // bool placed = false; - // while (!placed && attempts < 1000) - // { - // int x = WorldGen.genRand.Next(100, Main.maxTilesX - 100); - // int y = WorldGen.genRand.Next((int)Main.worldSurface + 100, (int)Main.rockLayer + 200); - - // if (WorldGen.InWorld(x, y) && !Main.tile[x, y].HasTile && Main.tile[x, y].WallType == 0) - // { - // // Generate the mine house - // WorldGen.MineHouse(x, y); - - // // Now try to place a buried chest inside the mine house - // bool chestPlaced = false; - // int chestAttempts = 0; - - // // Search for a suitable spot inside the mine house area for the chest - // while (!chestPlaced && chestAttempts < 100) - // { - // // Look within a 15 tile radius of the original placement point - // int chestX = x + WorldGen.genRand.Next(-10, 11); - // int chestY = y + WorldGen.genRand.Next(-5, 6); - - // if (WorldGen.InWorld(chestX, chestY)) - // { - // // Check if this position is inside the mine house structure - // // Mine houses typically have wooden walls (wall ID 27) and wood/stone tiles - // if (Main.tile[chestX, chestY].WallType == 27 || - // (Main.tile[chestX, chestY].HasTile && - // (Main.tile[chestX, chestY].TileType == TileID.WoodBlock || - // Main.tile[chestX, chestY].TileType == TileID.Stone))) - // { - // // Try to place a buried chest with random style - // int chestStyle = WorldGen.genRand.Next(1, 11); // Regular underground chest styles - // if (WorldGen.AddBuriedChest(chestX, chestY, 0, false, 1)) - // { - // chestPlaced = true; - // ModContent.GetInstance().Logger.Info($"Placed buried chest at {chestX}, {chestY} in mine house"); - // } - // } - // } - // chestAttempts++; - // } - - // placed = true; - // } - // attempts++; - // } - // } - - // // Add extra life crystals and underground chests - // progress.Set(0.95); - // int extraLifeCrystals = Main.maxTilesX / 15; - // for (int i = 0; i < extraLifeCrystals; i++) - // { - // int attempts = 0; - // bool placed = false; - // while (!placed && attempts < 1000) - // { - // int x = WorldGen.genRand.Next(Main.offLimitBorderTiles, Main.maxTilesX - Main.offLimitBorderTiles); - // int y = WorldGen.genRand.Next((int)(Main.worldSurface * 2.0 + Main.rockLayer) / 3, Main.maxTilesY - 300); - // if (WorldGen.AddLifeCrystal(x, y)) - // { - // placed = true; - // } - // attempts++; - // } - // } - - // int extraChests = Main.maxTilesX / 30; - // for (int i = 0; i < extraChests; i++) - // { - // int attempts = 0; - // bool placed = false; - // while (!placed && attempts < 1000) - // { - // int x = WorldGen.genRand.Next(Main.offLimitBorderTiles, Main.maxTilesX - Main.offLimitBorderTiles); - // int y = WorldGen.genRand.Next((int)Main.worldSurface + 50, Main.maxTilesY - 350); - // if (WorldGen.AddBuriedChest(x, y, 0, false, 1)) - // { - // placed = true; - // } - // attempts++; - // } - // } - - // progress.Set(1.0); - - // })); - - // ModContent.GetInstance().Logger.Info("Added extra worldgen pass for multiple structures"); - // } - //} -} \ No newline at end of file + public class ExtraWorldGen : ModSystem + { + public override void ModifyWorldGenTasks(List tasks, ref double totalWeight) + { + AddExtraPyramids(tasks); + AddExtraMahoganyTrees(tasks); + AddExtraMinecartTracks(tasks); + AddExtraHives(tasks); + AddExtraSkyIslands(tasks); + AddExtraCaveHouses(tasks); + AddExtraTreasures(tasks); + + // New biome additions + AddExtraDeadMansChests(tasks); + AddExtraCorruptionPits(tasks); + AddExtraGraniteBiomes(tasks); + AddExtraMarbleBiomes(tasks); + + // New features + AddExtraLivingTrees(tasks); + + ModContent.GetInstance().Logger.Info("Added extra worldgen passes for multiple structures"); + } + + private void AddExtraPyramids(List tasks) + { + int pyramidsIndex = tasks.FindIndex(genpass => genpass.Name.Equals("Pyramids")); + if (pyramidsIndex == -1) return; + + tasks.Insert(pyramidsIndex + 1, new PassLegacy("Extra Pyramids", delegate (GenerationProgress progress, GameConfiguration passConfig) + { + progress.Message = "Adding extra pyramids..."; + int extraPyramids = WorldGen.genRand.Next(1, 2); + + for (int i = 0; i < extraPyramids; i++) + { + int attempts = 0; + bool placed = false; + + while (!placed && attempts < 1000) + { + int x = WorldGen.genRand.Next(300, Main.maxTilesX - 300); + int y = (int)Main.worldSurface - 10; + + if (WorldGen.InWorld(x, y) && Main.tile[x, y].TileType == TileID.Sand) + { + placed = WorldGen.Pyramid(x, y); + } + attempts++; + } + } + })); + } + // NOT CURRENTLY WORKING + private void AddExtraMahoganyTrees(List tasks) + { + int jungleTreesIndex = tasks.FindIndex(genpass => genpass.Name.Equals("Jungle Trees")); + if (jungleTreesIndex == -1) return; + + tasks.Insert(jungleTreesIndex + 1, new PassLegacy("Extra Rich Mahogany Trees", delegate (GenerationProgress progress, GameConfiguration passConfig) + { + progress.Message = "Planting extra mahogany trees..."; + try + { + var mahoganyTreeBiome = new MahoganyTreeBiome(); + int extraTrees = WorldGen.genRand.Next(40, 80); + int treesPlaced = 0; + int attempts = 0; + + while (treesPlaced < extraTrees && attempts < 10000) + { + int x = WorldGen.genRand.Next(200, Main.maxTilesX - 200); + int y = WorldGen.genRand.Next((int)Main.worldSurface + 100, (int)Main.rockLayer + 100); + Point point = new Point(x, y); + + if (IsJungleArea(point.X, point.Y)) + { + if (mahoganyTreeBiome.Place(point, GenVars.structures)) + { + treesPlaced++; + attempts = 0; // Reset attempts counter on success + } + } + attempts++; + } + ModContent.GetInstance().Logger.Info($"Placed {treesPlaced} extra mahogany trees"); + } + catch (Exception ex) + { + ModContent.GetInstance().Logger.Info($"Mahogany tree generation failed: {ex.Message}"); + } + })); + } + + private bool IsJungleArea(int x, int y) + { + // Check a small area around the point for jungle tiles + int jungleTiles = 0; + int totalTiles = 0; + + for (int checkX = x - 10; checkX <= x + 10; checkX += 2) + { + for (int checkY = y - 10; checkY <= y + 10; checkY += 2) + { + if (WorldGen.InWorld(checkX, checkY)) + { + Tile tile = Framing.GetTileSafely(checkX, checkY); + if (tile.HasTile && (tile.TileType == TileID.JungleGrass || tile.TileType == TileID.Mud)) + { + jungleTiles++; + } + totalTiles++; + } + } + } + + return totalTiles > 0 && (jungleTiles * 100 / totalTiles) >= 25; + } + + //NOT CURRENTLY WORKING + private void AddExtraLivingTrees(List tasks) + { + int livingTreesIndex = tasks.FindIndex(genpass => genpass.Name.Equals("Living Trees")); + if (livingTreesIndex == -1) return; + + tasks.Insert(livingTreesIndex + 1, new PassLegacy("Extra Surface Living Trees", delegate (GenerationProgress progress, GameConfiguration passConfig) + { + progress.Message = "Growing extra living trees..."; + int extraTrees = WorldGen.genRand.Next(300, 600); + int treesPlaced = 0; + int attempts = 0; + + while (treesPlaced < extraTrees && attempts < 1000) + { + int x = WorldGen.genRand.Next(200, Main.maxTilesX - 200); + int y = WorldGen.genRand.Next((int)Main.worldSurface - 20, (int)Main.worldSurface + 10); + + if (WorldGen.InWorld(x, y) && IsValidLivingTreeLocation(x, y)) + { + if (WorldGen.GrowTree(x, y) || WorldGen.GrowTree(x - 1, y) || WorldGen.GrowTree(x + 1, y)) + { + treesPlaced++; + attempts = 0; + } + } + attempts++; + } + ModContent.GetInstance().Logger.Info($"Placed {treesPlaced} extra living trees"); + })); + } + + private bool IsValidLivingTreeLocation(int x, int y) + { + if (!WorldGen.InWorld(x, y) || !Main.tile[x, y].HasTile) + return false; + + Tile tile = Framing.GetTileSafely(x, y); + if (tile.TileType != TileID.Grass && tile.TileType != TileID.HallowedGrass) + return false; + + for (int checkY = y - 10; checkY >= y - 30; checkY--) + { + if (WorldGen.InWorld(x, checkY) && Main.tile[x, checkY].HasTile) + return false; + } + + return true; + } + //WORKING + private void AddExtraCaveHouses(List tasks) + { + int buriedChestsIndex = tasks.FindIndex(genpass => genpass.Name.Equals("Buried Chests")); + if (buriedChestsIndex == -1) return; + + tasks[buriedChestsIndex] = new PassLegacy("Buried Chests", delegate (GenerationProgress progress, GameConfiguration passConfig) + { + progress.Message = Lang.gen[30].Value; + Main.tileSolid[226] = true; + Main.tileSolid[162] = true; + Main.tileSolid[225] = true; + CaveHouseBiome caveHouseBiome = GenVars.configuration.CreateBiome(); + + int random = passConfig.Get("CaveHouseCount").GetRandom(WorldGen.genRand) * 5; + int random2 = passConfig.Get("UnderworldChestCount").GetRandom(WorldGen.genRand) * 1; + int num = passConfig.Get("CaveChestCount").GetRandom(WorldGen.genRand) * 4; + int random3 = passConfig.Get("AdditionalDesertHouseCount").GetRandom(WorldGen.genRand) * 3; + + if (Main.starGame) + { + num = (int)((double)num * Main.starGameMath(0.2)); + } + int num2 = random + random2 + num + random3; + int num3 = 10000; + int num4 = 0; + while (num4 < num && num3 > 0) + { + progress.Set((double)num4 / (double)num2); + int num5 = WorldGen.genRand.Next(20, Main.maxTilesX - 20); + int num6 = WorldGen.genRand.Next((int)((GenVars.worldSurfaceHigh + 20.0 + Main.rockLayer) / 2.0), Main.maxTilesY - 230); + if (WorldGen.remixWorldGen) + { + num6 = WorldGen.genRand.Next((int)Main.worldSurface, Main.maxTilesY - 400); + } + ushort wall = Framing.GetTileSafely(num5, num6).WallType; + if (Main.wallDungeon[wall] || wall == 87 || WorldGen.oceanDepths(num5, num6) || !WorldGen.AddBuriedChest(num5, num6, 0, false, -1, false, 0)) + { + num3--; + num4--; + } + num4++; + } + num3 = 10000; + int num7 = 0; + while (num7 < random2 && num3 > 0) + { + progress.Set((double)(num7 + num) / (double)num2); + int num8 = WorldGen.genRand.Next(20, Main.maxTilesX - 20); + int num9 = WorldGen.genRand.Next(Main.UnderworldLayer, Main.maxTilesY - 50); + if (Main.wallDungeon[Framing.GetTileSafely(num8, num9).WallType] || !WorldGen.AddBuriedChest(num8, num9, 0, false, -1, false, 0)) + { + num3--; + num7--; + } + num7++; + } + num3 = 10000; + int num10 = 0; + while (num10 < random && num3 > 0) + { + progress.Set((double)(num10 + num + random2) / (double)num2); + int x = WorldGen.genRand.Next(80, Main.maxTilesX - 80); + int y = WorldGen.genRand.Next((int)(GenVars.worldSurfaceHigh + 20.0), Main.maxTilesY - 230); + if (WorldGen.remixWorldGen) + { + y = WorldGen.genRand.Next((int)Main.worldSurface, Main.maxTilesY - 400); + } + if (WorldGen.oceanDepths(x, y) || !caveHouseBiome.Place(new Point(x, y), GenVars.structures)) + { + num3--; + num10--; + } + num10++; + } + num3 = 10000; + Rectangle undergroundDesertHiveLocation = GenVars.UndergroundDesertHiveLocation; + if ((double)undergroundDesertHiveLocation.Y < Main.worldSurface + 26.0) + { + int num11 = (int)Main.worldSurface + 26 - undergroundDesertHiveLocation.Y; + undergroundDesertHiveLocation.Y += num11; + undergroundDesertHiveLocation.Height -= num11; + } + int num12 = 0; + while (num12 < random3 && num3 > 0) + { + progress.Set((double)(num12 + num + random2 + random) / (double)num2); + if (!caveHouseBiome.Place(WorldGen.RandomRectanglePoint(undergroundDesertHiveLocation), GenVars.structures)) + { + num3--; + num12--; + } + num12++; + } + Main.tileSolid[226] = false; + Main.tileSolid[162] = false; + Main.tileSolid[225] = false; + + ModContent.GetInstance().Logger.Info($"Placed cave houses: {num10} regular, {num12} desert, {num4} cave chests, {num7} underworld chests"); + }); + } + + private void AddExtraMinecartTracks(List tasks) + { + int trapsIndex = tasks.FindIndex(genpass => genpass.Name.Equals("Traps")); + if (trapsIndex == -1) return; + + tasks.Insert(trapsIndex + 1, new PassLegacy("Extra Minecart Tracks", delegate (GenerationProgress progress, GameConfiguration passConfig) + { + progress.Message = "Laying extra minecart tracks..."; + + try + { + var trackGenerator = new TrackGenerator(); + GenerateTracks(trackGenerator, 15, 20, 300, 2000); + GenerateTracks(trackGenerator, 15, 22, 100, 300); + } + catch + { + ModContent.GetInstance().Logger.Info("TrackGenerator not available, using alternative minecart track generation"); + GenerateAlternativeTracks(); + } + })); + } + // WORKING + private void GenerateTracks(TrackGenerator trackGenerator, int minCount, int maxCount, int minLength, int maxLength) + { + int trackCount = WorldGen.genRand.Next(minCount, maxCount); + int placed = 0; + int attempts = 0; + + while (placed < trackCount && attempts < Main.maxTilesX) + { + Point point = WorldGen.RandomWorldPoint((int)Main.worldSurface, 10, 200, 10); + if (trackGenerator.Place(point, minLength, maxLength)) + { + placed++; + attempts = 0; + } + else + { + attempts++; + } + } + } + + private void GenerateAlternativeTracks() + { + int extraTracks = WorldGen.genRand.Next(10, 18); + for (int i = 0; i < extraTracks; i++) + { + int attempts = 0; + bool placed = false; + + while (!placed && attempts < 500) + { + int x = WorldGen.genRand.Next(200, Main.maxTilesX - 200); + int y = WorldGen.genRand.Next((int)Main.worldSurface + 50, (int)Main.rockLayer + 100); + + if (WorldGen.InWorld(x, y)) + { + WorldGen.TileRunner(x, y, WorldGen.genRand.Next(8, 15), WorldGen.genRand.Next(50, 100), -1, false, 0f, 0f, true, true); + + for (int trackX = x - 5; trackX <= x + 5; trackX++) + { + if (WorldGen.InWorld(trackX, y) && !Main.tile[trackX, y].HasTile) + { + WorldGen.PlaceTile(trackX, y, TileID.MinecartTrack, true, false); + } + } + placed = true; + } + attempts++; + } + } + } + //WORKING + private void AddExtraHives(List tasks) + { + int hivesIndex = tasks.FindIndex(genpass => genpass.Name.Equals("Hives")); + if (hivesIndex == -1) hivesIndex = tasks.FindIndex(genpass => genpass.Name.Equals("Life Crystals")); + if (hivesIndex == -1) return; + + tasks.Insert(hivesIndex + 1, new PassLegacy("Extra Hives", delegate (GenerationProgress progress, GameConfiguration passConfig) + { + progress.Message = "Building extra hives..."; + + try + { + var hiveBiome = GenVars.configuration.CreateBiome(); + var honeyPatchBiome = GenVars.configuration.CreateBiome(); + double hiveNum = (double)Main.maxTilesX / 4200.0; + int extraHives = WorldGen.genRand.Next((int)(7.0 * hiveNum), (int)(11.0 * hiveNum)); + + for (int i = 0; i < extraHives; i++) + { + int attempts = 0; + bool placed = false; + + while (!placed && attempts < 1000) + { + Point point = WorldGen.RandomWorldPoint((int)(Main.worldSurface + Main.rockLayer) >> 1, 20, 300, 20); + + if (hiveBiome.Place(point, GenVars.structures)) + { + placed = true; + AddHoneyPatches(honeyPatchBiome, point); + } + attempts++; + } + } + } + catch + { + ModContent.GetInstance().Logger.Info("HiveBiome not available, using alternative hive generation"); + GenerateAlternativeHives(); + } + })); + } + + private void AddHoneyPatches(HoneyPatchBiome honeyPatchBiome, Point point) + { + int honeyPatches = WorldGen.genRand.Next(3); + int honeyPlaced = 0; + int honeyAttempts = 0; + + while (honeyPlaced < honeyPatches && honeyAttempts < 100) + { + double distance = WorldGen.genRand.NextDouble() * 60.0 + 30.0; + double angle = WorldGen.genRand.NextDouble() * 6.2831854820251465; + int honeyX = (int)(Math.Cos(angle) * distance) + point.X; + int honeyY = (int)(Math.Sin(angle) * distance) + point.Y; + honeyAttempts++; + + if (honeyPatchBiome.Place(new Point(honeyX, honeyY), GenVars.structures)) + { + honeyPlaced++; + } + } + } + + private void GenerateAlternativeHives() + { + int extraHives = WorldGen.genRand.Next(4, 8); + for (int i = 0; i < extraHives; i++) + { + int attempts = 0; + bool placed = false; + + while (!placed && attempts < 500) + { + int x = WorldGen.genRand.Next(200, Main.maxTilesX - 200); + int y = WorldGen.genRand.Next((int)((Main.worldSurface + Main.rockLayer) / 2), (int)Main.rockLayer + 200); + + if (IsJungleTile(Main.tile[x, y])) + { + int hiveSize = WorldGen.genRand.Next(30, 60); + WorldGen.TileRunner(x, y, hiveSize, 1, TileID.Hive, false, 0f, 0f, true, true); + WorldGen.TileRunner(x, y, hiveSize - 10, 1, -1, false, 0f, 0f, true, true); + + if (WorldGen.genRand.NextBool(3)) + { + WorldGen.TileRunner(x, y, WorldGen.genRand.Next(5, 15), 1, TileID.HoneyBlock, false, 0f, 0f, true, true); + } + placed = true; + } + attempts++; + } + } + } + //WORKING + private void AddExtraSkyIslands(List tasks) + { + int floatingIslandHousesIndex = tasks.FindIndex(genpass => genpass.Name.Equals("Floating Island Houses")); + if (floatingIslandHousesIndex == -1) return; + + tasks.Insert(floatingIslandHousesIndex + 1, new PassLegacy("Extra Sky Islands", delegate (GenerationProgress progress, GameConfiguration passConfig) + { + progress.Message = "Creating extra sky islands..."; + int extraIslands = WorldGen.genRand.Next(2, 4); + + for (int i = 0; i < extraIslands; i++) + { + int attempts = 0; + bool placed = false; + + while (!placed && attempts < 1000) + { + int x = WorldGen.genRand.Next((int)(Main.maxTilesX * 0.1), (int)(Main.maxTilesX * 0.9)); + int y = WorldGen.genRand.Next(90, (int)Main.worldSurface - 150); + + if (IsValidIslandLocation(x) && WorldGen.InWorld(x, y)) + { + CreateSkyIsland(x, y); + placed = true; + } + attempts++; + } + } + })); + } + + private bool IsValidIslandLocation(int x) + { + return !(x > Main.maxTilesX / 2 - 150 && x < Main.maxTilesX / 2 + 150); + } + + private void CreateSkyIsland(int x, int y) + { + WorldGen.CloudIsland(x, y); + + int islandStyle = GetIslandStyle(x); + WorldGen.IslandHouse(x, y, islandStyle); + PlantIslandGrass(x, y); + } + + private int GetIslandStyle(int x) + { + if (WorldGen.remixWorldGen && WorldGen.drunkWorldGen) + { + bool flag = (GenVars.crimsonLeft && x < Main.maxTilesX / 2) || (!GenVars.crimsonLeft && x > Main.maxTilesX / 2); + return flag ? 5 : 4; + } + else if (WorldGen.getGoodWorldGen || WorldGen.remixWorldGen) + { + return WorldGen.crimson ? 5 : 4; + } + else if (Main.tenthAnniversaryWorld) + { + return 6; + } + return 0; + } + + private void PlantIslandGrass(int x, int y) + { + for (int grassX = x - 50; grassX < x + 50; grassX++) + { + for (int grassY = y - 20; grassY < y + 50; grassY++) + { + if (WorldGen.InWorld(grassX, grassY)) + { + Tile tile = Main.tile[grassX, grassY]; + if (tile.HasTile && tile.TileType == TileID.Dirt) + { + WorldGen.PlaceTile(grassX, grassY, TileID.Grass, true, true); + } + } + } + } + } + + private void AddExtraTreasures(List tasks) + { + int finalCleanupIndex = tasks.FindIndex(genpass => genpass.Name.Equals("Final Cleanup")); + if (finalCleanupIndex == -1) return; + + tasks.Insert(finalCleanupIndex, new PassLegacy("Extra Life Crystals and Chests", delegate (GenerationProgress progress, GameConfiguration passConfig) + { + progress.Message = "Hiding extra treasures..."; + GenerateExtraLifeCrystals(); + })); + } + + private void GenerateExtraLifeCrystals() + { + int extraLifeCrystals = Main.maxTilesX / 20; + for (int i = 0; i < extraLifeCrystals; i++) + { + int attempts = 0; + bool placed = false; + + while (!placed && attempts < 1000) + { + int x = WorldGen.genRand.Next(Main.offLimitBorderTiles, Main.maxTilesX - Main.offLimitBorderTiles); + int y = WorldGen.genRand.Next((int)(Main.worldSurface * 2.0 + Main.rockLayer) / 3, Main.maxTilesY - 300); + + if (WorldGen.AddLifeCrystal(x, y)) placed = true; + attempts++; + } + } + } + //NOT WORKING (needs to be tested) + private void AddExtraDeadMansChests(List tasks) + { + int deadMansChestIndex = tasks.FindIndex(genpass => genpass.Name.Equals("Dead Mans Chest")); + if (deadMansChestIndex == -1) return; + + tasks.Insert(deadMansChestIndex + 1, new PassLegacy("Extra Dead Mans Chests", delegate (GenerationProgress progress, GameConfiguration passConfig) + { + progress.Message = "Placing extra dead mans chests..."; + + int extraChests = WorldGen.genRand.Next(50, 150); + int chestsPlaced = 0; + int attempts = 0; + + while (chestsPlaced < extraChests && attempts < 5000) + { + int x = WorldGen.genRand.Next(200, Main.maxTilesX - 200); + int y = WorldGen.genRand.Next((int)Main.worldSurface + 50, (int)Main.rockLayer + 200); + + if (WorldGen.InWorld(x, y) && IsValidSurfaceLocation(x, y)) + { + // Use vanilla dead man's chest placement + if (WorldGen.AddBuriedChest(x, y, 0, false, 2)) + { + chestsPlaced++; + } + } + attempts++; + } + + ModContent.GetInstance().Logger.Info($"Placed {chestsPlaced} extra dead mans chests"); + })); + } + //NOT WORKING + private void AddExtraCorruptionPits(List tasks) + { + int corruptionPitsIndex = tasks.FindIndex(genpass => genpass.Name.Equals("Corruption Pits")); + if (corruptionPitsIndex == -1) return; + + tasks.Insert(corruptionPitsIndex + 1, new PassLegacy("Extra Corruption Pits", delegate (GenerationProgress progress, GameConfiguration passConfig) + { + progress.Message = "Digging extra corruption pits..."; + + try + { + // Use the built-in CorruptionPitBiome system + var corruptionPitBiome = GenVars.configuration.CreateBiome(); + int extraPits = WorldGen.genRand.Next(50, 150); + int pitsPlaced = 0; + int attempts = 0; + + while (pitsPlaced < extraPits && attempts < 10000) + { + Point point = WorldGen.RandomWorldPoint((int)Main.worldSurface, 10, 200, 10); + + if (corruptionPitBiome.Place(point, GenVars.structures)) + { + pitsPlaced++; + } + attempts++; + } + + ModContent.GetInstance().Logger.Info($"Placed {pitsPlaced} extra corruption pits"); + } + catch (Exception ex) + { + ModContent.GetInstance().Logger.Info($"Corruption pit generation failed: {ex.Message}"); + } + })); + } + //WORKING + private void AddExtraGraniteBiomes(List tasks) + { + int graniteIndex = tasks.FindIndex(genpass => genpass.Name.Equals("Granite")); + if (graniteIndex == -1) return; + + tasks.Insert(graniteIndex + 1, new PassLegacy("Extra Granite Biomes", delegate (GenerationProgress progress, GameConfiguration passConfig) + { + progress.Message = "Forming extra granite biomes..."; + + try + { + var graniteBiome = GenVars.configuration.CreateBiome(); + int extraBiomes = WorldGen.genRand.Next(3, 7); + int biomesPlaced = 0; + int attempts = 0; + + while (biomesPlaced < extraBiomes && attempts < 10000) + { + Point point = WorldGen.RandomWorldPoint((int)Main.rockLayer, 50, 200, 50); + + if (graniteBiome.Place(point, GenVars.structures)) + { + biomesPlaced++; + } + attempts++; + } + + ModContent.GetInstance().Logger.Info($"Placed {biomesPlaced} extra granite biomes"); + } + catch + { + ModContent.GetInstance().Logger.Info("GraniteBiome not available, skipping extra granite biomes"); + } + })); + } + //WORKING + + private void AddExtraMarbleBiomes(List tasks) + { + int marbleIndex = tasks.FindIndex(genpass => genpass.Name.Equals("Marble")); + if (marbleIndex == -1) return; + + tasks.Insert(marbleIndex + 1, new PassLegacy("Extra Marble Biomes", delegate (GenerationProgress progress, GameConfiguration passConfig) + { + progress.Message = "Sculpting extra marble biomes..."; + + try + { + var marbleBiome = GenVars.configuration.CreateBiome(); + int extraBiomes = WorldGen.genRand.Next(3, 7); + int biomesPlaced = 0; + int attempts = 0; + + while (biomesPlaced < extraBiomes && attempts < 10000) + { + Point point = WorldGen.RandomWorldPoint((int)Main.rockLayer, 50, 200, 50); + + if (marbleBiome.Place(point, GenVars.structures)) + { + biomesPlaced++; + } + attempts++; + } + + ModContent.GetInstance().Logger.Info($"Placed {biomesPlaced} extra marble biomes"); + } + catch + { + ModContent.GetInstance().Logger.Info("MarbleBiome not available, skipping extra marble biomes"); + } + })); + } + // Helper Methods + private bool IsJungleBiome(Point point) + { + for (int checkX = point.X - 5; checkX <= point.X + 5; checkX++) + { + for (int checkY = point.Y - 5; checkY <= point.Y + 5; checkY++) + { + if (WorldGen.InWorld(checkX, checkY)) + { + Tile tile = Main.tile[checkX, checkY]; + if (tile.TileType == TileID.JungleGrass || tile.TileType == TileID.Mud) + { + return true; + } + } + } + } + return false; + } + + private bool IsJungleTile(Tile tile) + { + return tile.TileType == TileID.Mud || tile.TileType == TileID.JungleGrass; + } + + private bool IsCorruptionTile(Tile tile) + { + return tile.TileType == TileID.Ebonstone || tile.TileType == TileID.CorruptGrass; + } + + private bool IsValidSurfaceLocation(int x, int y) + { + // Check if location is on surface with grass + return Main.tile[x, y].TileType == TileID.Grass || Main.tile[x, y].TileType == TileID.Dirt; + } + + private bool IsValidUndergroundLocation(int x, int y) + { + // Check if location is in underground with stone or dirt + return Main.tile[x, y].TileType == TileID.Stone || Main.tile[x, y].TileType == TileID.Dirt; + } + } +} +//WORKING + public class JungleShrineModifier : ModSystem + { + public override void ModifyWorldGenTasks(List tasks, ref double totalWeight) + { + // Find the Jungle Chests pass + int jungleChestsIndex = tasks.FindIndex(genpass => genpass.Name.Equals("Jungle Chests")); + if (jungleChestsIndex == -1) return; + + // Replace it with our modified version + tasks[jungleChestsIndex] = new PassLegacy("Jungle Chests", delegate (GenerationProgress progress, GameConfiguration passConfig) + { + // This is the EXACT vanilla code with ONE LINE changed + int num = WorldGen.genRand.Next(40, Main.maxTilesX - 40); + int num2 = WorldGen.genRand.Next((int)(Main.worldSurface + Main.rockLayer) / 2, Main.maxTilesY - 400); + + // ONLY CHANGE THIS LINE: Increased from (7, 12) to (70, 120) + double num3 = (double)WorldGen.genRand.Next(10, 20); + num3 *= (double)Main.maxTilesX / 4200.0; + + int num4 = 0; + int num5 = 0; + while ((double)num5 < num3) + { + bool flag = true; + while (flag) + { + num4++; + num = WorldGen.genRand.Next(40, Main.maxTilesX / 2 - 40); + if (GenVars.dungeonSide < 0) + { + num += Main.maxTilesX / 2; + } + num2 = WorldGen.genRand.Next((int)(Main.worldSurface + Main.rockLayer) / 2, Main.maxTilesY - 400); + int i = WorldGen.genRand.Next(2, 4); + int num6 = WorldGen.genRand.Next(2, 4); + Rectangle area = new Rectangle(num - i - 1, num2 - num6 - 1, i + 1, num6 + 1); + + // Use Framing.GetTileSafely for reading + Tile tile = Framing.GetTileSafely(num, num2); + if (tile.HasTile && tile.TileType == 60) + { + int num7 = 30; + flag = false; + for (int j = num - num7; j < num + num7; j += 3) + { + for (int k = num2 - num7; k < num2 + num7; k += 3) + { + Tile checkTile = Framing.GetTileSafely(j, k); + if (checkTile.HasTile && (checkTile.TileType == 225 || checkTile.TileType == 229 || checkTile.TileType == 226 || checkTile.TileType == 119 || checkTile.TileType == 120)) + { + flag = true; + } + if (checkTile.WallType == 86 || checkTile.WallType == 87) + { + flag = true; + } + } + } + if (!GenVars.structures.CanPlace(area, 1)) + { + flag = true; + } + } + if (!flag) + { + ushort wall = 0; + if (GenVars.jungleHut == 119) + { + wall = 23; + } + else if (GenVars.jungleHut == 120) + { + wall = 24; + } + else if (GenVars.jungleHut == 158) + { + wall = 42; + } + else if (GenVars.jungleHut == 175) + { + wall = 45; + } + else if (GenVars.jungleHut == 45) + { + wall = 10; + } + + // FIRST: Clear the entire area and remove liquids + for (int l = num - i - 1; l <= num + i + 1; l++) + { + for (int m = num2 - num6 - 1; m <= num2 + num6 + 1; m++) + { + WorldGen.KillTile(l, m, noItem: true); // Clear everything first + WorldGen.KillWall(l, m); // Clear walls + // Remove liquids + WorldGen.PlaceLiquid(l, m, (byte)LiquidID.Water, 0); + } + } + + // SECOND: Build shrine outer walls + for (int l = num - i - 1; l <= num + i + 1; l++) + { + for (int m = num2 - num6 - 1; m <= num2 + num6 + 1; m++) + { + WorldGen.PlaceTile(l, m, GenVars.jungleHut, true, true); + } + } + + // THIRD: Hollow out interior and set interior walls + for (int n = num - i; n <= num + i; n++) + { + for (int num8 = num2 - num6; num8 <= num2 + num6; num8++) + { + WorldGen.KillTile(n, num8, noItem: true); + WorldGen.PlaceWall(n, num8, wall, true); + } + } + + bool flag2 = false; + int num9 = 0; + while (!flag2 && num9 < 100) + { + num9++; + int num10 = WorldGen.genRand.Next(num - i, num + i + 1); + int num11 = WorldGen.genRand.Next(num2 - num6, num2 + num6 - 2); + WorldGen.PlaceTile(num10, num11, 4, true, false, -1, 3); + if (Framing.GetTileSafely(num10, num11).TileType == 4) + { + flag2 = true; + } + } + + // FOURTH: Create entrance - clear the bottom but KEEP the interior walls + for (int num12 = num - i - 1; num12 <= num + i + 1; num12++) + { + for (int num13 = num2 + num6 - 2; num13 <= num2 + num6; num13++) + { + WorldGen.KillTile(num12, num13, noItem: true); + // Don't kill the walls here - we want to keep the interior walls + } + } + + // Make sure the entrance area has proper walls + for (int num12 = num - i; num12 <= num + i; num12++) + { + for (int num13 = num2 + num6 - 2; num13 <= num2 + num6 - 1; num13++) + { + WorldGen.PlaceWall(num12, num13, wall, true); + } + } + + // FIFTH: Add supporting pillars + for (int num16 = num - i - 1; num16 <= num + i + 1; num16++) + { + int num17 = 4; + int num18 = num2 + num6 + 2; + while (num18 < Main.maxTilesY && num17 > 0) + { + // Clear then place support + WorldGen.KillTile(num16, num18, noItem: true); + WorldGen.PlaceTile(num16, num18, 59, true, true); + num18++; + num17--; + } + } + + // SIXTH: Create pyramid roof + int currentWidth = i - WorldGen.genRand.Next(1, 3); + int roofY = num2 - num6 - 2; + while (currentWidth > -1) + { + for (int num20 = num - currentWidth - 1; num20 <= num + currentWidth + 1; num20++) + { + WorldGen.KillTile(num20, roofY, noItem: true); // Clear first + WorldGen.PlaceTile(num20, roofY, GenVars.jungleHut, true, true); + } + currentWidth -= WorldGen.genRand.Next(1, 3); + roofY--; + } + + GenVars.JChestX[GenVars.numJChests] = num; + GenVars.JChestY[GenVars.numJChests] = num2; + GenVars.structures.AddProtectedStructure(area, 0); + GenVars.numJChests++; + num4 = 0; + } + else if (num4 > Main.maxTilesX * 10) + { + num5++; + num4 = 0; + break; + } + } + num5++; + } + Main.tileSolid[137] = false; + }); + } + } \ No newline at end of file diff --git a/Localization/en-US.hjson b/Localization/en-US.hjson index 4fee0157..b9e4df87 100644 --- a/Localization/en-US.hjson +++ b/Localization/en-US.hjson @@ -145,6 +145,8 @@ Mods: { Label: Adventure Mirror Recall Frames Tooltip: "" } + + Headers.AdventureMirror: Adventure Mirror Header } PointsConfig: { @@ -409,6 +411,23 @@ Mods: { Off: Disables double tap dash. Use keybind instead ''' } + + Headers.AdventureMirror: Adventure Mirror Header + + OpenMapAfterRecall: { + Label: Open Map After Recall + Tooltip: "" + } + + ShowPopupText: { + Label: Show Popup Text + Tooltip: "" + } + + ShowPlayerIndicationWhenWhenHovering: { + Label: Show Player Indication When When Hovering + Tooltip: "" + } } PlayerOutlineConfig: { @@ -941,14 +960,23 @@ Mods: { } Items: { + AdventureMirror: { + DisplayName: Adventure Mirror + Tooltip: + ''' + Gaze in the mirror to go on adventures + Right click to use + ''' + } + AdventureBag: { DisplayName: Adventure Bag - Tooltip: Everything you need to start your PvP Adventure! + Tooltip: "" } BlightFruit: { - Tooltip: "" DisplayName: Blight Fruit + Tooltip: "" } } @@ -1076,15 +1104,5 @@ Mods: { FatalCarCrash.Label: Fatal Car Crash Part2.Label: Part2 } - Items: { - AdventureMirror: { - DisplayName: Adventure Mirror - Tooltip: - ''' - Gaze in the mirror to go on adventures - Right click to use - ''' - } - } } } diff --git a/LockedLihzahrdChest.cs b/LockedLihzahrdChest.cs index e5b4d613..ab269036 100644 --- a/LockedLihzahrdChest.cs +++ b/LockedLihzahrdChest.cs @@ -9,6 +9,10 @@ using MonoMod.Cil; using Terraria.DataStructures; using Terraria.GameContent.ObjectInteractions; +using Terraria.WorldBuilding; +using Terraria.IO; +using System.Collections.Generic; +using Terraria.GameContent.Generation; namespace PvPAdventure; @@ -19,6 +23,157 @@ public class LockedLihzahrdChest : ModTile public override void Load() { IL_Player.TileInteractionsUse += EditPlayerTileInteractionsUse; + On_WorldGen.templePart2 += AddExtraChestsDuringTempleGen; + } + + public override void Unload() + { + IL_Player.TileInteractionsUse -= EditPlayerTileInteractionsUse; + On_WorldGen.templePart2 -= AddExtraChestsDuringTempleGen; + } + + private void AddExtraChestsDuringTempleGen(On_WorldGen.orig_templePart2 orig) + { + // First run the original temple generation (which places vanilla chests) + orig(); + + // Then add our extra chests + AddExtraTempleChests(); + } + + private void AddExtraTempleChests() + { + if (GenVars.tLeft == 0 || GenVars.tRight == 0) + { + ModContent.GetInstance().Logger.Info("Temple bounds not set, skipping extra chests"); + return; + } + + int tLeft = GenVars.tLeft; + int tRight = GenVars.tRight; + int tTop = GenVars.tTop; + int tBottom = GenVars.tBottom; + int tRooms = GenVars.tRooms; + + ModContent.GetInstance().Logger.Info($"Adding extra chests to temple: {tLeft},{tTop} to {tRight},{tBottom}, rooms: {tRooms}"); + + int extraChests = tRooms * 30; // Reasonable amount + int chestsPlaced = 0; + + // Place locked chests directly, just like the vanilla temple generation does + for (int i = 0; i < extraChests; i++) + { + int attempts = 0; + bool placed = false; + + while (!placed && attempts < 1000) + { + int x = WorldGen.genRand.Next(tLeft + 5, tRight - 5); + int y = WorldGen.genRand.Next(tTop + 5, tBottom - 5); + + if (WorldGen.InWorld(x, y) && WorldGen.InWorld(x + 1, y + 1)) + { + Tile tile = Main.tile[x, y]; + Tile tileRight = Main.tile[x + 1, y]; + Tile tileBelow = Main.tile[x, y + 1]; + Tile tileBelowRight = Main.tile[x + 1, y + 1]; + + // Check if location is suitable: temple wall, empty space, solid floor below + if (tile.WallType == 87 && !tile.HasTile && + tileRight.WallType == 87 && !tileRight.HasTile && + tileBelow.HasTile && Main.tileSolid[tileBelow.TileType] && + tileBelowRight.HasTile && Main.tileSolid[tileBelowRight.TileType]) + { + // Check for nearby chests + bool chestNearby = false; + for (int checkX = x - 3; checkX <= x + 3; checkX++) + { + for (int checkY = y - 3; checkY <= y + 3; checkY++) + { + if (WorldGen.InWorld(checkX, checkY)) + { + Tile checkTile = Main.tile[checkX, checkY]; + if (checkTile.HasTile && (checkTile.TileType == TileID.Containers || + checkTile.TileType == ModContent.TileType())) + { + chestNearby = true; + break; + } + } + } + if (chestNearby) break; + } + + if (!chestNearby) + { + // Place locked chest directly using WorldGen.PlaceChest + int chestIndex = WorldGen.PlaceChest(x, y, (ushort)ModContent.TileType(), false, 0); + + if (chestIndex != -1) + { + // Manually populate with temple loot based on vanilla temple chest contents + Chest chest = Main.chest[chestIndex]; + if (chest != null) + { + int slot = 0; + + // Always include Lihzahrd Power Cell + chest.item[slot].SetDefaults(ItemID.LihzahrdPowerCell); + chest.item[slot].stack = 3; + slot++; + + // Always include Lihzahrd Furnace + chest.item[slot].SetDefaults(ItemID.LihzahrdFurnace); + chest.item[slot].stack = 12; + slot++; + + // 33% chance for Solar Tablet, otherwise Solar Tablet Fragments + if (WorldGen.genRand.NextBool(3)) + { + chest.item[slot].SetDefaults(ItemID.SolarTablet); + chest.item[slot].stack = 1; + } + else + { + chest.item[slot].SetDefaults(ItemID.LunarTabletFragment); + chest.item[slot].stack = WorldGen.genRand.Next(4, 9); + } + slot++; + + // Add some typical Gold Chest loot (coins, potions, etc) + if (WorldGen.genRand.NextBool(2)) + { + chest.item[slot].SetDefaults(ItemID.GoldCoin); + chest.item[slot].stack = WorldGen.genRand.Next(3, 8); + slot++; + } + + if (WorldGen.genRand.NextBool(2)) + { + chest.item[slot].SetDefaults(ItemID.HealingPotion); + chest.item[slot].stack = WorldGen.genRand.Next(2, 5); + slot++; + } + + if (WorldGen.genRand.NextBool(3)) + { + chest.item[slot].SetDefaults(ItemID.Torch); + chest.item[slot].stack = WorldGen.genRand.Next(15, 30); + slot++; + } + + placed = true; + chestsPlaced++; + } + } + } + } + } + attempts++; + } + } + + ModContent.GetInstance().Logger.Info($"Placed {chestsPlaced} extra locked temple chests"); } public override void SetStaticDefaults() @@ -65,7 +220,6 @@ public override void SetStaticDefaults() IL_WorldGen.templePart2 += EditWorldGentemplePart2; } - private void EditWorldGentemplePart2(ILContext il) { var cursor = new ILCursor(il); @@ -147,8 +301,6 @@ public override bool RightClick(int i, int j) } } - // TODO: It would be better to replace the netmessage with a custom packet to perfectly sync - // the chest unlock sound and dust emitted. if (Main.netMode == NetmodeID.MultiplayerClient) NetMessage.SendTileSquare(-1, left, top, 2, 2); From 80d7c6cea9f857210053645df977a1239f4763c3 Mon Sep 17 00:00:00 2001 From: emyhrberg <121192176+emyhrberg@users.noreply.github.com> Date: Mon, 1 Dec 2025 06:31:15 +0100 Subject: [PATCH 194/206] Various fixes to chat and more - Removed chat debug feature - Added so spawn selector is enabled when within range of teammates bed - Made players always respawn in world spawn instead of bed spawn after dying - Removed AM keybind - Fixed spawnbox zoom/UIScale compatibility --- Content/Items/AdventureMirror.cs | 36 +-- Core/Debug/DebugChat.cs | 2 + .../Players/AdventureMirrorPlayer.cs | 36 ++- Core/SpawnSelector/Systems/SpawnHooks.cs | 38 +++ Core/SpawnSelector/UI/BedsOnMap.cs | 1 - Core/Spawnbox/SpawnboxMap.cs | 10 +- Core/Spawnbox/SpawnboxWorld.cs | 216 +++++++----------- System/Client/Keybinds.cs | 2 - 8 files changed, 174 insertions(+), 167 deletions(-) create mode 100644 Core/SpawnSelector/Systems/SpawnHooks.cs diff --git a/Content/Items/AdventureMirror.cs b/Content/Items/AdventureMirror.cs index e1864ffe..605f2953 100644 --- a/Content/Items/AdventureMirror.cs +++ b/Content/Items/AdventureMirror.cs @@ -146,38 +146,16 @@ internal void CancelItemUse(Player player) player.reuseDelay = 0; } - public bool IsPlayerInSpawnRegion(Player player) - { - // Is player in resin's spawn region? - var regionManager = ModContent.GetInstance(); - Point tilePos = player.Center.ToTileCoordinates(); - var region = regionManager.GetRegionContaining(tilePos); - if (region != null) - { - return true; - } - - // Is player in bed spawn region? - Vector2 bedSpawnPoint = new(player.SpawnX, player.SpawnY); - float distanceToBedSpawn = Vector2.Distance(bedSpawnPoint * 16f, player.Center); - if (distanceToBedSpawn <= 25 * 16f) - { - return true; - } - - return false; - } - public override void UseStyle(Player player, Rectangle heldItemFrame) { base.UseStyle(player, heldItemFrame); - if (IsPlayerInSpawnRegion(player)) - { - //PopupTextHelper.NewText("cannot use in spawn!", player); - //CancelItemUse(player); - //return; - } + //if (IsPlayerInSpawnRegion(player)) + //{ + // //PopupTextHelper.NewText("cannot use in spawn!", player); + // //CancelItemUse(player); + // //return; + //} // If this player moves, cancel their use if (player.velocity.LengthSquared() > 0) @@ -253,7 +231,7 @@ private void OpenFullscreenMap() Main.mapFullscreenPos.Y = worldCenterY; // Zoom out a bit to see the whole map - Main.mapFullscreenScale = 0.01f; + //Main.mapFullscreenScale = 0.01f; } public override void UseAnimation(Player player) diff --git a/Core/Debug/DebugChat.cs b/Core/Debug/DebugChat.cs index 07c99398..12ca92b9 100644 --- a/Core/Debug/DebugChat.cs +++ b/Core/Debug/DebugChat.cs @@ -7,6 +7,7 @@ namespace PvPAdventure.Core.Debug; +#if DEBUG internal class DebugChat : ModSystem { public override void Load() @@ -41,3 +42,4 @@ private void OnAddNewChatMessage(On_RemadeChatMonitor.orig_AddNewMessage orig, R timeLeftField?.SetValue(msg, 60 * 60); } } +#endif \ No newline at end of file diff --git a/Core/SpawnSelector/Players/AdventureMirrorPlayer.cs b/Core/SpawnSelector/Players/AdventureMirrorPlayer.cs index d7eb5fa7..3878404c 100644 --- a/Core/SpawnSelector/Players/AdventureMirrorPlayer.cs +++ b/Core/SpawnSelector/Players/AdventureMirrorPlayer.cs @@ -35,9 +35,9 @@ public override void OnHurt(Player.HurtInfo info) } } - public bool IsPlayerInSpawnRegion(int extraTileOffset=0) + public bool IsPlayerInSpawnRegion() { - // Is player in spawn region? + // Is player in resin's spawn region? var regionManager = ModContent.GetInstance(); Point tilePos = Player.Center.ToTileCoordinates(); var region = regionManager.GetRegionContaining(tilePos); @@ -54,9 +54,41 @@ public bool IsPlayerInSpawnRegion(int extraTileOffset=0) return true; } + // Is player in any bed spawn region? + for (int i = 0; i < Main.maxPlayers; i++) + { + Player other = Main.player[i]; + + if (other == null || !other.active || other.whoAmI == Player.whoAmI) + continue; + + // Only care about same team and non-zero team + if (other.team == 0 || other.team != Player.team) + continue; + + // No bed set for this teammate + if (other.SpawnX == -1 || other.SpawnY == -1) + continue; + + Vector2 teammateBedTile = new Vector2(other.SpawnX, other.SpawnY); + float distanceToTeammateBed = Vector2.Distance(teammateBedTile * 16f, Player.Center); + + if (distanceToTeammateBed <= 25*16f) + { + return true; + } + } return false; } +#if DEBUG + public override void Kill(double damage, int hitDirection, bool pvp, PlayerDeathReason damageSource) + { + Player.respawnTimer = 0; + base.Kill(damage, hitDirection, pvp, damageSource); + } +#endif + public override void PostUpdate() { if (Main.dedServ) diff --git a/Core/SpawnSelector/Systems/SpawnHooks.cs b/Core/SpawnSelector/Systems/SpawnHooks.cs new file mode 100644 index 00000000..2fe7dd7f --- /dev/null +++ b/Core/SpawnSelector/Systems/SpawnHooks.cs @@ -0,0 +1,38 @@ +using Microsoft.Xna.Framework; +using Terraria; +using Terraria.ModLoader; + +namespace PvPAdventure.Core.SpawnSelector.Systems; + +/// +/// This allows the player to click on teammates to teleport to them. +/// +public class SpawnHooks : ModSystem +{ + public override void Load() + { + On_Player.Spawn_SetPosition += ForceWorldSpawn; + } + + public override void Unload() + { + On_Player.Spawn_SetPosition -= ForceWorldSpawn; + } + + private void ForceWorldSpawn(On_Player.orig_Spawn_SetPosition orig, Player self, int floorX, int floorY) + { + //orig(self, floorX, floorY); + + // Force all respawns to world spawn + int spawnX = Main.spawnTileX; + int spawnY = Main.spawnTileY; + //bool num = Player.Spawn_GetPositionAtWorldSpawn(ref floorX, ref floorY); + //this.Spawn_SetPosition(floorX, floorY); + //if (num && !this.Spawn_IsAreaAValidWorldSpawn(floorX, floorY)) + //{ + //Player.Spawn_ForceClearArea(floorX, floorY); + //} + Main.LocalPlayer.position.X = spawnX * 16 + 8 - Main.LocalPlayer.width / 2; + Main.LocalPlayer.position.Y = spawnY * 16 - Main.LocalPlayer.height; + } +} diff --git a/Core/SpawnSelector/UI/BedsOnMap.cs b/Core/SpawnSelector/UI/BedsOnMap.cs index ac8feb52..4b5815e9 100644 --- a/Core/SpawnSelector/UI/BedsOnMap.cs +++ b/Core/SpawnSelector/UI/BedsOnMap.cs @@ -19,7 +19,6 @@ internal class BedsOnMap : ModSystem public override void Load() { On_SpawnMapLayer.Draw += OnSpawnMapLayer; - } public override void Unload() diff --git a/Core/Spawnbox/SpawnboxMap.cs b/Core/Spawnbox/SpawnboxMap.cs index bf791302..292ff360 100644 --- a/Core/Spawnbox/SpawnboxMap.cs +++ b/Core/Spawnbox/SpawnboxMap.cs @@ -1,10 +1,12 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; +using PvPAdventure.Core.SpawnSelector.Players; using PvPAdventure.System; using Terraria; using Terraria.GameContent; using Terraria.Map; using Terraria.ModLoader; +using Terraria.WorldBuilding; using static PvPAdventure.System.RegionManager; namespace PvPAdventure.Core.Spawnbox; @@ -66,9 +68,15 @@ private static void DrawSpawnBoxOnFullscreenMap(ref MapOverlayDrawContext contex h = spawnRect.Height; } + var gm = ModContent.GetInstance(); + var am = Main.LocalPlayer.GetModPlayer(); + bool canPass = gm.CurrentPhase == GameManager.Phase.Playing + && am.IsPlayerInSpawnRegion(); + // now draw using the (possibly clipped) rect Texture2D pix = TextureAssets.MagicPixel.Value; - Color col = Color.Black * 0.7f; + Color col = Color.Black; + if (canPass) col = Color.Black * 0.5f; int thickness = 2; if (Main.mapFullscreen) diff --git a/Core/Spawnbox/SpawnboxWorld.cs b/Core/Spawnbox/SpawnboxWorld.cs index b2757d5c..6f44f88e 100644 --- a/Core/Spawnbox/SpawnboxWorld.cs +++ b/Core/Spawnbox/SpawnboxWorld.cs @@ -10,149 +10,101 @@ using Terraria.GameContent; using Terraria.ModLoader; using Terraria.UI; -using static PvPAdventure.System.RegionManager; -namespace PvPAdventure.Core.Spawnbox; - -[Autoload(Side = ModSide.Client)] -public class SpawnBoxWorld : ModSystem +namespace PvPAdventure.Core.Spawnbox { - // Initialize the interface layer. - private readonly SpawnBoxInterfaceLayer _spawnBoxInterfaceLayer = new(); - public Asset _playerBGTexture; - - // Load the texture. - public override void Load() + [Autoload(Side = ModSide.Client)] + public class SpawnBoxWorld : ModSystem { - if (!Main.dedServ) - _playerBGTexture = Ass.CustomPlayerBackground; - } + public Asset _playerBGTexture; - // Add the layer. - public override void ModifyInterfaceLayers(List layers) - { - if (!layers.Contains(_spawnBoxInterfaceLayer)) + public override void Load() { - // add at the bottom interface layer - // https://github.com/tModLoader/tModLoader/wiki/Vanilla-Interface-layers-values - var layerIndex = layers.FindIndex(layer => layer.Name == "Vanilla: Interface Logic 1"); - - if (layerIndex != -1) - layers.Insert(layerIndex + 1, _spawnBoxInterfaceLayer); + if (!Main.dedServ) + _playerBGTexture = Ass.CustomPlayerBackground; } - } - private class SpawnBoxInterfaceLayer() : GameInterfaceLayer("PvPAdventure: Spawn Box", InterfaceScaleType.UI) - { - protected override bool DrawSelf() + public override void ModifyInterfaceLayers(List layers) { - // To see how to draw coordinates properly, see the wiki on Coordinates. - // https://github.com/tModLoader/tModLoader/wiki/Coordinates - - // Draw the spawn box. - DrawSpawnBox(Main.spriteBatch); - return base.DrawSelf(); + // Insert just after a vanilla UI layer so it's always on top of the world. + int idx = layers.FindIndex(l => l.Name == "Vanilla: Interface Logic 1"); + if (idx != -1) + { + layers.Insert(idx + 1, new SpawnBoxInterfaceLayer()); + } } - private void DrawSpawnBox(SpriteBatch sb) + private sealed class SpawnBoxInterfaceLayer : GameInterfaceLayer { - var rm = ModContent.GetInstance(); - if (rm.Regions.Count == 0) - return; - - Region region = rm.Regions[0]; - - // 🔹 this is the “solid ring” bounds in TILE space - Rectangle ring = region.CollisionRingBounds; - - int leftTile = ring.X; - int rightTile = ring.X + ring.Width; // exclusive - int topTile = ring.Y; - int bottomTile = ring.Y + ring.Height; // exclusive - - // Tile -> world - float leftWorld = leftTile * 16f; - float rightWorld = rightTile * 16f; - float topWorld = topTile * 16f; - float bottomWorld = bottomTile * 16f; - - // World -> screen - float uiScale = Main.UIScale; - - float leftScreen = (leftWorld - Main.screenPosition.X) / uiScale; - float rightScreen = (rightWorld - Main.screenPosition.X) / uiScale; - float topScreen = (topWorld - Main.screenPosition.Y) / uiScale; - float bottomScreen = (bottomWorld - Main.screenPosition.Y) / uiScale; - - - var gm = ModContent.GetInstance(); - var am = Main.LocalPlayer.GetModPlayer(); - - float solidOpacity = 1.0f; - float lightOpacity = 0.5f; - - float opacity = gm.CurrentPhase == GameManager.Phase.Playing - ? (am.IsPlayerInSpawnRegion() ? lightOpacity : solidOpacity) - : solidOpacity; - - int l = (int)leftScreen; - int r = (int)rightScreen; - int t = (int)topScreen; - int b = (int)bottomScreen; - - int thickness = (int)Math.Max(1f, 16f / uiScale); - //Texture2D pix = TextureAssets.MagicPixel.Value; - //Color col = Color.Gray * 0.7f; - - // vanilla borders (top,left,bottom,right) - //sb.Draw(pix, new Rectangle(l, t, r - l, thickness), col); - //sb.Draw(pix, new Rectangle(l, b - thickness, r - l, thickness), col); - //sb.Draw(pix, new Rectangle(l, t, thickness, b - t), col); - //sb.Draw(pix, new Rectangle(r - thickness, t, thickness, b - t), col); - - Rectangle screenRect = new(l,t,r - l, b - t); - DrawNineSliceBorder(sb, screenRect, Color.White * opacity); - } - - private void DrawNineSliceBorder(SpriteBatch sb, Rectangle rect, Color color) - { - Texture2D tex = ModContent.GetInstance()._playerBGTexture.Value; - - - tex = Ass.Spawnbox.Value; - - int c = 16; // corner size - int x = rect.X; - int y = rect.Y; - int w = rect.Width; - int h = rect.Height; - - int ew = tex.Width - c * 2; - int eh = tex.Height - c * 2; - - // top-left - sb.Draw(tex, new Rectangle(x, y, c, c), new Rectangle(0, 0, c, c), color); - - // top - sb.Draw(tex, new Rectangle(x + c, y, w - c * 2, c), new Rectangle(c, 0, ew, c), color); - - // top-right - sb.Draw(tex, new Rectangle(x + w - c, y, c, c), new Rectangle(tex.Width - c, 0, c, c), color); - - // left - sb.Draw(tex, new Rectangle(x, y + c, c, h - c * 2), new Rectangle(0, c, c, eh), color); - - // right - sb.Draw(tex, new Rectangle(x + w - c, y + c, c, h - c * 2), new Rectangle(tex.Width - c, c, c, eh), color); - - // bottom-left - sb.Draw(tex, new Rectangle(x, y + h - c, c, c), new Rectangle(0, tex.Height - c, c, c), color); - - // bottom - sb.Draw(tex, new Rectangle(x + c, y + h - c, w - c * 2, c),new Rectangle(c, tex.Height - c, ew, c), color); - - // bottom-right - sb.Draw(tex, new Rectangle(x + w - c, y + h - c, c, c),new Rectangle(tex.Width - c, tex.Height - c, c, c), color); + public SpawnBoxInterfaceLayer() + : base("PvPAdventure: SpawnBox", InterfaceScaleType.Game) + { + } + + protected override bool DrawSelf() + { + DrawSpawnBox(Main.spriteBatch); + return true; + } + + private void DrawSpawnBox(SpriteBatch spriteBatch) + { + if (Main.dedServ) + return; + + // Set the spawnbox size. + int leftTile = Main.spawnTileX - 25; + int topTile = Main.spawnTileY - 25; + int rightTile = leftTile + 50; + int bottomTile = topTile + 50; + + // Get world coordinates. + Vector2 worldTopLeft = new(leftTile * 16f, topTile * 16f); + Vector2 worldBottomRight = new(rightTile * 16f, bottomTile * 16f); + + // Convert world coordinates to screen cordinates. + Vector2 screenTopLeft = worldTopLeft - Main.screenPosition; + Vector2 screenBottomRight = worldBottomRight - Main.screenPosition; + + int x = (int)Math.Floor(screenTopLeft.X); + int y = (int)Math.Floor(screenTopLeft.Y); + int w = (int)Math.Round(screenBottomRight.X - screenTopLeft.X); + int h = (int)Math.Round(screenBottomRight.Y - screenTopLeft.Y); + if (w <= 0 || h <= 0) + return; + + Rectangle rect = new(x, y, w, h); + rect.Inflate(16, 16); + + DrawNineSliceBorder(spriteBatch, rect); + } + + private void DrawNineSliceBorder(SpriteBatch sb, Rectangle rect) + { + // Set color + var gm = ModContent.GetInstance(); + var am = Main.LocalPlayer.GetModPlayer(); + bool canPass = gm.CurrentPhase == GameManager.Phase.Playing && am.IsPlayerInSpawnRegion(); + Color color = Color.Black * (canPass ? 0.5f : 1f); + + Texture2D tex = Ass.Spawnbox.Value; + const int srcCorner = 16; + int x = rect.X, y = rect.Y, w = rect.Width, h = rect.Height; + int srcEdgeWidth = tex.Width - srcCorner * 2; + int srcEdgeHeight = tex.Height - srcCorner * 2; + int dstCorner = srcCorner; + + sb.Draw(tex, new Rectangle(x, y, dstCorner, dstCorner), new Rectangle(0, 0, srcCorner, srcCorner), color); + sb.Draw(tex, new Rectangle(x + dstCorner, y, w - dstCorner * 2, dstCorner), new Rectangle(srcCorner, 0, srcEdgeWidth, srcCorner), color); + sb.Draw(tex, new Rectangle(x + w - dstCorner, y, dstCorner, dstCorner), new Rectangle(tex.Width - srcCorner, 0, srcCorner, srcCorner), color); + + sb.Draw(tex, new Rectangle(x, y + dstCorner, dstCorner, h - dstCorner * 2), new Rectangle(0, srcCorner, srcCorner, srcEdgeHeight), color); + sb.Draw(tex, new Rectangle(x + w - dstCorner, y + dstCorner, dstCorner, h - dstCorner * 2), new Rectangle(tex.Width - srcCorner, srcCorner, srcCorner, srcEdgeHeight), color); + + sb.Draw(tex, new Rectangle(x, y + h - dstCorner, dstCorner, dstCorner), new Rectangle(0, tex.Height - srcCorner, srcCorner, srcCorner), color); + sb.Draw(tex, new Rectangle(x + dstCorner, y + h - dstCorner, w - dstCorner * 2, dstCorner), new Rectangle(srcCorner, tex.Height - srcCorner, srcEdgeWidth, srcCorner), color); + sb.Draw(tex, new Rectangle(x + w - dstCorner, y + h - dstCorner, dstCorner, dstCorner), new Rectangle(tex.Width - srcCorner, tex.Height - srcCorner, srcCorner, srcCorner), color); + } } } } diff --git a/System/Client/Keybinds.cs b/System/Client/Keybinds.cs index 8d7699b5..d72d756f 100644 --- a/System/Client/Keybinds.cs +++ b/System/Client/Keybinds.cs @@ -9,13 +9,11 @@ public class Keybinds : ModSystem public ModKeybind Scoreboard { get; private set; } public ModKeybind BountyShop { get; private set; } public ModKeybind AllChat { get; private set; } - public ModKeybind AdventureMirrorKeybind { get; private set; } public override void Load() { Scoreboard = KeybindLoader.RegisterKeybind(Mod, "Scoreboard", Keys.OemTilde); BountyShop = KeybindLoader.RegisterKeybind(Mod, "BountyShop", Keys.P); AllChat = KeybindLoader.RegisterKeybind(Mod, "AllChat", Keys.U); - AdventureMirrorKeybind = KeybindLoader.RegisterKeybind(Mod, "AdventureMirror", Keys.M); } } \ No newline at end of file From 227bd4f23a1082307bee8f12ac52cf008df95454 Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Sun, 30 Nov 2025 22:14:18 -0800 Subject: [PATCH 195/206] Added biome key molds and made them replace the current biome keys fixed temple chests fixed nimbus rod made mechs drop max souls --- AdventureDropDatabase.cs | 6 +- AdventureItem.cs | 117 ++- AdventureNpc.cs | 1 + AdventureProjectile.cs | 2 +- Assets/Item/Corruption_Key_Mold.png | Bin 0 -> 519 bytes Assets/Item/Desert_Key_Mold.png | Bin 0 -> 404 bytes Assets/Item/Frozen_Key_Mold.png | Bin 0 -> 456 bytes Assets/Item/Hallowed_Key_Mold.png | Bin 0 -> 480 bytes Assets/Item/Jungle_Key_Mold.png | Bin 0 -> 512 bytes Localization/en-US.hjson | 1193 ++++++++++++++++++--------- LockedLihzahrdChest.cs | 3 +- System/RecipeManager.cs | 52 +- 12 files changed, 961 insertions(+), 413 deletions(-) create mode 100644 Assets/Item/Corruption_Key_Mold.png create mode 100644 Assets/Item/Desert_Key_Mold.png create mode 100644 Assets/Item/Frozen_Key_Mold.png create mode 100644 Assets/Item/Hallowed_Key_Mold.png create mode 100644 Assets/Item/Jungle_Key_Mold.png diff --git a/AdventureDropDatabase.cs b/AdventureDropDatabase.cs index 2b42cb82..34f971ee 100644 --- a/AdventureDropDatabase.cs +++ b/AdventureDropDatabase.cs @@ -517,7 +517,7 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) // Remove existing soul drops npcLoot.RemoveWhere(drop => (drop is CommonDrop commonDrop && commonDrop.itemId == ItemID.SoulofMight)); - npcLoot.Add(ItemDropRule.Common(ItemID.SoulofMight, 1, 31, 31)); + npcLoot.Add(ItemDropRule.Common(ItemID.SoulofMight, 1, 40, 40)); break; case NPCID.SkeletronPrime: @@ -527,7 +527,7 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) npcLoot.RemoveWhere(drop => (drop is CommonDrop commonDrop && commonDrop.itemId == ItemID.SoulofFright)); - npcLoot.Add(ItemDropRule.Common(ItemID.SoulofFright, 1, 31, 31)); + npcLoot.Add(ItemDropRule.Common(ItemID.SoulofFright, 1, 40, 40)); break; case NPCID.Retinazer: @@ -540,7 +540,7 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) npcLoot.Add(ItemDropRule.ByCondition( new Conditions.LegacyHack_IsBossAndNotExpert(), - ItemID.SoulofSight, 1, 31, 31)); + ItemID.SoulofSight, 1, 40, 40)); break; case NPCID.Plantera: diff --git a/AdventureItem.cs b/AdventureItem.cs index ace336a0..8a9d6a6e 100644 --- a/AdventureItem.cs +++ b/AdventureItem.cs @@ -3,13 +3,15 @@ using System.Linq; using Microsoft.Xna.Framework; using Terraria; +using Terraria.DataStructures; using Terraria.Enums; +using Terraria.GameContent.ItemDropRules; using Terraria.ID; using Terraria.Localization; using Terraria.ModLoader; using Terraria.ModLoader.Config; using Terraria.Utilities; - +using static PvPAdventure.AdventureNpc; namespace PvPAdventure; public class AdventureItem : GlobalItem @@ -332,7 +334,115 @@ public override bool CanUseItem(Player player) return true; } } - public class QuiverNerf : GlobalItem + public class CorruptionKeyMold : ModItem + { + public override string Texture => $"PvPAdventure/Assets/Item/Corruption_Key_Mold"; + + public override void SetStaticDefaults() + { + } + + public override void SetDefaults() + { + Item.maxStack = 9999; + Item.rare = ItemRarityID.Green; + } + } + + public class FrozenKeyMold : ModItem + { + public override string Texture => $"PvPAdventure/Assets/Item/Frozen_Key_Mold"; + + public override void SetStaticDefaults() + { + } + + public override void SetDefaults() + { + Item.maxStack = 9999; + Item.rare = ItemRarityID.Green; + } + } + + public class JungleKeyMold : ModItem + { + public override string Texture => $"PvPAdventure/Assets/Item/Jungle_Key_Mold"; + + public override void SetStaticDefaults() + { + } + + public override void SetDefaults() + { + Item.maxStack = 9999; + Item.rare = ItemRarityID.Green; + } + } + + public class HallowedKeyMold : ModItem + { + public override string Texture => $"PvPAdventure/Assets/Item/Hallowed_Key_Mold"; + + public override void SetStaticDefaults() + { + } + + public override void SetDefaults() + { + Item.maxStack = 9999; + Item.rare = ItemRarityID.Green; + } + } + + public class DesertKeyMold : ModItem + { + public override string Texture => $"PvPAdventure/Assets/Item/Desert_Key_Mold"; + + public override void SetStaticDefaults() + { + } + + public override void SetDefaults() + { + Item.maxStack = 9999; + Item.rare = ItemRarityID.Green; + } + } + public class BiomeKeyReplacer : GlobalItem + { + public override void OnSpawn(Item item, IEntitySource source) + { + switch (item.type) + { + case ItemID.CorruptionKey: + item.SetDefaults(ModContent.ItemType()); + break; + case ItemID.HallowedKey: + item.SetDefaults(ModContent.ItemType()); + break; + case ItemID.FrozenKey: + item.SetDefaults(ModContent.ItemType()); + break; + case ItemID.JungleKey: + item.SetDefaults(ModContent.ItemType()); + break; + case ItemID.DungeonDesertKey: + item.SetDefaults(ModContent.ItemType()); + break; + } + + if (item.type == ModContent.ItemType() || + item.type == ModContent.ItemType() || + item.type == ModContent.ItemType() || + item.type == ModContent.ItemType() || + item.type == ModContent.ItemType()) + { + item.stack = 1; + } + } + } +} +public class QuiverNerf : GlobalItem { public override void ModifyWeaponDamage(Item item, Player player, ref StatModifier damage) { @@ -455,5 +565,4 @@ public override void ModifyTooltips(Item item, List tooltips) tooltips.Add(new TooltipLine(Mod, "AllCraftTiles", "Counts as all crafting stations")); } } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/AdventureNpc.cs b/AdventureNpc.cs index 50b15104..57fc62f4 100644 --- a/AdventureNpc.cs +++ b/AdventureNpc.cs @@ -17,6 +17,7 @@ using Terraria.ModLoader; using Terraria.ModLoader.Config; using Terraria.ModLoader.IO; +using static PvPAdventure.AdventureItem; namespace PvPAdventure; diff --git a/AdventureProjectile.cs b/AdventureProjectile.cs index 60976ea4..0b271820 100644 --- a/AdventureProjectile.cs +++ b/AdventureProjectile.cs @@ -243,7 +243,7 @@ public class NimbusRodGlobalProjectile : GlobalProjectile { public override bool AppliesToEntity(Projectile entity, bool lateInstantiation) { - return entity.type == ProjectileID.RainNimbus; + return entity.type == ProjectileID.RainCloudRaining; } public override void PostAI(Projectile projectile) diff --git a/Assets/Item/Corruption_Key_Mold.png b/Assets/Item/Corruption_Key_Mold.png new file mode 100644 index 0000000000000000000000000000000000000000..62f7446ef9825053589aa1903c239756c6797325 GIT binary patch literal 519 zcmeAS@N?(olHy`uVBq!ia0vp^GC-`w!VDyX7}UgpltQvckS_y6l^O#>Lkk1LFQ8Dv z3kHT#0|tgy2@DKYGZ+}e3+C(!v;j(J1^9%x0%=7>2LruiTdO)x*Xc4BnEEa;oV~=L z-6ONv>}0proFK_q3qgnf|Nl=8DqRm$%~%rT7tG-B>_!@hljQC0!uxGY;#VMty~NYk zmHj0TBMYyH#=49opwLQB7sn8d^QD&(1rICmuqNmvJdCUmOJd~S8o<4^fmJ6VanZC% zIkJsU{on7dcAw?orJ1@u#niZ&MdO5Y8po+Zv4VzWoT?=WT0(eU}azs&}{+=NQ8#m{FKbJO57S0 nuk|zlHE6(XD9OxCEiOsSEx@g(?C{!npdJQKS3j3^P6Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0VzpDK~z{r)t9jf z!axj$tDBp%tE-NJIQkl{LKi{sZ3?b}PvIznqqFbe=2%I3hxV`OrP}tcAC!c0Y3|RZ zDeXmXQe&HfbM@J65z5NS_VJ8NW#-ed@iH#AyYcd@lPg>Q3eTqj+ixtEPvhk&i`i{Q zY$ux|+wc^ks^su6UPinc8ZSeN_jZP2LfYANXiiHx`IMi zNwi4M5lgDwG2)8zcZM_rr8)Qy*c<*7A~Zp8ifC}f6%x{DDjUXHq~|zGs#U687tR^} zT3U?5?hi*HBAt=FudPUU3bi}e4*hV?P{Mv4?B!D0J%zSQwcXl1g;lA&XK^=MwFx^mZVxG7o`Fz1|tI_ zQ(Z$NT?4}q0~0GlV=E&AZ36=<1A~BW6HrJXH00)|WTsW()}VN;rva!z18ze}W^QV6 aNn&mRZarm(*Tw_&FnGH9xvX@827EWO>jg<3OP;51`kmBX+ z4~_c&|G)3yQ$Sq|j3q&S!3+-1Zlr-YN#5=*oF8v4eFNmMmw5WRvcKeEWZ@OjSeKCm z6k6x$;uxZFe(9x)f-MR>ECEqB#4a)EUT})?;NIeJbNlRz{KpFJopCMrpsBcMt!abr zLPh_zN)he7=NPKYr??nOAA50=&!p|+&xNn+RP=mgUd`&AHR1Cac-+!^=GtA(;p zL@`?kFSq31+A5qWwVz}6@2`HWTVMY_cW`d@a(?FGw)4>&g;IeoS1oakC`m~yNwrEY zN(E93Mg~Tvx`sx&28JO9CRT>VRz?Qe1_o9J1_9kBpb$i8$jwj5OsmALLGfBo15kqo h+=i0O+|=Td#M}bhddd#3jR)#s@O1TaS?83{1OSxLs|x@C literal 0 HcmV?d00001 diff --git a/Localization/en-US.hjson b/Localization/en-US.hjson index 6b53842e..90f6fa22 100644 --- a/Localization/en-US.hjson +++ b/Localization/en-US.hjson @@ -369,7 +369,6 @@ Mods: { Tooltip: "" } - NoKnockbackItems: { Label: No Knockback Items Tooltip: "" @@ -378,190 +377,728 @@ Mods: { NoKnockbackProjectiles: { Label: No Knockback Projectiles - AwardBountyEveryKill: { - Label: Award Bounty Every Kill + AwardBountyEveryKill: { + Label: Award Bounty Every Kill + Tooltip: "" + } + } + + AdventureClientConfig: { + DisplayName: Client + + PlayerOutline: { + Label: Player Outline + Tooltip: "" + } + + ShiftEnterOpensAllChat: { + Label: Shift Enter Opens All Chat + Tooltip: "" + } + + ShowPauseMessage: { + Tooltip: "" + Label: Show Pause Message + } + + SoundEffect: { + Label: Sound Effect + Tooltip: "" + } + + IsVanillaDashEnabled: { + Label: Is Vanilla Dash Enabled + Tooltip: + ''' + On: Dash as usual with double tap + Off: Disables double tap dash. Use keybind instead + ''' + } + + OpenMapAfterRecall: { + Label: "[i:2435] Open Map After Recall" + Tooltip: Opens the map instantly after the mirror has finished channeling + } + ShowPopupText: { + Label: "[i:159] Show Popup Text" + Tooltip: Shows popup text related to item + } + + Headers.AdventureMirror: Adventure Mirror + + ShowPlayerIndicationWhenWhenHovering: { + Label: Show Player Indication When When Hovering + Tooltip: Shows arrow and player head on the fullscreen map when hovering the teleport option above a player + } + } + + PlayerOutlineConfig: { Tooltip: "" + + Self: { + Label: Self + Tooltip: "" + } + + Team: { + Label: Team + Tooltip: "" + } } - } - AdventureClientConfig: { - DisplayName: Client + CannotModify: You are not permitted to modify this config. - PlayerOutline: { - Label: Player Outline + PlayerDamageBalanceConfig: { Tooltip: "" + + ItemDamageMultipliers: { + Label: Item Damage Multipliers + Tooltip: "" + } + + ProjectileDamageMultipliers: { + Label: Projectile Damage Multipliers + Tooltip: "" + } + + ItemFalloff: { + Label: Item Falloff + Tooltip: "" + } + + ProjectileFalloff: { + Label: Projectile Falloff + Tooltip: "" + } + + DefaultFalloff: { + Tooltip: "" + Label: Default Falloff + } } - ShiftEnterOpensAllChat: { - Label: Shift Enter Opens All Chat + Falloff: { + Coefficient: { + Tooltip: "" + Label: Coefficient + } + + Forward: { + Label: Forward + Tooltip: "" + } + Tooltip: "" } - ShowPauseMessage: { + Statistics: { Tooltip: "" - Label: Show Pause Message + + Damage: { + Label: Damage + Tooltip: "" + } + + UseTime: { + Label: Use Time + Tooltip: "" + } + + UseAnimation: { + Label: Use Animation + Tooltip: "" + } + + ShootSpeed: { + Label: Shoot Speed + Tooltip: "" + } + + Crit: { + Label: Crit + Tooltip: "" + } + + Mana: { + Label: Mana + Tooltip: "" + } + + Scale: { + Label: Scale + Tooltip: "" + } + + Knockback: { + Label: Knockback + Tooltip: "" + } + + Value: { + Tooltip: "" + Label: Value + } } - SoundEffect: { - Label: Sound Effect + OptionalInt: { Tooltip: "" + + Value: { + Label: Value + Tooltip: "" + } } - - IsVanillaDashEnabled: { - Label: Is Vanilla Dash Enabled - Tooltip: - ''' - On: Dash as usual with double tap - Off: Disables double tap dash. Use keybind instead - ''' + + OptionalFloat: { + Tooltip: "" + + Value: { + Label: Value + Tooltip: "" + } } - OpenMapAfterRecall: { - Label: "[i:2435] Open Map After Recall" - Tooltip: Opens the map instantly after the mirror has finished channeling + HitMarkerConfig: { + Sound: { + Label: Sound + Tooltip: "" + } + + Volume: { + Label: Volume + Tooltip: "" + } + + PitchMinimum: { + Label: Pitch Minimum + Tooltip: "" + } + + PitchMaximum: { + Label: Pitch Maximum + Tooltip: "" + } + + Tooltip: "" + + SoundPath: { + Tooltip: "" + Label: Sound Path + } } - ShowPopupText: { - Label: "[i:159] Show Popup Text" - Tooltip: Shows popup text related to item + SoundEffectConfig: { + Tooltip: "" + + NpcHitMarker: { + Label: Npc Hit Marker + Tooltip: "" + } + + PlayerHitMarker: { + Label: Player Hit Marker + Tooltip: "" + } + + PlayerKillMarker: { + Label: Player Kill Marker + Tooltip: "" + } } - Headers.AdventureMirror: Adventure Mirror + PlayerHitMarkerConfig: { + Tooltip: "" + + SilenceVanilla: { + Label: Silence Vanilla + Tooltip: "" + } + } - ShowPlayerIndicationWhenWhenHovering: { - Label: Show Player Indication When When Hovering - Tooltip: Shows arrow and player head on the fullscreen map when hovering the teleport option above a player + KillMarkerConfig: { + SoundPath: { + Tooltip: "" + Label: Sound Path + } } - } - PlayerOutlineConfig: { - Tooltip: "" + PlayerKillMarkerConfig: { + SilenceVanilla: { + Tooltip: "" + Label: Silence Vanilla + } - Self: { - Label: Self Tooltip: "" } - Team: { - Label: Team + MarkerConfig`1: { + PitchMaximum: { + Tooltip: "" + Label: Pitch Maximum + } + + PitchMinimum: { + Tooltip: "" + Label: Pitch Minimum + } + + Volume: { + Tooltip: "" + Label: Volume + } + + Sound: { + Tooltip: "" + Label: Sound + } + } + + Killsound: { + Part2: { + Label: Part2 + Tooltip: "" + } + + FatalCarCrash: { + Label: Fatal Car Crash + Tooltip: "" + } + + Shronker: { + Label: Shronker + Tooltip: "" + } + + Sharkron: { + Label: Sharkron + Tooltip: "" + } + + Ronaldoz: { + Label: Ronaldoz + Tooltip: "" + } + + Zacharry: { + Label: Zacharry + Tooltip: "" + } + Tooltip: "" } - } - CannotModify: You are not permitted to modify this config. + Hitsound: { + Part1: { + Label: Part1 + Tooltip: "" + } - PlayerDamageBalanceConfig: { - Tooltip: "" + MarrowMurder: { + Label: Marrow Murder + Tooltip: "" + } + + Squelchy: { + Label: Squelchy + Tooltip: "" + } + + Crash: { + Label: Crash + Tooltip: "" + } + + Blip: { + Label: Blip + Tooltip: "" + } + + Buwee: { + Label: BuWEEEEE + Tooltip: "" + } + + OlBetsy: { + Label: Ol' Betsy + Tooltip: "" + } - ItemDamageMultipliers: { - Label: Item Damage Multipliers Tooltip: "" } - ProjectileDamageMultipliers: { - Label: Projectile Damage Multipliers + WorldGenerationConfig: { + LifeFruitMinimumDistanceBetween: { + Tooltip: "" + Label: Life Fruit Minimum Distance Between + } + + LifeFruitExpertChanceDenominator: { + Tooltip: "" + Label: Life Fruit Expert Chance Denominator + } + + LifeFruitChanceDenominator: { + Tooltip: "" + Label: Life Fruit Chance Denominator + } + Tooltip: "" + + PlanteraBulbChanceDenominator: { + Label: Plantera Bulb Chance Denominator + Tooltip: "" + } + + ChlorophyteSpreadChanceModifier: { + Label: Chlorophyte Spread Chance Modifier + Tooltip: "" + } + + ChlorophyteGrowChanceModifier: { + Label: Chlorophyte Grow Chance Modifier + Tooltip: "" + } + + ChlorophyteGrowLimitModifier: { + Label: Chlorophyte Grow Limit Modifier + Tooltip: "" + } } - ItemFalloff: { - Label: Item Falloff + NpcBalanceConfig: { + Tooltip: "" + + LifeMaxMultipliers: { + Label: Life Max Multipliers + Tooltip: "" + } + + DamageMultipliers: { + Label: Damage Multipliers + Tooltip: "" + } + + NoMechanicalBossSummonDrops: { + Label: No Mechanical Boss Summon Drops + Tooltip: "" + } + + NoBiomeKeyDrops: { + Label: No Biome Key Drops + Tooltip: "" + } + } + + FloatStatistic: { Tooltip: "" + + Value: { + Label: Value + Tooltip: "" + } } - ProjectileFalloff: { - Label: Projectile Falloff + ChestItemReplacement: { Tooltip: "" + + Items: { + Label: Items + Tooltip: "" + } } - DefaultFalloff: { + InvasionSizeValue: { + Value: { + Tooltip: "" + Label: Value + } + Tooltip: "" - Label: Default Falloff } - } - Falloff: { - Coefficient: { + TeamLifeConfig: { Tooltip: "" - Label: Coefficient + + Share: { + Label: Share + Tooltip: "" + } } - Forward: { - Label: Forward + AwardBountyEveryKill: { + Label: Award Bounty Every Kill Tooltip: "" } + } - Tooltip: "" + Item: { + Disabled: Cannot be used in this gamemode + NoUndergroundEmpressButterfly: Cannot be released here underground + NoUndergroundQueenSlimeCrystal: Cannot be summoned here underground } - Statistics: { - Tooltip: "" + Player.CannotRecall: Cannot recall! + Tiles.LockedLihzahrdChest.MapEntry: Locked Lihzahrd Chest + Sandstorm: "[c/FFC864:Desert winds are picking up...]" + Rain: "[c/6496FF:A storm is brewing overhead...]" - Damage: { - Label: Damage + NPCs: { + Bound: { + Merchant.DisplayName: Bound Merchant + ArmsDealer.DisplayName: Bound Arms Dealer + WitchDoctor.DisplayName: Bound Witch Doctor + Demolitionist.DisplayName: Bound. Demolitionist + + Steampunker: { + DisplayName: Chained Steampunker + Chat: At long last, I'm saved! The strangest people chained me up, they mentioned something about a hardcore challenge... + } + + Truffle: { + DisplayName: Buried Truffle + Chat: You woke me up. Dont eat children. + } + + Cyborg: { + DisplayName: Deactivated Cyborg + Chat: Press F2 to Enter Setup + } + + Chat: At long last, I'm saved! The strangest people tied me up + } + } + + Pause: { + 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! + } + + AncientChiselHotswapBuff: { + DisplayName: THE CURSE OF THE ANCIENT CHISEL + Description: YOU CAN'T USE THAT ACCESSORY SLOT! + } + + NewIchorPlayerDebuff: { + DisplayName: Ichor + Description: Defense reduced by one third + } + + BROISACHOJ: { + DisplayName: BRO IS A CHOJ + Description: You are too much of a CHOJ to dash effectively + } + + BuffDescription: { + BeetleMight1: Melee damage and speed increase by 8% + BeetleMight2: Melee damage and speed increase by 8% + BeetleMight3: Melee damage and speed increase by 8% + } + + Anathema: { + DisplayName: Anathema + Description: Enemy attacks can seek you out + } + + BitingEmbrace: { + DisplayName: Summon Tagged + Description: Take 7 more damage from enemies + } + + BrittleBones: { + DisplayName: Summon Tagged + Description: Take 6 more damage from enemies + } + + Hellhex: { + DisplayName: Firecracked + Description: You are going to burst with hellfire at any moment! + } + + Marked: { + DisplayName: Summon Tagged + Description: Take 9 more damage from enemies + } + + PlayerInSpawn: { + DisplayName: Spawn + Description: You're in spawn bro + } + + PressurePoints: { + DisplayName: Summon Tagged + Description: Take 6 more damage from enemies + } + + ShatteredArmor: { + DisplayName: Shattered Armor + Description: You're armor has been shattered by a brutal blow! + } + + Attuning: { + DisplayName: Attuning + Description: Your Spectre armor is attuning to your magic & mind! + } + + UncouthandBoring: { + DisplayName: Uncouth and Boring + Description: You are no longer a charming and mythical philosopher! + } + } + + Items: { + AdventureMirror: { + DisplayName: Adventure Mirror + Tooltip: + ''' + Gaze in the mirror to go on adventures + Right click to use + ''' + } + + AdventureBag: { + DisplayName: Adventure Bag Tooltip: "" } - UseTime: { - Label: Use Time + BlightFruit: { + DisplayName: Blight Fruit Tooltip: "" } + } - UseAnimation: { - Label: Use Animation + AdventureClientConfig: { + DisplayName: Adventure Client Config + + PlayerOutline: { + Label: Player Outline Tooltip: "" } - ShootSpeed: { - Label: Shoot Speed + ShiftEnterOpensAllChat: { + Label: Shift Enter Opens All Chat Tooltip: "" } - Crit: { - Label: Crit + ShowPauseMessage: { + Label: Show Pause Message Tooltip: "" } - Mana: { - Label: Mana + SoundEffect: { + Label: Sound Effect Tooltip: "" } - Scale: { - Label: Scale + BlightFruit: { + DisplayName: Blight Fruit + Tooltip: Permanently decreases maximum life by 5 + } + + Headers.AdventureMirror: Adventure Mirror Header + + OpenMapAfterRecall: { + Label: Open Map After Recall Tooltip: "" } - Knockback: { - Label: Knockback + ShowPopupText: { + Label: Show Popup Text Tooltip: "" } - Value: { + ShowPlayerIndicationWhenWhenHovering: { + Label: Show Player Indication When When Hovering + Tooltip: "" + } + + IsVanillaDashEnabled: { + Label: Is Vanilla Dash Enabled Tooltip: "" - Label: Value } } - OptionalInt: { + PlayerOutlineConfig: { Tooltip: "" - Value: { - Label: Value + Self: { + Label: Self + Tooltip: "" + } + + Team: { + Label: Team Tooltip: "" } } - OptionalFloat: { + SoundEffectConfig: { Tooltip: "" - Value: { - Label: Value + NpcHitMarker: { + Label: Npc Hit Marker + Tooltip: "" + } + + PlayerHitMarker: { + Label: Player Hit Marker + Tooltip: "" + } + + PlayerKillMarker: { + Label: Player Kill Marker Tooltip: "" } } - HitMarkerConfig: { + HitMarkerConfig.Tooltip: "" + + Hitsound: { + Tooltip: "" + + OlBetsy: { + Label: Ol Betsy + Tooltip: "" + } + + Buwee: { + Label: Buwee + Tooltip: "" + } + + Blip: { + Label: Blip + Tooltip: "" + } + + Crash: { + Label: Crash + Tooltip: "" + } + + Squelchy: { + Label: Squelchy + Tooltip: "" + } + + MarrowMurder: { + Label: Marrow Murder + Tooltip: "" + } + + Part1: { + Label: Part1 + Tooltip: "" + } + } + + MarkerConfig`1: { Sound: { Label: Sound Tooltip: "" @@ -581,172 +1118,206 @@ Mods: { Label: Pitch Maximum Tooltip: "" } + } + PlayerHitMarkerConfig: { Tooltip: "" - SoundPath: { + SilenceVanilla: { + Label: Silence Vanilla Tooltip: "" - Label: Sound Path } } - SoundEffectConfig: { + PlayerKillMarkerConfig: { Tooltip: "" - NpcHitMarker: { - Label: Npc Hit Marker + SilenceVanilla: { + Label: Silence Vanilla Tooltip: "" } + } - PlayerHitMarker: { - Label: Player Hit Marker + Killsound: { + Tooltip: "" + + Zacharry: { + Label: Zacharry Tooltip: "" } - PlayerKillMarker: { - Label: Player Kill Marker + Ronaldoz: { + Label: Ronaldoz + Tooltip: "" + } + + Sharkron: { + Label: Sharkron + Tooltip: "" + } + + Shronker: { + Label: Shronker + Tooltip: "" + } + + FatalCarCrash: { + Label: Fatal Car Crash + Tooltip: "" + } + + Part2: { + Label: Part2 Tooltip: "" } } - PlayerHitMarkerConfig: { + PlayerDamageBalanceConfig: { Tooltip: "" - SilenceVanilla: { - Label: Silence Vanilla + ItemDamageMultipliers: { + Label: Item Damage Multipliers Tooltip: "" } - } - KillMarkerConfig: { - SoundPath: { + ProjectileDamageMultipliers: { + Label: Projectile Damage Multipliers Tooltip: "" - Label: Sound Path } - } - PlayerKillMarkerConfig: { - SilenceVanilla: { + ItemFalloff: { + Label: Item Falloff Tooltip: "" - Label: Silence Vanilla } - Tooltip: "" - } - - MarkerConfig`1: { - PitchMaximum: { + ProjectileFalloff: { + Label: Projectile Falloff Tooltip: "" - Label: Pitch Maximum } - PitchMinimum: { + DefaultFalloff: { + Label: Default Falloff Tooltip: "" - Label: Pitch Minimum } + } - Volume: { + Falloff: { + Tooltip: "" + + Coefficient: { + Label: Coefficient Tooltip: "" - Label: Volume } - Sound: { + Forward: { + Label: Forward Tooltip: "" - Label: Sound } } - Killsound: { - Part2: { - Label: Part2 - Tooltip: "" - } + TeamLifeConfig: { + Tooltip: "" - FatalCarCrash: { - Label: Fatal Car Crash + Share: { + Label: Share Tooltip: "" } + } - Shronker: { - Label: Shronker + InvasionSizeValue: { + Tooltip: "" + + Value: { + Label: Value Tooltip: "" } + } - Sharkron: { - Label: Sharkron + Statistics: { + Tooltip: "" + + Damage: { + Label: Damage Tooltip: "" } - Ronaldoz: { - Label: Ronaldoz + UseTime: { + Label: Use Time Tooltip: "" } - Zacharry: { - Label: Zacharry + UseAnimation: { + Label: Use Animation Tooltip: "" } - Tooltip: "" - } - - Hitsound: { - Part1: { - Label: Part1 + ShootSpeed: { + Label: Shoot Speed Tooltip: "" } - MarrowMurder: { - Label: Marrow Murder + Crit: { + Label: Crit Tooltip: "" } - Squelchy: { - Label: Squelchy + Mana: { + Label: Mana Tooltip: "" } - Crash: { - Label: Crash + Scale: { + Label: Scale Tooltip: "" } - Blip: { - Label: Blip + Knockback: { + Label: Knockback Tooltip: "" } - Buwee: { - Label: BuWEEEEE + Value: { + Label: Value Tooltip: "" } + } - OlBetsy: { - Label: Ol' Betsy + OptionalInt: { + Tooltip: "" + + Value: { + Label: Value Tooltip: "" } + } + OptionalFloat: { Tooltip: "" + + Value: { + Label: Value + Tooltip: "" + } } WorldGenerationConfig: { - LifeFruitMinimumDistanceBetween: { + Tooltip: "" + + LifeFruitChanceDenominator: { + Label: Life Fruit Chance Denominator Tooltip: "" - Label: Life Fruit Minimum Distance Between } LifeFruitExpertChanceDenominator: { - Tooltip: "" Label: Life Fruit Expert Chance Denominator + Tooltip: "" } - LifeFruitChanceDenominator: { + LifeFruitMinimumDistanceBetween: { + Label: Life Fruit Minimum Distance Between Tooltip: "" - Label: Life Fruit Chance Denominator } - Tooltip: "" - PlanteraBulbChanceDenominator: { Label: Plantera Bulb Chance Denominator Tooltip: "" @@ -785,11 +1356,6 @@ Mods: { Label: No Mechanical Boss Summon Drops Tooltip: "" } - - NoBiomeKeyDrops: { - Label: No Biome Key Drops - Tooltip: "" - } } FloatStatistic: { @@ -809,171 +1375,78 @@ Mods: { Tooltip: "" } } - - InvasionSizeValue: { - Value: { - Tooltip: "" - Label: Value - } - - Tooltip: "" - } - - TeamLifeConfig: { - Tooltip: "" - - Share: { - Label: Share - Tooltip: "" - } - } - - GhostHealMaxDistanceNpc: { - Label: Ghost Heal Max Distance Npc - Tooltip: "" - } - - ProjectileCollisionDamageReduction: { - Label: Projectile Collision Damage Reduction - Tooltip: "" - } - - NoLineOfSightDamageReduction: { - Label: No Line Of Sight Damage Reduction - Tooltip: "" - } - } - - Item: { - Disabled: Cannot be used in this gamemode - NoUndergroundEmpressButterfly: Cannot be released here underground - NoUndergroundQueenSlimeCrystal: Cannot be summoned here underground - } - - Player.CannotRecall: Cannot recall! - Tiles.LockedLihzahrdChest.MapEntry: Locked Lihzahrd Chest - Sandstorm: "[c/FFC864:Desert winds are picking up...]" - Rain: "[c/6496FF:A storm is brewing overhead...]" - - NPCs: { - Bound: { - Merchant.DisplayName: Bound Merchant - ArmsDealer.DisplayName: Bound Arms Dealer - WitchDoctor.DisplayName: Bound Witch Doctor - Demolitionist.DisplayName: Bound. Demolitionist - - Steampunker: { - DisplayName: Chained Steampunker - Chat: At long last, I'm saved! The strangest people chained me up, they mentioned something about a hardcore challenge... - } - - Truffle: { - DisplayName: Buried Truffle - Chat: You woke me up. Dont eat children. - } - - Cyborg: { - DisplayName: Deactivated Cyborg - Chat: Press F2 to Enter Setup - } - - Chat: At long last, I'm saved! The strangest people tied me up - } } - Pause: { - True: "[c/FF0000:The game has been paused.]" - False: "[c/00FF00:The game has been resumed.]" - } + Tiles.LockedLihzahrdChest.MapEntry: Mods.PvPAdventure.Tiles.LockedLihzahrdChest.MapEntry Buffs: { - ShinyStoneHotswap: { - DisplayName: Shiny Stone Hotswap - Description: Shiny Stone is charging up! - } - - AncientChiselHotswapBuff: { - DisplayName: THE CURSE OF THE ANCIENT CHISEL - Description: YOU CAN'T USE THAT ACCESSORY SLOT! - } - - NewIchorPlayerDebuff: { - DisplayName: Ichor - Description: Defense reduced by one third - } - - BROISACHOJ: { - DisplayName: BRO IS A CHOJ - Description: You are too much of a CHOJ to dash effectively - } - - BuffDescription: { - BeetleMight1: Melee damage and speed increase by 8% - BeetleMight2: Melee damage and speed increase by 8% - BeetleMight3: Melee damage and speed increase by 8% - } - Anathema: { DisplayName: Anathema - Description: Enemy attacks can seek you out + Description: Mods.PvPAdventure.Buffs.Anathema.Description + } + + Attuning: { + DisplayName: Attuning + Description: Mods.PvPAdventure.Buffs.Attuning.Description } BitingEmbrace: { - DisplayName: Summon Tagged - Description: Take 7 more damage from enemies + DisplayName: Biting Embrace + Description: Mods.PvPAdventure.Buffs.BitingEmbrace.Description } BrittleBones: { - DisplayName: Summon Tagged - Description: Take 6 more damage from enemies + DisplayName: Brittle Bones + Description: Mods.PvPAdventure.Buffs.BrittleBones.Description + } + + BROISACHOJ: { + DisplayName: B R O I S A C H O J + Description: Mods.PvPAdventure.Buffs.BROISACHOJ.Description } Hellhex: { - DisplayName: Firecracked - Description: You are going to burst with hellfire at any moment! + DisplayName: Hellhex + Description: Mods.PvPAdventure.Buffs.Hellhex.Description } Marked: { - DisplayName: Summon Tagged - Description: Take 9 more damage from enemies + DisplayName: Marked + Description: Mods.PvPAdventure.Buffs.Marked.Description + } + + NewIchorPlayerDebuff: { + DisplayName: New Ichor Player Debuff + Description: Mods.PvPAdventure.Buffs.NewIchorPlayerDebuff.Description } PlayerInSpawn: { - DisplayName: Spawn - Description: You're in spawn bro + DisplayName: Player In Spawn + Description: Mods.PvPAdventure.Buffs.PlayerInSpawn.Description } PressurePoints: { - DisplayName: Summon Tagged - Description: Take 6 more damage from enemies + DisplayName: Pressure Points + Description: Mods.PvPAdventure.Buffs.PressurePoints.Description } ShatteredArmor: { DisplayName: Shattered Armor - Description: You're armor has been shattered by a brutal blow! + Description: Mods.PvPAdventure.Buffs.ShatteredArmor.Description } - Attuning: { - DisplayName: Attuning - Description: Your Spectre armor is attuning to your magic & mind! + ShinyStoneHotswap: { + DisplayName: Shiny Stone Hotswap + Description: Mods.PvPAdventure.Buffs.ShinyStoneHotswap.Description } UncouthandBoring: { - DisplayName: Uncouth and Boring - Description: You are no longer a charming and mythical philosopher! + DisplayName: Uncouthand Boring + Description: Mods.PvPAdventure.Buffs.UncouthandBoring.Description } } Items: { - AdventureMirror: { - DisplayName: Adventure Mirror - Tooltip: - ''' - Gaze in the mirror to go on adventures - Right click to use - ''' - } - AdventureBag: { DisplayName: Adventure Bag Tooltip: "" @@ -983,132 +1456,48 @@ Mods: { DisplayName: Blight Fruit Tooltip: "" } - } - - AdventureClientConfig: { - DisplayName: Adventure Client Config - - PlayerOutline: { - Label: Player Outline - Tooltip: "" - } - - ShiftEnterOpensAllChat: { - Label: Shift Enter Opens All Chat - Tooltip: "" - } - - ShowPauseMessage: { - Label: Show Pause Message - Tooltip: "" - } - - SoundEffect: { - Label: Sound Effect - Tooltip: "" - } - - BlightFruit: { - DisplayName: Blight Fruit - Tooltip: Permanently decreases maximum life by 5 - } - } - - PlayerOutlineConfig: { - Tooltip: "" - - Self: { - Label: Self - Tooltip: "" - } - - Team: { - Label: Team - Tooltip: "" - } - } - - SoundEffectConfig: { - Tooltip: "" - - NpcHitMarker: { - Label: Npc Hit Marker - Tooltip: "" - } - - PlayerHitMarker: { - Label: Player Hit Marker - Tooltip: "" - } - PlayerKillMarker: { - Label: Player Kill Marker + AdventureMirror: { + DisplayName: Adventure Mirror Tooltip: "" } - } - HitMarkerConfig.Tooltip: "" - - Hitsound: { - Tooltip: "" - OlBetsy.Label: Ol Betsy - Buwee.Label: Buwee - Blip.Label: Blip - Crash.Label: Crash - Squelchy.Label: Squelchy - MarrowMurder.Label: Marrow Murder - Part1.Label: Part1 - } - - MarkerConfig`1: { - Sound: { - Label: Sound - Tooltip: "" + JungleKeyMold: { + Tooltip: Used for crafting a Jungle Key + DisplayName: Jungle Key Mold } - Volume: { - Label: Volume - Tooltip: "" + HallowedKeyMold: { + Tooltip: Used for crafting a Hallowed Key + DisplayName: Hallowed Key Mold } - PitchMinimum: { - Label: Pitch Minimum - Tooltip: "" + FrozenKeyMold: { + Tooltip: Used for crafting a Frozen Key + DisplayName: Frozen Key Mold } - PitchMaximum: { - Label: Pitch Maximum - Tooltip: "" + DesertKeyMold: { + Tooltip: Used for crafting a Desert Key + DisplayName: Desert Key Mold } - } - - PlayerHitMarkerConfig: { - Tooltip: "" - SilenceVanilla: { - Label: Silence Vanilla - Tooltip: "" + CorruptionKeyMold: { + Tooltip: Used for crafting a Corruption Key + DisplayName: Corruption Key Mold } } - PlayerKillMarkerConfig: { - Tooltip: "" - - SilenceVanilla: { - Label: Silence Vanilla - Tooltip: "" + NPCs: { + Bound: { + ArmsDealer.DisplayName: Bound. Arms Dealer + Cyborg.DisplayName: Bound. Cyborg + Demolitionist.DisplayName: Bound. Demolitionist + Merchant.DisplayName: Bound. Merchant + Steampunker.DisplayName: Bound. Steampunker + Truffle.DisplayName: Bound. Truffle + WitchDoctor.DisplayName: Bound. Witch Doctor } } - - Killsound: { - Tooltip: "" - Zacharry.Label: Zacharry - Ronaldoz.Label: Ronaldoz - Sharkron.Label: Sharkron - Shronker.Label: Shronker - FatalCarCrash.Label: Fatal Car Crash - Part2.Label: Part2 - } } } -} \ No newline at end of file diff --git a/LockedLihzahrdChest.cs b/LockedLihzahrdChest.cs index ab269036..c916fdd2 100644 --- a/LockedLihzahrdChest.cs +++ b/LockedLihzahrdChest.cs @@ -57,10 +57,9 @@ private void AddExtraTempleChests() ModContent.GetInstance().Logger.Info($"Adding extra chests to temple: {tLeft},{tTop} to {tRight},{tBottom}, rooms: {tRooms}"); - int extraChests = tRooms * 30; // Reasonable amount + int extraChests = tRooms * 3; int chestsPlaced = 0; - // Place locked chests directly, just like the vanilla temple generation does for (int i = 0; i < extraChests; i++) { int attempts = 0; diff --git a/System/RecipeManager.cs b/System/RecipeManager.cs index 8eaa28e9..ee0afd69 100644 --- a/System/RecipeManager.cs +++ b/System/RecipeManager.cs @@ -4,6 +4,7 @@ using Terraria.ID; using Terraria.Localization; using Terraria.ModLoader; +using static PvPAdventure.AdventureItem; namespace PvPAdventure.System; @@ -47,7 +48,56 @@ public override void AddRecipes() } } - //shroomite bar crafting cost reduction + + // Corruption Key Recipe + Recipe.Create(ItemID.CorruptionKey) + .AddIngredient(ItemID.TempleKey, 1) + .AddIngredient(ModContent.ItemType()) + .AddIngredient(ItemID.SoulofFright, 5) + .AddIngredient(ItemID.SoulofSight, 5) + .AddIngredient(ItemID.SoulofMight, 5) + .AddTile(TileID.MythrilAnvil) + .Register(); + + // Frozen Key Recipe + Recipe.Create(ItemID.FrozenKey) + .AddIngredient(ItemID.TempleKey, 1) + .AddIngredient(ModContent.ItemType()) + .AddIngredient(ItemID.SoulofFright, 5) + .AddIngredient(ItemID.SoulofSight, 5) + .AddIngredient(ItemID.SoulofMight, 5) + .AddTile(TileID.MythrilAnvil) + .Register(); + + // Jungle Key Recipe + Recipe.Create(ItemID.JungleKey) + .AddIngredient(ItemID.TempleKey, 1) + .AddIngredient(ModContent.ItemType()) + .AddIngredient(ItemID.SoulofFright, 5) + .AddIngredient(ItemID.SoulofSight, 5) + .AddIngredient(ItemID.SoulofMight, 5) + .AddTile(TileID.MythrilAnvil) + .Register(); + + // Hallowed Key Recipe + Recipe.Create(ItemID.HallowedKey) + .AddIngredient(ItemID.TempleKey, 1) + .AddIngredient(ModContent.ItemType()) + .AddIngredient(ItemID.SoulofFright, 5) + .AddIngredient(ItemID.SoulofSight, 5) + .AddIngredient(ItemID.SoulofMight, 5) + .AddTile(TileID.MythrilAnvil) + .Register(); + + // Desert Key Recipe + Recipe.Create(ItemID.DungeonDesertKey) + .AddIngredient(ItemID.TempleKey, 1) + .AddIngredient(ModContent.ItemType()) + .AddIngredient(ItemID.SoulofFright, 5) + .AddIngredient(ItemID.SoulofSight, 5) + .AddIngredient(ItemID.SoulofMight, 5) + .AddTile(TileID.MythrilAnvil) + .Register(); Recipe.Create(ItemID.ShroomiteBar) .AddIngredient(ItemID.GlowingMushroom, 3) From 4810fdc9637be33349f8a27e31920ac0503e9e32 Mon Sep 17 00:00:00 2001 From: emyhrberg <121192176+emyhrberg@users.noreply.github.com> Date: Mon, 1 Dec 2025 11:24:20 +0100 Subject: [PATCH 196/206] Mini features 1. Inventory management is now possible even while dead 2. Inventory management is now possible even while using AM 3. Visual indicator of PvP disabled icons in spawn region --- Assets/SpawnSelector/CoolDown.png | Bin 0 -> 912 bytes Assets/SpawnSelector/Stop_Icon.png | Bin 0 -> 912 bytes Content/Items/AdventureMirror.cs | 2 +- Core/Debug/DebugPlayer.cs | 18 + Core/Helpers/AssetLoader.cs | 4 +- .../InventoryWhileDeadSystem.cs | 84 ++++ .../InventoryWhileUsingItemSystem.cs | 61 +++ .../Players/AdventureMirrorPlayer.cs | 8 - Core/SpawnSelector/Systems/ItemSlotHooks.cs | 433 +++++++++++++++++- .../UI/SpawnSelectorCharacter.cs | 12 +- Core/Spawnbox/PvPIcons.cs | 127 +++++ Core/Spawnbox/SpawnboxMap.cs | 41 +- 12 files changed, 764 insertions(+), 26 deletions(-) create mode 100644 Assets/SpawnSelector/CoolDown.png create mode 100644 Assets/SpawnSelector/Stop_Icon.png create mode 100644 Core/Debug/DebugPlayer.cs create mode 100644 Core/InventoryWhileDead/InventoryWhileDeadSystem.cs create mode 100644 Core/InventoryWhileDead/InventoryWhileUsingItemSystem.cs create mode 100644 Core/Spawnbox/PvPIcons.cs diff --git a/Assets/SpawnSelector/CoolDown.png b/Assets/SpawnSelector/CoolDown.png new file mode 100644 index 0000000000000000000000000000000000000000..0c2273111d6f8afd2428947fdd328f8a4959e328 GIT binary patch literal 912 zcmV;B18@9^P)vKj_88f55AW3IWo@NH~!g6Tm8=EqWB_4`{nP&&;&DEbVN!RTE<3Yc`p_ zoq6x`-kW)uC1%EHia1s8_!j|)Xr72T21epL#kynI^8|fwQZ-c>LsWz^Rqq7o&1B!$Y=ENL3 z?{uq*4ryV1_LdG_4aM(O22o#oPD+$O0T85dT@k zX73$sEbPeDqD%~YUxLkqqEcE_H>NdIUjlWWz37)k4m0UhJ>KfQtKL=T*fs{gy=h+C zT1isFkHGn&Uy53m%o(5np&KK_j^`$>?JgciSuP{lGto*WfWn~(%nX1)?UQm3Pct8b zQ6>WC8<%?G*m^MA6hf^T%)GB{MZb^CMs7l8#<+d)L?l6olIniB0%$$e6r#R7rV}Sj z01h$esAK}u5F@*b$NM1yBIumsUC{ud`z$Pw?;s2!SdJ(N$qd)-fH*8g130-ngkLqZ z1W{2Z?duP`?jJKkC~L8bW3(k26(^lXop*h-RFt^_Zn-wrhbDapzo*o)nWTL*?E@5O z!KD~*hJk^dh+b}J+d>Eoq~Gars(%vfI-xCD7^2eB=>P@GLhAOEA5l~$JaMFp&0bv& zpyoV@T!W7WfSPDy6-d|)!^!L*JN2Sv2$fM63=%druHJ{Fs*CBY?x>0SwIakAEcKHT zq7s9`4dOiDI4@d}mW3GZNJqE$)S+25z|=-*1KNReAXF|SQh)3Nw2kkAu&N%U0raGj;eZ?#j}(|0ZbCl zGONFTB{SW0US1y6x-srP(O$g{w`ApDNqCO`{8HKsMD6shbKR)q^ZuN69Q(p5iZ&hq m3WP(R`F8Em|Bq9gvit%vLq+z)<>a3L0000vKj_88f55AW3IWo@NH~!g6Tm8=EqWB_4`{nP&&;&DEbVN!RTE<3Yc`p_ zoq6x`-kW)uC1%EHia1s8_!j|)Xr72T21epL#kynI^8|fwQZ-c>LsWz^Rqq7o&1B!$Y=ENL3 z?{uq*4ryV1_LdG_4aM(O22o#oPD+$O0T85dT@k zX73$sEbPeDqD%~YUxLkqqEcE_H>NdIUjlWWz37)k4m0UhJ>KfQtKL=T*fs{gy=h+C zT1isFkHGn&Uy53m%o(5np&KK_j^`$>?JgciSuP{lGto*WfWn~(%nX1)?UQm3Pct8b zQ6>WC8<%?G*m^MA6hf^T%)GB{MZb^CMs7l8#<+d)L?l6olIniB0%$$e6r#R7rV}Sj z01h$esAK}u5F@*b$NM1yBIumsUC{ud`z$Pw?;s2!SdJ(N$qd)-fH*8g130-ngkLqZ z1W{2Z?duP`?jJKkC~L8bW3(k26(^lXop*h-RFt^_Zn-wrhbDapzo*o)nWTL*?E@5O z!KD~*hJk^dh+b}J+d>Eoq~Gars(%vfI-xCD7^2eB=>P@GLhAOEA5l~$JaMFp&0bv& zpyoV@T!W7WfSPDy6-d|)!^!L*JN2Sv2$fM63=%druHJ{Fs*CBY?x>0SwIakAEcKHT zq7s9`4dOiDI4@d}mW3GZNJqE$)S+25z|=-*1KNReAXF|SQh)3Nw2kkAu&N%U0raGj;eZ?#j}(|0ZbCl zGONFTB{SW0US1y6x-srP(O$g{w`ApDNqCO`{8HKsMD6shbKR)q^ZuN69Q(p5iZ&hq m3WP(R`F8Em|Bq9gvit%vLq+z)<>a3L0000 Question_Mark; + // Spawn selector assets public static Asset[] MapBG; public static Asset Arrow; public static Asset CustomPlayerBackground; public static Asset Spawnbox; + public static Asset Stop_Icon; + public static Asset Question_Mark; public static bool Initialized { get; set; } diff --git a/Core/InventoryWhileDead/InventoryWhileDeadSystem.cs b/Core/InventoryWhileDead/InventoryWhileDeadSystem.cs new file mode 100644 index 00000000..84aab72d --- /dev/null +++ b/Core/InventoryWhileDead/InventoryWhileDeadSystem.cs @@ -0,0 +1,84 @@ +using Terraria; +using Terraria.ModLoader; + +namespace PvPAdventure.Core.InventoryWhileDead; + +// Allows inventory access while player is dead. +internal class InventoryWhileDeadSystem : ModSystem +{ + public override void Load() + { + On_Main.DrawInterface_26_InterfaceLogic3 += ModifyInterfaceLogic; + On_Player.TryOpeningInGameOptionsBasedOnInput += ModifyIngameOptionsInput; + } + public override void Unload() + { + On_Main.DrawInterface_26_InterfaceLogic3 -= ModifyInterfaceLogic; + On_Player.TryOpeningInGameOptionsBasedOnInput -= ModifyIngameOptionsInput; + } + + private void ModifyIngameOptionsInput(On_Player.orig_TryOpeningInGameOptionsBasedOnInput orig, Player self) + { + //orig(self); + + // Override to allow inventory access while dead + if (self.dead) + { + if (self.controlInv) + { + if (self.releaseInventory) + { + self.releaseInventory = false; + self.ToggleInv(); // actually toggles the inventory + } + } + else + { + self.releaseInventory = true; + } + + return; + } + + // Vanilla logic + if (self.controlInv) + { + if (self.releaseInventory) + { + self.releaseInventory = false; + if (Main.ingameOptionsWindow) + { + IngameOptions.Close(); + } + else + { + IngameOptions.Open(); + } + } + } + else + { + self.releaseInventory = true; + } + } + + private void ModifyInterfaceLogic(On_Main.orig_DrawInterface_26_InterfaceLogic3 orig) + { + bool flag = Main.playerInventory; + if (Main.player[Main.myPlayer].dead) + { + //Main.playerInventory = false; // skip this + } + if (!Main.playerInventory) + { + Main.player[Main.myPlayer].chest = -1; + Main.InGuideCraftMenu = false; + Main.InReforgeMenu = false; + if (flag) + { + Recipe.FindRecipes(); + } + } + Main.hoverItemName = ""; + } +} diff --git a/Core/InventoryWhileDead/InventoryWhileUsingItemSystem.cs b/Core/InventoryWhileDead/InventoryWhileUsingItemSystem.cs new file mode 100644 index 00000000..b92116a0 --- /dev/null +++ b/Core/InventoryWhileDead/InventoryWhileUsingItemSystem.cs @@ -0,0 +1,61 @@ +//using MonoMod.RuntimeDetour; +//using PvPAdventure.Core.Helpers; +//using System; +//using System.Reflection; +//using Terraria; +//using Terraria.GameInput; +//using Terraria.ModLoader; +//using Terraria.UI; + +//namespace PvPAdventure.Core.InventoryWhileUsingItem; + +//internal class InventoryWhileUsingItemSystem : ModSystem +//{ +// private Hook ignoreMouseHook; +// private Hook leftClickHook; + +// public override void Load() +// { +// On_Main.DrawInterface_0_InterfaceLogic1 += ModifyInterface0; + +// // Mouse interface +// MethodInfo getter = typeof(PlayerInput).GetMethod( +// "get_IgnoreMouseInterface", +// BindingFlags.Public | BindingFlags.Static +// ); + +// if (getter == null) +// { +// Log.Error("Getter not found!"); +// return; +// } + +// ignoreMouseHook = new Hook(getter, (Func, bool>)OverrideIgnoreMouseInterface); +// } + +// //private bool OverrideIgnoreMouseInterface(Func orig) +// //{ + +// private void ModifyInterface0(On_Main.orig_DrawInterface_0_InterfaceLogic1 orig) +// { +// // do nothing +// } + +// public override void Unload() +// { +// On_Main.DrawInterface_0_InterfaceLogic1 -= ModifyInterface0; +// ignoreMouseHook?.Dispose(); +// } + +// private bool OverrideIgnoreMouseInterface(Func orig) +// { +// Player player = Main.LocalPlayer; + +// // Allow mouse to interact while using items +// if (player.itemAnimation > 0) +// return false; + +// // fallback to vanilla +// return orig(); +// } +//} diff --git a/Core/SpawnSelector/Players/AdventureMirrorPlayer.cs b/Core/SpawnSelector/Players/AdventureMirrorPlayer.cs index 3878404c..2fd68712 100644 --- a/Core/SpawnSelector/Players/AdventureMirrorPlayer.cs +++ b/Core/SpawnSelector/Players/AdventureMirrorPlayer.cs @@ -81,14 +81,6 @@ public bool IsPlayerInSpawnRegion() return false; } -#if DEBUG - public override void Kill(double damage, int hitDirection, bool pvp, PlayerDeathReason damageSource) - { - Player.respawnTimer = 0; - base.Kill(damage, hitDirection, pvp, damageSource); - } -#endif - public override void PostUpdate() { if (Main.dedServ) diff --git a/Core/SpawnSelector/Systems/ItemSlotHooks.cs b/Core/SpawnSelector/Systems/ItemSlotHooks.cs index 92cd76be..53d92783 100644 --- a/Core/SpawnSelector/Systems/ItemSlotHooks.cs +++ b/Core/SpawnSelector/Systems/ItemSlotHooks.cs @@ -1,7 +1,12 @@ -using Terraria; +using PvPAdventure.Content.Items; +using System; +using System.Linq; +using Terraria; +using Terraria.Audio; +using Terraria.DataStructures; +using Terraria.GameContent.Achievements; using Terraria.ModLoader; using Terraria.UI; -using PvPAdventure.Content.Items; namespace PvPAdventure.Core.SpawnSelector.Systems; @@ -14,6 +19,7 @@ public override void Load() { On_ItemSlot.LeftClick_SellOrTrash += Hook_LeftClick_SellOrTrash; On_ItemSlot.LeftClick_ItemArray_int_int += Hook_LeftClick_ItemArray; + On_ItemSlot.RightClick_ItemArray_int_int += Hook_RightClick; On_Player.SellItem += Hook_SellItem; On_Player.DropSelectedItem += Hook_DropSelectedItem; On_Player.dropItemCheck += Hook_DropItemCheck; @@ -28,6 +34,120 @@ public override void Unload() On_Player.dropItemCheck -= Hook_DropItemCheck; } + private static void Hook_RightClick( + On_ItemSlot.orig_RightClick_ItemArray_int_int orig, + Item[] inv, int context, int slot) + { + Player player = Main.player[Main.myPlayer]; + inv[slot].newAndShiny = false; + if (player.itemAnimation > 0 && player.HeldItem.type != ModContent.ItemType()) + { + return; + } + if (context == 15) + { + ItemSlot.HandleShopSlot(inv, slot, rightClickIsValid: true, leftClickIsValid: false); + } + else + { + if (!Main.mouseRight) + { + return; + } + if (context == 0 && Main.mouseRightRelease) + { + ItemSlot.TryItemSwap(inv[slot]); + } + if (context == 0 && ItemLoader.CanRightClick(inv[slot])) + { + if (Main.mouseRightRelease) + { + if (Main.ItemDropsDB.GetRulesForItemID(inv[slot].type).Any()) + { + ItemSlot.TryOpenContainer(inv[slot], player); + } + else + { + ItemLoader.RightClick(inv[slot], player); + } + } + return; + } + switch (Math.Abs(context)) + { + case 9: + case 11: + if (Main.mouseRightRelease) + { + ItemSlot.SwapVanityEquip(inv, context, slot, player); + } + break; + case 12: + case 25: + case 27: + case 33: + if (Main.mouseRightRelease) + { + ItemSlot.TryPickupDyeToCursor(context, inv, slot, player); + } + break; + case 0: + case 3: + case 4: + case 32: + if (inv[slot].maxStack == 1) + { + if (Main.mouseRightRelease) + { + ItemSlot.SwapEquip(inv, context, slot); + } + break; + } + goto default; + default: + { + if (Main.stackSplit > 1) + { + break; + } + bool flag = true; + bool flag2 = inv[slot].maxStack <= 1 && inv[slot].stack <= 1; + if (context == 0 && flag2) + { + flag = false; + } + if (context == 3 && flag2) + { + flag = false; + } + if (context == 4 && flag2) + { + flag = false; + } + if (context == 32 && flag2) + { + flag = false; + } + if (!flag) + { + break; + } + int num = Main.superFastStack + 1; + for (int i = 0; i < num; i++) + { + if (((Main.mouseItem.IsTheSameAs(inv[slot]) && ItemLoader.CanStack(Main.mouseItem, inv[slot])) || Main.mouseItem.type == 0) && (Main.mouseItem.stack < Main.mouseItem.maxStack || Main.mouseItem.type == 0)) + { + ItemSlot.PickupItemIntoMouse(inv, context, slot, player); + SoundEngine.PlaySound(12); + ItemSlot.RefreshStackSplitCooldown(); + } + } + break; + } + } + } + } + private void Hook_DropItemCheck(On_Player.orig_dropItemCheck orig, Player self) { // If the mouse is holding the Adventure Mirror, just block the drop. @@ -88,7 +208,7 @@ private static void Hook_LeftClick_ItemArray( if (isStorageSlot && isMirrorOnMouse) { //if (Main.mouseLeft && Main.mouseLeftRelease) - //PopupTextHelper.NewText("Cannot store Adventure Mirror!"); + //Main.NewText("Cannot store Adventure Mirror!"); // Do NOT call orig -> cancel the placement return; @@ -104,7 +224,312 @@ private static void Hook_LeftClick_ItemArray( } // Otherwise, normal behavior - orig(inv, context, slot); + //orig(inv, context, slot); + + // --- Normal behaviour --- + Player player = Main.player[Main.myPlayer]; + bool flag = Main.mouseLeftRelease && Main.mouseLeft; + if (flag) + { + if (ItemSlot.OverrideLeftClick(inv, context, slot)) + { + return; + } + inv[slot].newAndShiny = false; + if (ItemSlot.LeftClick_SellOrTrash(inv, context, slot) || player.itemAnimation != 0 || player.itemTime != 0) + { + // RETURN EARLY for all other items other than Adventure Mirror + // Meaning we allow ItemSlot use while AM is the held item. + if (player.HeldItem.type != ModContent.ItemType()) + { + return; + } + + } + } + int num = ItemSlot.PickItemMovementAction(inv, context, slot, Main.mouseItem); + if (num != 3 && !flag) + { + return; + } + switch (num) + { + case 0: + { + if (context == 6 && Main.mouseItem.type != 0) + { + inv[slot].SetDefaults(); + } + if ((ItemSlot.IsAccessoryContext(context) && !ItemLoader.CanEquipAccessory(inv[slot], slot, context < 0)) || (context == 11 && !inv[slot].FitsAccessoryVanitySlot) || (context < 0 && !LoaderManager.Get().CanAcceptItem(slot, inv[slot], context))) + { + break; + } + if (Main.mouseItem.maxStack <= 1 || inv[slot].type != Main.mouseItem.type || inv[slot].stack == inv[slot].maxStack || Main.mouseItem.stack == Main.mouseItem.maxStack) + { + Utils.Swap(ref inv[slot], ref Main.mouseItem); + } + if (inv[slot].stack > 0) + { + ItemSlot.AnnounceTransfer(new ItemSlot.ItemTransferInfo(inv[slot], 21, context, inv[slot].stack)); + } + else + { + ItemSlot.AnnounceTransfer(new ItemSlot.ItemTransferInfo(Main.mouseItem, context, 21, Main.mouseItem.stack)); + } + if (inv[slot].stack > 0) + { + switch (Math.Abs(context)) + { + case 0: + AchievementsHelper.NotifyItemPickup(player, inv[slot]); + break; + case 8: + case 9: + case 10: + case 11: + case 12: + case 16: + case 17: + case 25: + case 27: + case 33: + AchievementsHelper.HandleOnEquip(player, inv[slot], context); + break; + } + } + if (inv[slot].type == 0 || inv[slot].stack < 1) + { + inv[slot] = new Item(); + } + if (Main.mouseItem.IsTheSameAs(inv[slot]) && inv[slot].stack != inv[slot].maxStack && Main.mouseItem.stack != Main.mouseItem.maxStack && ItemLoader.TryStackItems(inv[slot], Main.mouseItem, out var numTransfered)) + { + ItemSlot.AnnounceTransfer(new ItemSlot.ItemTransferInfo(inv[slot], 21, context, numTransfered)); + } + if (Main.mouseItem.type == 0 || Main.mouseItem.stack < 1) + { + Main.mouseItem = new Item(); + } + if (Main.mouseItem.type > 0 || inv[slot].type > 0) + { + Recipe.FindRecipes(); + SoundEngine.PlaySound(7); + } + if (context == 3 && Main.netMode == 1) + { + NetMessage.SendData(32, -1, -1, null, player.chest, slot); + } + break; + } + case 1: + if (Main.mouseItem.stack == 1 && Main.mouseItem.type > 0 && inv[slot].type > 0 && inv[slot].IsNotTheSameAs(Main.mouseItem) && (context != 11 || Main.mouseItem.FitsAccessoryVanitySlot)) + { + if ((ItemSlot.IsAccessoryContext(context) && !ItemLoader.CanEquipAccessory(Main.mouseItem, slot, context < 0)) || (Math.Abs(context) == 11 && !Main.mouseItem.FitsAccessoryVanitySlot) || (context < 0 && !LoaderManager.Get().CanAcceptItem(slot, Main.mouseItem, context))) + { + break; + } + Utils.Swap(ref inv[slot], ref Main.mouseItem); + SoundEngine.PlaySound(7); + if (inv[slot].stack > 0) + { + switch (Math.Abs(context)) + { + case 0: + AchievementsHelper.NotifyItemPickup(player, inv[slot]); + break; + case 8: + case 9: + case 10: + case 11: + case 12: + case 16: + case 17: + case 25: + case 27: + case 33: + AchievementsHelper.HandleOnEquip(player, inv[slot], context); + break; + } + } + } + else if (Main.mouseItem.type == 0 && inv[slot].type > 0) + { + Utils.Swap(ref inv[slot], ref Main.mouseItem); + if (inv[slot].type == 0 || inv[slot].stack < 1) + { + inv[slot] = new Item(); + } + if (Main.mouseItem.type == 0 || Main.mouseItem.stack < 1) + { + Main.mouseItem = new Item(); + } + if (Main.mouseItem.type > 0 || inv[slot].type > 0) + { + Recipe.FindRecipes(); + SoundEngine.PlaySound(7); + } + } + else if (Main.mouseItem.type > 0 && inv[slot].type == 0 && (context != 11 || Main.mouseItem.FitsAccessoryVanitySlot)) + { + if ((ItemSlot.IsAccessoryContext(context) && !ItemLoader.CanEquipAccessory(Main.mouseItem, slot, context < 0)) || (Math.Abs(context) == 11 && !Main.mouseItem.FitsAccessoryVanitySlot) || (context < 0 && !LoaderManager.Get().CanAcceptItem(slot, Main.mouseItem, context))) + { + break; + } + inv[slot] = ItemLoader.TransferWithLimit(Main.mouseItem, 1); + Recipe.FindRecipes(); + SoundEngine.PlaySound(7); + if (inv[slot].stack > 0) + { + switch (Math.Abs(context)) + { + case 0: + AchievementsHelper.NotifyItemPickup(player, inv[slot]); + break; + case 8: + case 9: + case 10: + case 11: + case 12: + case 16: + case 17: + case 25: + case 27: + case 33: + AchievementsHelper.HandleOnEquip(player, inv[slot], context); + break; + } + } + } + if ((context == 23 || context == 24) && Main.netMode == 1) + { + NetMessage.SendData(121, -1, -1, null, Main.myPlayer, player.tileEntityAnchor.interactEntityID, slot); + } + if (context == 26 && Main.netMode == 1) + { + NetMessage.SendData(124, -1, -1, null, Main.myPlayer, player.tileEntityAnchor.interactEntityID, slot); + } + break; + case 2: + if (Main.mouseItem.stack == 1 && Main.mouseItem.dye > 0 && inv[slot].type > 0 && inv[slot].type != Main.mouseItem.type) + { + Utils.Swap(ref inv[slot], ref Main.mouseItem); + SoundEngine.PlaySound(7); + if (inv[slot].stack > 0) + { + switch (Math.Abs(context)) + { + case 0: + AchievementsHelper.NotifyItemPickup(player, inv[slot]); + break; + case 8: + case 9: + case 10: + case 11: + case 12: + case 16: + case 17: + case 25: + case 27: + case 33: + AchievementsHelper.HandleOnEquip(player, inv[slot], context); + break; + } + } + } + else if (Main.mouseItem.type == 0 && inv[slot].type > 0) + { + Utils.Swap(ref inv[slot], ref Main.mouseItem); + if (inv[slot].type == 0 || inv[slot].stack < 1) + { + inv[slot] = new Item(); + } + if (Main.mouseItem.type == 0 || Main.mouseItem.stack < 1) + { + Main.mouseItem = new Item(); + } + if (Main.mouseItem.type > 0 || inv[slot].type > 0) + { + Recipe.FindRecipes(); + SoundEngine.PlaySound(7); + } + } + else if (Main.mouseItem.dye > 0 && inv[slot].type == 0) + { + inv[slot] = ItemLoader.TransferWithLimit(Main.mouseItem, 1); + Recipe.FindRecipes(); + SoundEngine.PlaySound(7); + if (inv[slot].stack > 0) + { + switch (Math.Abs(context)) + { + case 0: + AchievementsHelper.NotifyItemPickup(player, inv[slot]); + break; + case 8: + case 9: + case 10: + case 11: + case 12: + case 16: + case 17: + case 25: + case 27: + case 33: + AchievementsHelper.HandleOnEquip(player, inv[slot], context); + break; + } + } + } + if (context == 25 && Main.netMode == 1) + { + NetMessage.SendData(121, -1, -1, null, Main.myPlayer, player.tileEntityAnchor.interactEntityID, slot, 1f); + } + if (context == 27 && Main.netMode == 1) + { + NetMessage.SendData(124, -1, -1, null, Main.myPlayer, player.tileEntityAnchor.interactEntityID, slot, 1f); + } + break; + case 3: + ItemSlot.HandleShopSlot(inv, slot, rightClickIsValid: false, leftClickIsValid: true); + break; + case 4: + if (PlayerLoader.CanSellItem(player, player.TalkNPC, inv, Main.mouseItem)) + { + Chest chest = Main.instance.shop[Main.npcShop]; + if (player.SellItem(Main.mouseItem)) + { + int soldItemIndex = chest.AddItemToShop(Main.mouseItem); + Main.mouseItem.SetDefaults(); + SoundEngine.PlaySound(18); + ItemSlot.AnnounceTransfer(new ItemSlot.ItemTransferInfo(inv[slot], 21, 15)); + PlayerLoader.PostSellItem(player, player.TalkNPC, chest.item, chest.item[soldItemIndex]); + } + else if (Main.mouseItem.value == 0) + { + int soldItemIndex2 = chest.AddItemToShop(Main.mouseItem); + Main.mouseItem.SetDefaults(); + SoundEngine.PlaySound(7); + ItemSlot.AnnounceTransfer(new ItemSlot.ItemTransferInfo(inv[slot], 21, 15)); + PlayerLoader.PostSellItem(player, player.TalkNPC, chest.item, chest.item[soldItemIndex2]); + } + Recipe.FindRecipes(); + Main.stackSplit = 9999; + } + break; + case 5: + if (Main.mouseItem.IsAir) + { + SoundEngine.PlaySound(7); + Main.mouseItem = inv[slot].Clone(); + Main.mouseItem.stack = Main.mouseItem.maxStack; + Main.mouseItem.OnCreated(new JourneyDuplicationItemCreationContext()); + ItemSlot.AnnounceTransfer(new ItemSlot.ItemTransferInfo(inv[slot], 29, 21)); + } + break; + } + if ((uint)context > 2u && context != 5 && context != 32) + { + inv[slot].favorited = false; + } } // SELLING TO NPCS diff --git a/Core/SpawnSelector/UI/SpawnSelectorCharacter.cs b/Core/SpawnSelector/UI/SpawnSelectorCharacter.cs index 5427db31..5305f365 100644 --- a/Core/SpawnSelector/UI/SpawnSelectorCharacter.cs +++ b/Core/SpawnSelector/UI/SpawnSelectorCharacter.cs @@ -11,6 +11,7 @@ using Terraria.ModLoader; using Terraria.UI; using Terraria.UI.Chat; +using tModPorter; namespace PvPAdventure.Core.SpawnSelector.UI { @@ -216,7 +217,9 @@ protected override void DrawSelf(SpriteBatch sb) //DrawArrow(player); // Draw player head if hovering - DrawPlayerHeadOnMap(player); + var config = ModContent.GetInstance(); + if (IsMouseHovering && !config.ShowPlayerIndicationWhenWhenHovering) + DrawPlayerHeadOnMap(player); // Draw player respawn timer if it exists string respawnTimeInSeconds = (player.respawnTimer / 60 + 1).ToString(); @@ -228,12 +231,7 @@ protected override void DrawSelf(SpriteBatch sb) private void DrawPlayerHeadOnMap(Player p) { - if (p == null || !p.active || p.dead) - return; - - var config = ModContent.GetInstance(); - if (!IsMouseHovering || !config.ShowPlayerIndicationWhenWhenHovering) - return; + Main.instance.MouseText("Teleport to " + p.name); diff --git a/Core/Spawnbox/PvPIcons.cs b/Core/Spawnbox/PvPIcons.cs new file mode 100644 index 00000000..6a19e54a --- /dev/null +++ b/Core/Spawnbox/PvPIcons.cs @@ -0,0 +1,127 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using PvPAdventure.Core.Helpers; +using PvPAdventure.System; +using System.Collections.Generic; +using Terraria; +using Terraria.ModLoader; +using Terraria.UI; + +namespace PvPAdventure.Core.Spawnbox; + +/// +/// Draws "PvP forbidden icons" above players when players are in the spawn region. +/// +[Autoload(Side = ModSide.Client)] +public class PvPIconDrawerLayer : ModSystem +{ + public override void PostUpdateEverything() + { + var gm = ModContent.GetInstance(); + var rm = ModContent.GetInstance(); + + // Iterate all players. + // Set the conditional PvP flag if player is in spawn box and the game is live. + for (int i = 0; i < Main.maxPlayers; i++) + { + Player p = Main.player[i]; + if (!p.active || p.dead) + continue; + + bool inRegion = rm.GetRegionContaining(p.Center.ToTileCoordinates()) != null; + bool isPlaying = gm.CurrentPhase == GameManager.Phase.Playing; + bool shouldDisablePvP = inRegion; + + var mp = p.GetModPlayer(); + if (mp.ShowPvPIcon != shouldDisablePvP) + { + mp.ShowPvPIcon = shouldDisablePvP; + } + } + } + public override void ModifyInterfaceLayers(List layers) + { + int index = layers.FindIndex(layer => layer.Name == "Vanilla: Interface Logic 1"); + if (index != -1) + layers.Insert(index + 1, new PvPIconLayer()); + } + + private sealed class PvPIconLayer : GameInterfaceLayer + { + public PvPIconLayer() + : base("PvPAdventure:PvPIconLayer", InterfaceScaleType.Game) + { + } + + protected override bool DrawSelf() + { + // Check playing status + var gm = ModContent.GetInstance(); + bool isPlaying = gm.CurrentPhase == GameManager.Phase.Playing; + + SpriteBatch sb = Main.spriteBatch; + int headOffset = 12; // distance above head + + // Setup assets + var pvpTex = Main.Assets.Request("Images/UI/PVP_0"); + //var cooldownTex = Main.Assets.Request("Images/CoolDown"); // old asset + var cooldownTex = Ass.Stop_Icon; + + float iconFullW = pvpTex.Value.Width; + float iconFullH = pvpTex.Value.Height; + float iconW = iconFullW / 4f; + float iconH = iconFullH / 6f; + + // Iterate players and draw PvP icon if + for (int i = 0; i < Main.maxPlayers; i++) + { + Player p = Main.player[i]; + if (!p.active || p.dead) + continue; + + // Skip self + //if (p.whoAmI == Main.myPlayer) + //continue; + + if (!p.GetModPlayer().ShowPvPIcon) + continue; + + Vector2 screenPos = p.Top + new Vector2(-iconW / 2f, -headOffset - iconH) - Main.screenPosition; + + Rectangle iconRect = new( + (int)screenPos.X, + (int)screenPos.Y, + (int)iconW, + (int)iconH + ); + + Rectangle iconSrc = pvpTex.Frame(4, 6, 2, p.team); + + // Draw PvP icon + sb.Draw(pvpTex.Value, iconRect, iconSrc, Color.White * 1f); + + float cooldownWidth = iconW; + float cooldownHeight = iconH; + + Rectangle cdRect = new( + (int)(screenPos.X + (iconW - cooldownWidth) * 0.5f), + (int)(screenPos.Y + (iconH - cooldownHeight) * 0.5f), + (int)cooldownWidth, + (int)cooldownHeight + ); + + // Draw cooldown icon + //if (isPlaying) + sb.Draw(cooldownTex.Value, cdRect, Color.White * 1f); + } + + return true; + } + } +} + +public class PvPIconPlayer : ModPlayer +{ + public bool ShowPvPIcon; +} + diff --git a/Core/Spawnbox/SpawnboxMap.cs b/Core/Spawnbox/SpawnboxMap.cs index 292ff360..ec088c24 100644 --- a/Core/Spawnbox/SpawnboxMap.cs +++ b/Core/Spawnbox/SpawnboxMap.cs @@ -2,11 +2,11 @@ using Microsoft.Xna.Framework.Graphics; using PvPAdventure.Core.SpawnSelector.Players; using PvPAdventure.System; +using ReLogic.Graphics; using Terraria; using Terraria.GameContent; using Terraria.Map; using Terraria.ModLoader; -using Terraria.WorldBuilding; using static PvPAdventure.System.RegionManager; namespace PvPAdventure.Core.Spawnbox; @@ -83,9 +83,40 @@ private static void DrawSpawnBoxOnFullscreenMap(ref MapOverlayDrawContext contex thickness = (int)(1 * Main.mapFullscreenScale); // match 1 pixel at scale 1 // top, bottom, left, right - Main.spriteBatch.Draw(pix, new Rectangle(x, y, w, thickness), col); - Main.spriteBatch.Draw(pix, new Rectangle(x, y + h - thickness, w, thickness), col); - Main.spriteBatch.Draw(pix, new Rectangle(x, y, thickness, h), col); - Main.spriteBatch.Draw(pix, new Rectangle(x + w - thickness, y, thickness, h), col); + Main.spriteBatch.Draw(pix,new Rectangle(x + thickness, y, w - thickness * 2, thickness),col); + Main.spriteBatch.Draw(pix,new Rectangle(x + thickness, y + h - thickness, w - thickness * 2, thickness),col); + Main.spriteBatch.Draw(pix,new Rectangle(x, y, thickness, h),col); + Main.spriteBatch.Draw(pix,new Rectangle(x + w - thickness, y, thickness, h),col); + + var font = FontAssets.DeathText.Value; + + float scale = context.MapScale * context.DrawScale*0.3f; + + Vector2 textSize = font.MeasureString("SPAWN") * scale; + + Vector2 textPos = new Vector2( + x + w / 2f - textSize.X / 2f, + y + h / 2f - textSize.Y / 2f + ); + textPos.Y -= 50*scale; + + // Helper to draw text + void drawSpawnText(Vector2 offset, Color c) + { + Main.spriteBatch.DrawString( + font, + "SPAWN", + textPos + offset, + c, + 0f, + Vector2.Zero, + scale, + SpriteEffects.None, + 0f + ); + } + + //drawSpawnText(new Vector2(2, 2) * scale, Color.Black * 0.75f); + //drawSpawnText(Vector2.Zero, Color.White); } } From 17b9adbe8fe966e65da0c34a53d0066db6f32742 Mon Sep 17 00:00:00 2001 From: emyhrberg <121192176+emyhrberg@users.noreply.github.com> Date: Tue, 2 Dec 2025 07:52:57 +0100 Subject: [PATCH 197/206] Fixed spawn selector teammate hover head position - Also fixed a small issue causing the teammate player character panel not to be deleted after a player left with a !player.active check in SpawnSelectorBasePanel --- Core/Debug/DebugPlayer.cs | 4 +- .../{UI => Systems}/BedsOnMap.cs | 52 +--- Core/SpawnSelector/Systems/ItemSlotHooks.cs | 3 + .../SpawnSelector/Systems/PlayerHeadsOnMap.cs | 66 +++++ .../Systems/SpawnSelectorSystem.cs | 3 + .../UI/SpawnSelectorBasePanel.cs | 240 +++++++++--------- .../UI/SpawnSelectorCharacter.cs | 106 ++------ Core/Spawnbox/PvPIcons.cs | 2 +- 8 files changed, 218 insertions(+), 258 deletions(-) rename Core/SpawnSelector/{UI => Systems}/BedsOnMap.cs (67%) create mode 100644 Core/SpawnSelector/Systems/PlayerHeadsOnMap.cs diff --git a/Core/Debug/DebugPlayer.cs b/Core/Debug/DebugPlayer.cs index 80d703cb..da45dd9f 100644 --- a/Core/Debug/DebugPlayer.cs +++ b/Core/Debug/DebugPlayer.cs @@ -9,8 +9,8 @@ internal class DebugPlayer : ModPlayer { public override void Kill(double damage, int hitDirection, bool pvp, PlayerDeathReason damageSource) { - //Player.respawnTimer = 120; // 2 seconds - Player.respawnTimer = 600; // 10 seconds + Player.respawnTimer = 120; // 2 seconds + //Player.respawnTimer = 600; // 10 seconds //Player.respawnTimer = 0; base.Kill(damage, hitDirection, pvp, damageSource); } diff --git a/Core/SpawnSelector/UI/BedsOnMap.cs b/Core/SpawnSelector/Systems/BedsOnMap.cs similarity index 67% rename from Core/SpawnSelector/UI/BedsOnMap.cs rename to Core/SpawnSelector/Systems/BedsOnMap.cs index 4b5815e9..92a335ce 100644 --- a/Core/SpawnSelector/UI/BedsOnMap.cs +++ b/Core/SpawnSelector/Systems/BedsOnMap.cs @@ -1,6 +1,5 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; -using PvPAdventure.Core.SpawnSelector.Systems; using ReLogic.Content; using Terraria; using Terraria.DataStructures; @@ -10,7 +9,7 @@ using Terraria.ModLoader; using Terraria.UI; -namespace PvPAdventure.Core.SpawnSelector.UI; +namespace PvPAdventure.Core.SpawnSelector.Systems; internal class BedsOnMap : ModSystem { @@ -34,7 +33,7 @@ public override void PostSetupContent() } } - private void OnSpawnMapLayer(On_SpawnMapLayer.orig_Draw orig,SpawnMapLayer self,ref MapOverlayDrawContext context, ref string text) + private void OnSpawnMapLayer(On_SpawnMapLayer.orig_Draw orig, SpawnMapLayer self, ref MapOverlayDrawContext context, ref string text) { // Let vanilla draw spawn point + local bed first orig(self, ref context, ref text); @@ -52,10 +51,6 @@ private void OnSpawnMapLayer(On_SpawnMapLayer.orig_Draw orig,SpawnMapLayer self, Vector2 bedTilePos = new(player.SpawnX, player.SpawnY); -#if DEBUG - DrawBedSpawnDebugRect(player, bedTilePos); -#endif - // Safety check and load texture if needed spawnBedTexture ??= TextureAssets.SpawnBed; @@ -112,51 +107,10 @@ private void OnSpawnMapLayer(On_SpawnMapLayer.orig_Draw orig,SpawnMapLayer self, #endif } } - + } } } } - -#if DEBUG - private static void DrawBedSpawnDebugRect(Player player, Vector2 bedTilePos) - { - if (!Main.mapFullscreen) - { - return; - } - - // World-space center of the bed (pixels) - Vector2 bedWorld = bedTilePos * 16f; - - // Convert world -> fullscreen map screen coordinates - Vector2 screenCenter = new(Main.screenWidth / 2f, Main.screenHeight / 2f); - Vector2 bedOnMap = (bedWorld - Main.mapFullscreenPos) * Main.mapFullscreenScale + screenCenter; - - float radiusWorld = 25 * 16f; // 25 tiles in world space - float radiusOnMap = radiusWorld * Main.mapFullscreenScale; - - Texture2D pixel = TextureAssets.MagicPixel.Value; - float thickness = 2f; - - Rectangle rect = new( - (int)(bedOnMap.X - radiusOnMap), - (int)(bedOnMap.Y - radiusOnMap), - (int)(radiusOnMap * 2f), - (int)(radiusOnMap * 2f) - ); - - Color color = Main.teamColor[player.team] * 0.75f; - - // Top - Main.spriteBatch.Draw(pixel, new Rectangle(rect.Left, rect.Top, rect.Width, (int)thickness), color); - // Bottom - Main.spriteBatch.Draw(pixel, new Rectangle(rect.Left, rect.Bottom - (int)thickness, rect.Width, (int)thickness), color); - // Left - Main.spriteBatch.Draw(pixel, new Rectangle(rect.Left, rect.Top, (int)thickness, rect.Height), color); - // Right - Main.spriteBatch.Draw(pixel, new Rectangle(rect.Right - (int)thickness, rect.Top, (int)thickness, rect.Height), color); - } -#endif } diff --git a/Core/SpawnSelector/Systems/ItemSlotHooks.cs b/Core/SpawnSelector/Systems/ItemSlotHooks.cs index 53d92783..1f39693a 100644 --- a/Core/SpawnSelector/Systems/ItemSlotHooks.cs +++ b/Core/SpawnSelector/Systems/ItemSlotHooks.cs @@ -12,6 +12,7 @@ namespace PvPAdventure.Core.SpawnSelector.Systems; /// /// Prevents the Adventure Mirror from being removed from the player inventory via trashing or selling. +/// Various inventory hooks are used to achieve this. /// public class ItemSlotHooks : ModSystem { @@ -34,6 +35,7 @@ public override void Unload() On_Player.dropItemCheck -= Hook_DropItemCheck; } + // Vanilla method with the item animation check removed for Adventure Mirror. private static void Hook_RightClick( On_ItemSlot.orig_RightClick_ItemArray_int_int orig, Item[] inv, int context, int slot) @@ -193,6 +195,7 @@ private static bool Hook_LeftClick_SellOrTrash( private static bool IsAdventureMirror(Item item) => !item.IsAir && item.type == ModContent.ItemType(); + // Vanilla method with the item animation check removed for Adventure Mirror. // DRAGGING ONTO THE TRASH SLOT / CHESTS / BANKS private static void Hook_LeftClick_ItemArray( On_ItemSlot.orig_LeftClick_ItemArray_int_int orig, diff --git a/Core/SpawnSelector/Systems/PlayerHeadsOnMap.cs b/Core/SpawnSelector/Systems/PlayerHeadsOnMap.cs new file mode 100644 index 00000000..1e639e43 --- /dev/null +++ b/Core/SpawnSelector/Systems/PlayerHeadsOnMap.cs @@ -0,0 +1,66 @@ +using Microsoft.Xna.Framework; +using Terraria; +using Terraria.GameContent; +using Terraria.ModLoader; + +namespace PvPAdventure.Core.SpawnSelector.Systems; + +/// +/// Draws the selected player heads on map when highlighting the UI element for the player +/// +internal class PlayerHeadsOnMap : ModSystem +{ + public override void Load() + { + Main.OnPostFullscreenMapDraw += DrawHighlightedPlayerOnMap; + } + + public override void Unload() + { + Main.OnPostFullscreenMapDraw -= DrawHighlightedPlayerOnMap; + } + + private void DrawHighlightedPlayerOnMap(Vector2 mapOffset, float mapScale) + { + if (!Main.mapFullscreen) return; + + int idx = SpawnSelectorSystem.HoveredPlayerIndex; + if (idx < 0 || idx >= Main.maxPlayers) return; + + Player player = Main.player[idx]; + if (player == null || !player.active || player.dead) return; + + float tileX = (player.position.X + player.width * 0.5f) / 16f; + float tileY = (player.position.Y + player.gfxOffY + player.height * 0.5f) / 16f; + + float x = tileX * mapScale + mapOffset.X; + float y = tileY * mapScale + mapOffset.Y; + + x -= 7f; + y -= 3f; + //y -= 2f - mapScale / 5f * 2f; + //x -= 10f * mapScale; + //y -= 10f * mapScale; + + Vector2 headPos = new Vector2(x, y); + + float alpha = 1f; + float scale = 1.6f*Main.UIScale; + if (Main.UIScale > 1.5) + scale = 1.6f * Main.UIScale * 0.9f; + Color border = Main.GetPlayerHeadBordersColor(player); + + Main.spriteBatch.Begin(); + + // Draw player head + Main.MapPlayerRenderer.DrawPlayerHead(Main.Camera, player, headPos, alpha, scale, border); + + // Draw teleport to player text + string name = player.name; + Vector2 size = FontAssets.MouseText.Value.MeasureString(name); + Vector2 pos = headPos + new Vector2(-size.X * 0.5f+7*Main.UIScale, 30f*Main.UIScale); + Utils.DrawBorderString(Main.spriteBatch, name, pos, Color.White, 1f*Main.UIScale); + + Main.spriteBatch.End(); + } +} diff --git a/Core/SpawnSelector/Systems/SpawnSelectorSystem.cs b/Core/SpawnSelector/Systems/SpawnSelectorSystem.cs index 2f62726f..93aea42a 100644 --- a/Core/SpawnSelector/Systems/SpawnSelectorSystem.cs +++ b/Core/SpawnSelector/Systems/SpawnSelectorSystem.cs @@ -17,6 +17,9 @@ public class SpawnSelectorSystem : ModSystem public static void SetEnabled(bool newValue) => Enabled = newValue; public static bool GetEnabled() => Enabled; + // Hovering players + internal static int HoveredPlayerIndex = -1; + public override void Load() { if (!Main.dedServ) diff --git a/Core/SpawnSelector/UI/SpawnSelectorBasePanel.cs b/Core/SpawnSelector/UI/SpawnSelectorBasePanel.cs index 9d2d4a08..58e7a44b 100644 --- a/Core/SpawnSelector/UI/SpawnSelectorBasePanel.cs +++ b/Core/SpawnSelector/UI/SpawnSelectorBasePanel.cs @@ -5,173 +5,173 @@ using Terraria; using Terraria.GameContent.UI.Elements; -namespace PvPAdventure.Core.SpawnSelector.UI +namespace PvPAdventure.Core.SpawnSelector.UI; + +// +public class SpawnSelectorBasePanel : UIPanel { - public class SpawnSelectorBasePanel : UIPanel - { - private UIPanel _randomPanel; - private readonly List _playerItems = new(); + private UIPanel _randomPanel; + private readonly List _playerItems = new(); - private const float Spacing = 8f; - private const float HorizontalPadding = 16f; - private const float VerticalPadding = 12f; + private const float Spacing = 8f; + private const float HorizontalPadding = 16f; + private const float VerticalPadding = 12f; - public override void OnInitialize() - { - HAlign = 0.5f; - VAlign = 0.0f; - Top.Set(52, 0); + public override void OnInitialize() + { + HAlign = 0.5f; + VAlign = 0.0f; + Top.Set(52, 0); - BackgroundColor = new Color(33, 43, 79) * 0.8f; - SetPadding(0f); + BackgroundColor = new Color(33, 43, 79) * 0.8f; + SetPadding(0f); - BuildLayout(); - } + BuildLayout(); + } - private void BuildLayout() - { - RemoveAllChildren(); - _playerItems.Clear(); + private void BuildLayout() + { + RemoveAllChildren(); + _playerItems.Clear(); - var players = new List(); - var local = Main.LocalPlayer; + var players = new List(); + var local = Main.LocalPlayer; - if (local.team != 0) + if (local.team != 0) + { + for (int i = 0; i < Main.maxPlayers; i++) { - for (int i = 0; i < Main.maxPlayers; i++) - { - Player p = Main.player[i]; + Player p = Main.player[i]; - if (p == null) - continue; + if (p == null) + continue; - if (p.whoAmI == local.whoAmI || p.team != local.team) - continue; + if (p.whoAmI == local.whoAmI || p.team != local.team) + continue; - players.Add(p); - } + players.Add(p); } + } //#if DEBUG -// players.Add(Main.LocalPlayer); -// Main.NewText($"[DEBUG] Added local player '{Main.LocalPlayer.name}' to SpawnSelectorBasePanel"); +// players.Add(Main.LocalPlayer); +// Main.NewText($"[DEBUG] Added local player '{Main.LocalPlayer.name}' to SpawnSelectorBasePanel"); //#endif - int playerCount = players.Count; + int playerCount = players.Count; - float itemWidth = SpawnSelectorCharacter.ItemWidth; - float itemHeight = SpawnSelectorCharacter.ItemHeight; - float randomWidth = itemHeight; + float itemWidth = SpawnSelectorCharacter.ItemWidth; + float itemHeight = SpawnSelectorCharacter.ItemHeight; + float randomWidth = itemHeight; - float contentWidth = playerCount * itemWidth - + playerCount * Spacing - + randomWidth; + float contentWidth = playerCount * itemWidth + + playerCount * Spacing + + randomWidth; - float panelWidth = contentWidth + HorizontalPadding * 2f; - float panelHeight = itemHeight + VerticalPadding * 2f; + float panelWidth = contentWidth + HorizontalPadding * 2f; + float panelHeight = itemHeight + VerticalPadding * 2f; - if (panelWidth <= 0f) - panelWidth = itemWidth + HorizontalPadding * 2f; + if (panelWidth <= 0f) + panelWidth = itemWidth + HorizontalPadding * 2f; - if (panelHeight <= 0f) - panelHeight = itemHeight + VerticalPadding * 2f; + if (panelHeight <= 0f) + panelHeight = itemHeight + VerticalPadding * 2f; - Width.Set(panelWidth, 0f); - Height.Set(panelHeight, 0f); + Width.Set(panelWidth, 0f); + Height.Set(panelHeight, 0f); - float startX = HorizontalPadding; - float y = VerticalPadding; + float startX = HorizontalPadding; + float y = VerticalPadding; - for (int i = 0; i < playerCount; i++) - { - float x = startX + i * (itemWidth + Spacing); + for (int i = 0; i < playerCount; i++) + { + float x = startX + i * (itemWidth + Spacing); - var row = new SpawnSelectorCharacter(players[i]); - row.Left.Set(x, 0f); - row.Top.Set(y, 0f); + var row = new SpawnSelectorCharacter(players[i]); + row.Left.Set(x, 0f); + row.Top.Set(y, 0f); - Append(row); - _playerItems.Add(row); - } + Append(row); + _playerItems.Add(row); + } - _randomPanel = new SpawnSelectorQuestionMark( - startX, - itemHeight, - playerCount, - itemWidth, - Spacing, - y - ); - Append(_randomPanel); + _randomPanel = new SpawnSelectorQuestionMark( + startX, + itemHeight, + playerCount, + itemWidth, + Spacing, + y + ); + Append(_randomPanel); - Recalculate(); - RecalculateChildren(); + Recalculate(); + RecalculateChildren(); - Log.Debug($"UISpawnSelectorPanel.BuildLayout: players={playerCount}"); - } + Log.Debug($"UISpawnSelectorPanel.BuildLayout: players={playerCount}"); + } - public void Rebuild() - { - BuildLayout(); - } + public void Rebuild() + { + BuildLayout(); + } - public override void Update(GameTime gameTime) + public override void Update(GameTime gameTime) + { + if (NeedsRebuild()) { - if (NeedsRebuild()) - { - Rebuild(); - } - - base.Update(gameTime); + Rebuild(); } - public override void Draw(SpriteBatch spriteBatch) - { - base.Draw(spriteBatch); - } + base.Update(gameTime); + } - private bool NeedsRebuild() - { - var dims = GetDimensions(); - if (dims.Width <= 0f || dims.Height <= 0f) - return true; + public override void Draw(SpriteBatch spriteBatch) + { + base.Draw(spriteBatch); + } - if (_randomPanel == null) - return true; + private bool NeedsRebuild() + { + var dims = GetDimensions(); + if (dims.Width <= 0f || dims.Height <= 0f) + return true; - var randomDims = _randomPanel.GetDimensions(); - if (randomDims.Width <= 0f || randomDims.Height <= 0f) - return true; + if (_randomPanel == null) + return true; - var local = Main.LocalPlayer; - var players = new List(); + var randomDims = _randomPanel.GetDimensions(); + if (randomDims.Width <= 0f || randomDims.Height <= 0f) + return true; - for (int i = 0; i < Main.maxPlayers; i++) - { - var p = Main.player[i]; - if (p == null) - continue; - if (p.whoAmI == local.whoAmI || p.team != local.team) - continue; + var local = Main.LocalPlayer; + var players = new List(); - players.Add(p.whoAmI); - } + for (int i = 0; i < Main.maxPlayers; i++) + { + var p = Main.player[i]; + if (p == null || !p.active) + continue; + if (p.whoAmI == local.whoAmI || p.team != local.team) + continue; + + players.Add(p.whoAmI); + } //#if DEBUG -// players.Add(local.whoAmI); +// players.Add(local.whoAmI); //#endif - if (players.Count != _playerItems.Count) - return true; - - for (int i = 0; i < players.Count; i++) - { - if (_playerItems[i] == null) return true; - if (_playerItems[i].PlayerIndex != players[i]) return true; - } + if (players.Count != _playerItems.Count) + return true; - return false; + for (int i = 0; i < players.Count; i++) + { + if (_playerItems[i] == null) return true; + if (_playerItems[i].PlayerIndex != players[i]) return true; } + return false; } + } diff --git a/Core/SpawnSelector/UI/SpawnSelectorCharacter.cs b/Core/SpawnSelector/UI/SpawnSelectorCharacter.cs index 5305f365..4abc28a2 100644 --- a/Core/SpawnSelector/UI/SpawnSelectorCharacter.cs +++ b/Core/SpawnSelector/UI/SpawnSelectorCharacter.cs @@ -2,6 +2,7 @@ using Microsoft.Xna.Framework.Graphics; using PvPAdventure.Core.Helpers; using PvPAdventure.Core.SpawnSelector.Players; +using PvPAdventure.Core.SpawnSelector.Systems; using ReLogic.Content; using System; using Terraria; @@ -9,9 +10,8 @@ using Terraria.GameContent.UI.Elements; using Terraria.ID; using Terraria.ModLoader; +using Terraria.ModLoader.UI; using Terraria.UI; -using Terraria.UI.Chat; -using tModPorter; namespace PvPAdventure.Core.SpawnSelector.UI { @@ -92,8 +92,8 @@ protected override void DrawSelf(SpriteBatch sb) //sb.Draw(_playerBGTexture.Value, pos, Color.White*0.5f); Rectangle rect = new( - x: (int)pos.X-6, - y: (int)pos.Y-6, + x: (int)pos.X - 6, + y: (int)pos.Y - 6, width: 100, height: 72); @@ -102,15 +102,6 @@ protected override void DrawSelf(SpriteBatch sb) DrawNineSlice(sb, rect.X, rect.Y, rect.Width, rect.Height, _playerBGTexture.Value, Color.White, 5); DrawMapFullscreenBackground(sb, rect, player); - sb.End(); - sb.Begin(SpriteSortMode.Deferred, - BlendState.AlphaBlend, - SamplerState.PointClamp, - DepthStencilState.Default, - RasterizerState.CullNone, - null, - Main.UIScaleMatrix); - AdventureMirrorPlayer.ForceFullBrightOnce = true; try { @@ -131,16 +122,6 @@ protected override void DrawSelf(SpriteBatch sb) AdventureMirrorPlayer.ForceFullBrightOnce = false; } - // Switch back to "normal" UI batch - sb.End(); - sb.Begin(SpriteSortMode.Deferred, - BlendState.AlphaBlend, - SamplerState.LinearClamp, - DepthStencilState.None, - RasterizerState.CullCounterClockwise, - null, - Main.UIScaleMatrix); - // Use the actual layout widths, not the texture width const float leftColumnWidth = 106f; // player background column const float rightAreaWidth = ItemWidth - 22f - leftColumnWidth; // 260 - 12 - 106 = 142 @@ -160,28 +141,18 @@ protected override void DrawSelf(SpriteBatch sb) ); // Draw name - Utils.DrawBorderString(sb,name,namePos,Color.White,nameScale); + Utils.DrawBorderString(sb, name, namePos, Color.White, nameScale); // Draw divider - sb.Draw( - _dividerTexture.Value, - new Vector2(rightAreaLeft-12, inner.Y + 21f), - null, - Color.White, - 0f, - Vector2.Zero, - new Vector2(rightAreaWidth/8+2.2f, 1f), - SpriteEffects.None, - 0f - ); + sb.Draw(_dividerTexture.Value, new Vector2(rightAreaLeft - 12, inner.Y + 21f), null, Color.White, 0f, Vector2.Zero, new Vector2(rightAreaWidth / 8 + 2.2f, 1f), SpriteEffects.None, 0f); // Stat panel settings float statScale = 0.88f; float statGap = 5f * statScale; // Draw stat panel - float panelWidth = rightAreaWidth+24; - Vector2 panelPos = new(rightAreaLeft-14, inner.Y + 29f); + float panelWidth = rightAreaWidth + 24; + Vector2 panelPos = new(rightAreaLeft - 14, inner.Y + 29f); DrawPanel(sb, panelPos, panelWidth); string hpText = $"{player.statLife} HP"; @@ -204,22 +175,14 @@ protected override void DrawSelf(SpriteBatch sb) // Draw health sb.Draw(heart.Value, new Vector2(startX, y), null, Color.White, 0f, Vector2.Zero, statScale, SpriteEffects.None, 0f); startX += heartW; - Utils.DrawBorderString(sb, hpText, new Vector2(startX+1, y + 1f), Color.White, statScale); + Utils.DrawBorderString(sb, hpText, new Vector2(startX + 1, y + 1f), Color.White, statScale); startX += hpSize.X; startX += statGap; // Draw mana sb.Draw(mana.Value, new Vector2(startX, y - 2), null, Color.White, 0f, Vector2.Zero, statScale, SpriteEffects.None, 0f); startX += manaW; - Utils.DrawBorderString(sb, mpText, new Vector2(startX+1, y + 1f), Color.White, statScale); - - // Draw arrow - //DrawArrow(player); - - // Draw player head if hovering - var config = ModContent.GetInstance(); - if (IsMouseHovering && !config.ShowPlayerIndicationWhenWhenHovering) - DrawPlayerHeadOnMap(player); + Utils.DrawBorderString(sb, mpText, new Vector2(startX + 1, y + 1f), Color.White, statScale); // Draw player respawn timer if it exists string respawnTimeInSeconds = (player.respawnTimer / 60 + 1).ToString(); @@ -227,45 +190,12 @@ protected override void DrawSelf(SpriteBatch sb) { Utils.DrawBorderStringBig(sb, respawnTimeInSeconds, pos + new Vector2(31, 4), Color.Gray, scale: 1f); } - } - - private void DrawPlayerHeadOnMap(Player p) - { - - Main.instance.MouseText("Teleport to " + p.name); - - float mapScale = Main.mapFullscreenScale; - - // Player in tile coords - Vector2 tilePos = p.Center / 16f; - - // Screen-space position on the fullscreen map (pixels) - Vector2 mapScreenCenter = new( - Main.screenWidth / 2f, - Main.screenHeight / 2f - ); - Vector2 headPosScreen = (tilePos - Main.mapFullscreenPos) * mapScale + mapScreenCenter; - //headPosScreen += new Vector2(80, 40); // offset - headPosScreen *= Main.UIScale; - - Matrix invUi = Matrix.Invert(Main.UIScaleMatrix); - Vector2 headPosUI = Vector2.Transform(headPosScreen, invUi); - - Color c = Main.teamColor[p.team]; - - // Draw head in UI-space - Main.MapPlayerRenderer.DrawPlayerHead(Main.Camera, p, headPosUI, scale: 1.3f, borderColor: c); - - // Text centered below head, also in UI-space - string name = p.name ?? string.Empty; - float textScale = 1f; - Vector2 nameSize = FontAssets.MouseText.Value.MeasureString(name) * textScale; - Vector2 namePos = new( - headPosUI.X - nameSize.X * 0.5f, - headPosUI.Y + 30f - ); - Utils.DrawBorderString(Main.spriteBatch, "Teleport to " + name, namePos, Color.White, textScale); + // Draw teleport to if it exists + if (!player.dead && IsMouseHovering) + { + Main.instance.MouseText("Teleport to " + player.name); + } } public override void MouseOver(UIMouseEvent evt) @@ -276,6 +206,7 @@ public override void MouseOver(UIMouseEvent evt) if (p == null || !p.active || p.dead) return; BackgroundColor = new Color(73, 92, 161, 150); + SpawnSelectorSystem.HoveredPlayerIndex = _playerIndex; } public override void MouseOut(UIMouseEvent evt) @@ -287,6 +218,8 @@ public override void MouseOut(UIMouseEvent evt) return; BackgroundColor = new Color(63, 82, 151) * 0.8f; + if (SpawnSelectorSystem.HoveredPlayerIndex == _playerIndex) + SpawnSelectorSystem.HoveredPlayerIndex = -1; } public override void LeftClick(UIMouseEvent evt) @@ -334,7 +267,7 @@ private void DrawPanel(SpriteBatch spriteBatch, Vector2 position, float width) ); } - + [Obsolete("Doesn't work in MP. Use the new method instead.")] public static void DrawMapFullscreenBackground_BadMP(SpriteBatch sb, Rectangle rect, Player player) { if (player == null || !player.active) @@ -420,6 +353,7 @@ public static void DrawMapFullscreenBackground_BadMP(SpriteBatch sb, Rectangle r sb.Draw(asset.Value, rect, color); } + // Finds the biome of the given player and draws it. public static void DrawMapFullscreenBackground(SpriteBatch sb, Rectangle rect, Player player) { if (player == null || !player.active) diff --git a/Core/Spawnbox/PvPIcons.cs b/Core/Spawnbox/PvPIcons.cs index 6a19e54a..2ae534a3 100644 --- a/Core/Spawnbox/PvPIcons.cs +++ b/Core/Spawnbox/PvPIcons.cs @@ -10,7 +10,7 @@ namespace PvPAdventure.Core.Spawnbox; /// -/// Draws "PvP forbidden icons" above players when players are in the spawn region. +/// Draws PvP icons above players when players are in the spawn region. /// [Autoload(Side = ModSide.Client)] public class PvPIconDrawerLayer : ModSystem From 19ff08ca8288cfc4602759fe75b3bf124d62c7b7 Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Wed, 3 Dec 2025 15:58:34 -0800 Subject: [PATCH 198/206] Hoo boy --- AdventureDropDatabase.cs | 71 +++++++++++++++++---------- AdventureItem.cs | 22 ++++++++- AdventurePlayer.cs | 101 +++++++++++++++++++++++++++++++++++++++ System/RecipeManager.cs | 5 +- 4 files changed, 170 insertions(+), 29 deletions(-) diff --git a/AdventureDropDatabase.cs b/AdventureDropDatabase.cs index 34f971ee..bbe9169d 100644 --- a/AdventureDropDatabase.cs +++ b/AdventureDropDatabase.cs @@ -11,6 +11,7 @@ using static PvPAdventure.System.BountyManager; using static PvPAdventure.AdventureConfig; using PvPAdventure.System; +using System.Collections.Generic; namespace PvPAdventure; @@ -222,13 +223,13 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) npcLoot.RemoveWhere(drop => (drop is CommonDrop commonDrop && commonDrop.itemId == ItemID.MagicQuiver) || drop is LeadingConditionRule); - npcLoot.Add(ItemDropRule.Common(ItemID.MagicQuiver, 10)); + npcLoot.Add(ItemDropRule.Common(ItemID.MagicQuiver, 10)); break; case NPCID.RedDevil: foreach (var drop in drops) ModifyDropRate(drop, ItemID.UnholyTrident, 1, 10); - npcLoot.Add(ItemDropRule.Common(ItemID.FireFeather, 10, 1, 1)); + npcLoot.Add(ItemDropRule.Common(ItemID.FireFeather, 10, 1, 1)); break; @@ -313,10 +314,10 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) foreach (var drop in drops) { - ModifyDropRate(drop, ItemID.Cutlass, 1, 10); - ModifyDropRate(drop, ItemID.GoldRing, 1, 10); + ModifyDropRate(drop, ItemID.Cutlass, 1, 10); + ModifyDropRate(drop, ItemID.GoldRing, 1, 10); } - break; + break; case NPCID.EyeofCthulhu: foreach (var drop in drops) @@ -324,10 +325,10 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) break; case NPCID.DungeonSpirit: - npcLoot.RemoveWhere(drop => - (drop is CommonDrop commonDrop && commonDrop.itemId == ItemID.Ectoplasm) || - drop is LeadingConditionRule); - npcLoot.Add(ItemDropRule.Common(ItemID.Ectoplasm, 1, 3, 5)); + npcLoot.RemoveWhere(drop => + (drop is CommonDrop commonDrop && commonDrop.itemId == ItemID.Ectoplasm) || + drop is LeadingConditionRule); + npcLoot.Add(ItemDropRule.Common(ItemID.Ectoplasm, 1, 3, 5)); break; case NPCID.KingSlime: @@ -409,6 +410,35 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) ); break; + case NPCID.BigMimicHallow: + npcLoot.RemoveWhere(drop => true); // Removes all drops + npcLoot.Add(ItemDropRule.Common(ItemID.IlluminantHook, 4, 1, 1)); + npcLoot.Add(ItemDropRule.Common(ItemID.GoldCoin, 1, 10, 25)); + npcLoot.Add(ItemDropRule.Common(ItemID.GreaterHealingPotion, 1, 20, 30)); + npcLoot.Add(ItemDropRule.Common(ItemID.GreaterManaPotion, 1, 75, 150)); + + npcLoot.Add(ItemDropRule.OneFromOptions(1, + ItemID.DaedalusStormbow, + ItemID.CrystalVileShard, + ItemID.FlyingKnife + )); + break; + case NPCID.BigMimicCorruption: + npcLoot.RemoveWhere(drop => true); // Removes all drops + npcLoot.Add(ItemDropRule.Common(ItemID.GoldCoin, 1, 10, 25)); + npcLoot.Add(ItemDropRule.Common(ItemID.GreaterHealingPotion, 1, 20, 30)); + npcLoot.Add(ItemDropRule.Common(ItemID.GreaterManaPotion, 1, 75, 150)); + npcLoot.Add(ItemDropRule.OneFromOptions(1, + ItemID.ClingerStaff, + ItemID.DartRifle, + ItemID.ChainGuillotines + )); + npcLoot.Add(ItemDropRule.OneFromOptionsWithNumerator(5, 2, + ItemID.PutridScent, + ItemID.WormHook + )); + break; + case NPCID.SkeletronHead: npcLoot.Add(ItemDropRule.Common(ItemID.GoldenKey, 1, 3, 3)); npcLoot.Add(ItemDropRule.Common(ItemID.Marrow, 1000, 1000, 1000)); @@ -544,9 +574,7 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) break; case NPCID.Plantera: - npcLoot.RemoveWhere(drop => - (drop is CommonDrop commonDrop && commonDrop.itemId == ItemID.PygmyStaff) || - drop is LeadingConditionRule); + npcLoot.RemoveWhere(drop => drop is LeadingConditionRule); npcLoot.Add(ItemDropRule.Common(ItemID.TempleKey, 1, 1, 1)); npcLoot.Add( new OneFromRulesRule(1, @@ -556,21 +584,16 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) ItemDropRule.Common(ItemID.PygmyStaff) ) ); - var plantFirstKillRule = new LeadingConditionRule(new FirstBossKillCondition(NPCID.Plantera)); - plantFirstKillRule.OnSuccess(ItemDropRule.Common(ItemID.VenusMagnum, 1)); - var grenadelauncher = ItemDropRule.Common(ItemID.GrenadeLauncher); grenadelauncher.OnSuccess(ItemDropRule.Common(ItemID.RocketIII, 1, 400, 500), hideLootReport: true); - - var afterFirstKill = new OneFromRulesRule(1, - grenadelauncher, - ItemDropRule.Common(ItemID.NettleBurst), - ItemDropRule.Common(ItemID.FlowerPow), - ItemDropRule.Common(ItemID.VenusMagnum) + npcLoot.Add( + new OneFromRulesRule(1, + grenadelauncher, + ItemDropRule.Common(ItemID.NettleBurst), + ItemDropRule.Common(ItemID.FlowerPow), + ItemDropRule.Common(ItemID.VenusMagnum) + ) ); - - plantFirstKillRule.OnFailedConditions(afterFirstKill); - npcLoot.Add(plantFirstKillRule); break; } } diff --git a/AdventureItem.cs b/AdventureItem.cs index 8a9d6a6e..6d81d0b7 100644 --- a/AdventureItem.cs +++ b/AdventureItem.cs @@ -32,6 +32,10 @@ public override void SetDefaults(Item item) item.rare = ItemRarityID.Yellow; } + if (item.type == ItemID.ShadowKey) + { + item.maxStack = 9999; + } if (RecallItems[item.type]) { @@ -560,7 +564,23 @@ public override void ModifyTooltips(Item item, List tooltips) OverrideColor = new Color(255, 100, 100) }); } - if (item.type == ItemID.LunarCraftingStation) + if (item.type == ItemID.ShadowKey) + { + for (int i = 0; i < tooltips.Count; i++) + { + if (tooltips[i].Text.Contains("Opens all Shadow Chests and Obsidian Lock Boxes") || + tooltips[i].Text.Contains("all")) + { + tooltips[i].Text = "Opens Shadow Chests and Obsidian Lock Boxes"; + break; + } + } + tooltips.Add(new TooltipLine(Mod, "ShadowKey", "Only opens a single Shadow Chest") + { + OverrideColor = new Color(255, 100, 100) + }); + } + if (item.type == ItemID.LunarCraftingStation) { tooltips.Add(new TooltipLine(Mod, "AllCraftTiles", "Counts as all crafting stations")); } diff --git a/AdventurePlayer.cs b/AdventurePlayer.cs index 3bf5f119..5763b7ef 100644 --- a/AdventurePlayer.cs +++ b/AdventurePlayer.cs @@ -2468,6 +2468,7 @@ public override void OnRespawn() } } } + public class ShinyStoneHotswap : ModBuff { public override string Texture => $"PvPAdventure/Assets/Buff/ShinyStoneHotswap"; @@ -2504,7 +2505,107 @@ public override void SetStaticDefaults() } } +public class ConsumableShadowKeyPlayer : ModPlayer +{ + private Dictionary trackedLockedChests = new Dictionary(); + + public override void PostUpdate() + { + // Only track and consume on the client that owns this player + if (Player.whoAmI != Main.myPlayer) + return; + + // Scan every frame for consistency + int scanRange = 10; + int playerTileX = (int)(Player.Center.X / 16); + int playerTileY = (int)(Player.Center.Y / 16); + + HashSet foundLockedChests = new HashSet(); + + for (int i = playerTileX - scanRange; i < playerTileX + scanRange; i++) + { + for (int j = playerTileY - scanRange; j < playerTileY + scanRange; j++) + { + if (!WorldGen.InWorld(i, j)) + continue; + + Tile tile = Main.tile[i, j]; + + if (tile != null && tile.TileType == TileID.Containers) + { + int left = i - (tile.TileFrameX % 36) / 18; + int top = j - (tile.TileFrameY % 36) / 18; + Point chestPos = new Point(left, top); + + if (foundLockedChests.Contains(chestPos)) + continue; + + Tile topLeftTile = Main.tile[left, top]; + int frameX = topLeftTile.TileFrameX; + + if (frameX == 144) + { + foundLockedChests.Add(chestPos); + + if (!trackedLockedChests.ContainsKey(chestPos)) + { + trackedLockedChests.Add(chestPos, (int)Main.GameUpdateCount); + } + } + } + } + } + + // Check if any tracked chests are now unlocked + List chestsToRemove = new List(); + foreach (var kvp in trackedLockedChests) + { + Point chestPos = kvp.Key; + if (!foundLockedChests.Contains(chestPos)) + { + if (WorldGen.InWorld(chestPos.X, chestPos.Y)) + { + float distance = Vector2.Distance(new Vector2(chestPos.X * 16, chestPos.Y * 16), Player.Center); + + // Only consume key if chest is within interaction range + // Terraria's tile interaction range is about 6.5 tiles (104 pixels) + if (distance <= 104) + { + // Consume Shadow Key - only players within interaction range could have unlocked it + if (Player.HasItem(ItemID.ShadowKey)) + { + Player.ConsumeItem(ItemID.ShadowKey); + } + } + } + + chestsToRemove.Add(chestPos); + } + } + + // Remove processed chests from tracking + foreach (Point pos in chestsToRemove) + { + trackedLockedChests.Remove(pos); + } + + // Clean up chests that are far away + List distantChests = new List(); + foreach (var kvp in trackedLockedChests) + { + float distance = Vector2.Distance(new Vector2(kvp.Key.X * 16, kvp.Key.Y * 16), Player.Center); + if (distance > scanRange * 16 * 1.5f) + { + distantChests.Add(kvp.Key); + } + } + foreach (Point pos in distantChests) + { + trackedLockedChests.Remove(pos); + } + } +} public class PlayerInSpawn : ModBuff { public override string Texture => $"PvPAdventure/Assets/Buff/PlayerInSpawn"; diff --git a/System/RecipeManager.cs b/System/RecipeManager.cs index ee0afd69..3ec90bed 100644 --- a/System/RecipeManager.cs +++ b/System/RecipeManager.cs @@ -433,11 +433,9 @@ 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() @@ -471,7 +469,6 @@ public class AnyHallowedMimic1 : ModSystem ItemID.DaedalusStormbow, ItemID.CrystalVileShard, ItemID.FlyingKnife, - ItemID.IlluminantHook, }; public override void AddRecipeGroups() @@ -863,7 +860,7 @@ public override void AddRecipes() foreach (int itemID in AnyCorruptionMimic1.PrimaryItems.Where(id => id != ItemID.Fake_CorruptionChest)) { Recipe.Create(itemID) - .AddRecipeGroup($"PvPAdventure:AnyCorruptionMimicPrimaryExclude{itemID}", 3) + .AddRecipeGroup($"PvPAdventure:AnyCorruptionMimicPrimaryExclude{itemID}", 2) .AddCondition(shimmerCondition) .DisableDecraft() .Register(); From b277e35ec92d16b909dbe56b78ae3aab8b43bdf2 Mon Sep 17 00:00:00 2001 From: emyhrberg <121192176+emyhrberg@users.noreply.github.com> Date: Thu, 4 Dec 2025 01:56:46 +0100 Subject: [PATCH 199/206] Fixed minor spawn teleport issue --- Core/SpawnSelector/Systems/SpawnHooks.cs | 9 +++++++-- Core/Spawnbox/PvPIcons.cs | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Core/SpawnSelector/Systems/SpawnHooks.cs b/Core/SpawnSelector/Systems/SpawnHooks.cs index 2fe7dd7f..78ec0859 100644 --- a/Core/SpawnSelector/Systems/SpawnHooks.cs +++ b/Core/SpawnSelector/Systems/SpawnHooks.cs @@ -32,7 +32,12 @@ private void ForceWorldSpawn(On_Player.orig_Spawn_SetPosition orig, Player self, //{ //Player.Spawn_ForceClearArea(floorX, floorY); //} - Main.LocalPlayer.position.X = spawnX * 16 + 8 - Main.LocalPlayer.width / 2; - Main.LocalPlayer.position.Y = spawnY * 16 - Main.LocalPlayer.height; + + if (self == Main.LocalPlayer) + { + Main.LocalPlayer.position.X = spawnX * 16 + 8 - Main.LocalPlayer.width / 2; + Main.LocalPlayer.position.Y = spawnY * 16 - Main.LocalPlayer.height; + } + } } diff --git a/Core/Spawnbox/PvPIcons.cs b/Core/Spawnbox/PvPIcons.cs index 2ae534a3..75df3b6d 100644 --- a/Core/Spawnbox/PvPIcons.cs +++ b/Core/Spawnbox/PvPIcons.cs @@ -112,7 +112,7 @@ protected override bool DrawSelf() // Draw cooldown icon //if (isPlaying) - sb.Draw(cooldownTex.Value, cdRect, Color.White * 1f); + sb.Draw(cooldownTex.Value, cdRect, Color.White * 0.8f); } return true; From 879ac3defc23631aef4f933e49d4a24cc82aedf5 Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Wed, 3 Dec 2025 20:38:04 -0800 Subject: [PATCH 200/206] Revert "Merge branch 'feature/RTP-Spawn-Selector' into feature/missinginmaster" This reverts commit c61a2d8a92d457874ac0a7dd44ec5e328a0b4e16, reversing changes made to 227bd4f23a1082307bee8f12ac52cf008df95454. --- Assets/SpawnSelector/CoolDown.png | Bin 912 -> 0 bytes Assets/SpawnSelector/Stop_Icon.png | Bin 912 -> 0 bytes Content/Items/AdventureMirror.cs | 34 +- Core/Debug/DebugChat.cs | 2 - Core/Debug/DebugPlayer.cs | 18 - Core/Helpers/AssetLoader.cs | 5 +- .../InventoryWhileDeadSystem.cs | 84 ---- .../InventoryWhileUsingItemSystem.cs | 61 --- .../Players/AdventureMirrorPlayer.cs | 28 +- Core/SpawnSelector/Systems/ItemSlotHooks.cs | 436 +----------------- .../SpawnSelector/Systems/PlayerHeadsOnMap.cs | 66 --- Core/SpawnSelector/Systems/SpawnHooks.cs | 38 -- .../Systems/SpawnSelectorSystem.cs | 3 - .../{Systems => UI}/BedsOnMap.cs | 53 ++- .../UI/SpawnSelectorBasePanel.cs | 240 +++++----- .../UI/SpawnSelectorCharacter.cs | 108 ++++- Core/Spawnbox/PvPIcons.cs | 127 ----- Core/Spawnbox/SpawnboxMap.cs | 49 +- Core/Spawnbox/SpawnboxWorld.cs | 216 +++++---- System/Client/Keybinds.cs | 2 + 20 files changed, 432 insertions(+), 1138 deletions(-) delete mode 100644 Assets/SpawnSelector/CoolDown.png delete mode 100644 Assets/SpawnSelector/Stop_Icon.png delete mode 100644 Core/Debug/DebugPlayer.cs delete mode 100644 Core/InventoryWhileDead/InventoryWhileDeadSystem.cs delete mode 100644 Core/InventoryWhileDead/InventoryWhileUsingItemSystem.cs delete mode 100644 Core/SpawnSelector/Systems/PlayerHeadsOnMap.cs delete mode 100644 Core/SpawnSelector/Systems/SpawnHooks.cs rename Core/SpawnSelector/{Systems => UI}/BedsOnMap.cs (67%) delete mode 100644 Core/Spawnbox/PvPIcons.cs diff --git a/Assets/SpawnSelector/CoolDown.png b/Assets/SpawnSelector/CoolDown.png deleted file mode 100644 index 0c2273111d6f8afd2428947fdd328f8a4959e328..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 912 zcmV;B18@9^P)vKj_88f55AW3IWo@NH~!g6Tm8=EqWB_4`{nP&&;&DEbVN!RTE<3Yc`p_ zoq6x`-kW)uC1%EHia1s8_!j|)Xr72T21epL#kynI^8|fwQZ-c>LsWz^Rqq7o&1B!$Y=ENL3 z?{uq*4ryV1_LdG_4aM(O22o#oPD+$O0T85dT@k zX73$sEbPeDqD%~YUxLkqqEcE_H>NdIUjlWWz37)k4m0UhJ>KfQtKL=T*fs{gy=h+C zT1isFkHGn&Uy53m%o(5np&KK_j^`$>?JgciSuP{lGto*WfWn~(%nX1)?UQm3Pct8b zQ6>WC8<%?G*m^MA6hf^T%)GB{MZb^CMs7l8#<+d)L?l6olIniB0%$$e6r#R7rV}Sj z01h$esAK}u5F@*b$NM1yBIumsUC{ud`z$Pw?;s2!SdJ(N$qd)-fH*8g130-ngkLqZ z1W{2Z?duP`?jJKkC~L8bW3(k26(^lXop*h-RFt^_Zn-wrhbDapzo*o)nWTL*?E@5O z!KD~*hJk^dh+b}J+d>Eoq~Gars(%vfI-xCD7^2eB=>P@GLhAOEA5l~$JaMFp&0bv& zpyoV@T!W7WfSPDy6-d|)!^!L*JN2Sv2$fM63=%druHJ{Fs*CBY?x>0SwIakAEcKHT zq7s9`4dOiDI4@d}mW3GZNJqE$)S+25z|=-*1KNReAXF|SQh)3Nw2kkAu&N%U0raGj;eZ?#j}(|0ZbCl zGONFTB{SW0US1y6x-srP(O$g{w`ApDNqCO`{8HKsMD6shbKR)q^ZuN69Q(p5iZ&hq m3WP(R`F8Em|Bq9gvit%vLq+z)<>a3L0000vKj_88f55AW3IWo@NH~!g6Tm8=EqWB_4`{nP&&;&DEbVN!RTE<3Yc`p_ zoq6x`-kW)uC1%EHia1s8_!j|)Xr72T21epL#kynI^8|fwQZ-c>LsWz^Rqq7o&1B!$Y=ENL3 z?{uq*4ryV1_LdG_4aM(O22o#oPD+$O0T85dT@k zX73$sEbPeDqD%~YUxLkqqEcE_H>NdIUjlWWz37)k4m0UhJ>KfQtKL=T*fs{gy=h+C zT1isFkHGn&Uy53m%o(5np&KK_j^`$>?JgciSuP{lGto*WfWn~(%nX1)?UQm3Pct8b zQ6>WC8<%?G*m^MA6hf^T%)GB{MZb^CMs7l8#<+d)L?l6olIniB0%$$e6r#R7rV}Sj z01h$esAK}u5F@*b$NM1yBIumsUC{ud`z$Pw?;s2!SdJ(N$qd)-fH*8g130-ngkLqZ z1W{2Z?duP`?jJKkC~L8bW3(k26(^lXop*h-RFt^_Zn-wrhbDapzo*o)nWTL*?E@5O z!KD~*hJk^dh+b}J+d>Eoq~Gars(%vfI-xCD7^2eB=>P@GLhAOEA5l~$JaMFp&0bv& zpyoV@T!W7WfSPDy6-d|)!^!L*JN2Sv2$fM63=%druHJ{Fs*CBY?x>0SwIakAEcKHT zq7s9`4dOiDI4@d}mW3GZNJqE$)S+25z|=-*1KNReAXF|SQh)3Nw2kkAu&N%U0raGj;eZ?#j}(|0ZbCl zGONFTB{SW0US1y6x-srP(O$g{w`ApDNqCO`{8HKsMD6shbKR)q^ZuN69Q(p5iZ&hq m3WP(R`F8Em|Bq9gvit%vLq+z)<>a3L0000(); + Point tilePos = player.Center.ToTileCoordinates(); + var region = regionManager.GetRegionContaining(tilePos); + if (region != null) + { + return true; + } + + // Is player in bed spawn region? + Vector2 bedSpawnPoint = new(player.SpawnX, player.SpawnY); + float distanceToBedSpawn = Vector2.Distance(bedSpawnPoint * 16f, player.Center); + if (distanceToBedSpawn <= 25 * 16f) + { + return true; + } + + return false; + } + public override void UseStyle(Player player, Rectangle heldItemFrame) { base.UseStyle(player, heldItemFrame); - //if (IsPlayerInSpawnRegion(player)) - //{ - // //PopupTextHelper.NewText("cannot use in spawn!", player); - // //CancelItemUse(player); - // //return; - //} + if (IsPlayerInSpawnRegion(player)) + { + //PopupTextHelper.NewText("cannot use in spawn!", player); + //CancelItemUse(player); + //return; + } // If this player moves, cancel their use if (player.velocity.LengthSquared() > 0) diff --git a/Core/Debug/DebugChat.cs b/Core/Debug/DebugChat.cs index 12ca92b9..07c99398 100644 --- a/Core/Debug/DebugChat.cs +++ b/Core/Debug/DebugChat.cs @@ -7,7 +7,6 @@ namespace PvPAdventure.Core.Debug; -#if DEBUG internal class DebugChat : ModSystem { public override void Load() @@ -42,4 +41,3 @@ private void OnAddNewChatMessage(On_RemadeChatMonitor.orig_AddNewMessage orig, R timeLeftField?.SetValue(msg, 60 * 60); } } -#endif \ No newline at end of file diff --git a/Core/Debug/DebugPlayer.cs b/Core/Debug/DebugPlayer.cs deleted file mode 100644 index da45dd9f..00000000 --- a/Core/Debug/DebugPlayer.cs +++ /dev/null @@ -1,18 +0,0 @@ - -using Terraria.DataStructures; -using Terraria.ModLoader; - -namespace PvPAdventure.Core.Debug; - -#if DEBUG -internal class DebugPlayer : ModPlayer -{ - public override void Kill(double damage, int hitDirection, bool pvp, PlayerDeathReason damageSource) - { - Player.respawnTimer = 120; // 2 seconds - //Player.respawnTimer = 600; // 10 seconds - //Player.respawnTimer = 0; - base.Kill(damage, hitDirection, pvp, damageSource); - } -} -#endif diff --git a/Core/Helpers/AssetLoader.cs b/Core/Helpers/AssetLoader.cs index 776da002..ed2a2158 100644 --- a/Core/Helpers/AssetLoader.cs +++ b/Core/Helpers/AssetLoader.cs @@ -7,15 +7,12 @@ namespace PvPAdventure.Core.Helpers; public static class Ass { - // Spawn selector assets + public static Asset Question_Mark; public static Asset[] MapBG; public static Asset Arrow; public static Asset CustomPlayerBackground; public static Asset Spawnbox; public static Asset Pause; - public static Asset Stop_Icon; - public static Asset Question_Mark; - public static bool Initialized { get; set; } diff --git a/Core/InventoryWhileDead/InventoryWhileDeadSystem.cs b/Core/InventoryWhileDead/InventoryWhileDeadSystem.cs deleted file mode 100644 index 84aab72d..00000000 --- a/Core/InventoryWhileDead/InventoryWhileDeadSystem.cs +++ /dev/null @@ -1,84 +0,0 @@ -using Terraria; -using Terraria.ModLoader; - -namespace PvPAdventure.Core.InventoryWhileDead; - -// Allows inventory access while player is dead. -internal class InventoryWhileDeadSystem : ModSystem -{ - public override void Load() - { - On_Main.DrawInterface_26_InterfaceLogic3 += ModifyInterfaceLogic; - On_Player.TryOpeningInGameOptionsBasedOnInput += ModifyIngameOptionsInput; - } - public override void Unload() - { - On_Main.DrawInterface_26_InterfaceLogic3 -= ModifyInterfaceLogic; - On_Player.TryOpeningInGameOptionsBasedOnInput -= ModifyIngameOptionsInput; - } - - private void ModifyIngameOptionsInput(On_Player.orig_TryOpeningInGameOptionsBasedOnInput orig, Player self) - { - //orig(self); - - // Override to allow inventory access while dead - if (self.dead) - { - if (self.controlInv) - { - if (self.releaseInventory) - { - self.releaseInventory = false; - self.ToggleInv(); // actually toggles the inventory - } - } - else - { - self.releaseInventory = true; - } - - return; - } - - // Vanilla logic - if (self.controlInv) - { - if (self.releaseInventory) - { - self.releaseInventory = false; - if (Main.ingameOptionsWindow) - { - IngameOptions.Close(); - } - else - { - IngameOptions.Open(); - } - } - } - else - { - self.releaseInventory = true; - } - } - - private void ModifyInterfaceLogic(On_Main.orig_DrawInterface_26_InterfaceLogic3 orig) - { - bool flag = Main.playerInventory; - if (Main.player[Main.myPlayer].dead) - { - //Main.playerInventory = false; // skip this - } - if (!Main.playerInventory) - { - Main.player[Main.myPlayer].chest = -1; - Main.InGuideCraftMenu = false; - Main.InReforgeMenu = false; - if (flag) - { - Recipe.FindRecipes(); - } - } - Main.hoverItemName = ""; - } -} diff --git a/Core/InventoryWhileDead/InventoryWhileUsingItemSystem.cs b/Core/InventoryWhileDead/InventoryWhileUsingItemSystem.cs deleted file mode 100644 index b92116a0..00000000 --- a/Core/InventoryWhileDead/InventoryWhileUsingItemSystem.cs +++ /dev/null @@ -1,61 +0,0 @@ -//using MonoMod.RuntimeDetour; -//using PvPAdventure.Core.Helpers; -//using System; -//using System.Reflection; -//using Terraria; -//using Terraria.GameInput; -//using Terraria.ModLoader; -//using Terraria.UI; - -//namespace PvPAdventure.Core.InventoryWhileUsingItem; - -//internal class InventoryWhileUsingItemSystem : ModSystem -//{ -// private Hook ignoreMouseHook; -// private Hook leftClickHook; - -// public override void Load() -// { -// On_Main.DrawInterface_0_InterfaceLogic1 += ModifyInterface0; - -// // Mouse interface -// MethodInfo getter = typeof(PlayerInput).GetMethod( -// "get_IgnoreMouseInterface", -// BindingFlags.Public | BindingFlags.Static -// ); - -// if (getter == null) -// { -// Log.Error("Getter not found!"); -// return; -// } - -// ignoreMouseHook = new Hook(getter, (Func, bool>)OverrideIgnoreMouseInterface); -// } - -// //private bool OverrideIgnoreMouseInterface(Func orig) -// //{ - -// private void ModifyInterface0(On_Main.orig_DrawInterface_0_InterfaceLogic1 orig) -// { -// // do nothing -// } - -// public override void Unload() -// { -// On_Main.DrawInterface_0_InterfaceLogic1 -= ModifyInterface0; -// ignoreMouseHook?.Dispose(); -// } - -// private bool OverrideIgnoreMouseInterface(Func orig) -// { -// Player player = Main.LocalPlayer; - -// // Allow mouse to interact while using items -// if (player.itemAnimation > 0) -// return false; - -// // fallback to vanilla -// return orig(); -// } -//} diff --git a/Core/SpawnSelector/Players/AdventureMirrorPlayer.cs b/Core/SpawnSelector/Players/AdventureMirrorPlayer.cs index 2fd68712..d7eb5fa7 100644 --- a/Core/SpawnSelector/Players/AdventureMirrorPlayer.cs +++ b/Core/SpawnSelector/Players/AdventureMirrorPlayer.cs @@ -35,9 +35,9 @@ public override void OnHurt(Player.HurtInfo info) } } - public bool IsPlayerInSpawnRegion() + public bool IsPlayerInSpawnRegion(int extraTileOffset=0) { - // Is player in resin's spawn region? + // Is player in spawn region? var regionManager = ModContent.GetInstance(); Point tilePos = Player.Center.ToTileCoordinates(); var region = regionManager.GetRegionContaining(tilePos); @@ -54,30 +54,6 @@ public bool IsPlayerInSpawnRegion() return true; } - // Is player in any bed spawn region? - for (int i = 0; i < Main.maxPlayers; i++) - { - Player other = Main.player[i]; - - if (other == null || !other.active || other.whoAmI == Player.whoAmI) - continue; - - // Only care about same team and non-zero team - if (other.team == 0 || other.team != Player.team) - continue; - - // No bed set for this teammate - if (other.SpawnX == -1 || other.SpawnY == -1) - continue; - - Vector2 teammateBedTile = new Vector2(other.SpawnX, other.SpawnY); - float distanceToTeammateBed = Vector2.Distance(teammateBedTile * 16f, Player.Center); - - if (distanceToTeammateBed <= 25*16f) - { - return true; - } - } return false; } diff --git a/Core/SpawnSelector/Systems/ItemSlotHooks.cs b/Core/SpawnSelector/Systems/ItemSlotHooks.cs index 1f39693a..92cd76be 100644 --- a/Core/SpawnSelector/Systems/ItemSlotHooks.cs +++ b/Core/SpawnSelector/Systems/ItemSlotHooks.cs @@ -1,18 +1,12 @@ -using PvPAdventure.Content.Items; -using System; -using System.Linq; -using Terraria; -using Terraria.Audio; -using Terraria.DataStructures; -using Terraria.GameContent.Achievements; +using Terraria; using Terraria.ModLoader; using Terraria.UI; +using PvPAdventure.Content.Items; namespace PvPAdventure.Core.SpawnSelector.Systems; /// /// Prevents the Adventure Mirror from being removed from the player inventory via trashing or selling. -/// Various inventory hooks are used to achieve this. /// public class ItemSlotHooks : ModSystem { @@ -20,7 +14,6 @@ public override void Load() { On_ItemSlot.LeftClick_SellOrTrash += Hook_LeftClick_SellOrTrash; On_ItemSlot.LeftClick_ItemArray_int_int += Hook_LeftClick_ItemArray; - On_ItemSlot.RightClick_ItemArray_int_int += Hook_RightClick; On_Player.SellItem += Hook_SellItem; On_Player.DropSelectedItem += Hook_DropSelectedItem; On_Player.dropItemCheck += Hook_DropItemCheck; @@ -35,121 +28,6 @@ public override void Unload() On_Player.dropItemCheck -= Hook_DropItemCheck; } - // Vanilla method with the item animation check removed for Adventure Mirror. - private static void Hook_RightClick( - On_ItemSlot.orig_RightClick_ItemArray_int_int orig, - Item[] inv, int context, int slot) - { - Player player = Main.player[Main.myPlayer]; - inv[slot].newAndShiny = false; - if (player.itemAnimation > 0 && player.HeldItem.type != ModContent.ItemType()) - { - return; - } - if (context == 15) - { - ItemSlot.HandleShopSlot(inv, slot, rightClickIsValid: true, leftClickIsValid: false); - } - else - { - if (!Main.mouseRight) - { - return; - } - if (context == 0 && Main.mouseRightRelease) - { - ItemSlot.TryItemSwap(inv[slot]); - } - if (context == 0 && ItemLoader.CanRightClick(inv[slot])) - { - if (Main.mouseRightRelease) - { - if (Main.ItemDropsDB.GetRulesForItemID(inv[slot].type).Any()) - { - ItemSlot.TryOpenContainer(inv[slot], player); - } - else - { - ItemLoader.RightClick(inv[slot], player); - } - } - return; - } - switch (Math.Abs(context)) - { - case 9: - case 11: - if (Main.mouseRightRelease) - { - ItemSlot.SwapVanityEquip(inv, context, slot, player); - } - break; - case 12: - case 25: - case 27: - case 33: - if (Main.mouseRightRelease) - { - ItemSlot.TryPickupDyeToCursor(context, inv, slot, player); - } - break; - case 0: - case 3: - case 4: - case 32: - if (inv[slot].maxStack == 1) - { - if (Main.mouseRightRelease) - { - ItemSlot.SwapEquip(inv, context, slot); - } - break; - } - goto default; - default: - { - if (Main.stackSplit > 1) - { - break; - } - bool flag = true; - bool flag2 = inv[slot].maxStack <= 1 && inv[slot].stack <= 1; - if (context == 0 && flag2) - { - flag = false; - } - if (context == 3 && flag2) - { - flag = false; - } - if (context == 4 && flag2) - { - flag = false; - } - if (context == 32 && flag2) - { - flag = false; - } - if (!flag) - { - break; - } - int num = Main.superFastStack + 1; - for (int i = 0; i < num; i++) - { - if (((Main.mouseItem.IsTheSameAs(inv[slot]) && ItemLoader.CanStack(Main.mouseItem, inv[slot])) || Main.mouseItem.type == 0) && (Main.mouseItem.stack < Main.mouseItem.maxStack || Main.mouseItem.type == 0)) - { - ItemSlot.PickupItemIntoMouse(inv, context, slot, player); - SoundEngine.PlaySound(12); - ItemSlot.RefreshStackSplitCooldown(); - } - } - break; - } - } - } - } - private void Hook_DropItemCheck(On_Player.orig_dropItemCheck orig, Player self) { // If the mouse is holding the Adventure Mirror, just block the drop. @@ -195,7 +73,6 @@ private static bool Hook_LeftClick_SellOrTrash( private static bool IsAdventureMirror(Item item) => !item.IsAir && item.type == ModContent.ItemType(); - // Vanilla method with the item animation check removed for Adventure Mirror. // DRAGGING ONTO THE TRASH SLOT / CHESTS / BANKS private static void Hook_LeftClick_ItemArray( On_ItemSlot.orig_LeftClick_ItemArray_int_int orig, @@ -211,7 +88,7 @@ private static void Hook_LeftClick_ItemArray( if (isStorageSlot && isMirrorOnMouse) { //if (Main.mouseLeft && Main.mouseLeftRelease) - //Main.NewText("Cannot store Adventure Mirror!"); + //PopupTextHelper.NewText("Cannot store Adventure Mirror!"); // Do NOT call orig -> cancel the placement return; @@ -227,312 +104,7 @@ private static void Hook_LeftClick_ItemArray( } // Otherwise, normal behavior - //orig(inv, context, slot); - - // --- Normal behaviour --- - Player player = Main.player[Main.myPlayer]; - bool flag = Main.mouseLeftRelease && Main.mouseLeft; - if (flag) - { - if (ItemSlot.OverrideLeftClick(inv, context, slot)) - { - return; - } - inv[slot].newAndShiny = false; - if (ItemSlot.LeftClick_SellOrTrash(inv, context, slot) || player.itemAnimation != 0 || player.itemTime != 0) - { - // RETURN EARLY for all other items other than Adventure Mirror - // Meaning we allow ItemSlot use while AM is the held item. - if (player.HeldItem.type != ModContent.ItemType()) - { - return; - } - - } - } - int num = ItemSlot.PickItemMovementAction(inv, context, slot, Main.mouseItem); - if (num != 3 && !flag) - { - return; - } - switch (num) - { - case 0: - { - if (context == 6 && Main.mouseItem.type != 0) - { - inv[slot].SetDefaults(); - } - if ((ItemSlot.IsAccessoryContext(context) && !ItemLoader.CanEquipAccessory(inv[slot], slot, context < 0)) || (context == 11 && !inv[slot].FitsAccessoryVanitySlot) || (context < 0 && !LoaderManager.Get().CanAcceptItem(slot, inv[slot], context))) - { - break; - } - if (Main.mouseItem.maxStack <= 1 || inv[slot].type != Main.mouseItem.type || inv[slot].stack == inv[slot].maxStack || Main.mouseItem.stack == Main.mouseItem.maxStack) - { - Utils.Swap(ref inv[slot], ref Main.mouseItem); - } - if (inv[slot].stack > 0) - { - ItemSlot.AnnounceTransfer(new ItemSlot.ItemTransferInfo(inv[slot], 21, context, inv[slot].stack)); - } - else - { - ItemSlot.AnnounceTransfer(new ItemSlot.ItemTransferInfo(Main.mouseItem, context, 21, Main.mouseItem.stack)); - } - if (inv[slot].stack > 0) - { - switch (Math.Abs(context)) - { - case 0: - AchievementsHelper.NotifyItemPickup(player, inv[slot]); - break; - case 8: - case 9: - case 10: - case 11: - case 12: - case 16: - case 17: - case 25: - case 27: - case 33: - AchievementsHelper.HandleOnEquip(player, inv[slot], context); - break; - } - } - if (inv[slot].type == 0 || inv[slot].stack < 1) - { - inv[slot] = new Item(); - } - if (Main.mouseItem.IsTheSameAs(inv[slot]) && inv[slot].stack != inv[slot].maxStack && Main.mouseItem.stack != Main.mouseItem.maxStack && ItemLoader.TryStackItems(inv[slot], Main.mouseItem, out var numTransfered)) - { - ItemSlot.AnnounceTransfer(new ItemSlot.ItemTransferInfo(inv[slot], 21, context, numTransfered)); - } - if (Main.mouseItem.type == 0 || Main.mouseItem.stack < 1) - { - Main.mouseItem = new Item(); - } - if (Main.mouseItem.type > 0 || inv[slot].type > 0) - { - Recipe.FindRecipes(); - SoundEngine.PlaySound(7); - } - if (context == 3 && Main.netMode == 1) - { - NetMessage.SendData(32, -1, -1, null, player.chest, slot); - } - break; - } - case 1: - if (Main.mouseItem.stack == 1 && Main.mouseItem.type > 0 && inv[slot].type > 0 && inv[slot].IsNotTheSameAs(Main.mouseItem) && (context != 11 || Main.mouseItem.FitsAccessoryVanitySlot)) - { - if ((ItemSlot.IsAccessoryContext(context) && !ItemLoader.CanEquipAccessory(Main.mouseItem, slot, context < 0)) || (Math.Abs(context) == 11 && !Main.mouseItem.FitsAccessoryVanitySlot) || (context < 0 && !LoaderManager.Get().CanAcceptItem(slot, Main.mouseItem, context))) - { - break; - } - Utils.Swap(ref inv[slot], ref Main.mouseItem); - SoundEngine.PlaySound(7); - if (inv[slot].stack > 0) - { - switch (Math.Abs(context)) - { - case 0: - AchievementsHelper.NotifyItemPickup(player, inv[slot]); - break; - case 8: - case 9: - case 10: - case 11: - case 12: - case 16: - case 17: - case 25: - case 27: - case 33: - AchievementsHelper.HandleOnEquip(player, inv[slot], context); - break; - } - } - } - else if (Main.mouseItem.type == 0 && inv[slot].type > 0) - { - Utils.Swap(ref inv[slot], ref Main.mouseItem); - if (inv[slot].type == 0 || inv[slot].stack < 1) - { - inv[slot] = new Item(); - } - if (Main.mouseItem.type == 0 || Main.mouseItem.stack < 1) - { - Main.mouseItem = new Item(); - } - if (Main.mouseItem.type > 0 || inv[slot].type > 0) - { - Recipe.FindRecipes(); - SoundEngine.PlaySound(7); - } - } - else if (Main.mouseItem.type > 0 && inv[slot].type == 0 && (context != 11 || Main.mouseItem.FitsAccessoryVanitySlot)) - { - if ((ItemSlot.IsAccessoryContext(context) && !ItemLoader.CanEquipAccessory(Main.mouseItem, slot, context < 0)) || (Math.Abs(context) == 11 && !Main.mouseItem.FitsAccessoryVanitySlot) || (context < 0 && !LoaderManager.Get().CanAcceptItem(slot, Main.mouseItem, context))) - { - break; - } - inv[slot] = ItemLoader.TransferWithLimit(Main.mouseItem, 1); - Recipe.FindRecipes(); - SoundEngine.PlaySound(7); - if (inv[slot].stack > 0) - { - switch (Math.Abs(context)) - { - case 0: - AchievementsHelper.NotifyItemPickup(player, inv[slot]); - break; - case 8: - case 9: - case 10: - case 11: - case 12: - case 16: - case 17: - case 25: - case 27: - case 33: - AchievementsHelper.HandleOnEquip(player, inv[slot], context); - break; - } - } - } - if ((context == 23 || context == 24) && Main.netMode == 1) - { - NetMessage.SendData(121, -1, -1, null, Main.myPlayer, player.tileEntityAnchor.interactEntityID, slot); - } - if (context == 26 && Main.netMode == 1) - { - NetMessage.SendData(124, -1, -1, null, Main.myPlayer, player.tileEntityAnchor.interactEntityID, slot); - } - break; - case 2: - if (Main.mouseItem.stack == 1 && Main.mouseItem.dye > 0 && inv[slot].type > 0 && inv[slot].type != Main.mouseItem.type) - { - Utils.Swap(ref inv[slot], ref Main.mouseItem); - SoundEngine.PlaySound(7); - if (inv[slot].stack > 0) - { - switch (Math.Abs(context)) - { - case 0: - AchievementsHelper.NotifyItemPickup(player, inv[slot]); - break; - case 8: - case 9: - case 10: - case 11: - case 12: - case 16: - case 17: - case 25: - case 27: - case 33: - AchievementsHelper.HandleOnEquip(player, inv[slot], context); - break; - } - } - } - else if (Main.mouseItem.type == 0 && inv[slot].type > 0) - { - Utils.Swap(ref inv[slot], ref Main.mouseItem); - if (inv[slot].type == 0 || inv[slot].stack < 1) - { - inv[slot] = new Item(); - } - if (Main.mouseItem.type == 0 || Main.mouseItem.stack < 1) - { - Main.mouseItem = new Item(); - } - if (Main.mouseItem.type > 0 || inv[slot].type > 0) - { - Recipe.FindRecipes(); - SoundEngine.PlaySound(7); - } - } - else if (Main.mouseItem.dye > 0 && inv[slot].type == 0) - { - inv[slot] = ItemLoader.TransferWithLimit(Main.mouseItem, 1); - Recipe.FindRecipes(); - SoundEngine.PlaySound(7); - if (inv[slot].stack > 0) - { - switch (Math.Abs(context)) - { - case 0: - AchievementsHelper.NotifyItemPickup(player, inv[slot]); - break; - case 8: - case 9: - case 10: - case 11: - case 12: - case 16: - case 17: - case 25: - case 27: - case 33: - AchievementsHelper.HandleOnEquip(player, inv[slot], context); - break; - } - } - } - if (context == 25 && Main.netMode == 1) - { - NetMessage.SendData(121, -1, -1, null, Main.myPlayer, player.tileEntityAnchor.interactEntityID, slot, 1f); - } - if (context == 27 && Main.netMode == 1) - { - NetMessage.SendData(124, -1, -1, null, Main.myPlayer, player.tileEntityAnchor.interactEntityID, slot, 1f); - } - break; - case 3: - ItemSlot.HandleShopSlot(inv, slot, rightClickIsValid: false, leftClickIsValid: true); - break; - case 4: - if (PlayerLoader.CanSellItem(player, player.TalkNPC, inv, Main.mouseItem)) - { - Chest chest = Main.instance.shop[Main.npcShop]; - if (player.SellItem(Main.mouseItem)) - { - int soldItemIndex = chest.AddItemToShop(Main.mouseItem); - Main.mouseItem.SetDefaults(); - SoundEngine.PlaySound(18); - ItemSlot.AnnounceTransfer(new ItemSlot.ItemTransferInfo(inv[slot], 21, 15)); - PlayerLoader.PostSellItem(player, player.TalkNPC, chest.item, chest.item[soldItemIndex]); - } - else if (Main.mouseItem.value == 0) - { - int soldItemIndex2 = chest.AddItemToShop(Main.mouseItem); - Main.mouseItem.SetDefaults(); - SoundEngine.PlaySound(7); - ItemSlot.AnnounceTransfer(new ItemSlot.ItemTransferInfo(inv[slot], 21, 15)); - PlayerLoader.PostSellItem(player, player.TalkNPC, chest.item, chest.item[soldItemIndex2]); - } - Recipe.FindRecipes(); - Main.stackSplit = 9999; - } - break; - case 5: - if (Main.mouseItem.IsAir) - { - SoundEngine.PlaySound(7); - Main.mouseItem = inv[slot].Clone(); - Main.mouseItem.stack = Main.mouseItem.maxStack; - Main.mouseItem.OnCreated(new JourneyDuplicationItemCreationContext()); - ItemSlot.AnnounceTransfer(new ItemSlot.ItemTransferInfo(inv[slot], 29, 21)); - } - break; - } - if ((uint)context > 2u && context != 5 && context != 32) - { - inv[slot].favorited = false; - } + orig(inv, context, slot); } // SELLING TO NPCS diff --git a/Core/SpawnSelector/Systems/PlayerHeadsOnMap.cs b/Core/SpawnSelector/Systems/PlayerHeadsOnMap.cs deleted file mode 100644 index 1e639e43..00000000 --- a/Core/SpawnSelector/Systems/PlayerHeadsOnMap.cs +++ /dev/null @@ -1,66 +0,0 @@ -using Microsoft.Xna.Framework; -using Terraria; -using Terraria.GameContent; -using Terraria.ModLoader; - -namespace PvPAdventure.Core.SpawnSelector.Systems; - -/// -/// Draws the selected player heads on map when highlighting the UI element for the player -/// -internal class PlayerHeadsOnMap : ModSystem -{ - public override void Load() - { - Main.OnPostFullscreenMapDraw += DrawHighlightedPlayerOnMap; - } - - public override void Unload() - { - Main.OnPostFullscreenMapDraw -= DrawHighlightedPlayerOnMap; - } - - private void DrawHighlightedPlayerOnMap(Vector2 mapOffset, float mapScale) - { - if (!Main.mapFullscreen) return; - - int idx = SpawnSelectorSystem.HoveredPlayerIndex; - if (idx < 0 || idx >= Main.maxPlayers) return; - - Player player = Main.player[idx]; - if (player == null || !player.active || player.dead) return; - - float tileX = (player.position.X + player.width * 0.5f) / 16f; - float tileY = (player.position.Y + player.gfxOffY + player.height * 0.5f) / 16f; - - float x = tileX * mapScale + mapOffset.X; - float y = tileY * mapScale + mapOffset.Y; - - x -= 7f; - y -= 3f; - //y -= 2f - mapScale / 5f * 2f; - //x -= 10f * mapScale; - //y -= 10f * mapScale; - - Vector2 headPos = new Vector2(x, y); - - float alpha = 1f; - float scale = 1.6f*Main.UIScale; - if (Main.UIScale > 1.5) - scale = 1.6f * Main.UIScale * 0.9f; - Color border = Main.GetPlayerHeadBordersColor(player); - - Main.spriteBatch.Begin(); - - // Draw player head - Main.MapPlayerRenderer.DrawPlayerHead(Main.Camera, player, headPos, alpha, scale, border); - - // Draw teleport to player text - string name = player.name; - Vector2 size = FontAssets.MouseText.Value.MeasureString(name); - Vector2 pos = headPos + new Vector2(-size.X * 0.5f+7*Main.UIScale, 30f*Main.UIScale); - Utils.DrawBorderString(Main.spriteBatch, name, pos, Color.White, 1f*Main.UIScale); - - Main.spriteBatch.End(); - } -} diff --git a/Core/SpawnSelector/Systems/SpawnHooks.cs b/Core/SpawnSelector/Systems/SpawnHooks.cs deleted file mode 100644 index 2fe7dd7f..00000000 --- a/Core/SpawnSelector/Systems/SpawnHooks.cs +++ /dev/null @@ -1,38 +0,0 @@ -using Microsoft.Xna.Framework; -using Terraria; -using Terraria.ModLoader; - -namespace PvPAdventure.Core.SpawnSelector.Systems; - -/// -/// This allows the player to click on teammates to teleport to them. -/// -public class SpawnHooks : ModSystem -{ - public override void Load() - { - On_Player.Spawn_SetPosition += ForceWorldSpawn; - } - - public override void Unload() - { - On_Player.Spawn_SetPosition -= ForceWorldSpawn; - } - - private void ForceWorldSpawn(On_Player.orig_Spawn_SetPosition orig, Player self, int floorX, int floorY) - { - //orig(self, floorX, floorY); - - // Force all respawns to world spawn - int spawnX = Main.spawnTileX; - int spawnY = Main.spawnTileY; - //bool num = Player.Spawn_GetPositionAtWorldSpawn(ref floorX, ref floorY); - //this.Spawn_SetPosition(floorX, floorY); - //if (num && !this.Spawn_IsAreaAValidWorldSpawn(floorX, floorY)) - //{ - //Player.Spawn_ForceClearArea(floorX, floorY); - //} - Main.LocalPlayer.position.X = spawnX * 16 + 8 - Main.LocalPlayer.width / 2; - Main.LocalPlayer.position.Y = spawnY * 16 - Main.LocalPlayer.height; - } -} diff --git a/Core/SpawnSelector/Systems/SpawnSelectorSystem.cs b/Core/SpawnSelector/Systems/SpawnSelectorSystem.cs index 93aea42a..2f62726f 100644 --- a/Core/SpawnSelector/Systems/SpawnSelectorSystem.cs +++ b/Core/SpawnSelector/Systems/SpawnSelectorSystem.cs @@ -17,9 +17,6 @@ public class SpawnSelectorSystem : ModSystem public static void SetEnabled(bool newValue) => Enabled = newValue; public static bool GetEnabled() => Enabled; - // Hovering players - internal static int HoveredPlayerIndex = -1; - public override void Load() { if (!Main.dedServ) diff --git a/Core/SpawnSelector/Systems/BedsOnMap.cs b/Core/SpawnSelector/UI/BedsOnMap.cs similarity index 67% rename from Core/SpawnSelector/Systems/BedsOnMap.cs rename to Core/SpawnSelector/UI/BedsOnMap.cs index 92a335ce..ac8feb52 100644 --- a/Core/SpawnSelector/Systems/BedsOnMap.cs +++ b/Core/SpawnSelector/UI/BedsOnMap.cs @@ -1,5 +1,6 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; +using PvPAdventure.Core.SpawnSelector.Systems; using ReLogic.Content; using Terraria; using Terraria.DataStructures; @@ -9,7 +10,7 @@ using Terraria.ModLoader; using Terraria.UI; -namespace PvPAdventure.Core.SpawnSelector.Systems; +namespace PvPAdventure.Core.SpawnSelector.UI; internal class BedsOnMap : ModSystem { @@ -18,6 +19,7 @@ internal class BedsOnMap : ModSystem public override void Load() { On_SpawnMapLayer.Draw += OnSpawnMapLayer; + } public override void Unload() @@ -33,7 +35,7 @@ public override void PostSetupContent() } } - private void OnSpawnMapLayer(On_SpawnMapLayer.orig_Draw orig, SpawnMapLayer self, ref MapOverlayDrawContext context, ref string text) + private void OnSpawnMapLayer(On_SpawnMapLayer.orig_Draw orig,SpawnMapLayer self,ref MapOverlayDrawContext context, ref string text) { // Let vanilla draw spawn point + local bed first orig(self, ref context, ref text); @@ -51,6 +53,10 @@ private void OnSpawnMapLayer(On_SpawnMapLayer.orig_Draw orig, SpawnMapLayer self Vector2 bedTilePos = new(player.SpawnX, player.SpawnY); +#if DEBUG + DrawBedSpawnDebugRect(player, bedTilePos); +#endif + // Safety check and load texture if needed spawnBedTexture ??= TextureAssets.SpawnBed; @@ -107,10 +113,51 @@ private void OnSpawnMapLayer(On_SpawnMapLayer.orig_Draw orig, SpawnMapLayer self #endif } } - + } } } } + +#if DEBUG + private static void DrawBedSpawnDebugRect(Player player, Vector2 bedTilePos) + { + if (!Main.mapFullscreen) + { + return; + } + + // World-space center of the bed (pixels) + Vector2 bedWorld = bedTilePos * 16f; + + // Convert world -> fullscreen map screen coordinates + Vector2 screenCenter = new(Main.screenWidth / 2f, Main.screenHeight / 2f); + Vector2 bedOnMap = (bedWorld - Main.mapFullscreenPos) * Main.mapFullscreenScale + screenCenter; + + float radiusWorld = 25 * 16f; // 25 tiles in world space + float radiusOnMap = radiusWorld * Main.mapFullscreenScale; + + Texture2D pixel = TextureAssets.MagicPixel.Value; + float thickness = 2f; + + Rectangle rect = new( + (int)(bedOnMap.X - radiusOnMap), + (int)(bedOnMap.Y - radiusOnMap), + (int)(radiusOnMap * 2f), + (int)(radiusOnMap * 2f) + ); + + Color color = Main.teamColor[player.team] * 0.75f; + + // Top + Main.spriteBatch.Draw(pixel, new Rectangle(rect.Left, rect.Top, rect.Width, (int)thickness), color); + // Bottom + Main.spriteBatch.Draw(pixel, new Rectangle(rect.Left, rect.Bottom - (int)thickness, rect.Width, (int)thickness), color); + // Left + Main.spriteBatch.Draw(pixel, new Rectangle(rect.Left, rect.Top, (int)thickness, rect.Height), color); + // Right + Main.spriteBatch.Draw(pixel, new Rectangle(rect.Right - (int)thickness, rect.Top, (int)thickness, rect.Height), color); + } +#endif } diff --git a/Core/SpawnSelector/UI/SpawnSelectorBasePanel.cs b/Core/SpawnSelector/UI/SpawnSelectorBasePanel.cs index 58e7a44b..9d2d4a08 100644 --- a/Core/SpawnSelector/UI/SpawnSelectorBasePanel.cs +++ b/Core/SpawnSelector/UI/SpawnSelectorBasePanel.cs @@ -5,173 +5,173 @@ using Terraria; using Terraria.GameContent.UI.Elements; -namespace PvPAdventure.Core.SpawnSelector.UI; - -// -public class SpawnSelectorBasePanel : UIPanel +namespace PvPAdventure.Core.SpawnSelector.UI { - private UIPanel _randomPanel; - private readonly List _playerItems = new(); - - private const float Spacing = 8f; - private const float HorizontalPadding = 16f; - private const float VerticalPadding = 12f; - - public override void OnInitialize() + public class SpawnSelectorBasePanel : UIPanel { - HAlign = 0.5f; - VAlign = 0.0f; - Top.Set(52, 0); + private UIPanel _randomPanel; + private readonly List _playerItems = new(); - BackgroundColor = new Color(33, 43, 79) * 0.8f; - SetPadding(0f); + private const float Spacing = 8f; + private const float HorizontalPadding = 16f; + private const float VerticalPadding = 12f; - BuildLayout(); - } + public override void OnInitialize() + { + HAlign = 0.5f; + VAlign = 0.0f; + Top.Set(52, 0); - private void BuildLayout() - { - RemoveAllChildren(); - _playerItems.Clear(); + BackgroundColor = new Color(33, 43, 79) * 0.8f; + SetPadding(0f); - var players = new List(); - var local = Main.LocalPlayer; + BuildLayout(); + } - if (local.team != 0) + private void BuildLayout() { - for (int i = 0; i < Main.maxPlayers; i++) + RemoveAllChildren(); + _playerItems.Clear(); + + var players = new List(); + var local = Main.LocalPlayer; + + if (local.team != 0) { - Player p = Main.player[i]; + for (int i = 0; i < Main.maxPlayers; i++) + { + Player p = Main.player[i]; - if (p == null) - continue; + if (p == null) + continue; - if (p.whoAmI == local.whoAmI || p.team != local.team) - continue; + if (p.whoAmI == local.whoAmI || p.team != local.team) + continue; - players.Add(p); + players.Add(p); + } } - } //#if DEBUG -// players.Add(Main.LocalPlayer); -// Main.NewText($"[DEBUG] Added local player '{Main.LocalPlayer.name}' to SpawnSelectorBasePanel"); +// players.Add(Main.LocalPlayer); +// Main.NewText($"[DEBUG] Added local player '{Main.LocalPlayer.name}' to SpawnSelectorBasePanel"); //#endif - int playerCount = players.Count; + int playerCount = players.Count; - float itemWidth = SpawnSelectorCharacter.ItemWidth; - float itemHeight = SpawnSelectorCharacter.ItemHeight; - float randomWidth = itemHeight; + float itemWidth = SpawnSelectorCharacter.ItemWidth; + float itemHeight = SpawnSelectorCharacter.ItemHeight; + float randomWidth = itemHeight; - float contentWidth = playerCount * itemWidth - + playerCount * Spacing - + randomWidth; + float contentWidth = playerCount * itemWidth + + playerCount * Spacing + + randomWidth; - float panelWidth = contentWidth + HorizontalPadding * 2f; - float panelHeight = itemHeight + VerticalPadding * 2f; + float panelWidth = contentWidth + HorizontalPadding * 2f; + float panelHeight = itemHeight + VerticalPadding * 2f; - if (panelWidth <= 0f) - panelWidth = itemWidth + HorizontalPadding * 2f; + if (panelWidth <= 0f) + panelWidth = itemWidth + HorizontalPadding * 2f; - if (panelHeight <= 0f) - panelHeight = itemHeight + VerticalPadding * 2f; + if (panelHeight <= 0f) + panelHeight = itemHeight + VerticalPadding * 2f; - Width.Set(panelWidth, 0f); - Height.Set(panelHeight, 0f); + Width.Set(panelWidth, 0f); + Height.Set(panelHeight, 0f); - float startX = HorizontalPadding; - float y = VerticalPadding; + float startX = HorizontalPadding; + float y = VerticalPadding; - for (int i = 0; i < playerCount; i++) - { - float x = startX + i * (itemWidth + Spacing); + for (int i = 0; i < playerCount; i++) + { + float x = startX + i * (itemWidth + Spacing); - var row = new SpawnSelectorCharacter(players[i]); - row.Left.Set(x, 0f); - row.Top.Set(y, 0f); + var row = new SpawnSelectorCharacter(players[i]); + row.Left.Set(x, 0f); + row.Top.Set(y, 0f); - Append(row); - _playerItems.Add(row); - } + Append(row); + _playerItems.Add(row); + } - _randomPanel = new SpawnSelectorQuestionMark( - startX, - itemHeight, - playerCount, - itemWidth, - Spacing, - y - ); - Append(_randomPanel); + _randomPanel = new SpawnSelectorQuestionMark( + startX, + itemHeight, + playerCount, + itemWidth, + Spacing, + y + ); + Append(_randomPanel); - Recalculate(); - RecalculateChildren(); + Recalculate(); + RecalculateChildren(); - Log.Debug($"UISpawnSelectorPanel.BuildLayout: players={playerCount}"); - } - - public void Rebuild() - { - BuildLayout(); - } + Log.Debug($"UISpawnSelectorPanel.BuildLayout: players={playerCount}"); + } - public override void Update(GameTime gameTime) - { - if (NeedsRebuild()) + public void Rebuild() { - Rebuild(); + BuildLayout(); } - base.Update(gameTime); - } + public override void Update(GameTime gameTime) + { + if (NeedsRebuild()) + { + Rebuild(); + } - public override void Draw(SpriteBatch spriteBatch) - { - base.Draw(spriteBatch); - } + base.Update(gameTime); + } - private bool NeedsRebuild() - { - var dims = GetDimensions(); - if (dims.Width <= 0f || dims.Height <= 0f) - return true; + public override void Draw(SpriteBatch spriteBatch) + { + base.Draw(spriteBatch); + } - if (_randomPanel == null) - return true; + private bool NeedsRebuild() + { + var dims = GetDimensions(); + if (dims.Width <= 0f || dims.Height <= 0f) + return true; - var randomDims = _randomPanel.GetDimensions(); - if (randomDims.Width <= 0f || randomDims.Height <= 0f) - return true; + if (_randomPanel == null) + return true; - var local = Main.LocalPlayer; - var players = new List(); + var randomDims = _randomPanel.GetDimensions(); + if (randomDims.Width <= 0f || randomDims.Height <= 0f) + return true; - for (int i = 0; i < Main.maxPlayers; i++) - { - var p = Main.player[i]; - if (p == null || !p.active) - continue; - if (p.whoAmI == local.whoAmI || p.team != local.team) - continue; + var local = Main.LocalPlayer; + var players = new List(); - players.Add(p.whoAmI); - } + for (int i = 0; i < Main.maxPlayers; i++) + { + var p = Main.player[i]; + if (p == null) + continue; + if (p.whoAmI == local.whoAmI || p.team != local.team) + continue; + + players.Add(p.whoAmI); + } //#if DEBUG -// players.Add(local.whoAmI); +// players.Add(local.whoAmI); //#endif - if (players.Count != _playerItems.Count) - return true; + if (players.Count != _playerItems.Count) + return true; - for (int i = 0; i < players.Count; i++) - { - if (_playerItems[i] == null) return true; - if (_playerItems[i].PlayerIndex != players[i]) return true; + for (int i = 0; i < players.Count; i++) + { + if (_playerItems[i] == null) return true; + if (_playerItems[i].PlayerIndex != players[i]) return true; + } + + return false; } - return false; } - } diff --git a/Core/SpawnSelector/UI/SpawnSelectorCharacter.cs b/Core/SpawnSelector/UI/SpawnSelectorCharacter.cs index 4abc28a2..5427db31 100644 --- a/Core/SpawnSelector/UI/SpawnSelectorCharacter.cs +++ b/Core/SpawnSelector/UI/SpawnSelectorCharacter.cs @@ -2,7 +2,6 @@ using Microsoft.Xna.Framework.Graphics; using PvPAdventure.Core.Helpers; using PvPAdventure.Core.SpawnSelector.Players; -using PvPAdventure.Core.SpawnSelector.Systems; using ReLogic.Content; using System; using Terraria; @@ -10,8 +9,8 @@ using Terraria.GameContent.UI.Elements; using Terraria.ID; using Terraria.ModLoader; -using Terraria.ModLoader.UI; using Terraria.UI; +using Terraria.UI.Chat; namespace PvPAdventure.Core.SpawnSelector.UI { @@ -92,8 +91,8 @@ protected override void DrawSelf(SpriteBatch sb) //sb.Draw(_playerBGTexture.Value, pos, Color.White*0.5f); Rectangle rect = new( - x: (int)pos.X - 6, - y: (int)pos.Y - 6, + x: (int)pos.X-6, + y: (int)pos.Y-6, width: 100, height: 72); @@ -102,6 +101,15 @@ protected override void DrawSelf(SpriteBatch sb) DrawNineSlice(sb, rect.X, rect.Y, rect.Width, rect.Height, _playerBGTexture.Value, Color.White, 5); DrawMapFullscreenBackground(sb, rect, player); + sb.End(); + sb.Begin(SpriteSortMode.Deferred, + BlendState.AlphaBlend, + SamplerState.PointClamp, + DepthStencilState.Default, + RasterizerState.CullNone, + null, + Main.UIScaleMatrix); + AdventureMirrorPlayer.ForceFullBrightOnce = true; try { @@ -122,6 +130,16 @@ protected override void DrawSelf(SpriteBatch sb) AdventureMirrorPlayer.ForceFullBrightOnce = false; } + // Switch back to "normal" UI batch + sb.End(); + sb.Begin(SpriteSortMode.Deferred, + BlendState.AlphaBlend, + SamplerState.LinearClamp, + DepthStencilState.None, + RasterizerState.CullCounterClockwise, + null, + Main.UIScaleMatrix); + // Use the actual layout widths, not the texture width const float leftColumnWidth = 106f; // player background column const float rightAreaWidth = ItemWidth - 22f - leftColumnWidth; // 260 - 12 - 106 = 142 @@ -141,18 +159,28 @@ protected override void DrawSelf(SpriteBatch sb) ); // Draw name - Utils.DrawBorderString(sb, name, namePos, Color.White, nameScale); + Utils.DrawBorderString(sb,name,namePos,Color.White,nameScale); // Draw divider - sb.Draw(_dividerTexture.Value, new Vector2(rightAreaLeft - 12, inner.Y + 21f), null, Color.White, 0f, Vector2.Zero, new Vector2(rightAreaWidth / 8 + 2.2f, 1f), SpriteEffects.None, 0f); + sb.Draw( + _dividerTexture.Value, + new Vector2(rightAreaLeft-12, inner.Y + 21f), + null, + Color.White, + 0f, + Vector2.Zero, + new Vector2(rightAreaWidth/8+2.2f, 1f), + SpriteEffects.None, + 0f + ); // Stat panel settings float statScale = 0.88f; float statGap = 5f * statScale; // Draw stat panel - float panelWidth = rightAreaWidth + 24; - Vector2 panelPos = new(rightAreaLeft - 14, inner.Y + 29f); + float panelWidth = rightAreaWidth+24; + Vector2 panelPos = new(rightAreaLeft-14, inner.Y + 29f); DrawPanel(sb, panelPos, panelWidth); string hpText = $"{player.statLife} HP"; @@ -175,14 +203,20 @@ protected override void DrawSelf(SpriteBatch sb) // Draw health sb.Draw(heart.Value, new Vector2(startX, y), null, Color.White, 0f, Vector2.Zero, statScale, SpriteEffects.None, 0f); startX += heartW; - Utils.DrawBorderString(sb, hpText, new Vector2(startX + 1, y + 1f), Color.White, statScale); + Utils.DrawBorderString(sb, hpText, new Vector2(startX+1, y + 1f), Color.White, statScale); startX += hpSize.X; startX += statGap; // Draw mana sb.Draw(mana.Value, new Vector2(startX, y - 2), null, Color.White, 0f, Vector2.Zero, statScale, SpriteEffects.None, 0f); startX += manaW; - Utils.DrawBorderString(sb, mpText, new Vector2(startX + 1, y + 1f), Color.White, statScale); + Utils.DrawBorderString(sb, mpText, new Vector2(startX+1, y + 1f), Color.White, statScale); + + // Draw arrow + //DrawArrow(player); + + // Draw player head if hovering + DrawPlayerHeadOnMap(player); // Draw player respawn timer if it exists string respawnTimeInSeconds = (player.respawnTimer / 60 + 1).ToString(); @@ -190,12 +224,50 @@ protected override void DrawSelf(SpriteBatch sb) { Utils.DrawBorderStringBig(sb, respawnTimeInSeconds, pos + new Vector2(31, 4), Color.Gray, scale: 1f); } + } - // Draw teleport to if it exists - if (!player.dead && IsMouseHovering) - { - Main.instance.MouseText("Teleport to " + player.name); - } + private void DrawPlayerHeadOnMap(Player p) + { + if (p == null || !p.active || p.dead) + return; + + var config = ModContent.GetInstance(); + if (!IsMouseHovering || !config.ShowPlayerIndicationWhenWhenHovering) + return; + + Main.instance.MouseText("Teleport to " + p.name); + + float mapScale = Main.mapFullscreenScale; + + // Player in tile coords + Vector2 tilePos = p.Center / 16f; + + // Screen-space position on the fullscreen map (pixels) + Vector2 mapScreenCenter = new( + Main.screenWidth / 2f, + Main.screenHeight / 2f + ); + Vector2 headPosScreen = (tilePos - Main.mapFullscreenPos) * mapScale + mapScreenCenter; + //headPosScreen += new Vector2(80, 40); // offset + headPosScreen *= Main.UIScale; + + Matrix invUi = Matrix.Invert(Main.UIScaleMatrix); + Vector2 headPosUI = Vector2.Transform(headPosScreen, invUi); + + Color c = Main.teamColor[p.team]; + + // Draw head in UI-space + Main.MapPlayerRenderer.DrawPlayerHead(Main.Camera, p, headPosUI, scale: 1.3f, borderColor: c); + + // Text centered below head, also in UI-space + string name = p.name ?? string.Empty; + float textScale = 1f; + Vector2 nameSize = FontAssets.MouseText.Value.MeasureString(name) * textScale; + Vector2 namePos = new( + headPosUI.X - nameSize.X * 0.5f, + headPosUI.Y + 30f + ); + Utils.DrawBorderString(Main.spriteBatch, "Teleport to " + name, namePos, Color.White, textScale); } public override void MouseOver(UIMouseEvent evt) @@ -206,7 +278,6 @@ public override void MouseOver(UIMouseEvent evt) if (p == null || !p.active || p.dead) return; BackgroundColor = new Color(73, 92, 161, 150); - SpawnSelectorSystem.HoveredPlayerIndex = _playerIndex; } public override void MouseOut(UIMouseEvent evt) @@ -218,8 +289,6 @@ public override void MouseOut(UIMouseEvent evt) return; BackgroundColor = new Color(63, 82, 151) * 0.8f; - if (SpawnSelectorSystem.HoveredPlayerIndex == _playerIndex) - SpawnSelectorSystem.HoveredPlayerIndex = -1; } public override void LeftClick(UIMouseEvent evt) @@ -267,7 +336,7 @@ private void DrawPanel(SpriteBatch spriteBatch, Vector2 position, float width) ); } - [Obsolete("Doesn't work in MP. Use the new method instead.")] + public static void DrawMapFullscreenBackground_BadMP(SpriteBatch sb, Rectangle rect, Player player) { if (player == null || !player.active) @@ -353,7 +422,6 @@ public static void DrawMapFullscreenBackground_BadMP(SpriteBatch sb, Rectangle r sb.Draw(asset.Value, rect, color); } - // Finds the biome of the given player and draws it. public static void DrawMapFullscreenBackground(SpriteBatch sb, Rectangle rect, Player player) { if (player == null || !player.active) diff --git a/Core/Spawnbox/PvPIcons.cs b/Core/Spawnbox/PvPIcons.cs deleted file mode 100644 index 2ae534a3..00000000 --- a/Core/Spawnbox/PvPIcons.cs +++ /dev/null @@ -1,127 +0,0 @@ -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Graphics; -using PvPAdventure.Core.Helpers; -using PvPAdventure.System; -using System.Collections.Generic; -using Terraria; -using Terraria.ModLoader; -using Terraria.UI; - -namespace PvPAdventure.Core.Spawnbox; - -/// -/// Draws PvP icons above players when players are in the spawn region. -/// -[Autoload(Side = ModSide.Client)] -public class PvPIconDrawerLayer : ModSystem -{ - public override void PostUpdateEverything() - { - var gm = ModContent.GetInstance(); - var rm = ModContent.GetInstance(); - - // Iterate all players. - // Set the conditional PvP flag if player is in spawn box and the game is live. - for (int i = 0; i < Main.maxPlayers; i++) - { - Player p = Main.player[i]; - if (!p.active || p.dead) - continue; - - bool inRegion = rm.GetRegionContaining(p.Center.ToTileCoordinates()) != null; - bool isPlaying = gm.CurrentPhase == GameManager.Phase.Playing; - bool shouldDisablePvP = inRegion; - - var mp = p.GetModPlayer(); - if (mp.ShowPvPIcon != shouldDisablePvP) - { - mp.ShowPvPIcon = shouldDisablePvP; - } - } - } - public override void ModifyInterfaceLayers(List layers) - { - int index = layers.FindIndex(layer => layer.Name == "Vanilla: Interface Logic 1"); - if (index != -1) - layers.Insert(index + 1, new PvPIconLayer()); - } - - private sealed class PvPIconLayer : GameInterfaceLayer - { - public PvPIconLayer() - : base("PvPAdventure:PvPIconLayer", InterfaceScaleType.Game) - { - } - - protected override bool DrawSelf() - { - // Check playing status - var gm = ModContent.GetInstance(); - bool isPlaying = gm.CurrentPhase == GameManager.Phase.Playing; - - SpriteBatch sb = Main.spriteBatch; - int headOffset = 12; // distance above head - - // Setup assets - var pvpTex = Main.Assets.Request("Images/UI/PVP_0"); - //var cooldownTex = Main.Assets.Request("Images/CoolDown"); // old asset - var cooldownTex = Ass.Stop_Icon; - - float iconFullW = pvpTex.Value.Width; - float iconFullH = pvpTex.Value.Height; - float iconW = iconFullW / 4f; - float iconH = iconFullH / 6f; - - // Iterate players and draw PvP icon if - for (int i = 0; i < Main.maxPlayers; i++) - { - Player p = Main.player[i]; - if (!p.active || p.dead) - continue; - - // Skip self - //if (p.whoAmI == Main.myPlayer) - //continue; - - if (!p.GetModPlayer().ShowPvPIcon) - continue; - - Vector2 screenPos = p.Top + new Vector2(-iconW / 2f, -headOffset - iconH) - Main.screenPosition; - - Rectangle iconRect = new( - (int)screenPos.X, - (int)screenPos.Y, - (int)iconW, - (int)iconH - ); - - Rectangle iconSrc = pvpTex.Frame(4, 6, 2, p.team); - - // Draw PvP icon - sb.Draw(pvpTex.Value, iconRect, iconSrc, Color.White * 1f); - - float cooldownWidth = iconW; - float cooldownHeight = iconH; - - Rectangle cdRect = new( - (int)(screenPos.X + (iconW - cooldownWidth) * 0.5f), - (int)(screenPos.Y + (iconH - cooldownHeight) * 0.5f), - (int)cooldownWidth, - (int)cooldownHeight - ); - - // Draw cooldown icon - //if (isPlaying) - sb.Draw(cooldownTex.Value, cdRect, Color.White * 1f); - } - - return true; - } - } -} - -public class PvPIconPlayer : ModPlayer -{ - public bool ShowPvPIcon; -} - diff --git a/Core/Spawnbox/SpawnboxMap.cs b/Core/Spawnbox/SpawnboxMap.cs index ec088c24..bf791302 100644 --- a/Core/Spawnbox/SpawnboxMap.cs +++ b/Core/Spawnbox/SpawnboxMap.cs @@ -1,8 +1,6 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; -using PvPAdventure.Core.SpawnSelector.Players; using PvPAdventure.System; -using ReLogic.Graphics; using Terraria; using Terraria.GameContent; using Terraria.Map; @@ -68,55 +66,18 @@ private static void DrawSpawnBoxOnFullscreenMap(ref MapOverlayDrawContext contex h = spawnRect.Height; } - var gm = ModContent.GetInstance(); - var am = Main.LocalPlayer.GetModPlayer(); - bool canPass = gm.CurrentPhase == GameManager.Phase.Playing - && am.IsPlayerInSpawnRegion(); - // now draw using the (possibly clipped) rect Texture2D pix = TextureAssets.MagicPixel.Value; - Color col = Color.Black; - if (canPass) col = Color.Black * 0.5f; + Color col = Color.Black * 0.7f; int thickness = 2; if (Main.mapFullscreen) thickness = (int)(1 * Main.mapFullscreenScale); // match 1 pixel at scale 1 // top, bottom, left, right - Main.spriteBatch.Draw(pix,new Rectangle(x + thickness, y, w - thickness * 2, thickness),col); - Main.spriteBatch.Draw(pix,new Rectangle(x + thickness, y + h - thickness, w - thickness * 2, thickness),col); - Main.spriteBatch.Draw(pix,new Rectangle(x, y, thickness, h),col); - Main.spriteBatch.Draw(pix,new Rectangle(x + w - thickness, y, thickness, h),col); - - var font = FontAssets.DeathText.Value; - - float scale = context.MapScale * context.DrawScale*0.3f; - - Vector2 textSize = font.MeasureString("SPAWN") * scale; - - Vector2 textPos = new Vector2( - x + w / 2f - textSize.X / 2f, - y + h / 2f - textSize.Y / 2f - ); - textPos.Y -= 50*scale; - - // Helper to draw text - void drawSpawnText(Vector2 offset, Color c) - { - Main.spriteBatch.DrawString( - font, - "SPAWN", - textPos + offset, - c, - 0f, - Vector2.Zero, - scale, - SpriteEffects.None, - 0f - ); - } - - //drawSpawnText(new Vector2(2, 2) * scale, Color.Black * 0.75f); - //drawSpawnText(Vector2.Zero, Color.White); + Main.spriteBatch.Draw(pix, new Rectangle(x, y, w, thickness), col); + Main.spriteBatch.Draw(pix, new Rectangle(x, y + h - thickness, w, thickness), col); + Main.spriteBatch.Draw(pix, new Rectangle(x, y, thickness, h), col); + Main.spriteBatch.Draw(pix, new Rectangle(x + w - thickness, y, thickness, h), col); } } diff --git a/Core/Spawnbox/SpawnboxWorld.cs b/Core/Spawnbox/SpawnboxWorld.cs index 6f44f88e..b2757d5c 100644 --- a/Core/Spawnbox/SpawnboxWorld.cs +++ b/Core/Spawnbox/SpawnboxWorld.cs @@ -10,101 +10,149 @@ using Terraria.GameContent; using Terraria.ModLoader; using Terraria.UI; +using static PvPAdventure.System.RegionManager; -namespace PvPAdventure.Core.Spawnbox +namespace PvPAdventure.Core.Spawnbox; + +[Autoload(Side = ModSide.Client)] +public class SpawnBoxWorld : ModSystem { - [Autoload(Side = ModSide.Client)] - public class SpawnBoxWorld : ModSystem + // Initialize the interface layer. + private readonly SpawnBoxInterfaceLayer _spawnBoxInterfaceLayer = new(); + public Asset _playerBGTexture; + + // Load the texture. + public override void Load() { - public Asset _playerBGTexture; + if (!Main.dedServ) + _playerBGTexture = Ass.CustomPlayerBackground; + } - public override void Load() + // Add the layer. + public override void ModifyInterfaceLayers(List layers) + { + if (!layers.Contains(_spawnBoxInterfaceLayer)) { - if (!Main.dedServ) - _playerBGTexture = Ass.CustomPlayerBackground; + // add at the bottom interface layer + // https://github.com/tModLoader/tModLoader/wiki/Vanilla-Interface-layers-values + var layerIndex = layers.FindIndex(layer => layer.Name == "Vanilla: Interface Logic 1"); + + if (layerIndex != -1) + layers.Insert(layerIndex + 1, _spawnBoxInterfaceLayer); } + } - public override void ModifyInterfaceLayers(List layers) + private class SpawnBoxInterfaceLayer() : GameInterfaceLayer("PvPAdventure: Spawn Box", InterfaceScaleType.UI) + { + protected override bool DrawSelf() { - // Insert just after a vanilla UI layer so it's always on top of the world. - int idx = layers.FindIndex(l => l.Name == "Vanilla: Interface Logic 1"); - if (idx != -1) - { - layers.Insert(idx + 1, new SpawnBoxInterfaceLayer()); - } + // To see how to draw coordinates properly, see the wiki on Coordinates. + // https://github.com/tModLoader/tModLoader/wiki/Coordinates + + // Draw the spawn box. + DrawSpawnBox(Main.spriteBatch); + return base.DrawSelf(); } - private sealed class SpawnBoxInterfaceLayer : GameInterfaceLayer + private void DrawSpawnBox(SpriteBatch sb) { - public SpawnBoxInterfaceLayer() - : base("PvPAdventure: SpawnBox", InterfaceScaleType.Game) - { - } - - protected override bool DrawSelf() - { - DrawSpawnBox(Main.spriteBatch); - return true; - } - - private void DrawSpawnBox(SpriteBatch spriteBatch) - { - if (Main.dedServ) - return; - - // Set the spawnbox size. - int leftTile = Main.spawnTileX - 25; - int topTile = Main.spawnTileY - 25; - int rightTile = leftTile + 50; - int bottomTile = topTile + 50; - - // Get world coordinates. - Vector2 worldTopLeft = new(leftTile * 16f, topTile * 16f); - Vector2 worldBottomRight = new(rightTile * 16f, bottomTile * 16f); - - // Convert world coordinates to screen cordinates. - Vector2 screenTopLeft = worldTopLeft - Main.screenPosition; - Vector2 screenBottomRight = worldBottomRight - Main.screenPosition; - - int x = (int)Math.Floor(screenTopLeft.X); - int y = (int)Math.Floor(screenTopLeft.Y); - int w = (int)Math.Round(screenBottomRight.X - screenTopLeft.X); - int h = (int)Math.Round(screenBottomRight.Y - screenTopLeft.Y); - if (w <= 0 || h <= 0) - return; - - Rectangle rect = new(x, y, w, h); - rect.Inflate(16, 16); - - DrawNineSliceBorder(spriteBatch, rect); - } - - private void DrawNineSliceBorder(SpriteBatch sb, Rectangle rect) - { - // Set color - var gm = ModContent.GetInstance(); - var am = Main.LocalPlayer.GetModPlayer(); - bool canPass = gm.CurrentPhase == GameManager.Phase.Playing && am.IsPlayerInSpawnRegion(); - Color color = Color.Black * (canPass ? 0.5f : 1f); - - Texture2D tex = Ass.Spawnbox.Value; - const int srcCorner = 16; - int x = rect.X, y = rect.Y, w = rect.Width, h = rect.Height; - int srcEdgeWidth = tex.Width - srcCorner * 2; - int srcEdgeHeight = tex.Height - srcCorner * 2; - int dstCorner = srcCorner; - - sb.Draw(tex, new Rectangle(x, y, dstCorner, dstCorner), new Rectangle(0, 0, srcCorner, srcCorner), color); - sb.Draw(tex, new Rectangle(x + dstCorner, y, w - dstCorner * 2, dstCorner), new Rectangle(srcCorner, 0, srcEdgeWidth, srcCorner), color); - sb.Draw(tex, new Rectangle(x + w - dstCorner, y, dstCorner, dstCorner), new Rectangle(tex.Width - srcCorner, 0, srcCorner, srcCorner), color); - - sb.Draw(tex, new Rectangle(x, y + dstCorner, dstCorner, h - dstCorner * 2), new Rectangle(0, srcCorner, srcCorner, srcEdgeHeight), color); - sb.Draw(tex, new Rectangle(x + w - dstCorner, y + dstCorner, dstCorner, h - dstCorner * 2), new Rectangle(tex.Width - srcCorner, srcCorner, srcCorner, srcEdgeHeight), color); - - sb.Draw(tex, new Rectangle(x, y + h - dstCorner, dstCorner, dstCorner), new Rectangle(0, tex.Height - srcCorner, srcCorner, srcCorner), color); - sb.Draw(tex, new Rectangle(x + dstCorner, y + h - dstCorner, w - dstCorner * 2, dstCorner), new Rectangle(srcCorner, tex.Height - srcCorner, srcEdgeWidth, srcCorner), color); - sb.Draw(tex, new Rectangle(x + w - dstCorner, y + h - dstCorner, dstCorner, dstCorner), new Rectangle(tex.Width - srcCorner, tex.Height - srcCorner, srcCorner, srcCorner), color); - } + var rm = ModContent.GetInstance(); + if (rm.Regions.Count == 0) + return; + + Region region = rm.Regions[0]; + + // 🔹 this is the “solid ring” bounds in TILE space + Rectangle ring = region.CollisionRingBounds; + + int leftTile = ring.X; + int rightTile = ring.X + ring.Width; // exclusive + int topTile = ring.Y; + int bottomTile = ring.Y + ring.Height; // exclusive + + // Tile -> world + float leftWorld = leftTile * 16f; + float rightWorld = rightTile * 16f; + float topWorld = topTile * 16f; + float bottomWorld = bottomTile * 16f; + + // World -> screen + float uiScale = Main.UIScale; + + float leftScreen = (leftWorld - Main.screenPosition.X) / uiScale; + float rightScreen = (rightWorld - Main.screenPosition.X) / uiScale; + float topScreen = (topWorld - Main.screenPosition.Y) / uiScale; + float bottomScreen = (bottomWorld - Main.screenPosition.Y) / uiScale; + + + var gm = ModContent.GetInstance(); + var am = Main.LocalPlayer.GetModPlayer(); + + float solidOpacity = 1.0f; + float lightOpacity = 0.5f; + + float opacity = gm.CurrentPhase == GameManager.Phase.Playing + ? (am.IsPlayerInSpawnRegion() ? lightOpacity : solidOpacity) + : solidOpacity; + + int l = (int)leftScreen; + int r = (int)rightScreen; + int t = (int)topScreen; + int b = (int)bottomScreen; + + int thickness = (int)Math.Max(1f, 16f / uiScale); + //Texture2D pix = TextureAssets.MagicPixel.Value; + //Color col = Color.Gray * 0.7f; + + // vanilla borders (top,left,bottom,right) + //sb.Draw(pix, new Rectangle(l, t, r - l, thickness), col); + //sb.Draw(pix, new Rectangle(l, b - thickness, r - l, thickness), col); + //sb.Draw(pix, new Rectangle(l, t, thickness, b - t), col); + //sb.Draw(pix, new Rectangle(r - thickness, t, thickness, b - t), col); + + Rectangle screenRect = new(l,t,r - l, b - t); + DrawNineSliceBorder(sb, screenRect, Color.White * opacity); + } + + private void DrawNineSliceBorder(SpriteBatch sb, Rectangle rect, Color color) + { + Texture2D tex = ModContent.GetInstance()._playerBGTexture.Value; + + + tex = Ass.Spawnbox.Value; + + int c = 16; // corner size + int x = rect.X; + int y = rect.Y; + int w = rect.Width; + int h = rect.Height; + + int ew = tex.Width - c * 2; + int eh = tex.Height - c * 2; + + // top-left + sb.Draw(tex, new Rectangle(x, y, c, c), new Rectangle(0, 0, c, c), color); + + // top + sb.Draw(tex, new Rectangle(x + c, y, w - c * 2, c), new Rectangle(c, 0, ew, c), color); + + // top-right + sb.Draw(tex, new Rectangle(x + w - c, y, c, c), new Rectangle(tex.Width - c, 0, c, c), color); + + // left + sb.Draw(tex, new Rectangle(x, y + c, c, h - c * 2), new Rectangle(0, c, c, eh), color); + + // right + sb.Draw(tex, new Rectangle(x + w - c, y + c, c, h - c * 2), new Rectangle(tex.Width - c, c, c, eh), color); + + // bottom-left + sb.Draw(tex, new Rectangle(x, y + h - c, c, c), new Rectangle(0, tex.Height - c, c, c), color); + + // bottom + sb.Draw(tex, new Rectangle(x + c, y + h - c, w - c * 2, c),new Rectangle(c, tex.Height - c, ew, c), color); + + // bottom-right + sb.Draw(tex, new Rectangle(x + w - c, y + h - c, c, c),new Rectangle(tex.Width - c, tex.Height - c, c, c), color); } } } diff --git a/System/Client/Keybinds.cs b/System/Client/Keybinds.cs index d72d756f..8d7699b5 100644 --- a/System/Client/Keybinds.cs +++ b/System/Client/Keybinds.cs @@ -9,11 +9,13 @@ public class Keybinds : ModSystem public ModKeybind Scoreboard { get; private set; } public ModKeybind BountyShop { get; private set; } public ModKeybind AllChat { get; private set; } + public ModKeybind AdventureMirrorKeybind { get; private set; } public override void Load() { Scoreboard = KeybindLoader.RegisterKeybind(Mod, "Scoreboard", Keys.OemTilde); BountyShop = KeybindLoader.RegisterKeybind(Mod, "BountyShop", Keys.P); AllChat = KeybindLoader.RegisterKeybind(Mod, "AllChat", Keys.U); + AdventureMirrorKeybind = KeybindLoader.RegisterKeybind(Mod, "AdventureMirror", Keys.M); } } \ No newline at end of file From e7fa1ead2b84971bf71e3d38337414aa95e883f3 Mon Sep 17 00:00:00 2001 From: emyhrberg <121192176+emyhrberg@users.noreply.github.com> Date: Thu, 4 Dec 2025 05:46:08 +0100 Subject: [PATCH 201/206] Updated stop icon --- Assets/SpawnSelector/CoolDown.png | Bin 912 -> 0 bytes Assets/SpawnSelector/Stop_Icon.png | Bin 912 -> 772 bytes Core/Debug/DebugChat.cs | 4 ++-- Core/SpawnSelector/Systems/ItemSlotHooks.cs | 8 ++++---- Core/SpawnSelector/UI/SpawnSelectorBasePanel.cs | 1 - Core/Spawnbox/PvPIcons.cs | 4 ++-- 6 files changed, 8 insertions(+), 9 deletions(-) delete mode 100644 Assets/SpawnSelector/CoolDown.png diff --git a/Assets/SpawnSelector/CoolDown.png b/Assets/SpawnSelector/CoolDown.png deleted file mode 100644 index 0c2273111d6f8afd2428947fdd328f8a4959e328..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 912 zcmV;B18@9^P)vKj_88f55AW3IWo@NH~!g6Tm8=EqWB_4`{nP&&;&DEbVN!RTE<3Yc`p_ zoq6x`-kW)uC1%EHia1s8_!j|)Xr72T21epL#kynI^8|fwQZ-c>LsWz^Rqq7o&1B!$Y=ENL3 z?{uq*4ryV1_LdG_4aM(O22o#oPD+$O0T85dT@k zX73$sEbPeDqD%~YUxLkqqEcE_H>NdIUjlWWz37)k4m0UhJ>KfQtKL=T*fs{gy=h+C zT1isFkHGn&Uy53m%o(5np&KK_j^`$>?JgciSuP{lGto*WfWn~(%nX1)?UQm3Pct8b zQ6>WC8<%?G*m^MA6hf^T%)GB{MZb^CMs7l8#<+d)L?l6olIniB0%$$e6r#R7rV}Sj z01h$esAK}u5F@*b$NM1yBIumsUC{ud`z$Pw?;s2!SdJ(N$qd)-fH*8g130-ngkLqZ z1W{2Z?duP`?jJKkC~L8bW3(k26(^lXop*h-RFt^_Zn-wrhbDapzo*o)nWTL*?E@5O z!KD~*hJk^dh+b}J+d>Eoq~Gars(%vfI-xCD7^2eB=>P@GLhAOEA5l~$JaMFp&0bv& zpyoV@T!W7WfSPDy6-d|)!^!L*JN2Sv2$fM63=%druHJ{Fs*CBY?x>0SwIakAEcKHT zq7s9`4dOiDI4@d}mW3GZNJqE$)S+25z|=-*1KNReAXF|SQh)3Nw2kkAu&N%U0raGj;eZ?#j}(|0ZbCl zGONFTB{SW0US1y6x-srP(O$g{w`ApDNqCO`{8HKsMD6shbKR)q^ZuN69Q(p5iZ&hq m3WP(R`F8Em|Bq9gvit%vLq+z)<>a3L00002Ds3LF5QusXyV3& z?u^8b;KsPr_(D{C5JDP_#s(-QeK9Si?=shvs7XVofW4on${t(nb{Rg?be4rJxiv$d%5A6fybEg#2|!01^L7#k-OZ4y!QJLBf4bjKMmjoF z{VJ<&(X{AjEJxzF^5ZLRx;>yMP0iHXn39175Ry{Lu*6y&)rDW>bmqkpO zY*oqQc1a{y#k$F_*eyH^g6^6Q4|Wff4}QPztu*bdHczL z#jIL&mBBD`;xsugImwf*9&)O^fj-<)w!j&9+_6d+G@EKxW+0cP7B}*^3>rqR6_IGP zvC%f>_K;~`A0p8Rt}cCp!C-_=LnFAl3ejW)!{{+(6u>eqxSj~()zS*p5U`?QQ6%?| zctI-^ELH)bPzcFXQ5u3^fyd>MXsz+#{aXUd5GT(=mXojxB3M?BbSed+ t)qvBt>m3ELbHbhIkMRQ9y|ydgY*jgP3599z1yCAch3)p8P-P#l(NW ztBDE$(!@wOkr)%eDxocU6zC6VyF1U!w7V?rY`0YtV&ZEynZBKQ@AKZ9d6^|<#%YQ; zRqyy00f=axh&be#Z`&TXxCd&+e`nSBOW%aASL-Dh76}Yx7d&->ndklr0EIYiChdSw zGXT%|3CDtv{Oc z&x6Vw%tj~#nE*_YSA>fj=_T)PgTY{_Hm;1Lvl4>?ii8m6#2h>CbgPOEe`#TT_LdG_4aM(O22o#oPD+$O0T85dT@kX73$sEbPeDqD%~Y zUxLkqqEcE_H>NdIUjlWWz37)k4m0UhJ>KfQtKL=T*fs{gy=h+CT1isFkHGn&Uy53m z%o(5np&KK_j^`$>?Jgcie_1Xg*)!2fCV;}B3Cs+DK<$%q4^J~6gHa{|=Np%L;@EmH z+Y~~r8O*$|ZAHJ2%tmfPX2!UE@kAs+h?44lxdLcC)fA$>Jf;&TOaKls=%{1@(-0%O zi^uyR0wU;~<6Y4JqWdf?knbQ2B3O2a!m66`vmEm;_%($eVw1Ig7T@Ik;Jc(R`j|PC6 zXk!&f*bc+V>>xY!f1+gwl~ETA5;iuj-iM^Bi|MTHsEPWuBE%Rh^^+2!5`(+EhV3WM zTY^v>Ge!c$fK{%5ScXO)mH|zAJ^Nk{NC=cA10O!&^UcRiAv`HT`r{SrAT)Yyzts!L zp^&f<(^(1DyI$0M))|mk7Wa3L0000()) - { - return; - } + //if (player.HeldItem.type != ModContent.ItemType()) + //{ + //return; + //} } } diff --git a/Core/SpawnSelector/UI/SpawnSelectorBasePanel.cs b/Core/SpawnSelector/UI/SpawnSelectorBasePanel.cs index 58e7a44b..1e291bbb 100644 --- a/Core/SpawnSelector/UI/SpawnSelectorBasePanel.cs +++ b/Core/SpawnSelector/UI/SpawnSelectorBasePanel.cs @@ -7,7 +7,6 @@ namespace PvPAdventure.Core.SpawnSelector.UI; -// public class SpawnSelectorBasePanel : UIPanel { private UIPanel _randomPanel; diff --git a/Core/Spawnbox/PvPIcons.cs b/Core/Spawnbox/PvPIcons.cs index 75df3b6d..580a6df8 100644 --- a/Core/Spawnbox/PvPIcons.cs +++ b/Core/Spawnbox/PvPIcons.cs @@ -105,14 +105,14 @@ protected override bool DrawSelf() Rectangle cdRect = new( (int)(screenPos.X + (iconW - cooldownWidth) * 0.5f), - (int)(screenPos.Y + (iconH - cooldownHeight) * 0.5f), + (int)(screenPos.Y + (iconH - cooldownHeight) * 0.5f-2), (int)cooldownWidth, (int)cooldownHeight ); // Draw cooldown icon //if (isPlaying) - sb.Draw(cooldownTex.Value, cdRect, Color.White * 0.8f); + sb.Draw(cooldownTex.Value, cdRect, Color.White * 1f); } return true; From f5359b88ec40a97465a003b9e9c2dde4800c839d Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Wed, 3 Dec 2025 20:56:40 -0800 Subject: [PATCH 202/206] waddddd --- Assets/SpawnSelector/CoolDown.png | Bin 0 -> 912 bytes Assets/SpawnSelector/Stop_Icon.png | Bin 0 -> 912 bytes Content/Items/AdventureMirror.cs | 34 +- Core/Debug/DebugChat.cs | 2 + Core/Debug/DebugPlayer.cs | 18 + Core/Helpers/AssetLoader.cs | 5 +- .../InventoryWhileDeadSystem.cs | 84 ++++ .../InventoryWhileUsingItemSystem.cs | 61 +++ .../Players/AdventureMirrorPlayer.cs | 28 +- .../{UI => Systems}/BedsOnMap.cs | 53 +-- Core/SpawnSelector/Systems/ItemSlotHooks.cs | 436 +++++++++++++++++- .../SpawnSelector/Systems/PlayerHeadsOnMap.cs | 66 +++ Core/SpawnSelector/Systems/SpawnHooks.cs | 6 +- .../Systems/SpawnSelectorSystem.cs | 3 + .../UI/SpawnSelectorBasePanel.cs | 240 +++++----- .../UI/SpawnSelectorCharacter.cs | 108 +---- Core/Spawnbox/PvPIcons.cs | 2 +- Core/Spawnbox/SpawnboxMap.cs | 49 +- Core/Spawnbox/SpawnboxWorld.cs | 216 ++++----- System/Client/Keybinds.cs | 2 - 20 files changed, 977 insertions(+), 436 deletions(-) create mode 100644 Assets/SpawnSelector/CoolDown.png create mode 100644 Assets/SpawnSelector/Stop_Icon.png create mode 100644 Core/Debug/DebugPlayer.cs create mode 100644 Core/InventoryWhileDead/InventoryWhileDeadSystem.cs create mode 100644 Core/InventoryWhileDead/InventoryWhileUsingItemSystem.cs rename Core/SpawnSelector/{UI => Systems}/BedsOnMap.cs (67%) create mode 100644 Core/SpawnSelector/Systems/PlayerHeadsOnMap.cs diff --git a/Assets/SpawnSelector/CoolDown.png b/Assets/SpawnSelector/CoolDown.png new file mode 100644 index 0000000000000000000000000000000000000000..0c2273111d6f8afd2428947fdd328f8a4959e328 GIT binary patch literal 912 zcmV;B18@9^P)vKj_88f55AW3IWo@NH~!g6Tm8=EqWB_4`{nP&&;&DEbVN!RTE<3Yc`p_ zoq6x`-kW)uC1%EHia1s8_!j|)Xr72T21epL#kynI^8|fwQZ-c>LsWz^Rqq7o&1B!$Y=ENL3 z?{uq*4ryV1_LdG_4aM(O22o#oPD+$O0T85dT@k zX73$sEbPeDqD%~YUxLkqqEcE_H>NdIUjlWWz37)k4m0UhJ>KfQtKL=T*fs{gy=h+C zT1isFkHGn&Uy53m%o(5np&KK_j^`$>?JgciSuP{lGto*WfWn~(%nX1)?UQm3Pct8b zQ6>WC8<%?G*m^MA6hf^T%)GB{MZb^CMs7l8#<+d)L?l6olIniB0%$$e6r#R7rV}Sj z01h$esAK}u5F@*b$NM1yBIumsUC{ud`z$Pw?;s2!SdJ(N$qd)-fH*8g130-ngkLqZ z1W{2Z?duP`?jJKkC~L8bW3(k26(^lXop*h-RFt^_Zn-wrhbDapzo*o)nWTL*?E@5O z!KD~*hJk^dh+b}J+d>Eoq~Gars(%vfI-xCD7^2eB=>P@GLhAOEA5l~$JaMFp&0bv& zpyoV@T!W7WfSPDy6-d|)!^!L*JN2Sv2$fM63=%druHJ{Fs*CBY?x>0SwIakAEcKHT zq7s9`4dOiDI4@d}mW3GZNJqE$)S+25z|=-*1KNReAXF|SQh)3Nw2kkAu&N%U0raGj;eZ?#j}(|0ZbCl zGONFTB{SW0US1y6x-srP(O$g{w`ApDNqCO`{8HKsMD6shbKR)q^ZuN69Q(p5iZ&hq m3WP(R`F8Em|Bq9gvit%vLq+z)<>a3L0000vKj_88f55AW3IWo@NH~!g6Tm8=EqWB_4`{nP&&;&DEbVN!RTE<3Yc`p_ zoq6x`-kW)uC1%EHia1s8_!j|)Xr72T21epL#kynI^8|fwQZ-c>LsWz^Rqq7o&1B!$Y=ENL3 z?{uq*4ryV1_LdG_4aM(O22o#oPD+$O0T85dT@k zX73$sEbPeDqD%~YUxLkqqEcE_H>NdIUjlWWz37)k4m0UhJ>KfQtKL=T*fs{gy=h+C zT1isFkHGn&Uy53m%o(5np&KK_j^`$>?JgciSuP{lGto*WfWn~(%nX1)?UQm3Pct8b zQ6>WC8<%?G*m^MA6hf^T%)GB{MZb^CMs7l8#<+d)L?l6olIniB0%$$e6r#R7rV}Sj z01h$esAK}u5F@*b$NM1yBIumsUC{ud`z$Pw?;s2!SdJ(N$qd)-fH*8g130-ngkLqZ z1W{2Z?duP`?jJKkC~L8bW3(k26(^lXop*h-RFt^_Zn-wrhbDapzo*o)nWTL*?E@5O z!KD~*hJk^dh+b}J+d>Eoq~Gars(%vfI-xCD7^2eB=>P@GLhAOEA5l~$JaMFp&0bv& zpyoV@T!W7WfSPDy6-d|)!^!L*JN2Sv2$fM63=%druHJ{Fs*CBY?x>0SwIakAEcKHT zq7s9`4dOiDI4@d}mW3GZNJqE$)S+25z|=-*1KNReAXF|SQh)3Nw2kkAu&N%U0raGj;eZ?#j}(|0ZbCl zGONFTB{SW0US1y6x-srP(O$g{w`ApDNqCO`{8HKsMD6shbKR)q^ZuN69Q(p5iZ&hq m3WP(R`F8Em|Bq9gvit%vLq+z)<>a3L0000(); - Point tilePos = player.Center.ToTileCoordinates(); - var region = regionManager.GetRegionContaining(tilePos); - if (region != null) - { - return true; - } - - // Is player in bed spawn region? - Vector2 bedSpawnPoint = new(player.SpawnX, player.SpawnY); - float distanceToBedSpawn = Vector2.Distance(bedSpawnPoint * 16f, player.Center); - if (distanceToBedSpawn <= 25 * 16f) - { - return true; - } - - return false; - } - public override void UseStyle(Player player, Rectangle heldItemFrame) { base.UseStyle(player, heldItemFrame); - if (IsPlayerInSpawnRegion(player)) - { - //PopupTextHelper.NewText("cannot use in spawn!", player); - //CancelItemUse(player); - //return; - } + //if (IsPlayerInSpawnRegion(player)) + //{ + // //PopupTextHelper.NewText("cannot use in spawn!", player); + // //CancelItemUse(player); + // //return; + //} // If this player moves, cancel their use if (player.velocity.LengthSquared() > 0) diff --git a/Core/Debug/DebugChat.cs b/Core/Debug/DebugChat.cs index 07c99398..12ca92b9 100644 --- a/Core/Debug/DebugChat.cs +++ b/Core/Debug/DebugChat.cs @@ -7,6 +7,7 @@ namespace PvPAdventure.Core.Debug; +#if DEBUG internal class DebugChat : ModSystem { public override void Load() @@ -41,3 +42,4 @@ private void OnAddNewChatMessage(On_RemadeChatMonitor.orig_AddNewMessage orig, R timeLeftField?.SetValue(msg, 60 * 60); } } +#endif \ No newline at end of file diff --git a/Core/Debug/DebugPlayer.cs b/Core/Debug/DebugPlayer.cs new file mode 100644 index 00000000..da45dd9f --- /dev/null +++ b/Core/Debug/DebugPlayer.cs @@ -0,0 +1,18 @@ + +using Terraria.DataStructures; +using Terraria.ModLoader; + +namespace PvPAdventure.Core.Debug; + +#if DEBUG +internal class DebugPlayer : ModPlayer +{ + public override void Kill(double damage, int hitDirection, bool pvp, PlayerDeathReason damageSource) + { + Player.respawnTimer = 120; // 2 seconds + //Player.respawnTimer = 600; // 10 seconds + //Player.respawnTimer = 0; + base.Kill(damage, hitDirection, pvp, damageSource); + } +} +#endif diff --git a/Core/Helpers/AssetLoader.cs b/Core/Helpers/AssetLoader.cs index ed2a2158..776da002 100644 --- a/Core/Helpers/AssetLoader.cs +++ b/Core/Helpers/AssetLoader.cs @@ -7,12 +7,15 @@ namespace PvPAdventure.Core.Helpers; public static class Ass { - public static Asset Question_Mark; + // Spawn selector assets public static Asset[] MapBG; public static Asset Arrow; public static Asset CustomPlayerBackground; public static Asset Spawnbox; public static Asset Pause; + public static Asset Stop_Icon; + public static Asset Question_Mark; + public static bool Initialized { get; set; } diff --git a/Core/InventoryWhileDead/InventoryWhileDeadSystem.cs b/Core/InventoryWhileDead/InventoryWhileDeadSystem.cs new file mode 100644 index 00000000..84aab72d --- /dev/null +++ b/Core/InventoryWhileDead/InventoryWhileDeadSystem.cs @@ -0,0 +1,84 @@ +using Terraria; +using Terraria.ModLoader; + +namespace PvPAdventure.Core.InventoryWhileDead; + +// Allows inventory access while player is dead. +internal class InventoryWhileDeadSystem : ModSystem +{ + public override void Load() + { + On_Main.DrawInterface_26_InterfaceLogic3 += ModifyInterfaceLogic; + On_Player.TryOpeningInGameOptionsBasedOnInput += ModifyIngameOptionsInput; + } + public override void Unload() + { + On_Main.DrawInterface_26_InterfaceLogic3 -= ModifyInterfaceLogic; + On_Player.TryOpeningInGameOptionsBasedOnInput -= ModifyIngameOptionsInput; + } + + private void ModifyIngameOptionsInput(On_Player.orig_TryOpeningInGameOptionsBasedOnInput orig, Player self) + { + //orig(self); + + // Override to allow inventory access while dead + if (self.dead) + { + if (self.controlInv) + { + if (self.releaseInventory) + { + self.releaseInventory = false; + self.ToggleInv(); // actually toggles the inventory + } + } + else + { + self.releaseInventory = true; + } + + return; + } + + // Vanilla logic + if (self.controlInv) + { + if (self.releaseInventory) + { + self.releaseInventory = false; + if (Main.ingameOptionsWindow) + { + IngameOptions.Close(); + } + else + { + IngameOptions.Open(); + } + } + } + else + { + self.releaseInventory = true; + } + } + + private void ModifyInterfaceLogic(On_Main.orig_DrawInterface_26_InterfaceLogic3 orig) + { + bool flag = Main.playerInventory; + if (Main.player[Main.myPlayer].dead) + { + //Main.playerInventory = false; // skip this + } + if (!Main.playerInventory) + { + Main.player[Main.myPlayer].chest = -1; + Main.InGuideCraftMenu = false; + Main.InReforgeMenu = false; + if (flag) + { + Recipe.FindRecipes(); + } + } + Main.hoverItemName = ""; + } +} diff --git a/Core/InventoryWhileDead/InventoryWhileUsingItemSystem.cs b/Core/InventoryWhileDead/InventoryWhileUsingItemSystem.cs new file mode 100644 index 00000000..b92116a0 --- /dev/null +++ b/Core/InventoryWhileDead/InventoryWhileUsingItemSystem.cs @@ -0,0 +1,61 @@ +//using MonoMod.RuntimeDetour; +//using PvPAdventure.Core.Helpers; +//using System; +//using System.Reflection; +//using Terraria; +//using Terraria.GameInput; +//using Terraria.ModLoader; +//using Terraria.UI; + +//namespace PvPAdventure.Core.InventoryWhileUsingItem; + +//internal class InventoryWhileUsingItemSystem : ModSystem +//{ +// private Hook ignoreMouseHook; +// private Hook leftClickHook; + +// public override void Load() +// { +// On_Main.DrawInterface_0_InterfaceLogic1 += ModifyInterface0; + +// // Mouse interface +// MethodInfo getter = typeof(PlayerInput).GetMethod( +// "get_IgnoreMouseInterface", +// BindingFlags.Public | BindingFlags.Static +// ); + +// if (getter == null) +// { +// Log.Error("Getter not found!"); +// return; +// } + +// ignoreMouseHook = new Hook(getter, (Func, bool>)OverrideIgnoreMouseInterface); +// } + +// //private bool OverrideIgnoreMouseInterface(Func orig) +// //{ + +// private void ModifyInterface0(On_Main.orig_DrawInterface_0_InterfaceLogic1 orig) +// { +// // do nothing +// } + +// public override void Unload() +// { +// On_Main.DrawInterface_0_InterfaceLogic1 -= ModifyInterface0; +// ignoreMouseHook?.Dispose(); +// } + +// private bool OverrideIgnoreMouseInterface(Func orig) +// { +// Player player = Main.LocalPlayer; + +// // Allow mouse to interact while using items +// if (player.itemAnimation > 0) +// return false; + +// // fallback to vanilla +// return orig(); +// } +//} diff --git a/Core/SpawnSelector/Players/AdventureMirrorPlayer.cs b/Core/SpawnSelector/Players/AdventureMirrorPlayer.cs index d7eb5fa7..2fd68712 100644 --- a/Core/SpawnSelector/Players/AdventureMirrorPlayer.cs +++ b/Core/SpawnSelector/Players/AdventureMirrorPlayer.cs @@ -35,9 +35,9 @@ public override void OnHurt(Player.HurtInfo info) } } - public bool IsPlayerInSpawnRegion(int extraTileOffset=0) + public bool IsPlayerInSpawnRegion() { - // Is player in spawn region? + // Is player in resin's spawn region? var regionManager = ModContent.GetInstance(); Point tilePos = Player.Center.ToTileCoordinates(); var region = regionManager.GetRegionContaining(tilePos); @@ -54,6 +54,30 @@ public bool IsPlayerInSpawnRegion(int extraTileOffset=0) return true; } + // Is player in any bed spawn region? + for (int i = 0; i < Main.maxPlayers; i++) + { + Player other = Main.player[i]; + + if (other == null || !other.active || other.whoAmI == Player.whoAmI) + continue; + + // Only care about same team and non-zero team + if (other.team == 0 || other.team != Player.team) + continue; + + // No bed set for this teammate + if (other.SpawnX == -1 || other.SpawnY == -1) + continue; + + Vector2 teammateBedTile = new Vector2(other.SpawnX, other.SpawnY); + float distanceToTeammateBed = Vector2.Distance(teammateBedTile * 16f, Player.Center); + + if (distanceToTeammateBed <= 25*16f) + { + return true; + } + } return false; } diff --git a/Core/SpawnSelector/UI/BedsOnMap.cs b/Core/SpawnSelector/Systems/BedsOnMap.cs similarity index 67% rename from Core/SpawnSelector/UI/BedsOnMap.cs rename to Core/SpawnSelector/Systems/BedsOnMap.cs index ac8feb52..92a335ce 100644 --- a/Core/SpawnSelector/UI/BedsOnMap.cs +++ b/Core/SpawnSelector/Systems/BedsOnMap.cs @@ -1,6 +1,5 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; -using PvPAdventure.Core.SpawnSelector.Systems; using ReLogic.Content; using Terraria; using Terraria.DataStructures; @@ -10,7 +9,7 @@ using Terraria.ModLoader; using Terraria.UI; -namespace PvPAdventure.Core.SpawnSelector.UI; +namespace PvPAdventure.Core.SpawnSelector.Systems; internal class BedsOnMap : ModSystem { @@ -19,7 +18,6 @@ internal class BedsOnMap : ModSystem public override void Load() { On_SpawnMapLayer.Draw += OnSpawnMapLayer; - } public override void Unload() @@ -35,7 +33,7 @@ public override void PostSetupContent() } } - private void OnSpawnMapLayer(On_SpawnMapLayer.orig_Draw orig,SpawnMapLayer self,ref MapOverlayDrawContext context, ref string text) + private void OnSpawnMapLayer(On_SpawnMapLayer.orig_Draw orig, SpawnMapLayer self, ref MapOverlayDrawContext context, ref string text) { // Let vanilla draw spawn point + local bed first orig(self, ref context, ref text); @@ -53,10 +51,6 @@ private void OnSpawnMapLayer(On_SpawnMapLayer.orig_Draw orig,SpawnMapLayer self, Vector2 bedTilePos = new(player.SpawnX, player.SpawnY); -#if DEBUG - DrawBedSpawnDebugRect(player, bedTilePos); -#endif - // Safety check and load texture if needed spawnBedTexture ??= TextureAssets.SpawnBed; @@ -113,51 +107,10 @@ private void OnSpawnMapLayer(On_SpawnMapLayer.orig_Draw orig,SpawnMapLayer self, #endif } } - + } } } } - -#if DEBUG - private static void DrawBedSpawnDebugRect(Player player, Vector2 bedTilePos) - { - if (!Main.mapFullscreen) - { - return; - } - - // World-space center of the bed (pixels) - Vector2 bedWorld = bedTilePos * 16f; - - // Convert world -> fullscreen map screen coordinates - Vector2 screenCenter = new(Main.screenWidth / 2f, Main.screenHeight / 2f); - Vector2 bedOnMap = (bedWorld - Main.mapFullscreenPos) * Main.mapFullscreenScale + screenCenter; - - float radiusWorld = 25 * 16f; // 25 tiles in world space - float radiusOnMap = radiusWorld * Main.mapFullscreenScale; - - Texture2D pixel = TextureAssets.MagicPixel.Value; - float thickness = 2f; - - Rectangle rect = new( - (int)(bedOnMap.X - radiusOnMap), - (int)(bedOnMap.Y - radiusOnMap), - (int)(radiusOnMap * 2f), - (int)(radiusOnMap * 2f) - ); - - Color color = Main.teamColor[player.team] * 0.75f; - - // Top - Main.spriteBatch.Draw(pixel, new Rectangle(rect.Left, rect.Top, rect.Width, (int)thickness), color); - // Bottom - Main.spriteBatch.Draw(pixel, new Rectangle(rect.Left, rect.Bottom - (int)thickness, rect.Width, (int)thickness), color); - // Left - Main.spriteBatch.Draw(pixel, new Rectangle(rect.Left, rect.Top, (int)thickness, rect.Height), color); - // Right - Main.spriteBatch.Draw(pixel, new Rectangle(rect.Right - (int)thickness, rect.Top, (int)thickness, rect.Height), color); - } -#endif } diff --git a/Core/SpawnSelector/Systems/ItemSlotHooks.cs b/Core/SpawnSelector/Systems/ItemSlotHooks.cs index 92cd76be..1f39693a 100644 --- a/Core/SpawnSelector/Systems/ItemSlotHooks.cs +++ b/Core/SpawnSelector/Systems/ItemSlotHooks.cs @@ -1,12 +1,18 @@ -using Terraria; +using PvPAdventure.Content.Items; +using System; +using System.Linq; +using Terraria; +using Terraria.Audio; +using Terraria.DataStructures; +using Terraria.GameContent.Achievements; using Terraria.ModLoader; using Terraria.UI; -using PvPAdventure.Content.Items; namespace PvPAdventure.Core.SpawnSelector.Systems; /// /// Prevents the Adventure Mirror from being removed from the player inventory via trashing or selling. +/// Various inventory hooks are used to achieve this. /// public class ItemSlotHooks : ModSystem { @@ -14,6 +20,7 @@ public override void Load() { On_ItemSlot.LeftClick_SellOrTrash += Hook_LeftClick_SellOrTrash; On_ItemSlot.LeftClick_ItemArray_int_int += Hook_LeftClick_ItemArray; + On_ItemSlot.RightClick_ItemArray_int_int += Hook_RightClick; On_Player.SellItem += Hook_SellItem; On_Player.DropSelectedItem += Hook_DropSelectedItem; On_Player.dropItemCheck += Hook_DropItemCheck; @@ -28,6 +35,121 @@ public override void Unload() On_Player.dropItemCheck -= Hook_DropItemCheck; } + // Vanilla method with the item animation check removed for Adventure Mirror. + private static void Hook_RightClick( + On_ItemSlot.orig_RightClick_ItemArray_int_int orig, + Item[] inv, int context, int slot) + { + Player player = Main.player[Main.myPlayer]; + inv[slot].newAndShiny = false; + if (player.itemAnimation > 0 && player.HeldItem.type != ModContent.ItemType()) + { + return; + } + if (context == 15) + { + ItemSlot.HandleShopSlot(inv, slot, rightClickIsValid: true, leftClickIsValid: false); + } + else + { + if (!Main.mouseRight) + { + return; + } + if (context == 0 && Main.mouseRightRelease) + { + ItemSlot.TryItemSwap(inv[slot]); + } + if (context == 0 && ItemLoader.CanRightClick(inv[slot])) + { + if (Main.mouseRightRelease) + { + if (Main.ItemDropsDB.GetRulesForItemID(inv[slot].type).Any()) + { + ItemSlot.TryOpenContainer(inv[slot], player); + } + else + { + ItemLoader.RightClick(inv[slot], player); + } + } + return; + } + switch (Math.Abs(context)) + { + case 9: + case 11: + if (Main.mouseRightRelease) + { + ItemSlot.SwapVanityEquip(inv, context, slot, player); + } + break; + case 12: + case 25: + case 27: + case 33: + if (Main.mouseRightRelease) + { + ItemSlot.TryPickupDyeToCursor(context, inv, slot, player); + } + break; + case 0: + case 3: + case 4: + case 32: + if (inv[slot].maxStack == 1) + { + if (Main.mouseRightRelease) + { + ItemSlot.SwapEquip(inv, context, slot); + } + break; + } + goto default; + default: + { + if (Main.stackSplit > 1) + { + break; + } + bool flag = true; + bool flag2 = inv[slot].maxStack <= 1 && inv[slot].stack <= 1; + if (context == 0 && flag2) + { + flag = false; + } + if (context == 3 && flag2) + { + flag = false; + } + if (context == 4 && flag2) + { + flag = false; + } + if (context == 32 && flag2) + { + flag = false; + } + if (!flag) + { + break; + } + int num = Main.superFastStack + 1; + for (int i = 0; i < num; i++) + { + if (((Main.mouseItem.IsTheSameAs(inv[slot]) && ItemLoader.CanStack(Main.mouseItem, inv[slot])) || Main.mouseItem.type == 0) && (Main.mouseItem.stack < Main.mouseItem.maxStack || Main.mouseItem.type == 0)) + { + ItemSlot.PickupItemIntoMouse(inv, context, slot, player); + SoundEngine.PlaySound(12); + ItemSlot.RefreshStackSplitCooldown(); + } + } + break; + } + } + } + } + private void Hook_DropItemCheck(On_Player.orig_dropItemCheck orig, Player self) { // If the mouse is holding the Adventure Mirror, just block the drop. @@ -73,6 +195,7 @@ private static bool Hook_LeftClick_SellOrTrash( private static bool IsAdventureMirror(Item item) => !item.IsAir && item.type == ModContent.ItemType(); + // Vanilla method with the item animation check removed for Adventure Mirror. // DRAGGING ONTO THE TRASH SLOT / CHESTS / BANKS private static void Hook_LeftClick_ItemArray( On_ItemSlot.orig_LeftClick_ItemArray_int_int orig, @@ -88,7 +211,7 @@ private static void Hook_LeftClick_ItemArray( if (isStorageSlot && isMirrorOnMouse) { //if (Main.mouseLeft && Main.mouseLeftRelease) - //PopupTextHelper.NewText("Cannot store Adventure Mirror!"); + //Main.NewText("Cannot store Adventure Mirror!"); // Do NOT call orig -> cancel the placement return; @@ -104,7 +227,312 @@ private static void Hook_LeftClick_ItemArray( } // Otherwise, normal behavior - orig(inv, context, slot); + //orig(inv, context, slot); + + // --- Normal behaviour --- + Player player = Main.player[Main.myPlayer]; + bool flag = Main.mouseLeftRelease && Main.mouseLeft; + if (flag) + { + if (ItemSlot.OverrideLeftClick(inv, context, slot)) + { + return; + } + inv[slot].newAndShiny = false; + if (ItemSlot.LeftClick_SellOrTrash(inv, context, slot) || player.itemAnimation != 0 || player.itemTime != 0) + { + // RETURN EARLY for all other items other than Adventure Mirror + // Meaning we allow ItemSlot use while AM is the held item. + if (player.HeldItem.type != ModContent.ItemType()) + { + return; + } + + } + } + int num = ItemSlot.PickItemMovementAction(inv, context, slot, Main.mouseItem); + if (num != 3 && !flag) + { + return; + } + switch (num) + { + case 0: + { + if (context == 6 && Main.mouseItem.type != 0) + { + inv[slot].SetDefaults(); + } + if ((ItemSlot.IsAccessoryContext(context) && !ItemLoader.CanEquipAccessory(inv[slot], slot, context < 0)) || (context == 11 && !inv[slot].FitsAccessoryVanitySlot) || (context < 0 && !LoaderManager.Get().CanAcceptItem(slot, inv[slot], context))) + { + break; + } + if (Main.mouseItem.maxStack <= 1 || inv[slot].type != Main.mouseItem.type || inv[slot].stack == inv[slot].maxStack || Main.mouseItem.stack == Main.mouseItem.maxStack) + { + Utils.Swap(ref inv[slot], ref Main.mouseItem); + } + if (inv[slot].stack > 0) + { + ItemSlot.AnnounceTransfer(new ItemSlot.ItemTransferInfo(inv[slot], 21, context, inv[slot].stack)); + } + else + { + ItemSlot.AnnounceTransfer(new ItemSlot.ItemTransferInfo(Main.mouseItem, context, 21, Main.mouseItem.stack)); + } + if (inv[slot].stack > 0) + { + switch (Math.Abs(context)) + { + case 0: + AchievementsHelper.NotifyItemPickup(player, inv[slot]); + break; + case 8: + case 9: + case 10: + case 11: + case 12: + case 16: + case 17: + case 25: + case 27: + case 33: + AchievementsHelper.HandleOnEquip(player, inv[slot], context); + break; + } + } + if (inv[slot].type == 0 || inv[slot].stack < 1) + { + inv[slot] = new Item(); + } + if (Main.mouseItem.IsTheSameAs(inv[slot]) && inv[slot].stack != inv[slot].maxStack && Main.mouseItem.stack != Main.mouseItem.maxStack && ItemLoader.TryStackItems(inv[slot], Main.mouseItem, out var numTransfered)) + { + ItemSlot.AnnounceTransfer(new ItemSlot.ItemTransferInfo(inv[slot], 21, context, numTransfered)); + } + if (Main.mouseItem.type == 0 || Main.mouseItem.stack < 1) + { + Main.mouseItem = new Item(); + } + if (Main.mouseItem.type > 0 || inv[slot].type > 0) + { + Recipe.FindRecipes(); + SoundEngine.PlaySound(7); + } + if (context == 3 && Main.netMode == 1) + { + NetMessage.SendData(32, -1, -1, null, player.chest, slot); + } + break; + } + case 1: + if (Main.mouseItem.stack == 1 && Main.mouseItem.type > 0 && inv[slot].type > 0 && inv[slot].IsNotTheSameAs(Main.mouseItem) && (context != 11 || Main.mouseItem.FitsAccessoryVanitySlot)) + { + if ((ItemSlot.IsAccessoryContext(context) && !ItemLoader.CanEquipAccessory(Main.mouseItem, slot, context < 0)) || (Math.Abs(context) == 11 && !Main.mouseItem.FitsAccessoryVanitySlot) || (context < 0 && !LoaderManager.Get().CanAcceptItem(slot, Main.mouseItem, context))) + { + break; + } + Utils.Swap(ref inv[slot], ref Main.mouseItem); + SoundEngine.PlaySound(7); + if (inv[slot].stack > 0) + { + switch (Math.Abs(context)) + { + case 0: + AchievementsHelper.NotifyItemPickup(player, inv[slot]); + break; + case 8: + case 9: + case 10: + case 11: + case 12: + case 16: + case 17: + case 25: + case 27: + case 33: + AchievementsHelper.HandleOnEquip(player, inv[slot], context); + break; + } + } + } + else if (Main.mouseItem.type == 0 && inv[slot].type > 0) + { + Utils.Swap(ref inv[slot], ref Main.mouseItem); + if (inv[slot].type == 0 || inv[slot].stack < 1) + { + inv[slot] = new Item(); + } + if (Main.mouseItem.type == 0 || Main.mouseItem.stack < 1) + { + Main.mouseItem = new Item(); + } + if (Main.mouseItem.type > 0 || inv[slot].type > 0) + { + Recipe.FindRecipes(); + SoundEngine.PlaySound(7); + } + } + else if (Main.mouseItem.type > 0 && inv[slot].type == 0 && (context != 11 || Main.mouseItem.FitsAccessoryVanitySlot)) + { + if ((ItemSlot.IsAccessoryContext(context) && !ItemLoader.CanEquipAccessory(Main.mouseItem, slot, context < 0)) || (Math.Abs(context) == 11 && !Main.mouseItem.FitsAccessoryVanitySlot) || (context < 0 && !LoaderManager.Get().CanAcceptItem(slot, Main.mouseItem, context))) + { + break; + } + inv[slot] = ItemLoader.TransferWithLimit(Main.mouseItem, 1); + Recipe.FindRecipes(); + SoundEngine.PlaySound(7); + if (inv[slot].stack > 0) + { + switch (Math.Abs(context)) + { + case 0: + AchievementsHelper.NotifyItemPickup(player, inv[slot]); + break; + case 8: + case 9: + case 10: + case 11: + case 12: + case 16: + case 17: + case 25: + case 27: + case 33: + AchievementsHelper.HandleOnEquip(player, inv[slot], context); + break; + } + } + } + if ((context == 23 || context == 24) && Main.netMode == 1) + { + NetMessage.SendData(121, -1, -1, null, Main.myPlayer, player.tileEntityAnchor.interactEntityID, slot); + } + if (context == 26 && Main.netMode == 1) + { + NetMessage.SendData(124, -1, -1, null, Main.myPlayer, player.tileEntityAnchor.interactEntityID, slot); + } + break; + case 2: + if (Main.mouseItem.stack == 1 && Main.mouseItem.dye > 0 && inv[slot].type > 0 && inv[slot].type != Main.mouseItem.type) + { + Utils.Swap(ref inv[slot], ref Main.mouseItem); + SoundEngine.PlaySound(7); + if (inv[slot].stack > 0) + { + switch (Math.Abs(context)) + { + case 0: + AchievementsHelper.NotifyItemPickup(player, inv[slot]); + break; + case 8: + case 9: + case 10: + case 11: + case 12: + case 16: + case 17: + case 25: + case 27: + case 33: + AchievementsHelper.HandleOnEquip(player, inv[slot], context); + break; + } + } + } + else if (Main.mouseItem.type == 0 && inv[slot].type > 0) + { + Utils.Swap(ref inv[slot], ref Main.mouseItem); + if (inv[slot].type == 0 || inv[slot].stack < 1) + { + inv[slot] = new Item(); + } + if (Main.mouseItem.type == 0 || Main.mouseItem.stack < 1) + { + Main.mouseItem = new Item(); + } + if (Main.mouseItem.type > 0 || inv[slot].type > 0) + { + Recipe.FindRecipes(); + SoundEngine.PlaySound(7); + } + } + else if (Main.mouseItem.dye > 0 && inv[slot].type == 0) + { + inv[slot] = ItemLoader.TransferWithLimit(Main.mouseItem, 1); + Recipe.FindRecipes(); + SoundEngine.PlaySound(7); + if (inv[slot].stack > 0) + { + switch (Math.Abs(context)) + { + case 0: + AchievementsHelper.NotifyItemPickup(player, inv[slot]); + break; + case 8: + case 9: + case 10: + case 11: + case 12: + case 16: + case 17: + case 25: + case 27: + case 33: + AchievementsHelper.HandleOnEquip(player, inv[slot], context); + break; + } + } + } + if (context == 25 && Main.netMode == 1) + { + NetMessage.SendData(121, -1, -1, null, Main.myPlayer, player.tileEntityAnchor.interactEntityID, slot, 1f); + } + if (context == 27 && Main.netMode == 1) + { + NetMessage.SendData(124, -1, -1, null, Main.myPlayer, player.tileEntityAnchor.interactEntityID, slot, 1f); + } + break; + case 3: + ItemSlot.HandleShopSlot(inv, slot, rightClickIsValid: false, leftClickIsValid: true); + break; + case 4: + if (PlayerLoader.CanSellItem(player, player.TalkNPC, inv, Main.mouseItem)) + { + Chest chest = Main.instance.shop[Main.npcShop]; + if (player.SellItem(Main.mouseItem)) + { + int soldItemIndex = chest.AddItemToShop(Main.mouseItem); + Main.mouseItem.SetDefaults(); + SoundEngine.PlaySound(18); + ItemSlot.AnnounceTransfer(new ItemSlot.ItemTransferInfo(inv[slot], 21, 15)); + PlayerLoader.PostSellItem(player, player.TalkNPC, chest.item, chest.item[soldItemIndex]); + } + else if (Main.mouseItem.value == 0) + { + int soldItemIndex2 = chest.AddItemToShop(Main.mouseItem); + Main.mouseItem.SetDefaults(); + SoundEngine.PlaySound(7); + ItemSlot.AnnounceTransfer(new ItemSlot.ItemTransferInfo(inv[slot], 21, 15)); + PlayerLoader.PostSellItem(player, player.TalkNPC, chest.item, chest.item[soldItemIndex2]); + } + Recipe.FindRecipes(); + Main.stackSplit = 9999; + } + break; + case 5: + if (Main.mouseItem.IsAir) + { + SoundEngine.PlaySound(7); + Main.mouseItem = inv[slot].Clone(); + Main.mouseItem.stack = Main.mouseItem.maxStack; + Main.mouseItem.OnCreated(new JourneyDuplicationItemCreationContext()); + ItemSlot.AnnounceTransfer(new ItemSlot.ItemTransferInfo(inv[slot], 29, 21)); + } + break; + } + if ((uint)context > 2u && context != 5 && context != 32) + { + inv[slot].favorited = false; + } } // SELLING TO NPCS diff --git a/Core/SpawnSelector/Systems/PlayerHeadsOnMap.cs b/Core/SpawnSelector/Systems/PlayerHeadsOnMap.cs new file mode 100644 index 00000000..1e639e43 --- /dev/null +++ b/Core/SpawnSelector/Systems/PlayerHeadsOnMap.cs @@ -0,0 +1,66 @@ +using Microsoft.Xna.Framework; +using Terraria; +using Terraria.GameContent; +using Terraria.ModLoader; + +namespace PvPAdventure.Core.SpawnSelector.Systems; + +/// +/// Draws the selected player heads on map when highlighting the UI element for the player +/// +internal class PlayerHeadsOnMap : ModSystem +{ + public override void Load() + { + Main.OnPostFullscreenMapDraw += DrawHighlightedPlayerOnMap; + } + + public override void Unload() + { + Main.OnPostFullscreenMapDraw -= DrawHighlightedPlayerOnMap; + } + + private void DrawHighlightedPlayerOnMap(Vector2 mapOffset, float mapScale) + { + if (!Main.mapFullscreen) return; + + int idx = SpawnSelectorSystem.HoveredPlayerIndex; + if (idx < 0 || idx >= Main.maxPlayers) return; + + Player player = Main.player[idx]; + if (player == null || !player.active || player.dead) return; + + float tileX = (player.position.X + player.width * 0.5f) / 16f; + float tileY = (player.position.Y + player.gfxOffY + player.height * 0.5f) / 16f; + + float x = tileX * mapScale + mapOffset.X; + float y = tileY * mapScale + mapOffset.Y; + + x -= 7f; + y -= 3f; + //y -= 2f - mapScale / 5f * 2f; + //x -= 10f * mapScale; + //y -= 10f * mapScale; + + Vector2 headPos = new Vector2(x, y); + + float alpha = 1f; + float scale = 1.6f*Main.UIScale; + if (Main.UIScale > 1.5) + scale = 1.6f * Main.UIScale * 0.9f; + Color border = Main.GetPlayerHeadBordersColor(player); + + Main.spriteBatch.Begin(); + + // Draw player head + Main.MapPlayerRenderer.DrawPlayerHead(Main.Camera, player, headPos, alpha, scale, border); + + // Draw teleport to player text + string name = player.name; + Vector2 size = FontAssets.MouseText.Value.MeasureString(name); + Vector2 pos = headPos + new Vector2(-size.X * 0.5f+7*Main.UIScale, 30f*Main.UIScale); + Utils.DrawBorderString(Main.spriteBatch, name, pos, Color.White, 1f*Main.UIScale); + + Main.spriteBatch.End(); + } +} diff --git a/Core/SpawnSelector/Systems/SpawnHooks.cs b/Core/SpawnSelector/Systems/SpawnHooks.cs index 78ec0859..e31fc512 100644 --- a/Core/SpawnSelector/Systems/SpawnHooks.cs +++ b/Core/SpawnSelector/Systems/SpawnHooks.cs @@ -35,9 +35,9 @@ private void ForceWorldSpawn(On_Player.orig_Spawn_SetPosition orig, Player self, if (self == Main.LocalPlayer) { - Main.LocalPlayer.position.X = spawnX * 16 + 8 - Main.LocalPlayer.width / 2; - Main.LocalPlayer.position.Y = spawnY * 16 - Main.LocalPlayer.height; - } + Main.LocalPlayer.position.X = spawnX * 16 + 8 - Main.LocalPlayer.width / 2; + Main.LocalPlayer.position.Y = spawnY * 16 - Main.LocalPlayer.height; + } } } diff --git a/Core/SpawnSelector/Systems/SpawnSelectorSystem.cs b/Core/SpawnSelector/Systems/SpawnSelectorSystem.cs index 2f62726f..93aea42a 100644 --- a/Core/SpawnSelector/Systems/SpawnSelectorSystem.cs +++ b/Core/SpawnSelector/Systems/SpawnSelectorSystem.cs @@ -17,6 +17,9 @@ public class SpawnSelectorSystem : ModSystem public static void SetEnabled(bool newValue) => Enabled = newValue; public static bool GetEnabled() => Enabled; + // Hovering players + internal static int HoveredPlayerIndex = -1; + public override void Load() { if (!Main.dedServ) diff --git a/Core/SpawnSelector/UI/SpawnSelectorBasePanel.cs b/Core/SpawnSelector/UI/SpawnSelectorBasePanel.cs index 9d2d4a08..58e7a44b 100644 --- a/Core/SpawnSelector/UI/SpawnSelectorBasePanel.cs +++ b/Core/SpawnSelector/UI/SpawnSelectorBasePanel.cs @@ -5,173 +5,173 @@ using Terraria; using Terraria.GameContent.UI.Elements; -namespace PvPAdventure.Core.SpawnSelector.UI +namespace PvPAdventure.Core.SpawnSelector.UI; + +// +public class SpawnSelectorBasePanel : UIPanel { - public class SpawnSelectorBasePanel : UIPanel - { - private UIPanel _randomPanel; - private readonly List _playerItems = new(); + private UIPanel _randomPanel; + private readonly List _playerItems = new(); - private const float Spacing = 8f; - private const float HorizontalPadding = 16f; - private const float VerticalPadding = 12f; + private const float Spacing = 8f; + private const float HorizontalPadding = 16f; + private const float VerticalPadding = 12f; - public override void OnInitialize() - { - HAlign = 0.5f; - VAlign = 0.0f; - Top.Set(52, 0); + public override void OnInitialize() + { + HAlign = 0.5f; + VAlign = 0.0f; + Top.Set(52, 0); - BackgroundColor = new Color(33, 43, 79) * 0.8f; - SetPadding(0f); + BackgroundColor = new Color(33, 43, 79) * 0.8f; + SetPadding(0f); - BuildLayout(); - } + BuildLayout(); + } - private void BuildLayout() - { - RemoveAllChildren(); - _playerItems.Clear(); + private void BuildLayout() + { + RemoveAllChildren(); + _playerItems.Clear(); - var players = new List(); - var local = Main.LocalPlayer; + var players = new List(); + var local = Main.LocalPlayer; - if (local.team != 0) + if (local.team != 0) + { + for (int i = 0; i < Main.maxPlayers; i++) { - for (int i = 0; i < Main.maxPlayers; i++) - { - Player p = Main.player[i]; + Player p = Main.player[i]; - if (p == null) - continue; + if (p == null) + continue; - if (p.whoAmI == local.whoAmI || p.team != local.team) - continue; + if (p.whoAmI == local.whoAmI || p.team != local.team) + continue; - players.Add(p); - } + players.Add(p); } + } //#if DEBUG -// players.Add(Main.LocalPlayer); -// Main.NewText($"[DEBUG] Added local player '{Main.LocalPlayer.name}' to SpawnSelectorBasePanel"); +// players.Add(Main.LocalPlayer); +// Main.NewText($"[DEBUG] Added local player '{Main.LocalPlayer.name}' to SpawnSelectorBasePanel"); //#endif - int playerCount = players.Count; + int playerCount = players.Count; - float itemWidth = SpawnSelectorCharacter.ItemWidth; - float itemHeight = SpawnSelectorCharacter.ItemHeight; - float randomWidth = itemHeight; + float itemWidth = SpawnSelectorCharacter.ItemWidth; + float itemHeight = SpawnSelectorCharacter.ItemHeight; + float randomWidth = itemHeight; - float contentWidth = playerCount * itemWidth - + playerCount * Spacing - + randomWidth; + float contentWidth = playerCount * itemWidth + + playerCount * Spacing + + randomWidth; - float panelWidth = contentWidth + HorizontalPadding * 2f; - float panelHeight = itemHeight + VerticalPadding * 2f; + float panelWidth = contentWidth + HorizontalPadding * 2f; + float panelHeight = itemHeight + VerticalPadding * 2f; - if (panelWidth <= 0f) - panelWidth = itemWidth + HorizontalPadding * 2f; + if (panelWidth <= 0f) + panelWidth = itemWidth + HorizontalPadding * 2f; - if (panelHeight <= 0f) - panelHeight = itemHeight + VerticalPadding * 2f; + if (panelHeight <= 0f) + panelHeight = itemHeight + VerticalPadding * 2f; - Width.Set(panelWidth, 0f); - Height.Set(panelHeight, 0f); + Width.Set(panelWidth, 0f); + Height.Set(panelHeight, 0f); - float startX = HorizontalPadding; - float y = VerticalPadding; + float startX = HorizontalPadding; + float y = VerticalPadding; - for (int i = 0; i < playerCount; i++) - { - float x = startX + i * (itemWidth + Spacing); + for (int i = 0; i < playerCount; i++) + { + float x = startX + i * (itemWidth + Spacing); - var row = new SpawnSelectorCharacter(players[i]); - row.Left.Set(x, 0f); - row.Top.Set(y, 0f); + var row = new SpawnSelectorCharacter(players[i]); + row.Left.Set(x, 0f); + row.Top.Set(y, 0f); - Append(row); - _playerItems.Add(row); - } + Append(row); + _playerItems.Add(row); + } - _randomPanel = new SpawnSelectorQuestionMark( - startX, - itemHeight, - playerCount, - itemWidth, - Spacing, - y - ); - Append(_randomPanel); + _randomPanel = new SpawnSelectorQuestionMark( + startX, + itemHeight, + playerCount, + itemWidth, + Spacing, + y + ); + Append(_randomPanel); - Recalculate(); - RecalculateChildren(); + Recalculate(); + RecalculateChildren(); - Log.Debug($"UISpawnSelectorPanel.BuildLayout: players={playerCount}"); - } + Log.Debug($"UISpawnSelectorPanel.BuildLayout: players={playerCount}"); + } - public void Rebuild() - { - BuildLayout(); - } + public void Rebuild() + { + BuildLayout(); + } - public override void Update(GameTime gameTime) + public override void Update(GameTime gameTime) + { + if (NeedsRebuild()) { - if (NeedsRebuild()) - { - Rebuild(); - } - - base.Update(gameTime); + Rebuild(); } - public override void Draw(SpriteBatch spriteBatch) - { - base.Draw(spriteBatch); - } + base.Update(gameTime); + } - private bool NeedsRebuild() - { - var dims = GetDimensions(); - if (dims.Width <= 0f || dims.Height <= 0f) - return true; + public override void Draw(SpriteBatch spriteBatch) + { + base.Draw(spriteBatch); + } - if (_randomPanel == null) - return true; + private bool NeedsRebuild() + { + var dims = GetDimensions(); + if (dims.Width <= 0f || dims.Height <= 0f) + return true; - var randomDims = _randomPanel.GetDimensions(); - if (randomDims.Width <= 0f || randomDims.Height <= 0f) - return true; + if (_randomPanel == null) + return true; - var local = Main.LocalPlayer; - var players = new List(); + var randomDims = _randomPanel.GetDimensions(); + if (randomDims.Width <= 0f || randomDims.Height <= 0f) + return true; - for (int i = 0; i < Main.maxPlayers; i++) - { - var p = Main.player[i]; - if (p == null) - continue; - if (p.whoAmI == local.whoAmI || p.team != local.team) - continue; + var local = Main.LocalPlayer; + var players = new List(); - players.Add(p.whoAmI); - } + for (int i = 0; i < Main.maxPlayers; i++) + { + var p = Main.player[i]; + if (p == null || !p.active) + continue; + if (p.whoAmI == local.whoAmI || p.team != local.team) + continue; + + players.Add(p.whoAmI); + } //#if DEBUG -// players.Add(local.whoAmI); +// players.Add(local.whoAmI); //#endif - if (players.Count != _playerItems.Count) - return true; - - for (int i = 0; i < players.Count; i++) - { - if (_playerItems[i] == null) return true; - if (_playerItems[i].PlayerIndex != players[i]) return true; - } + if (players.Count != _playerItems.Count) + return true; - return false; + for (int i = 0; i < players.Count; i++) + { + if (_playerItems[i] == null) return true; + if (_playerItems[i].PlayerIndex != players[i]) return true; } + return false; } + } diff --git a/Core/SpawnSelector/UI/SpawnSelectorCharacter.cs b/Core/SpawnSelector/UI/SpawnSelectorCharacter.cs index 5427db31..4abc28a2 100644 --- a/Core/SpawnSelector/UI/SpawnSelectorCharacter.cs +++ b/Core/SpawnSelector/UI/SpawnSelectorCharacter.cs @@ -2,6 +2,7 @@ using Microsoft.Xna.Framework.Graphics; using PvPAdventure.Core.Helpers; using PvPAdventure.Core.SpawnSelector.Players; +using PvPAdventure.Core.SpawnSelector.Systems; using ReLogic.Content; using System; using Terraria; @@ -9,8 +10,8 @@ using Terraria.GameContent.UI.Elements; using Terraria.ID; using Terraria.ModLoader; +using Terraria.ModLoader.UI; using Terraria.UI; -using Terraria.UI.Chat; namespace PvPAdventure.Core.SpawnSelector.UI { @@ -91,8 +92,8 @@ protected override void DrawSelf(SpriteBatch sb) //sb.Draw(_playerBGTexture.Value, pos, Color.White*0.5f); Rectangle rect = new( - x: (int)pos.X-6, - y: (int)pos.Y-6, + x: (int)pos.X - 6, + y: (int)pos.Y - 6, width: 100, height: 72); @@ -101,15 +102,6 @@ protected override void DrawSelf(SpriteBatch sb) DrawNineSlice(sb, rect.X, rect.Y, rect.Width, rect.Height, _playerBGTexture.Value, Color.White, 5); DrawMapFullscreenBackground(sb, rect, player); - sb.End(); - sb.Begin(SpriteSortMode.Deferred, - BlendState.AlphaBlend, - SamplerState.PointClamp, - DepthStencilState.Default, - RasterizerState.CullNone, - null, - Main.UIScaleMatrix); - AdventureMirrorPlayer.ForceFullBrightOnce = true; try { @@ -130,16 +122,6 @@ protected override void DrawSelf(SpriteBatch sb) AdventureMirrorPlayer.ForceFullBrightOnce = false; } - // Switch back to "normal" UI batch - sb.End(); - sb.Begin(SpriteSortMode.Deferred, - BlendState.AlphaBlend, - SamplerState.LinearClamp, - DepthStencilState.None, - RasterizerState.CullCounterClockwise, - null, - Main.UIScaleMatrix); - // Use the actual layout widths, not the texture width const float leftColumnWidth = 106f; // player background column const float rightAreaWidth = ItemWidth - 22f - leftColumnWidth; // 260 - 12 - 106 = 142 @@ -159,28 +141,18 @@ protected override void DrawSelf(SpriteBatch sb) ); // Draw name - Utils.DrawBorderString(sb,name,namePos,Color.White,nameScale); + Utils.DrawBorderString(sb, name, namePos, Color.White, nameScale); // Draw divider - sb.Draw( - _dividerTexture.Value, - new Vector2(rightAreaLeft-12, inner.Y + 21f), - null, - Color.White, - 0f, - Vector2.Zero, - new Vector2(rightAreaWidth/8+2.2f, 1f), - SpriteEffects.None, - 0f - ); + sb.Draw(_dividerTexture.Value, new Vector2(rightAreaLeft - 12, inner.Y + 21f), null, Color.White, 0f, Vector2.Zero, new Vector2(rightAreaWidth / 8 + 2.2f, 1f), SpriteEffects.None, 0f); // Stat panel settings float statScale = 0.88f; float statGap = 5f * statScale; // Draw stat panel - float panelWidth = rightAreaWidth+24; - Vector2 panelPos = new(rightAreaLeft-14, inner.Y + 29f); + float panelWidth = rightAreaWidth + 24; + Vector2 panelPos = new(rightAreaLeft - 14, inner.Y + 29f); DrawPanel(sb, panelPos, panelWidth); string hpText = $"{player.statLife} HP"; @@ -203,20 +175,14 @@ protected override void DrawSelf(SpriteBatch sb) // Draw health sb.Draw(heart.Value, new Vector2(startX, y), null, Color.White, 0f, Vector2.Zero, statScale, SpriteEffects.None, 0f); startX += heartW; - Utils.DrawBorderString(sb, hpText, new Vector2(startX+1, y + 1f), Color.White, statScale); + Utils.DrawBorderString(sb, hpText, new Vector2(startX + 1, y + 1f), Color.White, statScale); startX += hpSize.X; startX += statGap; // Draw mana sb.Draw(mana.Value, new Vector2(startX, y - 2), null, Color.White, 0f, Vector2.Zero, statScale, SpriteEffects.None, 0f); startX += manaW; - Utils.DrawBorderString(sb, mpText, new Vector2(startX+1, y + 1f), Color.White, statScale); - - // Draw arrow - //DrawArrow(player); - - // Draw player head if hovering - DrawPlayerHeadOnMap(player); + Utils.DrawBorderString(sb, mpText, new Vector2(startX + 1, y + 1f), Color.White, statScale); // Draw player respawn timer if it exists string respawnTimeInSeconds = (player.respawnTimer / 60 + 1).ToString(); @@ -224,50 +190,12 @@ protected override void DrawSelf(SpriteBatch sb) { Utils.DrawBorderStringBig(sb, respawnTimeInSeconds, pos + new Vector2(31, 4), Color.Gray, scale: 1f); } - } - - private void DrawPlayerHeadOnMap(Player p) - { - if (p == null || !p.active || p.dead) - return; - var config = ModContent.GetInstance(); - if (!IsMouseHovering || !config.ShowPlayerIndicationWhenWhenHovering) - return; - - Main.instance.MouseText("Teleport to " + p.name); - - float mapScale = Main.mapFullscreenScale; - - // Player in tile coords - Vector2 tilePos = p.Center / 16f; - - // Screen-space position on the fullscreen map (pixels) - Vector2 mapScreenCenter = new( - Main.screenWidth / 2f, - Main.screenHeight / 2f - ); - Vector2 headPosScreen = (tilePos - Main.mapFullscreenPos) * mapScale + mapScreenCenter; - //headPosScreen += new Vector2(80, 40); // offset - headPosScreen *= Main.UIScale; - - Matrix invUi = Matrix.Invert(Main.UIScaleMatrix); - Vector2 headPosUI = Vector2.Transform(headPosScreen, invUi); - - Color c = Main.teamColor[p.team]; - - // Draw head in UI-space - Main.MapPlayerRenderer.DrawPlayerHead(Main.Camera, p, headPosUI, scale: 1.3f, borderColor: c); - - // Text centered below head, also in UI-space - string name = p.name ?? string.Empty; - float textScale = 1f; - Vector2 nameSize = FontAssets.MouseText.Value.MeasureString(name) * textScale; - Vector2 namePos = new( - headPosUI.X - nameSize.X * 0.5f, - headPosUI.Y + 30f - ); - Utils.DrawBorderString(Main.spriteBatch, "Teleport to " + name, namePos, Color.White, textScale); + // Draw teleport to if it exists + if (!player.dead && IsMouseHovering) + { + Main.instance.MouseText("Teleport to " + player.name); + } } public override void MouseOver(UIMouseEvent evt) @@ -278,6 +206,7 @@ public override void MouseOver(UIMouseEvent evt) if (p == null || !p.active || p.dead) return; BackgroundColor = new Color(73, 92, 161, 150); + SpawnSelectorSystem.HoveredPlayerIndex = _playerIndex; } public override void MouseOut(UIMouseEvent evt) @@ -289,6 +218,8 @@ public override void MouseOut(UIMouseEvent evt) return; BackgroundColor = new Color(63, 82, 151) * 0.8f; + if (SpawnSelectorSystem.HoveredPlayerIndex == _playerIndex) + SpawnSelectorSystem.HoveredPlayerIndex = -1; } public override void LeftClick(UIMouseEvent evt) @@ -336,7 +267,7 @@ private void DrawPanel(SpriteBatch spriteBatch, Vector2 position, float width) ); } - + [Obsolete("Doesn't work in MP. Use the new method instead.")] public static void DrawMapFullscreenBackground_BadMP(SpriteBatch sb, Rectangle rect, Player player) { if (player == null || !player.active) @@ -422,6 +353,7 @@ public static void DrawMapFullscreenBackground_BadMP(SpriteBatch sb, Rectangle r sb.Draw(asset.Value, rect, color); } + // Finds the biome of the given player and draws it. public static void DrawMapFullscreenBackground(SpriteBatch sb, Rectangle rect, Player player) { if (player == null || !player.active) diff --git a/Core/Spawnbox/PvPIcons.cs b/Core/Spawnbox/PvPIcons.cs index 75df3b6d..2ae534a3 100644 --- a/Core/Spawnbox/PvPIcons.cs +++ b/Core/Spawnbox/PvPIcons.cs @@ -112,7 +112,7 @@ protected override bool DrawSelf() // Draw cooldown icon //if (isPlaying) - sb.Draw(cooldownTex.Value, cdRect, Color.White * 0.8f); + sb.Draw(cooldownTex.Value, cdRect, Color.White * 1f); } return true; diff --git a/Core/Spawnbox/SpawnboxMap.cs b/Core/Spawnbox/SpawnboxMap.cs index bf791302..ec088c24 100644 --- a/Core/Spawnbox/SpawnboxMap.cs +++ b/Core/Spawnbox/SpawnboxMap.cs @@ -1,6 +1,8 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; +using PvPAdventure.Core.SpawnSelector.Players; using PvPAdventure.System; +using ReLogic.Graphics; using Terraria; using Terraria.GameContent; using Terraria.Map; @@ -66,18 +68,55 @@ private static void DrawSpawnBoxOnFullscreenMap(ref MapOverlayDrawContext contex h = spawnRect.Height; } + var gm = ModContent.GetInstance(); + var am = Main.LocalPlayer.GetModPlayer(); + bool canPass = gm.CurrentPhase == GameManager.Phase.Playing + && am.IsPlayerInSpawnRegion(); + // now draw using the (possibly clipped) rect Texture2D pix = TextureAssets.MagicPixel.Value; - Color col = Color.Black * 0.7f; + Color col = Color.Black; + if (canPass) col = Color.Black * 0.5f; int thickness = 2; if (Main.mapFullscreen) thickness = (int)(1 * Main.mapFullscreenScale); // match 1 pixel at scale 1 // top, bottom, left, right - Main.spriteBatch.Draw(pix, new Rectangle(x, y, w, thickness), col); - Main.spriteBatch.Draw(pix, new Rectangle(x, y + h - thickness, w, thickness), col); - Main.spriteBatch.Draw(pix, new Rectangle(x, y, thickness, h), col); - Main.spriteBatch.Draw(pix, new Rectangle(x + w - thickness, y, thickness, h), col); + Main.spriteBatch.Draw(pix,new Rectangle(x + thickness, y, w - thickness * 2, thickness),col); + Main.spriteBatch.Draw(pix,new Rectangle(x + thickness, y + h - thickness, w - thickness * 2, thickness),col); + Main.spriteBatch.Draw(pix,new Rectangle(x, y, thickness, h),col); + Main.spriteBatch.Draw(pix,new Rectangle(x + w - thickness, y, thickness, h),col); + + var font = FontAssets.DeathText.Value; + + float scale = context.MapScale * context.DrawScale*0.3f; + + Vector2 textSize = font.MeasureString("SPAWN") * scale; + + Vector2 textPos = new Vector2( + x + w / 2f - textSize.X / 2f, + y + h / 2f - textSize.Y / 2f + ); + textPos.Y -= 50*scale; + + // Helper to draw text + void drawSpawnText(Vector2 offset, Color c) + { + Main.spriteBatch.DrawString( + font, + "SPAWN", + textPos + offset, + c, + 0f, + Vector2.Zero, + scale, + SpriteEffects.None, + 0f + ); + } + + //drawSpawnText(new Vector2(2, 2) * scale, Color.Black * 0.75f); + //drawSpawnText(Vector2.Zero, Color.White); } } diff --git a/Core/Spawnbox/SpawnboxWorld.cs b/Core/Spawnbox/SpawnboxWorld.cs index b2757d5c..6f44f88e 100644 --- a/Core/Spawnbox/SpawnboxWorld.cs +++ b/Core/Spawnbox/SpawnboxWorld.cs @@ -10,149 +10,101 @@ using Terraria.GameContent; using Terraria.ModLoader; using Terraria.UI; -using static PvPAdventure.System.RegionManager; -namespace PvPAdventure.Core.Spawnbox; - -[Autoload(Side = ModSide.Client)] -public class SpawnBoxWorld : ModSystem +namespace PvPAdventure.Core.Spawnbox { - // Initialize the interface layer. - private readonly SpawnBoxInterfaceLayer _spawnBoxInterfaceLayer = new(); - public Asset _playerBGTexture; - - // Load the texture. - public override void Load() + [Autoload(Side = ModSide.Client)] + public class SpawnBoxWorld : ModSystem { - if (!Main.dedServ) - _playerBGTexture = Ass.CustomPlayerBackground; - } + public Asset _playerBGTexture; - // Add the layer. - public override void ModifyInterfaceLayers(List layers) - { - if (!layers.Contains(_spawnBoxInterfaceLayer)) + public override void Load() { - // add at the bottom interface layer - // https://github.com/tModLoader/tModLoader/wiki/Vanilla-Interface-layers-values - var layerIndex = layers.FindIndex(layer => layer.Name == "Vanilla: Interface Logic 1"); - - if (layerIndex != -1) - layers.Insert(layerIndex + 1, _spawnBoxInterfaceLayer); + if (!Main.dedServ) + _playerBGTexture = Ass.CustomPlayerBackground; } - } - private class SpawnBoxInterfaceLayer() : GameInterfaceLayer("PvPAdventure: Spawn Box", InterfaceScaleType.UI) - { - protected override bool DrawSelf() + public override void ModifyInterfaceLayers(List layers) { - // To see how to draw coordinates properly, see the wiki on Coordinates. - // https://github.com/tModLoader/tModLoader/wiki/Coordinates - - // Draw the spawn box. - DrawSpawnBox(Main.spriteBatch); - return base.DrawSelf(); + // Insert just after a vanilla UI layer so it's always on top of the world. + int idx = layers.FindIndex(l => l.Name == "Vanilla: Interface Logic 1"); + if (idx != -1) + { + layers.Insert(idx + 1, new SpawnBoxInterfaceLayer()); + } } - private void DrawSpawnBox(SpriteBatch sb) + private sealed class SpawnBoxInterfaceLayer : GameInterfaceLayer { - var rm = ModContent.GetInstance(); - if (rm.Regions.Count == 0) - return; - - Region region = rm.Regions[0]; - - // 🔹 this is the “solid ring” bounds in TILE space - Rectangle ring = region.CollisionRingBounds; - - int leftTile = ring.X; - int rightTile = ring.X + ring.Width; // exclusive - int topTile = ring.Y; - int bottomTile = ring.Y + ring.Height; // exclusive - - // Tile -> world - float leftWorld = leftTile * 16f; - float rightWorld = rightTile * 16f; - float topWorld = topTile * 16f; - float bottomWorld = bottomTile * 16f; - - // World -> screen - float uiScale = Main.UIScale; - - float leftScreen = (leftWorld - Main.screenPosition.X) / uiScale; - float rightScreen = (rightWorld - Main.screenPosition.X) / uiScale; - float topScreen = (topWorld - Main.screenPosition.Y) / uiScale; - float bottomScreen = (bottomWorld - Main.screenPosition.Y) / uiScale; - - - var gm = ModContent.GetInstance(); - var am = Main.LocalPlayer.GetModPlayer(); - - float solidOpacity = 1.0f; - float lightOpacity = 0.5f; - - float opacity = gm.CurrentPhase == GameManager.Phase.Playing - ? (am.IsPlayerInSpawnRegion() ? lightOpacity : solidOpacity) - : solidOpacity; - - int l = (int)leftScreen; - int r = (int)rightScreen; - int t = (int)topScreen; - int b = (int)bottomScreen; - - int thickness = (int)Math.Max(1f, 16f / uiScale); - //Texture2D pix = TextureAssets.MagicPixel.Value; - //Color col = Color.Gray * 0.7f; - - // vanilla borders (top,left,bottom,right) - //sb.Draw(pix, new Rectangle(l, t, r - l, thickness), col); - //sb.Draw(pix, new Rectangle(l, b - thickness, r - l, thickness), col); - //sb.Draw(pix, new Rectangle(l, t, thickness, b - t), col); - //sb.Draw(pix, new Rectangle(r - thickness, t, thickness, b - t), col); - - Rectangle screenRect = new(l,t,r - l, b - t); - DrawNineSliceBorder(sb, screenRect, Color.White * opacity); - } - - private void DrawNineSliceBorder(SpriteBatch sb, Rectangle rect, Color color) - { - Texture2D tex = ModContent.GetInstance()._playerBGTexture.Value; - - - tex = Ass.Spawnbox.Value; - - int c = 16; // corner size - int x = rect.X; - int y = rect.Y; - int w = rect.Width; - int h = rect.Height; - - int ew = tex.Width - c * 2; - int eh = tex.Height - c * 2; - - // top-left - sb.Draw(tex, new Rectangle(x, y, c, c), new Rectangle(0, 0, c, c), color); - - // top - sb.Draw(tex, new Rectangle(x + c, y, w - c * 2, c), new Rectangle(c, 0, ew, c), color); - - // top-right - sb.Draw(tex, new Rectangle(x + w - c, y, c, c), new Rectangle(tex.Width - c, 0, c, c), color); - - // left - sb.Draw(tex, new Rectangle(x, y + c, c, h - c * 2), new Rectangle(0, c, c, eh), color); - - // right - sb.Draw(tex, new Rectangle(x + w - c, y + c, c, h - c * 2), new Rectangle(tex.Width - c, c, c, eh), color); - - // bottom-left - sb.Draw(tex, new Rectangle(x, y + h - c, c, c), new Rectangle(0, tex.Height - c, c, c), color); - - // bottom - sb.Draw(tex, new Rectangle(x + c, y + h - c, w - c * 2, c),new Rectangle(c, tex.Height - c, ew, c), color); - - // bottom-right - sb.Draw(tex, new Rectangle(x + w - c, y + h - c, c, c),new Rectangle(tex.Width - c, tex.Height - c, c, c), color); + public SpawnBoxInterfaceLayer() + : base("PvPAdventure: SpawnBox", InterfaceScaleType.Game) + { + } + + protected override bool DrawSelf() + { + DrawSpawnBox(Main.spriteBatch); + return true; + } + + private void DrawSpawnBox(SpriteBatch spriteBatch) + { + if (Main.dedServ) + return; + + // Set the spawnbox size. + int leftTile = Main.spawnTileX - 25; + int topTile = Main.spawnTileY - 25; + int rightTile = leftTile + 50; + int bottomTile = topTile + 50; + + // Get world coordinates. + Vector2 worldTopLeft = new(leftTile * 16f, topTile * 16f); + Vector2 worldBottomRight = new(rightTile * 16f, bottomTile * 16f); + + // Convert world coordinates to screen cordinates. + Vector2 screenTopLeft = worldTopLeft - Main.screenPosition; + Vector2 screenBottomRight = worldBottomRight - Main.screenPosition; + + int x = (int)Math.Floor(screenTopLeft.X); + int y = (int)Math.Floor(screenTopLeft.Y); + int w = (int)Math.Round(screenBottomRight.X - screenTopLeft.X); + int h = (int)Math.Round(screenBottomRight.Y - screenTopLeft.Y); + if (w <= 0 || h <= 0) + return; + + Rectangle rect = new(x, y, w, h); + rect.Inflate(16, 16); + + DrawNineSliceBorder(spriteBatch, rect); + } + + private void DrawNineSliceBorder(SpriteBatch sb, Rectangle rect) + { + // Set color + var gm = ModContent.GetInstance(); + var am = Main.LocalPlayer.GetModPlayer(); + bool canPass = gm.CurrentPhase == GameManager.Phase.Playing && am.IsPlayerInSpawnRegion(); + Color color = Color.Black * (canPass ? 0.5f : 1f); + + Texture2D tex = Ass.Spawnbox.Value; + const int srcCorner = 16; + int x = rect.X, y = rect.Y, w = rect.Width, h = rect.Height; + int srcEdgeWidth = tex.Width - srcCorner * 2; + int srcEdgeHeight = tex.Height - srcCorner * 2; + int dstCorner = srcCorner; + + sb.Draw(tex, new Rectangle(x, y, dstCorner, dstCorner), new Rectangle(0, 0, srcCorner, srcCorner), color); + sb.Draw(tex, new Rectangle(x + dstCorner, y, w - dstCorner * 2, dstCorner), new Rectangle(srcCorner, 0, srcEdgeWidth, srcCorner), color); + sb.Draw(tex, new Rectangle(x + w - dstCorner, y, dstCorner, dstCorner), new Rectangle(tex.Width - srcCorner, 0, srcCorner, srcCorner), color); + + sb.Draw(tex, new Rectangle(x, y + dstCorner, dstCorner, h - dstCorner * 2), new Rectangle(0, srcCorner, srcCorner, srcEdgeHeight), color); + sb.Draw(tex, new Rectangle(x + w - dstCorner, y + dstCorner, dstCorner, h - dstCorner * 2), new Rectangle(tex.Width - srcCorner, srcCorner, srcCorner, srcEdgeHeight), color); + + sb.Draw(tex, new Rectangle(x, y + h - dstCorner, dstCorner, dstCorner), new Rectangle(0, tex.Height - srcCorner, srcCorner, srcCorner), color); + sb.Draw(tex, new Rectangle(x + dstCorner, y + h - dstCorner, w - dstCorner * 2, dstCorner), new Rectangle(srcCorner, tex.Height - srcCorner, srcEdgeWidth, srcCorner), color); + sb.Draw(tex, new Rectangle(x + w - dstCorner, y + h - dstCorner, dstCorner, dstCorner), new Rectangle(tex.Width - srcCorner, tex.Height - srcCorner, srcCorner, srcCorner), color); + } } } } diff --git a/System/Client/Keybinds.cs b/System/Client/Keybinds.cs index 8d7699b5..d72d756f 100644 --- a/System/Client/Keybinds.cs +++ b/System/Client/Keybinds.cs @@ -9,13 +9,11 @@ public class Keybinds : ModSystem public ModKeybind Scoreboard { get; private set; } public ModKeybind BountyShop { get; private set; } public ModKeybind AllChat { get; private set; } - public ModKeybind AdventureMirrorKeybind { get; private set; } public override void Load() { Scoreboard = KeybindLoader.RegisterKeybind(Mod, "Scoreboard", Keys.OemTilde); BountyShop = KeybindLoader.RegisterKeybind(Mod, "BountyShop", Keys.P); AllChat = KeybindLoader.RegisterKeybind(Mod, "AllChat", Keys.U); - AdventureMirrorKeybind = KeybindLoader.RegisterKeybind(Mod, "AdventureMirror", Keys.M); } } \ No newline at end of file From 9990e036b298c4932a24f78d302419b1bc437b5c Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Fri, 5 Dec 2025 22:28:08 -0800 Subject: [PATCH 203/206] shadow key --- AdventureDropDatabase.cs | 12 ++++---- Dogshit.cs | 59 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 6 deletions(-) diff --git a/AdventureDropDatabase.cs b/AdventureDropDatabase.cs index bbe9169d..99bc9053 100644 --- a/AdventureDropDatabase.cs +++ b/AdventureDropDatabase.cs @@ -413,9 +413,9 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) case NPCID.BigMimicHallow: npcLoot.RemoveWhere(drop => true); // Removes all drops npcLoot.Add(ItemDropRule.Common(ItemID.IlluminantHook, 4, 1, 1)); - npcLoot.Add(ItemDropRule.Common(ItemID.GoldCoin, 1, 10, 25)); - npcLoot.Add(ItemDropRule.Common(ItemID.GreaterHealingPotion, 1, 20, 30)); - npcLoot.Add(ItemDropRule.Common(ItemID.GreaterManaPotion, 1, 75, 150)); + npcLoot.Add(ItemDropRule.Common(ItemID.GoldCoin, 1, 7, 7)); + npcLoot.Add(ItemDropRule.Common(ItemID.GreaterHealingPotion, 1, 8, 10)); + npcLoot.Add(ItemDropRule.Common(ItemID.GreaterManaPotion, 1, 6, 14)); npcLoot.Add(ItemDropRule.OneFromOptions(1, ItemID.DaedalusStormbow, @@ -425,9 +425,9 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) break; case NPCID.BigMimicCorruption: npcLoot.RemoveWhere(drop => true); // Removes all drops - npcLoot.Add(ItemDropRule.Common(ItemID.GoldCoin, 1, 10, 25)); - npcLoot.Add(ItemDropRule.Common(ItemID.GreaterHealingPotion, 1, 20, 30)); - npcLoot.Add(ItemDropRule.Common(ItemID.GreaterManaPotion, 1, 75, 150)); + npcLoot.Add(ItemDropRule.Common(ItemID.GoldCoin, 1, 7, 7)); + npcLoot.Add(ItemDropRule.Common(ItemID.GreaterHealingPotion, 1, 8, 10)); + npcLoot.Add(ItemDropRule.Common(ItemID.GreaterManaPotion, 1, 6, 14)); npcLoot.Add(ItemDropRule.OneFromOptions(1, ItemID.ClingerStaff, ItemID.DartRifle, diff --git a/Dogshit.cs b/Dogshit.cs index 87a30bae..542e166b 100644 --- a/Dogshit.cs +++ b/Dogshit.cs @@ -18,6 +18,7 @@ using Terraria.DataStructures; using Terraria.GameContent.Biomes; using Terraria.GameContent.Personalities; +using Terraria.Utilities; namespace PvPAdventure { public class IncreasedRainSystem : ModSystem @@ -1344,4 +1345,62 @@ public override void ModifyWorldGenTasks(List tasks, ref double totalWe Main.tileSolid[137] = false; }); } +} + + public class ShadowKeyWorldGen : ModSystem + { + public override void Load() + { + IL_WorldGen.AddBuriedChest_int_int_int_bool_int_bool_ushort += AddBuriedChest_IL; + } + + private void AddBuriedChest_IL(ILContext il) + { + var cursor = new ILCursor(il); + + try + { + int patchCount = 0; + + while (cursor.TryGotoNext(MoveType.Before, + i => i.MatchLdsfld(typeof(GenVars), "generatedShadowKey"))) + { + Mod.Logger.Info($"Found generatedShadowKey field at index {cursor.Index}"); + + if (cursor.TryGotoNext(MoveType.Before, + i => i.MatchLdcI4(3) && + i.Next != null && + i.Next.MatchCallvirt("Next"))) + { + Mod.Logger.Info($"Found Shadow Key Next(3) call at index {cursor.Index}"); + + cursor.Remove(); + + cursor.Emit(OpCodes.Ldc_I4_1); + + patchCount++; + Mod.Logger.Info($"Patched occurrence #{patchCount}"); + + cursor.Index++; + } + else + { + cursor.Index++; + } + } + + if (patchCount > 0) + { + Mod.Logger.Info($"Successfully patched {patchCount} Shadow Key generation location(s)"); + } + else + { + Mod.Logger.Error("Failed to find any Shadow Key generation patterns to patch"); + } + } + catch (Exception e) + { + Mod.Logger.Error($"Error patching AddBuriedChest: {e}"); + } + } } \ No newline at end of file From 72177824f1ec1a5b37b479117f69dbb588e860b8 Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Sat, 6 Dec 2025 10:21:18 -0800 Subject: [PATCH 204/206] Update AdventureDropDatabase.cs --- AdventureDropDatabase.cs | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/AdventureDropDatabase.cs b/AdventureDropDatabase.cs index bbe9169d..358040e5 100644 --- a/AdventureDropDatabase.cs +++ b/AdventureDropDatabase.cs @@ -79,6 +79,9 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) foreach (var drop in drops) ModifyDropRate(drop, ItemID.Kraken, 1, 20); + foreach (var drop in drops) + ModifyDropRate(drop, ItemID., 1, 20); + switch (npc.type) { case NPCID.BoneLee: @@ -147,7 +150,6 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) case NPCID.TacticalSkeleton: foreach (var drop in drops) ModifyDropRate(drop, ItemID.TacticalShotgun, 1, 1); - npcLoot.Add(ItemDropRule.Common(ItemID.RifleScope, 1)); break; case NPCID.SkeletonCommando: @@ -268,6 +270,20 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) } break; + case NPCID.ManEater: + foreach (var drop in drops) + { + ModifyDropRate(drop, ItemID.Vine, 1, 1); + } + break; + + case NPCID.SpikedJungleSlime: + foreach (var drop in drops) + { + ModifyDropRate(drop, ItemID.Stinger, 1, 1); + } + break; + case NPCID.Hornet: foreach (var drop in drops) { @@ -413,9 +429,9 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) case NPCID.BigMimicHallow: npcLoot.RemoveWhere(drop => true); // Removes all drops npcLoot.Add(ItemDropRule.Common(ItemID.IlluminantHook, 4, 1, 1)); - npcLoot.Add(ItemDropRule.Common(ItemID.GoldCoin, 1, 10, 25)); - npcLoot.Add(ItemDropRule.Common(ItemID.GreaterHealingPotion, 1, 20, 30)); - npcLoot.Add(ItemDropRule.Common(ItemID.GreaterManaPotion, 1, 75, 150)); + npcLoot.Add(ItemDropRule.Common(ItemID.GoldCoin, 1, 3, 3)); + npcLoot.Add(ItemDropRule.Common(ItemID.GreaterHealingPotion, 1, 5, 10)); + npcLoot.Add(ItemDropRule.Common(ItemID.GreaterManaPotion, 1, 5, 15)); npcLoot.Add(ItemDropRule.OneFromOptions(1, ItemID.DaedalusStormbow, @@ -425,9 +441,9 @@ public static void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) break; case NPCID.BigMimicCorruption: npcLoot.RemoveWhere(drop => true); // Removes all drops - npcLoot.Add(ItemDropRule.Common(ItemID.GoldCoin, 1, 10, 25)); - npcLoot.Add(ItemDropRule.Common(ItemID.GreaterHealingPotion, 1, 20, 30)); - npcLoot.Add(ItemDropRule.Common(ItemID.GreaterManaPotion, 1, 75, 150)); + npcLoot.Add(ItemDropRule.Common(ItemID.GoldCoin, 1, 3, 3)); + npcLoot.Add(ItemDropRule.Common(ItemID.GreaterHealingPotion, 1, 5, 10)); + npcLoot.Add(ItemDropRule.Common(ItemID.GreaterManaPotion, 1, 5, 15)); npcLoot.Add(ItemDropRule.OneFromOptions(1, ItemID.ClingerStaff, ItemID.DartRifle, From 65adaf4dbd3ffc368ca4244abdfc693e2abc19f9 Mon Sep 17 00:00:00 2001 From: emyhrberg <121192176+emyhrberg@users.noreply.github.com> Date: Sun, 7 Dec 2025 14:46:33 +0100 Subject: [PATCH 205/206] Refactor DashKeybindSystem --- .../DashKeybindSystem.cs} | 56 ++++++++++++------- Core/Features/Dash/DashKeybindSystem.cs | 28 ---------- Core/Features/Dash/DetourVanillaDashSystem.cs | 44 --------------- Localization/en-US.hjson | 10 ++-- PvPAdventure.cs | 4 +- System/Client/Keybinds.cs | 2 + 6 files changed, 46 insertions(+), 98 deletions(-) rename Core/{Features/Dash/KeybindSystem.cs => DashKeybind/DashKeybindSystem.cs} (88%) delete mode 100644 Core/Features/Dash/DashKeybindSystem.cs delete mode 100644 Core/Features/Dash/DetourVanillaDashSystem.cs diff --git a/Core/Features/Dash/KeybindSystem.cs b/Core/DashKeybind/DashKeybindSystem.cs similarity index 88% rename from Core/Features/Dash/KeybindSystem.cs rename to Core/DashKeybind/DashKeybindSystem.cs index 7cbeeb82..3ff4b14c 100644 --- a/Core/Features/Dash/KeybindSystem.cs +++ b/Core/DashKeybind/DashKeybindSystem.cs @@ -1,7 +1,7 @@ using System; using System.IO; using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Input; +using PvPAdventure.System.Client; using Terraria; using Terraria.DataStructures; using Terraria.GameInput; @@ -9,31 +9,51 @@ using Terraria.ID; using Terraria.ModLoader; -namespace PvPAdventure.Core.Features.Dash +namespace PvPAdventure.Core.DashKeybind { - internal enum PvPAdventureMessageType : byte - { - Dash = 0 - } - internal enum DashPacketType : byte { Request = 0, Perform = 1 } - public class KeybindSystem : ModSystem + public class DashKeybindSystem : ModSystem { - public static ModKeybind DashKB; - public override void Load() { - DashKB = KeybindLoader.RegisterKeybind(Mod, "Dash", Keys.Z); + On_Player.DoCommonDashHandle += VanillaDashDetour; + On_Player.DashMovement += CustomDashHandle; } - public override void Unload() { - DashKB = null; + On_Player.DoCommonDashHandle -= VanillaDashDetour; + On_Player.DashMovement -= CustomDashHandle; + } + private static void VanillaDashDetour(On_Player.orig_DoCommonDashHandle orig, Player self, out int dir, out bool dashing, Player.DashStartAction dashStartAction) + { + var config = ModContent.GetInstance(); + + // Execute vanilla dash only if enabled in config + if (config.IsVanillaDashEnabled) + { + orig.Invoke(self, out dir, out dashing, dashStartAction); + return; + } + else + { + // Must set out parameters even if not dashing + dir = 0; + dashing = false; + } + } + private static void CustomDashHandle(On_Player.orig_DashMovement orig, Player self) + { + if (self.whoAmI == Main.myPlayer && ModContent.GetInstance().Dash.JustPressed) + { + //Log.Info($"Dash key pressed on player {self.whoAmI} (dashDelay={self.dashDelay})."); + } + + orig(self); } internal static void HandlePacket(BinaryReader reader, int sender) @@ -58,7 +78,7 @@ internal static void HandlePacket(BinaryReader reader, int sender) if (!player.active || player.dead) break; - var dashPlayer = player.GetModPlayer(); + var dashPlayer = player.GetModPlayer(); if (dashPlayer.PerformDash(direction, force: false, out byte dashTypeUsed, dashTypeHint > 0 ? dashTypeHint : (int?)null)) { dashPlayer.BroadcastDash(direction, dashTypeUsed); @@ -89,7 +109,7 @@ internal static void HandlePacket(BinaryReader reader, int sender) if (direction == 0) direction = 1; - var dashPlayer = remotePlayer.GetModPlayer(); + var dashPlayer = remotePlayer.GetModPlayer(); dashPlayer.PerformDash(direction, force: true, out _, dashTypeUsed > 0 ? dashTypeUsed : (int?)null); break; } @@ -106,16 +126,14 @@ private static sbyte ClampDirection(int direction) } } - public class KeybindPlayer : ModPlayer + public class DashKeybindPlayer : ModPlayer { - private const int DefaultDashType = 2; - private bool restoreDashType; private int dashTypeToRestore; public override void ProcessTriggers(TriggersSet triggers) { - if (KeybindSystem.DashKB == null || !KeybindSystem.DashKB.JustPressed) + if (ModContent.GetInstance().Dash == null || !ModContent.GetInstance().Dash.JustPressed) return; int inputDirection = NormalizeDirection(GetInputDirection()); diff --git a/Core/Features/Dash/DashKeybindSystem.cs b/Core/Features/Dash/DashKeybindSystem.cs deleted file mode 100644 index c0b6ee1d..00000000 --- a/Core/Features/Dash/DashKeybindSystem.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Terraria; -using Terraria.ModLoader; - -namespace PvPAdventure.Core.Features.Dash -{ - public class DashKeybind : ModSystem - { - public override void Load() - { - On_Player.DashMovement += CustomDashHandle; - } - - public override void Unload() - { - On_Player.DashMovement -= CustomDashHandle; - } - - private static void CustomDashHandle(On_Player.orig_DashMovement orig, Player self) - { - if (self.whoAmI == Main.myPlayer && KeybindSystem.DashKB?.JustPressed == true) - { - ModContent.GetInstance().Logger.Info($"Dash key pressed on player {self.whoAmI} (dashDelay={self.dashDelay})."); - } - - orig(self); - } - } -} \ No newline at end of file diff --git a/Core/Features/Dash/DetourVanillaDashSystem.cs b/Core/Features/Dash/DetourVanillaDashSystem.cs deleted file mode 100644 index 39850040..00000000 --- a/Core/Features/Dash/DetourVanillaDashSystem.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Terraria; -using Terraria.ModLoader; - -namespace PvPAdventure.Core.Features.Dash -{ - internal class DetourVanillaDashSystem : ModSystem - { - public override void Load() - { - On_Player.DoCommonDashHandle += VanillaDashDetour; - } - public override void Unload() - { - On_Player.DoCommonDashHandle -= VanillaDashDetour; - } - - private static void VanillaDashDetour(On_Player.orig_DoCommonDashHandle orig, Player self, out int dir, out bool dashing, Player.DashStartAction dashStartAction) - { - // Get client config - var clientConfig = ModContent.GetInstance(); - - // Execute vanilla dash only if enabled in config - if (clientConfig.IsVanillaDashEnabled) - { - orig.Invoke(self, out dir, out dashing, dashStartAction); - return; - } - else - { - // Must set out parameters even if not dashing - dir = 0; - dashing = false; - } - - //if (self.whoAmI != Main.myPlayer) - //orig.Invoke(self, out dir, out dashing, dashStartAction); - } - } -} diff --git a/Localization/en-US.hjson b/Localization/en-US.hjson index f7a5fcb3..ee3cacce 100644 --- a/Localization/en-US.hjson +++ b/Localization/en-US.hjson @@ -359,11 +359,11 @@ Mods: { IsVanillaDashEnabled: { Label: Is Vanilla Dash Enabled - Tooltip: - ''' - On: Dash as usual with double tap - Off: Disables double tap dash. Use keybind instead - ''' + Tooltip: + ''' + On: Dash as usual with double tap + Off: Disables double tap dash. Use keybind instead + ''' } } diff --git a/PvPAdventure.cs b/PvPAdventure.cs index c93f0864..b93660cb 100644 --- a/PvPAdventure.cs +++ b/PvPAdventure.cs @@ -2,7 +2,7 @@ using System.Linq; using Microsoft.Xna.Framework; using MonoMod.Cil; -using PvPAdventure.Core.Features.Dash; +using PvPAdventure.Core.DashKeybind; using PvPAdventure.System; using Terraria; using Terraria.Enums; @@ -53,7 +53,7 @@ public override void HandlePacket(BinaryReader reader, int whoAmI) switch (id) { case AdventurePacketIdentifier.Dash: - KeybindSystem.HandlePacket(reader, whoAmI); + DashKeybindSystem.HandlePacket(reader, whoAmI); break; case AdventurePacketIdentifier.BountyTransaction: diff --git a/System/Client/Keybinds.cs b/System/Client/Keybinds.cs index d72d756f..e8be8c22 100644 --- a/System/Client/Keybinds.cs +++ b/System/Client/Keybinds.cs @@ -9,11 +9,13 @@ public class Keybinds : ModSystem public ModKeybind Scoreboard { get; private set; } public ModKeybind BountyShop { get; private set; } public ModKeybind AllChat { get; private set; } + public ModKeybind Dash { get; private set; } public override void Load() { Scoreboard = KeybindLoader.RegisterKeybind(Mod, "Scoreboard", Keys.OemTilde); BountyShop = KeybindLoader.RegisterKeybind(Mod, "BountyShop", Keys.P); AllChat = KeybindLoader.RegisterKeybind(Mod, "AllChat", Keys.U); + Dash = KeybindLoader.RegisterKeybind(Mod, "Dash", Keys.F); } } \ No newline at end of file From 04ba4b2032d8f5698a8ef147267f2d840410f0ab Mon Sep 17 00:00:00 2001 From: emyhrberg <121192176+emyhrberg@users.noreply.github.com> Date: Sun, 7 Dec 2025 14:57:49 +0100 Subject: [PATCH 206/206] Fixed dash sync again --- PvPAdventure.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/PvPAdventure.cs b/PvPAdventure.cs index ced5989b..81484cdc 100644 --- a/PvPAdventure.cs +++ b/PvPAdventure.cs @@ -1,13 +1,14 @@ -using System; -using System.IO; -using System.Linq; using Microsoft.Xna.Framework; using MonoMod.Cil; using PvPAdventure.Content.Items; +using PvPAdventure.Core.DashKeybind; using PvPAdventure.Core.Helpers; using PvPAdventure.System; +using System; using System.Collections.Generic; using System.IO; +using System.IO; +using System.Linq; using System.Linq; using Terraria; using Terraria.Chat; @@ -308,6 +309,9 @@ public override void HandlePacket(BinaryReader reader, int whoAmI) break; } + case AdventurePacketIdentifier.Dash: + DashKeybindSystem.HandlePacket(reader, whoAmI); + break; } } } \ No newline at end of file
  • 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 TjRc4l00000NkvXXu0mjfT}fgv literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG19.png b/Assets/SpawnSelector/MapBG19.png new file mode 100644 index 0000000000000000000000000000000000000000..e09d63beca3e9c4df18b0f9cc353e702410e045e GIT binary patch literal 10791 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 literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG2.png b/Assets/SpawnSelector/MapBG2.png new file mode 100644 index 0000000000000000000000000000000000000000..29e70dfc4ce50a1c4c5a039f112251fb76f66858 GIT binary patch literal 3466 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 literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG22.png b/Assets/SpawnSelector/MapBG22.png new file mode 100644 index 0000000000000000000000000000000000000000..31894cc715fccc23807cde0fd83770c535300b4a GIT binary patch literal 14635 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 literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG24.png b/Assets/SpawnSelector/MapBG24.png new file mode 100644 index 0000000000000000000000000000000000000000..bfdde406dbd4ed6f6626a58dc541f4cf5c9fa891 GIT binary patch literal 4523 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 JPDHLkV1ipLy4?T( literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG25.png b/Assets/SpawnSelector/MapBG25.png new file mode 100644 index 0000000000000000000000000000000000000000..55894c3432d1665d13a58fb7626f2425f5fcc2b6 GIT binary patch literal 291 zcmeAS@N?(olHy`uVBq!ia0vp^#X#)H!3HEBeVpw8q&N#aB7uV3!XV7ZFl&wkQ1Gg! zi(^Q|oVRxkxtJUUTo2~HuTMXkkZ{ygxI`}Wrq7iRd>@`yl<)uX*#7MC_6gCmR?l#H zmwnE#_0D~pWG>0V-(MMP`e!I6wRK1;rFGDskyNO$&0-6O)J>*nmfkgAberUESG@er Za4wg#av{@;n?MgTc)I$ztaD0e0szuAYOw$S literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG26.png b/Assets/SpawnSelector/MapBG26.png new file mode 100644 index 0000000000000000000000000000000000000000..9e0ca8525a3041e233990b08a0f493defc327be6 GIT binary patch literal 3331 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 N002ovPDHLkV1g_MTpa)a literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG27.png b/Assets/SpawnSelector/MapBG27.png new file mode 100644 index 0000000000000000000000000000000000000000..9e1777bf7462fc822391c62ffdfe64780570244d GIT binary patch literal 4784 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 KMNUMnLSTXk6kMzT literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG28.png b/Assets/SpawnSelector/MapBG28.png new file mode 100644 index 0000000000000000000000000000000000000000..cd98391369e763e2ebb7189d856cc685bda3b3bf GIT binary patch literal 7876 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 i)URfItR4_a*Z&`sSpvlvkTRYC0000mZ*1 literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG29.png b/Assets/SpawnSelector/MapBG29.png new file mode 100644 index 0000000000000000000000000000000000000000..398b4026506be17dc52a781e222846b10510d6e3 GIT binary patch literal 9729 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 P00000NkvXXu0mjfTq$B} literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG3.png b/Assets/SpawnSelector/MapBG3.png new file mode 100644 index 0000000000000000000000000000000000000000..83d62de5354c154ddcd0b0b57600fbe4cb0a7b86 GIT binary patch literal 4762 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 JPDHLkV1gp6sLlWY literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG32.png b/Assets/SpawnSelector/MapBG32.png new file mode 100644 index 0000000000000000000000000000000000000000..0061a6faba6c83e007299f9cb4a815edcd6c6c02 GIT binary patch literal 4568 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 RO-TR%002ovPDHLkV1hz9l@b5| literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG34.png b/Assets/SpawnSelector/MapBG34.png new file mode 100644 index 0000000000000000000000000000000000000000..590bd700a504c91fe4a5fd1ae5382e02cc265bc8 GIT binary patch literal 5236 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 P00000NkvXXu0mjfT9R`O literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG36.png b/Assets/SpawnSelector/MapBG36.png new file mode 100644 index 0000000000000000000000000000000000000000..9caa5e09ffec909d4e5fa2d3443c1c2c8f0f4e84 GIT binary patch literal 7611 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 Uq#5Kmod5s;07*qoM6N<$f*~cvCIA2c literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG38.png b/Assets/SpawnSelector/MapBG38.png new file mode 100644 index 0000000000000000000000000000000000000000..d89acb0a66dddf14c028242e7dec2ceccf7a9bfd GIT binary patch literal 2580 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 literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG4.png b/Assets/SpawnSelector/MapBG4.png new file mode 100644 index 0000000000000000000000000000000000000000..1dc6974cc1ffcdb5b30e56bda1860f3b4b3198be GIT binary patch literal 5575 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 Qi2wiq07*qoM6N<$f)X9AVn<#g$Fe0$v?-Dz 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 IM6N<$f`91v8UO$Q literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG7.png b/Assets/SpawnSelector/MapBG7.png new file mode 100644 index 0000000000000000000000000000000000000000..6c0228133dd534210c3a13947dbb56f89da52984 GIT binary patch literal 5501 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 literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG8.png b/Assets/SpawnSelector/MapBG8.png new file mode 100644 index 0000000000000000000000000000000000000000..c944a3093f165af7be8aac5d9f3b23991b0cd0b3 GIT binary patch literal 7262 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 literal 0 HcmV?d00001 diff --git a/Assets/SpawnSelector/MapBG9.png b/Assets/SpawnSelector/MapBG9.png new file mode 100644 index 0000000000000000000000000000000000000000..57f8c27bc5456f8f0881778707c90d18c322a1dc GIT binary patch literal 7093 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 literal 0 HcmV?d00001 diff --git a/Content/Items/AdventureMirror.cs b/Content/Items/AdventureMirror.cs index c5f7118a..be84ac39 100644 --- a/Content/Items/AdventureMirror.cs +++ b/Content/Items/AdventureMirror.cs @@ -1,6 +1,7 @@ using Microsoft.Xna.Framework; using PvPAdventure.Core.Features.SpawnSelector.Players; using Terraria; +using Terraria.Audio; using Terraria.ID; using Terraria.ModLoader; @@ -26,6 +27,19 @@ public override bool CanUseItem(Player player) { var adventureMirrorPlayer = player.GetModPlayer(); + if (adventureMirrorPlayer.IsPlayerInSpawnRegion()) + { + PopupText.NewText(new AdvancedPopupRequest + { + Color = Color.Crimson, + Text = "Cannot use in spawn!", + Velocity = new(0f, -4f), + DurationInFrames = 60 + }, player.Top); + + return false; + }; + if (adventureMirrorPlayer.CancelIfPlayerMoves()) return false; @@ -37,7 +51,6 @@ public override bool CanUseItem(Player player) public override bool CanRightClick() => true; public override bool ConsumeItem(Player player) => false; - public override void RightClick(Player player) { var adventureMirrorPlayer = player.GetModPlayer(); @@ -51,6 +64,8 @@ public override void RightClick(Player player) var config = ModContent.GetInstance(); int recallFrames = config.AdventureMirrorRecallFrames + 1; + SoundEngine.PlaySound(SoundID.Item6); // magic mirror + adventureMirrorPlayer.StartMirrorUse(recallFrames); } diff --git a/Core/Debug/DebugKeybinds.cs b/Core/Debug/DebugKeybinds.cs new file mode 100644 index 00000000..dddcf3e2 --- /dev/null +++ b/Core/Debug/DebugKeybinds.cs @@ -0,0 +1,66 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Input; +using PvPAdventure.Core.Features.SpawnSelector.Systems; +using Terraria; +using Terraria.GameInput; +using Terraria.ModLoader; +using Terraria.UI; + +namespace PvPAdventure.Core.Debug; + +#if DEBUG +[Autoload(Side = ModSide.Client)] +public class DebugKeybinds : ModSystem +{ + public ModKeybind OpenControls { get; private set; } + public ModKeybind SwitchTeams { get; private set; } + public ModKeybind AddPlayerToSpawnSelector { get; private set; } + public ModKeybind ClearPlayersFromSpawnSelector { get; private set; } + + public override void Load() + { + OpenControls = KeybindLoader.RegisterKeybind(Mod, "OpenControls", Keys.NumPad0); + SwitchTeams = KeybindLoader.RegisterKeybind(Mod, "SwitchTeams", Keys.NumPad1); + AddPlayerToSpawnSelector = KeybindLoader.RegisterKeybind(Mod, "AddPlayerToSpawnSelector", Keys.NumPad2); + ClearPlayersFromSpawnSelector = KeybindLoader.RegisterKeybind(Mod, "ClearPlayersFromSpawnSelector", Keys.NumPad3); + } +} + +public class DebugKeybindsPlayer : ModPlayer +{ + public override void ProcessTriggers(TriggersSet triggersSet) + { + var key = ModContent.GetInstance(); + + // Open controls + if (key.OpenControls.JustPressed) + { + IngameFancyUI.OpenKeybinds(); + } + + // Switch teams + if (key.SwitchTeams.JustPressed) + { + Player.team = (Player.team + 1) % 6; // Cycle through teams 0-5 + Main.NewText(Player.name + " switched to team: " + (Terraria.Enums.Team)Player.team); + } + + if (key.AddPlayerToSpawnSelector.JustPressed) + { + var sys = ModContent.GetInstance(); + sys.state.spawnSelectorPanel.DebugAddPlayer(); + Main.NewText("Added SpawnSelectorSystem player"); + //sys.state.spawnSelectorPanel.Rebuild(); + } + + if (key.ClearPlayersFromSpawnSelector.JustPressed) + { + var sys = ModContent.GetInstance(); + sys.state.spawnSelectorPanel.DebugClearPlayers(); + Main.NewText("Cleared SpawnSelectorSystem players"); + //sys.state.spawnSelectorPanel.Rebuild(); + } + } +} + +#endif \ No newline at end of file diff --git a/Core/Features/SpawnSelector/Hooks/ItemSlotHooks.cs b/Core/Features/SpawnSelector/Hooks/ItemSlotHooks.cs index a94c310a..dc3f9dbb 100644 --- a/Core/Features/SpawnSelector/Hooks/ItemSlotHooks.cs +++ b/Core/Features/SpawnSelector/Hooks/ItemSlotHooks.cs @@ -40,6 +40,7 @@ private static void Hook_LeftClick_ItemArray( On_ItemSlot.orig_LeftClick_ItemArray_int_int orig, Item[] inv, int context, int slot) { + if (context == ItemSlot.Context.TrashItem && !Main.mouseItem.IsAir && Main.mouseItem.type == ModContent.ItemType()) diff --git a/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs b/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs index 680c50f5..9c48d582 100644 --- a/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs +++ b/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs @@ -9,6 +9,7 @@ using Terraria.GameInput; using Terraria.ID; using Terraria.ModLoader; +using static PvPAdventure.System.RegionManager; namespace PvPAdventure.Core.Features.SpawnSelector.Players; @@ -26,20 +27,19 @@ public void StartMirrorUse(int durationFrames) MirrorTimer = durationFrames; } - private void UpdateSpawnSelectorEnabledState() + public bool IsPlayerInSpawnRegion() { // Force SSS to be enabled when player is within the spawn region. var regionManager = ModContent.GetInstance(); Point tilePos = Player.Center.ToTileCoordinates(); var region = regionManager.GetRegionContaining(tilePos); - bool inRegion = region != null; - if (inRegion) - SpawnSelectorSystem.SetEnabled(true); - - // Force closes SSS whenever map is closed. - if (!Main.mapFullscreen) - SpawnSelectorSystem.SetEnabled(false); + if (region != null) + { + return true; + } + return false; } + public bool CancelIfPlayerMoves() { if (Player.velocity.LengthSquared() <= 0f) @@ -75,7 +75,13 @@ public bool CancelIfPlayerMoves() public override void PostUpdate() { - UpdateSpawnSelectorEnabledState(); + // Open SSS whenever player is in spawn region. + if (IsPlayerInSpawnRegion()) + SpawnSelectorSystem.SetEnabled(true); + + // Closes SSS whenever map is closed. + if (!Main.mapFullscreen) + SpawnSelectorSystem.SetEnabled(false); if (!MirrorActive) return; @@ -107,16 +113,16 @@ public override void PostUpdate() }, Player.Top); } - // End of channel, teleport once + // Teleport to spawn if (MirrorTimer <= 0) { // Close player inventory - Main.playerInventory = false; + //Main.playerInventory = false; if (!Main.mapFullscreen) { - SoundEngine.PlaySound(SoundID.MenuOpen); - Main.mapFullscreen = true; + //SoundEngine.PlaySound(SoundID.MenuOpen); + //Main.mapFullscreen = true; float worldCenterX = Main.maxTilesX / 2f; float worldCenterY = Main.maxTilesY / 2f; @@ -130,7 +136,9 @@ public override void PostUpdate() CustomTeleportWithoutSound(spawnPos); } - SpawnSelectorSystem.SetEnabled(true); + SpawnSelectorSystem.SetEnabled(true); // This is redundant because spawn region already sets it to true + ModContent.GetInstance().state.spawnSelectorPanel.Rebuild(); + Player.RemoveAllGrapplingHooks(); MirrorActive = false; diff --git a/Core/Features/SpawnSelector/Systems/SpawnSelectorSystem.cs b/Core/Features/SpawnSelector/Systems/SpawnSelectorSystem.cs index a75209dd..4d174412 100644 --- a/Core/Features/SpawnSelector/Systems/SpawnSelectorSystem.cs +++ b/Core/Features/SpawnSelector/Systems/SpawnSelectorSystem.cs @@ -45,10 +45,11 @@ public override void Unload() private void OnTriggerPing(On_Main.orig_TriggerPing orig, Vector2 position) { // Skip ping execution if our panel is being hovered - if (teleportPanel != null && !teleportPanel.IsMouseHovering) + if (state.spawnSelectorPanel != null && state.spawnSelectorPanel.IsMouseHovering) { - orig(position); + return; } + orig(position); } public override void UpdateUI(GameTime gameTime) diff --git a/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs b/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs index 9a07da12..23a90a74 100644 --- a/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs +++ b/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs @@ -8,6 +8,8 @@ using Terraria; using Terraria.GameContent; using Terraria.GameContent.UI.Elements; +using Terraria.ModLoader; +using Terraria.ModLoader.UI; using Terraria.UI; namespace PvPAdventure.Core.Features.SpawnSelector.UI @@ -70,6 +72,25 @@ private void DrawHeadOnMap(Player p) Utils.DrawBorderString(Main.spriteBatch, p.name, headPos, Color.White); } + private void DrawNineSlice(SpriteBatch sb, int x, int y, int w, int h, Texture2D tex, Color color, int inset, int c = 5) + { + x += inset; y += inset; w -= inset * 2; h -= inset * 2; + int ew = tex.Width - c * 2; + int eh = tex.Height - c * 2; + + sb.Draw(tex, new Rectangle(x, y, c, c), new Rectangle(0, 0, c, c), color); + sb.Draw(tex, new Rectangle(x + c, y, w - c * 2, c), new Rectangle(c, 0, ew, c), color); + sb.Draw(tex, new Rectangle(x + w - c, y, c, c), new Rectangle(tex.Width - c, 0, c, c), color); + + sb.Draw(tex, new Rectangle(x, y + c, c, h - c * 2), new Rectangle(0, c, c, eh), color); + sb.Draw(tex, new Rectangle(x + c, y + c, w - c * 2, h - c * 2), new Rectangle(c, c, ew, eh), color); + sb.Draw(tex, new Rectangle(x + w - c, y + c, c, h - c * 2), new Rectangle(tex.Width - c, c, c, eh), color); + + sb.Draw(tex, new Rectangle(x, y + h - c, c, c), new Rectangle(0, tex.Height - c, c, c), color); + sb.Draw(tex, new Rectangle(x + c, y + h - c, w - c * 2, c), new Rectangle(c, tex.Height - c, ew, c), color); + sb.Draw(tex, new Rectangle(x + w - c, y + h - c, c, c), new Rectangle(tex.Width - c, tex.Height - c, c, c), color); + } + protected override void DrawSelf(SpriteBatch sb) { base.DrawSelf(sb); @@ -89,10 +110,17 @@ protected override void DrawSelf(SpriteBatch sb) // Left player background Vector2 pos = new(inner.X, inner.Y); - //sb.Draw(_playerBGTexture.Value, pos, Color.White); + //sb.Draw(_playerBGTexture.Value, pos, Color.White*0.5f); + + Rectangle rect = new( + x: (int)pos.X-6, + y: (int)pos.Y-6, + width: 100, + height: 72); - Rectangle rect = new((int)pos.X-5, (int)pos.Y-5, 106,72); + //DrawMask(sb, Ass.CornerMask4px.Value, rect, 9); + DrawNineSlice(sb, rect.X, rect.Y, rect.Width, rect.Height, _playerBGTexture.Value, Color.White, 5); DrawMapFullscreenBackground(sb, rect, player); sb.End(); @@ -112,8 +140,7 @@ protected override void DrawSelf(SpriteBatch sb) //Main.PlayerRenderer.DrawPlayer(Main.Camera,player,playerDrawPos,player.fullRotation,player.fullRotationOrigin,0f,0.9f); Color myTeamColor = Main.teamColor[Main.LocalPlayer.team]; - - Main.PlayerRenderer.DrawPlayerHead(Main.Camera, player, pos+ new Vector2(40,37), scale: 1.3f, borderColor: myTeamColor); + Main.PlayerRenderer.DrawPlayerHead(Main.Camera, player, pos+ new Vector2(40,37), scale: 1.3f, borderColor: Color.Yellow); } catch (Exception e) { @@ -134,84 +161,91 @@ protected override void DrawSelf(SpriteBatch sb) null, Main.UIScaleMatrix); - float leftColumnWidth = _playerBGTexture.Width(); - float startX = inner.X + leftColumnWidth; + // Use the actual layout widths, not the texture width + const float leftColumnWidth = 106f; // player background column + const float rightAreaWidth = ItemWidth - 22f - leftColumnWidth; // 260 - 12 - 106 = 142 - // Name centered - string name = string.IsNullOrEmpty(player.name) ? "Unknown player" : player.name; - Vector2 nameSize = FontAssets.MouseText.Value.MeasureString(name); - float centerX = inner.X + inner.Width * 0.5f+20; + float rightAreaLeft = inner.X + leftColumnWidth; + float rightAreaCenterX = rightAreaLeft + rightAreaWidth * 0.5f; - Utils.DrawBorderString( - sb, - name, - new Vector2(centerX, inner.Y), - Color.White, - scale: 1.1f + // Name centered in the right-area + string name = string.IsNullOrEmpty(player.name) ? "Unknown player" : player.name + ""; + float nameScale = 1f; + if (player.name.Length > 16) nameScale = 0.85f; + Vector2 nameSize = FontAssets.MouseText.Value.MeasureString(name) * nameScale; + + Vector2 namePos = new( + rightAreaCenterX - nameSize.X * 0.5f, + inner.Y ); - // Divider + // Draw name + Utils.DrawBorderString(sb,name,namePos,Color.White,nameScale); + + // Draw divider sb.Draw( _dividerTexture.Value, - new Vector2(startX + 44, inner.Y + 21f), + new Vector2(rightAreaLeft-12, inner.Y + 21f), null, Color.White, 0f, Vector2.Zero, - new Vector2((dims.X + dims.Width - startX) / 8-7, 1f), + new Vector2(rightAreaWidth/8+2.2f, 1f), SpriteEffects.None, 0f ); - // HP / MP panel - Vector2 panelPos = new(startX + 60f, inner.Y + 29f); - float panelWidth = 90f; - DrawPanel(sb, panelPos, panelWidth); + // Stat panel settings + float statScale = 0.88f; + float statGap = 5f * statScale; - Vector2 cursor = panelPos; + // Draw stat panel + float panelWidth = rightAreaWidth+24; + Vector2 panelPos = new(rightAreaLeft-14, inner.Y + 29f); + DrawPanel(sb, panelPos, panelWidth); - // HP - sb.Draw(TextureAssets.Heart.Value, cursor + new Vector2(4f, 2f), Color.White); - cursor.X += 6f + TextureAssets.Heart.Width(); string hpText = $"{player.statLife} HP"; - Utils.DrawBorderString(sb, hpText, cursor + new Vector2(0f, 3f), Color.White); - - // MP - //cursor.X += 80f; - //sb.Draw(TextureAssets.Mana.Value, cursor + new Vector2(-15f, 0f), Color.White); - //cursor.X += -11f + TextureAssets.Mana.Width(); - //string manaText = $"{player.statMana} MP"; - //Utils.DrawBorderString(sb, manaText, cursor + new Vector2(0f, 3f), Color.White); - + string mpText = $"{player.statMana} MP"; + + Vector2 hpSize = FontAssets.MouseText.Value.MeasureString(hpText) * statScale; + Vector2 mpSize = FontAssets.MouseText.Value.MeasureString(mpText) * statScale; + + var heart = TextureAssets.Heart; + var mana = TextureAssets.Mana; + + float heartW = heart.Width() * statScale; + float manaW = mana.Width() * statScale; + float hpBlockW = heartW + hpSize.X; + float mpBlockW = manaW + mpSize.X; + float totalWidth = hpBlockW + statGap + mpBlockW; + float startX = panelPos.X + (panelWidth - totalWidth) * 0.5f; + float y = panelPos.Y + 4f; + + // Draw health + sb.Draw(heart.Value, new Vector2(startX, y), null, Color.White, 0f, Vector2.Zero, statScale, SpriteEffects.None, 0f); + startX += heartW; + Utils.DrawBorderString(sb, hpText, new Vector2(startX+1, y + 1f), Color.White, statScale); + startX += hpSize.X; + startX += statGap; + + // Draw mana + sb.Draw(mana.Value, new Vector2(startX, y - 2), null, Color.White, 0f, Vector2.Zero, statScale, SpriteEffects.None, 0f); + startX += manaW; + Utils.DrawBorderString(sb, mpText, new Vector2(startX+1, y + 1f), Color.White, statScale); + // Set hover teleport tooltip if (IsMouseHovering) { Main.instance.MouseText("Teleport to " + name); var old = Main.UIScaleMatrix; - Main.spriteBatch.End(); - Main.spriteBatch.Begin( - SpriteSortMode.Immediate, - BlendState.AlphaBlend, - SamplerState.PointClamp, - DepthStencilState.None, - RasterizerState.CullCounterClockwise, - null, - Matrix.Identity - ); - - DrawHeadOnMap(player); - - Main.spriteBatch.End(); - Main.spriteBatch.Begin( - SpriteSortMode.Deferred, - BlendState.AlphaBlend, - SamplerState.PointClamp, - DepthStencilState.None, - RasterizerState.CullCounterClockwise, - null, - old - ); + //Main.spriteBatch.End(); + //Main.spriteBatch.Begin(SpriteSortMode.Immediate,BlendState.AlphaBlend,SamplerState.PointClamp,DepthStencilState.None,RasterizerState.CullCounterClockwise,null,Matrix.Identity); + + //DrawHeadOnMap(player); + + //Main.spriteBatch.End(); + //Main.spriteBatch.Begin(SpriteSortMode.Deferred,BlendState.AlphaBlend,SamplerState.PointClamp,DepthStencilState.None,RasterizerState.CullCounterClockwise,null,old); } //Main.NewText(Main.mouseY); // 482,435 is spawn @@ -325,15 +359,19 @@ public static void DrawMapFullscreenBackground(SpriteBatch sb, Rectangle rect, P else if (player.ZoneGraveyard) bgIndex = 26; } - var asset = bgIndex >= 0 && bgIndex < TextureAssets.MapBGs.Length - ? TextureAssets.MapBGs[bgIndex] - : TextureAssets.MapBGs[0]; + // Vanilla + //var asset = bgIndex >= 0 && bgIndex < TextureAssets.MapBGs.Length? TextureAssets.MapBGs[bgIndex]: TextureAssets.MapBGs[0]; + + // Our textures with rounded corners + int safeIndex = (bgIndex >= 0 && bgIndex < Ass.MapBG.Length) ? bgIndex: 0; + var asset = Ass.MapBG[safeIndex]; rect.X += 10; rect.Y += 10; rect.Width -= 20; rect.Height -= 20; + if (asset == null || asset.Value == null) return; sb.Draw(asset.Value, rect, color); } } diff --git a/Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs b/Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs index ac873ce2..96f1184c 100644 --- a/Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs +++ b/Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs @@ -35,28 +35,33 @@ private void BuildLayout() RemoveAllChildren(); _playerItems.Clear(); - // === ADD TEAMMATES var players = new List(); var local = Main.LocalPlayer; - if (local.team != 0) +#if DEBUG + // If we have debug players, use them instead of scanning teammates + if (_debugPlayers.Count > 0) { - for (int i = 0; i < Main.maxPlayers; i++) - { - Player p = Main.player[i]; - if (p == null || !p.active || p.whoAmI == local.whoAmI || p.team != local.team) - continue; - - players.Add(p); - } + players.AddRange(_debugPlayers); } - - // === TEST DATA: add 3 self player copies for singleplayer testing - if (players.Count == 0) + else +#endif { - for (int i = 0; i < 3; i++) + // ADD TEAMMATES + if (local.team != 0) { - players.Add(local); + for (int i = 0; i < Main.maxPlayers; i++) + { + Player p = Main.player[i]; + + if (p == null || !p.active) + continue; + + if (p.whoAmI == local.whoAmI || p.team != local.team) + continue; + + players.Add(p); + } } } @@ -92,8 +97,7 @@ private void BuildLayout() _playerItems.Add(row); } - // Square random panel to the right of the last player, - // with exactly one Spacing after the last player. + // Square random panel to the right of the last player _randomPanel = new UISpawnSelectorRandomPanel( startX, itemHeight, @@ -117,5 +121,30 @@ public override void Draw(SpriteBatch spriteBatch) { base.Draw(spriteBatch); } + + #region Debug +#if DEBUG + private readonly List _debugPlayers = new(); +#endif + public void DebugAddPlayer() + { +#if DEBUG + _debugPlayers.Add(Main.LocalPlayer); + BuildLayout(); + Log.Debug($"SpawnSelector DebugAddPlayer: debugPlayers={_debugPlayers.Count}"); +#endif + } + + public void DebugClearPlayers() + { +#if DEBUG + _debugPlayers.Clear(); + BuildLayout(); + Log.Debug("SpawnSelector DebugClearPlayers: cleared debug players"); +#endif + } + #endregion + + } } diff --git a/Core/Features/SpawnSelector/UI/UISpawnSelectorRandomPanel.cs b/Core/Features/SpawnSelector/UI/UISpawnSelectorRandomPanel.cs index 7b0a7b96..886a5461 100644 --- a/Core/Features/SpawnSelector/UI/UISpawnSelectorRandomPanel.cs +++ b/Core/Features/SpawnSelector/UI/UISpawnSelectorRandomPanel.cs @@ -3,10 +3,8 @@ using PvPAdventure.Core.Features.SpawnSelector.Systems; using PvPAdventure.Core.Helpers; using Terraria; -using Terraria.GameContent; using Terraria.GameContent.UI.Elements; using Terraria.ID; -using Terraria.ModLoader; using Terraria.UI; namespace PvPAdventure.Core.Features.SpawnSelector.UI diff --git a/Core/Helpers/AssetLoader.cs b/Core/Helpers/AssetLoader.cs index fc7575ec..747b6dd3 100644 --- a/Core/Helpers/AssetLoader.cs +++ b/Core/Helpers/AssetLoader.cs @@ -5,37 +5,39 @@ namespace PvPAdventure.Core.Helpers; -/// -/// Static class to hold all assets used in the mod. -/// public static class Ass { - // Add assets here public static Asset Question_Mark; + public static Asset[] MapBG; - // This bool automatically initializes all specified assets public static bool Initialized { get; set; } static Ass() { - foreach (FieldInfo field in typeof(Ass).GetFields()) + // Load MapBG1..MapBG42 + MapBG = new Asset[42]; + for (int i = 1; i <= 42; i++) { - if (field.FieldType == typeof(Asset)) + MapBG[i - 1] = ModContent.Request( + $"PvPAdventure/Assets/SpawnSelector/MapBG{i}", + AssetRequestMode.AsyncLoad); + } + + // Load single texture fields (NOT MapBG array) + foreach (FieldInfo f in typeof(Ass).GetFields()) + { + if (f.FieldType == typeof(Asset)) { - var asset = ModContent.Request($"PvPAdventure/Assets/SpawnSelector/{field.Name}", AssetRequestMode.AsyncLoad); - field.SetValue(null, asset); + var asset = ModContent.Request( + $"PvPAdventure/Assets/SpawnSelector/{f.Name}", + AssetRequestMode.AsyncLoad); + f.SetValue(null, asset); } } } } -/// -/// System that automatically initializes assets -/// public class LoadAssets : ModSystem { - public override void Load() - { - _ = Ass.Initialized; - } -} \ No newline at end of file + public override void Load() => _ = Ass.Initialized; +} diff --git a/Localization/en-US.hjson b/Localization/en-US.hjson index 57f2b368..e8aab73c 100644 --- a/Localization/en-US.hjson +++ b/Localization/en-US.hjson @@ -14,6 +14,11 @@ Mods: { BountyShop.DisplayName: Bounty Shop AllChat.DisplayName: All Chat AdventureMirror.DisplayName: Adventure Mirror + OpenControls.DisplayName: Open Controls + SwitchTeams.DisplayName: Switch Teams + AddPlayerToSpawnSelector.DisplayName: Add Player To Spawn Selector + RemovePlayerFromSpawnSelector.DisplayName: Remove Player From Spawn Selector + ClearPlayersFromSpawnSelector.DisplayName: Clear Players From Spawn Selector } Configs: { @@ -784,11 +789,11 @@ Mods: { Items: { AdventureMirror: { DisplayName: Adventure Mirror - Tooltip: - ''' - Gaze in the mirror to go on adventures - Right click to use - ''' + Tooltip: + ''' + Gaze in the mirror to go on adventures + Right click to use + ''' } } } From a690c82cadaf78458494e94ee7bf681f66a68159 Mon Sep 17 00:00:00 2001 From: EJCrispy Date: Sat, 15 Nov 2025 10:37:57 -0800 Subject: [PATCH 166/206] fixed a small issue with pirahina gun removed rain virus --- AdventureProjectile.cs | 43 ++++++++++++++---------------------------- Dogshit.cs | 41 ---------------------------------------- 2 files changed, 14 insertions(+), 70 deletions(-) diff --git a/AdventureProjectile.cs b/AdventureProjectile.cs index b3f3cdb6..5dda8065 100644 --- a/AdventureProjectile.cs +++ b/AdventureProjectile.cs @@ -790,7 +790,7 @@ public override void ModifyHitPlayer(Projectile projectile, Player target, ref P modifiers.SourceDamage *= 0.75f; } } - public class VanillaPirahinaGun : GlobalProjectile + public class VanillaPiranhaGun : GlobalProjectile { public override bool InstancePerEntity => true; @@ -807,6 +807,12 @@ public override void SetDefaults(Projectile projectile) projectile.friendly = true; } + public override void OnSpawn(Projectile projectile, IEntitySource source) + { + attachedPlayerIndex = -1; + attachOffset = Vector2.Zero; + } + public override void AI(Projectile projectile) { if (attachedPlayerIndex < 0) @@ -865,7 +871,7 @@ public override void OnHitPlayer(Projectile projectile, Player target, Player.Hu { attachedPlayerIndex = target.whoAmI; attachOffset = projectile.Center - target.Center; - projectile.ai[0] = 1f; // Set to "attached" state + projectile.ai[0] = 1f; projectile.ai[1] = target.whoAmI; projectile.netUpdate = true; } @@ -885,12 +891,11 @@ public override bool PreAI(Projectile projectile) { shouldDetach = true; } - else if (!owner.channel || owner.HeldItem.type != ItemID.PiranhaGun) { shouldDetach = true; } - else if (Vector2.Distance(projectile.Center, owner.Center) > 2000f) // this will detach the pirahinas if theyre too far away when attached to a player, we can change this + else if (Vector2.Distance(projectile.Center, owner.Center) > 2000f) //distance until detatch { shouldDetach = true; } @@ -916,7 +921,7 @@ public override bool PreAI(Projectile projectile) if (projectile.localAI[0] <= 0f) { - projectile.localAI[0] = 40f; // Attack every frame (temp), we can change ts + projectile.localAI[0] = 40f; // amount of frames it hits if (Main.myPlayer == projectile.owner) { @@ -932,7 +937,7 @@ public override bool PreAI(Projectile projectile) projectile.localAI[0]--; } - return false; // Don't run vanilla AI + return false; } public override bool CanHitPlayer(Projectile projectile, Player target) @@ -961,9 +966,7 @@ public override void ReceiveExtraAI(Projectile projectile, BitReader bitReader, attachOffset.Y = binaryReader.ReadSingle(); } } - - // GlobalItem even though in adventureprojectile because FUCK YOU - public class PiranhaGunItem : GlobalItem + public class PiranhaGunItemSystem : GlobalItem { public override bool AppliesToEntity(Item entity, bool lateInstantiation) { @@ -978,7 +981,7 @@ public override void HoldItem(Item item, Player player) Projectile proj = Main.projectile[i]; if (proj.active && proj.owner == player.whoAmI && proj.type == ProjectileID.MechanicalPiranha) { - var modProj = proj.GetGlobalProjectile(); + var modProj = proj.GetGlobalProjectile(); if (modProj != null && modProj.attachedPlayerIndex >= 0) { hasAttachedPiranha = true; @@ -1002,7 +1005,7 @@ public override bool CanUseItem(Item item, Player player) Projectile proj = Main.projectile[i]; if (proj.active && proj.owner == player.whoAmI && proj.type == ProjectileID.MechanicalPiranha) { - var modProj = proj.GetGlobalProjectile(); + var modProj = proj.GetGlobalProjectile(); if (modProj != null && modProj.attachedPlayerIndex >= 0) { return true; @@ -1012,22 +1015,4 @@ public override bool CanUseItem(Item item, Player player) return base.CanUseItem(item, player); } } - public class NoKnockbackProjectiles : GlobalProjectile - { - public override bool AppliesToEntity(Projectile entity, bool lateInstantiation) - { - int projType = entity.type; - - return projType == ProjectileID.Meteor1 || - projType == ProjectileID.Meteor2 || - projType == ProjectileID.Meteor3 || - projType == ProjectileID.HeatRay || - projType == ProjectileID.FlyingKnife || - projType == ProjectileID.LaserMachinegunLaser; - } - public override void ModifyHitPlayer(Projectile projectile, Player target, ref Player.HurtModifiers modifiers) - { - modifiers.Knockback *= 0f; - } - } } \ No newline at end of file diff --git a/Dogshit.cs b/Dogshit.cs index f7c7c875..58ab5461 100644 --- a/Dogshit.cs +++ b/Dogshit.cs @@ -16,47 +16,6 @@ using Terraria.WorldBuilding; namespace PvPAdventure { - public class IncreasedRainSystem : ModSystem - { - private int rainCheckTimer = 0; - private const int RainCheckInterval = 60; - - public override void PostUpdateWorld() - { - if (Main.netMode == NetmodeID.MultiplayerClient) - return; - - rainCheckTimer++; - - if (rainCheckTimer >= RainCheckInterval) - { - rainCheckTimer = 0; - - if (!Main.raining && !Main.bloodMoon && !Main.eclipse) - { - if (Main.rand.NextBool(1200)) //this is just the chance each second that rain starts, so basically 1/20 every minute, so 1 rain every 20 mins - { - StartRain(); - } - } - } - } - - private void StartRain() - { - Main.StartRain(); - - // Set a reasonable rain duration - Main.rainTime = Main.rand.Next(18000, 54000); // 5-15 minutes - Main.maxRaining = Main.rand.NextFloat(0.3f, 0.9f); - - // Sync to clients in multiplayer - if (Main.netMode == NetmodeID.Server) - { - NetMessage.SendData(MessageID.WorldData); - } - } - } public class MechBossSpawnSystem : ModSystem { private bool hasAnnouncedTonight = false; From 76d4c47adaf24f49f7069b1e158d36baeb77474c Mon Sep 17 00:00:00 2001 From: emyhrberg <121192176+emyhrberg@users.noreply.github.com> Date: Sat, 15 Nov 2025 19:49:23 +0100 Subject: [PATCH 167/206] Removed .sln and minor fixes - player head outline color - recalculate with debug now works instantly --- .gitignore | 1 + AdventureClientConfig.cs | 4 ++++ Core/Debug/DebugKeybinds.cs | 13 ++++++---- .../SpawnSelector/Hooks/ItemSlotHooks.cs | 16 ++++++++++++- .../Players/AdventureMirrorPlayer.cs | 21 +++++++++------- .../Players/ModifyPlayerDrawInfo.cs | 3 +++ .../Systems/SpawnSelectorSystem.cs | 2 +- .../UI/UISpawnSelectorCharacterListItem.cs | 23 +++++++++--------- .../SpawnSelector/UI/UISpawnSelectorPanel.cs | 4 +++- Localization/en-US.hjson | 5 ++++ PvPAdventure.sln | 24 ------------------- 11 files changed, 65 insertions(+), 51 deletions(-) delete mode 100644 PvPAdventure.sln diff --git a/.gitignore b/.gitignore index cc2f8d65..411758f9 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ .vs bin obj +*.sln \ No newline at end of file diff --git a/AdventureClientConfig.cs b/AdventureClientConfig.cs index 6f35f225..9307cbb0 100644 --- a/AdventureClientConfig.cs +++ b/AdventureClientConfig.cs @@ -14,6 +14,8 @@ public class AdventureClientConfig : ModConfig public bool ShiftEnterOpensAllChat { get; set; } [DefaultValue(true)] public bool ShowPauseMessage { get; set; } + [DefaultValue(false)] public bool OpenMapAfterRecall; + public class PlayerOutlineConfig { public bool Self { get; set; } = true; @@ -125,6 +127,8 @@ public class PlayerKillMarkerConfig : KillMarkerConfig [DefaultValue(null)] [NullAllowed] public HitMarkerConfig NpcHitMarker { get; set; } [DefaultValue(null)] [NullAllowed] public PlayerHitMarkerConfig PlayerHitMarker { get; set; } [DefaultValue(null)] [NullAllowed] public PlayerKillMarkerConfig PlayerKillMarker { get; set; } + + } public SoundEffectConfig SoundEffect { get; set; } = new(); diff --git a/Core/Debug/DebugKeybinds.cs b/Core/Debug/DebugKeybinds.cs index dddcf3e2..24eda970 100644 --- a/Core/Debug/DebugKeybinds.cs +++ b/Core/Debug/DebugKeybinds.cs @@ -42,23 +42,26 @@ public override void ProcessTriggers(TriggersSet triggersSet) if (key.SwitchTeams.JustPressed) { Player.team = (Player.team + 1) % 6; // Cycle through teams 0-5 - Main.NewText(Player.name + " switched to team: " + (Terraria.Enums.Team)Player.team); + Main.NewText("[DEBUG] " + Player.name + " switched to team: " + (Terraria.Enums.Team)Player.team); } if (key.AddPlayerToSpawnSelector.JustPressed) { var sys = ModContent.GetInstance(); sys.state.spawnSelectorPanel.DebugAddPlayer(); - Main.NewText("Added SpawnSelectorSystem player"); - //sys.state.spawnSelectorPanel.Rebuild(); + sys.state.spawnSelectorPanel.Rebuild(); + + sys.ui.SetState(null); + sys.ui.SetState(sys.state); + Main.NewText("[DEBUG] Added player to UISpawnSelectorPanel"); } if (key.ClearPlayersFromSpawnSelector.JustPressed) { var sys = ModContent.GetInstance(); sys.state.spawnSelectorPanel.DebugClearPlayers(); - Main.NewText("Cleared SpawnSelectorSystem players"); - //sys.state.spawnSelectorPanel.Rebuild(); + Main.NewText("[DEBUG] Cleared all players from UISpawnSelectorPanel"); + sys.state.spawnSelectorPanel.Rebuild(); } } } diff --git a/Core/Features/SpawnSelector/Hooks/ItemSlotHooks.cs b/Core/Features/SpawnSelector/Hooks/ItemSlotHooks.cs index dc3f9dbb..0e1dc632 100644 --- a/Core/Features/SpawnSelector/Hooks/ItemSlotHooks.cs +++ b/Core/Features/SpawnSelector/Hooks/ItemSlotHooks.cs @@ -2,6 +2,9 @@ using Terraria.ModLoader; using Terraria.UI; using PvPAdventure.Content.Items; +using Terraria.Audio; +using Terraria.ID; +using Microsoft.Xna.Framework; public class ItemSlotHooks : ModSystem { @@ -45,7 +48,18 @@ private static void Hook_LeftClick_ItemArray( && !Main.mouseItem.IsAir && Main.mouseItem.type == ModContent.ItemType()) { - //SoundEngine.PlaySound(SoundID.MenuClose); + + if (Main.mouseLeft && Main.mouseLeftRelease) + { + PopupText.NewText(new AdvancedPopupRequest + { + Color = Color.Crimson, + Text = "Cannot trash Adventure Mirror!", + Velocity = new(0f, -4f), + DurationInFrames = 60 + }, Main.LocalPlayer.Top); + } + return; } diff --git a/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs b/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs index 9c48d582..664582b2 100644 --- a/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs +++ b/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs @@ -75,12 +75,13 @@ public bool CancelIfPlayerMoves() public override void PostUpdate() { - // Open SSS whenever player is in spawn region. + if (!Main.mapFullscreen) + SpawnSelectorSystem.SetEnabled(false); + + // Open SSS when player is in spawn region, and close it when player is outside spawn region. if (IsPlayerInSpawnRegion()) SpawnSelectorSystem.SetEnabled(true); - - // Closes SSS whenever map is closed. - if (!Main.mapFullscreen) + else SpawnSelectorSystem.SetEnabled(false); if (!MirrorActive) @@ -117,19 +118,23 @@ public override void PostUpdate() if (MirrorTimer <= 0) { // Close player inventory - //Main.playerInventory = false; + var config = ModContent.GetInstance(); + if (config.OpenMapAfterRecall) Main.playerInventory = false; if (!Main.mapFullscreen) { - //SoundEngine.PlaySound(SoundID.MenuOpen); - //Main.mapFullscreen = true; + if (config.OpenMapAfterRecall) + { + //SoundEngine.PlaySound(SoundID.MenuOpen); + //Main.mapFullscreen = true; + } float worldCenterX = Main.maxTilesX / 2f; float worldCenterY = Main.maxTilesY / 2f; Main.mapFullscreenPos.X = worldCenterX; Main.mapFullscreenPos.Y = worldCenterY; - Main.mapFullscreenScale = 0.21f; + Main.mapFullscreenScale = 0.21f; // arbitrary zoom out value that fits the entire map Vector2 spawnPos = new(Main.spawnTileX * 16, Main.spawnTileY * 16 - 48); //Main.LocalPlayer.Teleport(spawnPos, 0); diff --git a/Core/Features/SpawnSelector/Players/ModifyPlayerDrawInfo.cs b/Core/Features/SpawnSelector/Players/ModifyPlayerDrawInfo.cs index 67dd894b..8d6342bb 100644 --- a/Core/Features/SpawnSelector/Players/ModifyPlayerDrawInfo.cs +++ b/Core/Features/SpawnSelector/Players/ModifyPlayerDrawInfo.cs @@ -11,6 +11,9 @@ public class ModifyPlayerDrawInfo : ModPlayer public static bool ForceFullBrightOnce; public override void ModifyDrawInfo(ref PlayerDrawSet drawInfo) { + if (drawInfo.headOnlyRender) + return; + if (!ForceFullBrightOnce) return; diff --git a/Core/Features/SpawnSelector/Systems/SpawnSelectorSystem.cs b/Core/Features/SpawnSelector/Systems/SpawnSelectorSystem.cs index 4d174412..0d081ef2 100644 --- a/Core/Features/SpawnSelector/Systems/SpawnSelectorSystem.cs +++ b/Core/Features/SpawnSelector/Systems/SpawnSelectorSystem.cs @@ -10,7 +10,7 @@ namespace PvPAdventure.Core.Features.SpawnSelector.Systems; [Autoload(Side = ModSide.Client)] public class SpawnSelectorSystem : ModSystem { - private UserInterface ui; + public UserInterface ui; public SpawnSelectorState state; private UISpawnSelectorPanel teleportPanel; diff --git a/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs b/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs index 23a90a74..935295d0 100644 --- a/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs +++ b/Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs @@ -62,13 +62,13 @@ private void DrawHeadOnMap(Player p) Color color = Main.teamColor[p.team]; - //Main.PlayerRenderer.DrawPlayerHead( - // Main.Camera, - // p, - // headPos, - // scale: 1.3f, - // borderColor: color - //); + Main.PlayerRenderer.DrawPlayerHead( + Main.Camera, + p, + headPos, + scale: 1.3f, + borderColor: color + ); Utils.DrawBorderString(Main.spriteBatch, p.name, headPos, Color.White); } @@ -135,12 +135,13 @@ protected override void DrawSelf(SpriteBatch sb) ModifyPlayerDrawInfo.ForceFullBrightOnce = true; try { - Vector2 playerDrawPos = pos + Main.screenPosition + new Vector2(32, 8); - - //Main.PlayerRenderer.DrawPlayer(Main.Camera,player,playerDrawPos,player.fullRotation,player.fullRotationOrigin,0f,0.9f); + Vector2 playerDrawPos = pos + Main.screenPosition + new Vector2(34, 9); + Vector2 headDrawPos = pos + new Vector2(38, 28); Color myTeamColor = Main.teamColor[Main.LocalPlayer.team]; - Main.PlayerRenderer.DrawPlayerHead(Main.Camera, player, pos+ new Vector2(40,37), scale: 1.3f, borderColor: Color.Yellow); + + //Main.PlayerRenderer.DrawPlayer(Main.Camera,player,playerDrawPos,player.fullRotation,player.fullRotationOrigin,0f,0.9f); + Main.MapPlayerRenderer.DrawPlayerHead(Main.Camera, player, headDrawPos, scale: 1.0f, borderColor: myTeamColor); } catch (Exception e) { diff --git a/Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs b/Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs index 96f1184c..15264461 100644 --- a/Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs +++ b/Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs @@ -84,7 +84,7 @@ private void BuildLayout() float startX = HorizontalPadding; float y = VerticalPadding; - // Players in a row + // Add players in a row for (int i = 0; i < playerCount; i++) { float x = startX + i * (itemWidth + Spacing); @@ -114,6 +114,8 @@ private void BuildLayout() public void Rebuild() { BuildLayout(); + Recalculate(); + RecalculateChildren(); Log.Debug("UISpawnSelectorPanel.Rebuild: UI rebuilt"); } diff --git a/Localization/en-US.hjson b/Localization/en-US.hjson index e8aab73c..c2b1f977 100644 --- a/Localization/en-US.hjson +++ b/Localization/en-US.hjson @@ -366,6 +366,11 @@ Mods: { Label: Sound Effect Tooltip: "" } + + OpenMapAfterRecall: { + Label: Open Map After Recall + Tooltip: "" + } } PlayerOutlineConfig: { diff --git a/PvPAdventure.sln b/PvPAdventure.sln deleted file mode 100644 index 1100145b..00000000 --- a/PvPAdventure.sln +++ /dev/null @@ -1,24 +0,0 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.5.2.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PvPAdventure", "PvPAdventure.csproj", "{8C67A48A-1DD4-1910-9CCD-872426FDE8EF}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {8C67A48A-1DD4-1910-9CCD-872426FDE8EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8C67A48A-1DD4-1910-9CCD-872426FDE8EF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8C67A48A-1DD4-1910-9CCD-872426FDE8EF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8C67A48A-1DD4-1910-9CCD-872426FDE8EF}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {1B553FCD-BFE6-48FF-B3CA-665132715AC9} - EndGlobalSection -EndGlobal From 92de9643d4bb6cba84b261732342a64db15d784f Mon Sep 17 00:00:00 2001 From: emyhrberg <121192176+emyhrberg@users.noreply.github.com> Date: Sat, 15 Nov 2025 20:22:08 +0100 Subject: [PATCH 168/206] Fixed 3 issues like playing phase, popup text etc --- Content/Items/AdventureMirror.cs | 18 ++++++++++++++---- .../Players/AdventureMirrorPlayer.cs | 16 ++++++++++------ 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/Content/Items/AdventureMirror.cs b/Content/Items/AdventureMirror.cs index be84ac39..9b9dcbd1 100644 --- a/Content/Items/AdventureMirror.cs +++ b/Content/Items/AdventureMirror.cs @@ -1,5 +1,6 @@ using Microsoft.Xna.Framework; using PvPAdventure.Core.Features.SpawnSelector.Players; +using PvPAdventure.System; using Terraria; using Terraria.Audio; using Terraria.ID; @@ -25,9 +26,13 @@ public override void SetDefaults() public override bool CanUseItem(Player player) { + var gm = ModContent.GetInstance(); + if (gm.CurrentPhase != GameManager.Phase.Playing) + return false; + var adventureMirrorPlayer = player.GetModPlayer(); - if (adventureMirrorPlayer.IsPlayerInSpawnRegion()) + if (player.whoAmI == Main.myPlayer) { PopupText.NewText(new AdvancedPopupRequest { @@ -36,9 +41,7 @@ public override bool CanUseItem(Player player) Velocity = new(0f, -4f), DurationInFrames = 60 }, player.Top); - - return false; - }; + } if (adventureMirrorPlayer.CancelIfPlayerMoves()) return false; @@ -53,11 +56,18 @@ public override bool CanUseItem(Player player) public override bool ConsumeItem(Player player) => false; public override void RightClick(Player player) { + var gm = ModContent.GetInstance(); + if (gm.CurrentPhase != GameManager.Phase.Playing) + return; + var adventureMirrorPlayer = player.GetModPlayer(); if (adventureMirrorPlayer.CancelIfPlayerMoves()) return; + if (adventureMirrorPlayer.IsPlayerInSpawnRegion()) + return; + if (adventureMirrorPlayer.MirrorActive) return; diff --git a/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs b/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs index 664582b2..9c3f269e 100644 --- a/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs +++ b/Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs @@ -10,6 +10,7 @@ using Terraria.ID; using Terraria.ModLoader; using static PvPAdventure.System.RegionManager; +using static Terraria.ModLoader.BackupIO; namespace PvPAdventure.Core.Features.SpawnSelector.Players; @@ -62,13 +63,16 @@ public bool CancelIfPlayerMoves() Player.reuseDelay = 0; } - PopupText.NewText(new AdvancedPopupRequest + if (Player.whoAmI == Main.myPlayer) { - Color = Color.Crimson, - Text = "Cannot use while moving!", - Velocity = new(0f, -4f), - DurationInFrames = 60 - }, Player.Top); + PopupText.NewText(new AdvancedPopupRequest + { + Color = Color.Crimson, + Text = "Cannot use while moving!", + Velocity = new(0f, -4f), + DurationInFrames = 60 + }, Player.Top); + } return true; } From 4ede504aa5e0aa470b50663670dab059713d0195 Mon Sep 17 00:00:00 2001 From: Alex <87573461+MatteSevai@users.noreply.github.com> Date: Sat, 15 Nov 2025 11:36:38 -0800 Subject: [PATCH 169/206] Revert "Merge branch 'feature/RTP-Spawn-Selector' into feature/missinginmaster" This reverts commit 31560cabf981ad567c8e415ce897f3c0debff340, reversing changes made to 396ea984ce4e5a614c7b58c6f0796d46e38ccd02. --- AdventureConfig.cs | 5 - Assets/SpawnSelector/CornerMask4px.png | Bin 268 -> 0 bytes Assets/SpawnSelector/FadeHorizontal.png | Bin 80 -> 0 bytes Assets/SpawnSelector/MapBG1.png | Bin 4406 -> 0 bytes Assets/SpawnSelector/MapBG10.png | Bin 2262 -> 0 bytes Assets/SpawnSelector/MapBG11.png | Bin 2836 -> 0 bytes Assets/SpawnSelector/MapBG12.png | Bin 3447 -> 0 bytes Assets/SpawnSelector/MapBG13.png | Bin 10442 -> 0 bytes Assets/SpawnSelector/MapBG14.png | Bin 6003 -> 0 bytes Assets/SpawnSelector/MapBG15.png | Bin 5034 -> 0 bytes Assets/SpawnSelector/MapBG16.png | Bin 10951 -> 0 bytes Assets/SpawnSelector/MapBG17.png | Bin 5892 -> 0 bytes Assets/SpawnSelector/MapBG18.png | Bin 7861 -> 0 bytes Assets/SpawnSelector/MapBG19.png | Bin 10791 -> 0 bytes Assets/SpawnSelector/MapBG2.png | Bin 3466 -> 0 bytes Assets/SpawnSelector/MapBG20.png | Bin 3376 -> 0 bytes Assets/SpawnSelector/MapBG21.png | Bin 4971 -> 0 bytes Assets/SpawnSelector/MapBG22.png | Bin 14635 -> 0 bytes Assets/SpawnSelector/MapBG23.png | Bin 4431 -> 0 bytes Assets/SpawnSelector/MapBG24.png | Bin 4523 -> 0 bytes Assets/SpawnSelector/MapBG25.png | Bin 291 -> 0 bytes Assets/SpawnSelector/MapBG26.png | Bin 3331 -> 0 bytes Assets/SpawnSelector/MapBG27.png | Bin 4784 -> 0 bytes Assets/SpawnSelector/MapBG28.png | Bin 7876 -> 0 bytes Assets/SpawnSelector/MapBG29.png | Bin 9729 -> 0 bytes Assets/SpawnSelector/MapBG3.png | Bin 4762 -> 0 bytes Assets/SpawnSelector/MapBG30.png | Bin 10879 -> 0 bytes Assets/SpawnSelector/MapBG31.png | Bin 9307 -> 0 bytes Assets/SpawnSelector/MapBG32.png | Bin 4568 -> 0 bytes Assets/SpawnSelector/MapBG33.png | Bin 1879 -> 0 bytes Assets/SpawnSelector/MapBG34.png | Bin 5236 -> 0 bytes Assets/SpawnSelector/MapBG35.png | Bin 6505 -> 0 bytes Assets/SpawnSelector/MapBG36.png | Bin 7611 -> 0 bytes Assets/SpawnSelector/MapBG37.png | Bin 2454 -> 0 bytes Assets/SpawnSelector/MapBG38.png | Bin 2580 -> 0 bytes Assets/SpawnSelector/MapBG39.png | Bin 2804 -> 0 bytes Assets/SpawnSelector/MapBG4.png | Bin 5575 -> 0 bytes Assets/SpawnSelector/MapBG40.png | Bin 5072 -> 0 bytes Assets/SpawnSelector/MapBG41.png | Bin 5990 -> 0 bytes Assets/SpawnSelector/MapBG42.png | Bin 4794 -> 0 bytes Assets/SpawnSelector/MapBG5.png | Bin 4478 -> 0 bytes Assets/SpawnSelector/MapBG6.png | Bin 5718 -> 0 bytes Assets/SpawnSelector/MapBG7.png | Bin 5501 -> 0 bytes Assets/SpawnSelector/MapBG8.png | Bin 7262 -> 0 bytes Assets/SpawnSelector/MapBG9.png | Bin 7093 -> 0 bytes Assets/SpawnSelector/Question_Mark.png | Bin 1710 -> 0 bytes Assets/SpawnSelector/Question_Mark_Blue.png | Bin 316 -> 0 bytes Assets/SpawnSelector/Teleportation_Potion.png | Bin 1776 -> 0 bytes Content/Items/AdventureMirror.cs | 82 ---- Content/Items/AdventureMirror.png | Bin 505 -> 0 bytes Content/Items/AdventureMirrorGlobalItem.cs | 31 -- Core/Debug/DebugKeybinds.cs | 66 --- .../SpawnSelector/Hooks/ItemSlotHooks.cs | 70 ---- .../SpawnSelector/Hooks/UnityHooks.cs | 45 --- .../Players/AdventureMirrorPlayer.cs | 273 ------------- .../Players/ModifyPlayerDrawInfo.cs | 47 --- .../Systems/SpawnSelectorState.cs | 47 --- .../Systems/SpawnSelectorSystem.cs | 94 ----- .../UI/UISpawnSelectorCharacterListItem.cs | 378 ------------------ .../SpawnSelector/UI/UISpawnSelectorPanel.cs | 150 ------- .../UI/UISpawnSelectorRandomPanel.cs | 91 ----- Core/Helpers/AssetLoader.cs | 43 -- Core/Helpers/Log.cs | 51 --- Localization/en-US.hjson | 26 -- Properties/launchSettings.json | 8 +- PvPAdventure.csproj | 56 ++- PvPAdventure.csproj.user | 9 - System/Client/Keybinds.cs | 2 - icon_small.png | Bin 942 -> 0 bytes 69 files changed, 27 insertions(+), 1547 deletions(-) delete mode 100644 Assets/SpawnSelector/CornerMask4px.png delete mode 100644 Assets/SpawnSelector/FadeHorizontal.png delete mode 100644 Assets/SpawnSelector/MapBG1.png delete mode 100644 Assets/SpawnSelector/MapBG10.png delete mode 100644 Assets/SpawnSelector/MapBG11.png delete mode 100644 Assets/SpawnSelector/MapBG12.png delete mode 100644 Assets/SpawnSelector/MapBG13.png delete mode 100644 Assets/SpawnSelector/MapBG14.png delete mode 100644 Assets/SpawnSelector/MapBG15.png delete mode 100644 Assets/SpawnSelector/MapBG16.png delete mode 100644 Assets/SpawnSelector/MapBG17.png delete mode 100644 Assets/SpawnSelector/MapBG18.png delete mode 100644 Assets/SpawnSelector/MapBG19.png delete mode 100644 Assets/SpawnSelector/MapBG2.png delete mode 100644 Assets/SpawnSelector/MapBG20.png delete mode 100644 Assets/SpawnSelector/MapBG21.png delete mode 100644 Assets/SpawnSelector/MapBG22.png delete mode 100644 Assets/SpawnSelector/MapBG23.png delete mode 100644 Assets/SpawnSelector/MapBG24.png delete mode 100644 Assets/SpawnSelector/MapBG25.png delete mode 100644 Assets/SpawnSelector/MapBG26.png delete mode 100644 Assets/SpawnSelector/MapBG27.png delete mode 100644 Assets/SpawnSelector/MapBG28.png delete mode 100644 Assets/SpawnSelector/MapBG29.png delete mode 100644 Assets/SpawnSelector/MapBG3.png delete mode 100644 Assets/SpawnSelector/MapBG30.png delete mode 100644 Assets/SpawnSelector/MapBG31.png delete mode 100644 Assets/SpawnSelector/MapBG32.png delete mode 100644 Assets/SpawnSelector/MapBG33.png delete mode 100644 Assets/SpawnSelector/MapBG34.png delete mode 100644 Assets/SpawnSelector/MapBG35.png delete mode 100644 Assets/SpawnSelector/MapBG36.png delete mode 100644 Assets/SpawnSelector/MapBG37.png delete mode 100644 Assets/SpawnSelector/MapBG38.png delete mode 100644 Assets/SpawnSelector/MapBG39.png delete mode 100644 Assets/SpawnSelector/MapBG4.png delete mode 100644 Assets/SpawnSelector/MapBG40.png delete mode 100644 Assets/SpawnSelector/MapBG41.png delete mode 100644 Assets/SpawnSelector/MapBG42.png delete mode 100644 Assets/SpawnSelector/MapBG5.png delete mode 100644 Assets/SpawnSelector/MapBG6.png delete mode 100644 Assets/SpawnSelector/MapBG7.png delete mode 100644 Assets/SpawnSelector/MapBG8.png delete mode 100644 Assets/SpawnSelector/MapBG9.png delete mode 100644 Assets/SpawnSelector/Question_Mark.png delete mode 100644 Assets/SpawnSelector/Question_Mark_Blue.png delete mode 100644 Assets/SpawnSelector/Teleportation_Potion.png delete mode 100644 Content/Items/AdventureMirror.cs delete mode 100644 Content/Items/AdventureMirror.png delete mode 100644 Content/Items/AdventureMirrorGlobalItem.cs delete mode 100644 Core/Debug/DebugKeybinds.cs delete mode 100644 Core/Features/SpawnSelector/Hooks/ItemSlotHooks.cs delete mode 100644 Core/Features/SpawnSelector/Hooks/UnityHooks.cs delete mode 100644 Core/Features/SpawnSelector/Players/AdventureMirrorPlayer.cs delete mode 100644 Core/Features/SpawnSelector/Players/ModifyPlayerDrawInfo.cs delete mode 100644 Core/Features/SpawnSelector/Systems/SpawnSelectorState.cs delete mode 100644 Core/Features/SpawnSelector/Systems/SpawnSelectorSystem.cs delete mode 100644 Core/Features/SpawnSelector/UI/UISpawnSelectorCharacterListItem.cs delete mode 100644 Core/Features/SpawnSelector/UI/UISpawnSelectorPanel.cs delete mode 100644 Core/Features/SpawnSelector/UI/UISpawnSelectorRandomPanel.cs delete mode 100644 Core/Helpers/AssetLoader.cs delete mode 100644 Core/Helpers/Log.cs delete mode 100644 PvPAdventure.csproj.user delete mode 100644 icon_small.png diff --git a/AdventureConfig.cs b/AdventureConfig.cs index 0d9f7fcd..99b3d97e 100644 --- a/AdventureConfig.cs +++ b/AdventureConfig.cs @@ -1,4 +1,3 @@ -using PvPAdventure.Content.Items; using System; using System.Collections.Generic; using System.ComponentModel; @@ -66,10 +65,6 @@ public class InvasionSizeValue [DefaultValue(4 * 60)] public int RecallFrames { get; set; } - [Range(0, 60 * 60)] - [DefaultValue(4 * 60)] - public int AdventureMirrorRecallFrames { get; set; } - [Range(0, 30 * 60)] [DefaultValue(1.5 * 60)] public int SpawnImmuneFrames { get; set; } diff --git a/Assets/SpawnSelector/CornerMask4px.png b/Assets/SpawnSelector/CornerMask4px.png deleted file mode 100644 index 8f03f4353fab813910a3a823b9e04bef34e0e43c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 268 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=mpxq^Ln`LHy=};MSV4p(@ZbLb zb3H{lZ)&8@W3iUKarBMIyO`v|bBf=+^Ixzk%l7-{*2%~FKi<2(UvA#1U7O3Nn}4_) z{raKXuV){VbL^V7Ph^O4m`oRZzCJU5@$riP0X5vAp?l?)oZ0{L-P^lQU#_vX7hI@P Tt+JF6FS$$$R;|6k9>*7jZH eLAl2peun<-g8yqaZ{Y?iVeoYIb6Mw<&;$Vdrx$+! diff --git a/Assets/SpawnSelector/MapBG1.png b/Assets/SpawnSelector/MapBG1.png deleted file mode 100644 index b981a57d181cb2d141f0111f55f8f900749a0fbf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4406 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 diff --git a/Assets/SpawnSelector/MapBG11.png b/Assets/SpawnSelector/MapBG11.png deleted file mode 100644 index 596da6219c45e4154b793f48f5328d7044f824e1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2836 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 Z`#;INucwpDS}Xtn002ovPDHLkV1j3tr<(u( diff --git a/Assets/SpawnSelector/MapBG13.png b/Assets/SpawnSelector/MapBG13.png deleted file mode 100644 index 0faf8c72b57e5894cf98f4174dba7df52ebfb493..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10442 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 A&j0`b diff --git a/Assets/SpawnSelector/MapBG14.png b/Assets/SpawnSelector/MapBG14.png deleted file mode 100644 index 4faf6041dc378e69e8e371f677587b097e583962..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6003 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 diff --git a/Assets/SpawnSelector/MapBG15.png b/Assets/SpawnSelector/MapBG15.png deleted file mode 100644 index 9a9a161874bee64b8d50adece645f80ff22526e3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5034 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 A-2eap diff --git a/Assets/SpawnSelector/MapBG16.png b/Assets/SpawnSelector/MapBG16.png deleted file mode 100644 index 3af0977db3e2648901ad5bba7a3e61f353b38f9c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10951 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 diff --git a/Assets/SpawnSelector/MapBG17.png b/Assets/SpawnSelector/MapBG17.png deleted file mode 100644 index 8d8592098518f261ed9f4d1b1c294ce2c38d0043..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5892 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