From aedf8d276f03ab8bab0056ff13ef738b6b43083e Mon Sep 17 00:00:00 2001 From: WarrentyExpired Date: Mon, 26 Oct 2026 12:26:54 -0400 Subject: [PATCH] #W# Treasure: DungeonBags/Crates. Bags are trapped level 0-3 loot. Crates are trapped and locked with level 4-6 loot. --- Info/NeedsFinished.txt | 16 + Projects/UOContent/Engines/TaskManager.cs | 30 -- .../DungeonTreasure/BaseDungeonTreasure.cs | 388 ++++++++++++++++++ .../RandomLootBag.cs | 0 .../Skill Items/Thief/ThiefPedestalLootBag.cs | 41 +- .../Items/TreasureChests/BaseTreasureBag.cs | 49 --- .../Items/TreasureChests/TreasureBagLevel1.cs | 76 ---- .../Items/TreasureChests/TreasureBagLevel2.cs | 104 ----- .../Items/TreasureChests/TreasureBagLevel3.cs | 281 ------------- .../Items/TreasureChests/TreasureBagLevel4.cs | 95 ----- ToAdd/SackOfHolding.cs | 196 +++++++++ 11 files changed, 626 insertions(+), 650 deletions(-) create mode 100644 Info/NeedsFinished.txt create mode 100644 Projects/UOContent/Items/DungeonTreasure/BaseDungeonTreasure.cs rename Projects/UOContent/Items/{TreasureChests => DungeonTreasure}/RandomLootBag.cs (100%) delete mode 100644 Projects/UOContent/Items/TreasureChests/BaseTreasureBag.cs delete mode 100644 Projects/UOContent/Items/TreasureChests/TreasureBagLevel1.cs delete mode 100644 Projects/UOContent/Items/TreasureChests/TreasureBagLevel2.cs delete mode 100644 Projects/UOContent/Items/TreasureChests/TreasureBagLevel3.cs delete mode 100644 Projects/UOContent/Items/TreasureChests/TreasureBagLevel4.cs create mode 100644 ToAdd/SackOfHolding.cs diff --git a/Info/NeedsFinished.txt b/Info/NeedsFinished.txt new file mode 100644 index 000000000..83ead29b3 --- /dev/null +++ b/Info/NeedsFinished.txt @@ -0,0 +1,16 @@ +Bounty Vendor + - Needs more rewards + +Monster Kill Points + - Need a way to spend them + - Need things to spend them on + +Treasure Maps + - Need to set location + +Sos' + - Need to look into them + +Spawned Treasure Chests + - I need to figure out what to do with these. They are very lackluster. + The new DungeonLootCrates fill the void for now. diff --git a/Projects/UOContent/Engines/TaskManager.cs b/Projects/UOContent/Engines/TaskManager.cs index a8cb80e4a..dd620f8d9 100644 --- a/Projects/UOContent/Engines/TaskManager.cs +++ b/Projects/UOContent/Engines/TaskManager.cs @@ -49,7 +49,6 @@ public static class TaskManager // ========================================== public static void On4HourTick(Mobile from = null) { - RespawnPedestals(from); } @@ -107,33 +106,4 @@ public static class TaskManager } } } - - private static void RespawnPedestals(Mobile from = null) - { - string targetFolder = Path.Combine(Core.BaseDirectory, "Data", "Spawns", "Pedestals"); - if (!Directory.Exists(targetFolder)) - { - Directory.CreateDirectory(targetFolder); - return; - } - string[] jsonFiles = Directory.GetFiles(targetFolder, "*.json", SearchOption.AllDirectories); - if (jsonFiles.Length == 0) - { - return; - } - Utility.PushColor(ConsoleColor.Green); - Console.WriteLine($"[PedestalBootTask] Refreshing {jsonFiles.Length} pedestal spawner file(s)..."); - Utility.PopColor(); - Mobile executer = from ?? World.Mobiles.Values.FirstOrDefault(m => m.AccessLevel >= AccessLevel.GameMaster); - if (executer == null) - { - Console.WriteLine("[TaskManager] Automated pedestal respawn skipped. A GM must be online to execute the [is command."); - return; - } - foreach (string filePath in jsonFiles) - { - string relativePath = Path.GetRelativePath(Core.BaseDirectory, filePath); - CommandSystem.Handle(executer, $"[is {relativePath}"); - } - } } diff --git a/Projects/UOContent/Items/DungeonTreasure/BaseDungeonTreasure.cs b/Projects/UOContent/Items/DungeonTreasure/BaseDungeonTreasure.cs new file mode 100644 index 000000000..3121ee3ae --- /dev/null +++ b/Projects/UOContent/Items/DungeonTreasure/BaseDungeonTreasure.cs @@ -0,0 +1,388 @@ +using System; +using ModernUO.Serialization; +using Server.Items; + +namespace Server.Custom +{ + // ========================================== + // 1. THE LOW-TIER BAG (Unlocked, Trapped, Tiers 0-3) + // ========================================== + [SerializationGenerator(0, false)] + public partial class DungeonLootBag : BaseDungeonTreasure + { + private static readonly (int, int)[] _appearances = + { + (0xE76, 0x3D), // Bag + (0xE75, 0x3C), // Backpack + (0xFFBA, 0x3C), // Backpack + (0xFFB9, 0x3C), // Backpack + (0xFFA6, 0x3C), // Backpack + (0xFFA5, 0x3C), // Backpack + (0xE79, 0x41) // Pouch + }; + + [Constructible] + public DungeonLootBag() : base(0xE76) + { + Name = "a discarded loot bag"; + (ItemID, GumpID) = _appearances.RandomElement(); + + // Roll until we get a tier between 0 and 3 + int tier; + do { tier = GetWeightedTier(); } while (tier < 0 || tier > 3); + MasterTier = tier; + + // Security + Locked = false; + SetupTrap(); + + // Generate + GenerateLoot(); + } + + public DungeonLootBag(Serial serial) : base(serial) { } + } + + // ========================================== + // 2. THE HIGH-TIER CRATE (Locked, Trapped, Tiers 3-6) + // ========================================== + [SerializationGenerator(0, false)] + public partial class DungeonLootCrate : BaseDungeonTreasure + { + private static readonly (int, int)[] _appearances = + { + (0x9A9, 0x44), // Small Crate + (0xE3F, 0x44), // Medium Crate + (0xE3D, 0x44), // Large Crate + (0x9A8, 0x4B), // Metal Box + (0xE43, 0x49), // Wooden Chest + (0xE77, 0x3E), // Barrel + (0x9AA, 0x43) // Wooden Box + }; + + [Constructible] + public DungeonLootCrate() : base(0x9A9) + { + Name = "a secured dungeon crate"; + (ItemID, GumpID) = _appearances.RandomElement(); + + // Roll until we get a tier between 3 and 6 + int tier; + do { tier = GetWeightedTier(); } while (tier < 3 || tier > 6); + MasterTier = tier; + + // Security + Locked = true; + LockLevel = 50 + (MasterTier * 10); + MaxLockLevel = LockLevel + 25; + RequiredSkill = LockLevel; + SetupTrap(); + + // Generate + GenerateLoot(); + } + + public DungeonLootCrate(Serial serial) : base(serial) { } + } + + + // ========================================== + // 3. THE ABSTRACT BASE BLUEPRINT + // ========================================== + [SerializationGenerator(0, false)] + public abstract partial class BaseDungeonTreasure : LockableContainer + { + [SerializableField(0)] + private int m_MasterTier; + + public BaseDungeonTreasure(int itemID) : base(itemID) + { + Movable = false; + Hue = Utility.Random(1, 1000); + } + + public BaseDungeonTreasure(Serial serial) : base(serial) { } + + public override bool Decays => true; + public override bool IsDecoContainer => false; + + private readonly TimeSpan _decayTime = TimeSpan.FromMinutes(Utility.RandomMinMax(15, 60)); + public override TimeSpan DecayTime => _decayTime; + + public override Rectangle2D Bounds + { + get + { + if (GumpID == 0x3D) return new Rectangle2D(29, 34, 108, 94); + if (GumpID == 0x3C) return new Rectangle2D(44, 65, 142, 94); + if (GumpID == 0x41) return new Rectangle2D(35, 38, 110, 78); + if (GumpID == 0x44) return new Rectangle2D(20, 10, 150, 90); + if (GumpID == 0x4B) return new Rectangle2D(16, 51, 168, 73); + if (GumpID == 0x49) return new Rectangle2D(18, 105, 144, 73); + if (GumpID == 0x3E) return new Rectangle2D(33, 36, 109, 112); + if (GumpID == 0x9AA) return new Rectangle2D(16, 51, 168, 73); + return new Rectangle2D(18, 20, 125, 62); + } + } + + protected void SetupTrap() + { + // Core UO Traps: 1 = Dart, 2 = Poison, 3 = Explosion, 4 = Magic + TrapType = (TrapType)Utility.RandomMinMax(1, 4); + TrapPower = 10 + (MasterTier * 15); // Scales damage/poison level with the tier + TrapLevel = MasterTier; + } + + protected static int GetWeightedTier() + { + var roll = Utility.Random(100); + + if (roll < 25) return 0; + else if (roll < 55) return 1; + else if (roll < 75) return 2; + else if (roll < 90) return 3; + else if (roll < 96) return 4; + else if (roll < 99) return 5; + else return 6; + } + + private static void GetRandomLevel(int pwr, out int attributeCount, out int min, out int max) + { + if (pwr == 1) + { + attributeCount = 1; + min = 10; + max = 20; + } + else if (pwr == 2) + { + attributeCount = Utility.RandomMinMax(1, 2); + min = 20; + max = 40; + } + else if (pwr == 3) + { + attributeCount = Utility.RandomMinMax(2, 3); + min = 30; + max = 60; + } + else if (pwr == 4) + { + attributeCount = Utility.RandomMinMax(2, 4); + min = 40; + max = 80; + } + else if (pwr == 5) + { + attributeCount = Utility.RandomMinMax(3, 5); + min = 60; + max = 80; + } + else if (pwr == 6) + { + attributeCount = Utility.RandomMinMax(4, 5); + min = 60; + max = 100; + } + else + { + attributeCount = 1; + min = 5; + max = 10; + } + } + + private static void GetRandomResists(int pwr, out int phy, out int fire, out int cold, out int poison, out int energy) + { + if (pwr == 1) + { + phy = Utility.RandomMinMax(1, 3); + fire = Utility.RandomMinMax(1, 3); + cold = Utility.RandomMinMax(1, 3); + poison = Utility.RandomMinMax(1, 3); + energy = Utility.RandomMinMax(1, 3); + } + else if (pwr == 2) + { + phy = Utility.RandomMinMax(2, 5); + fire = Utility.RandomMinMax(2, 5); + cold = Utility.RandomMinMax(2, 5); + poison = Utility.RandomMinMax(2, 5); + energy = Utility.RandomMinMax(2, 5); + } + else if (pwr == 3) + { + phy = Utility.RandomMinMax(4, 7); + fire = Utility.RandomMinMax(4, 7); + cold = Utility.RandomMinMax(4, 7); + poison = Utility.RandomMinMax(4, 7); + energy = Utility.RandomMinMax(4, 7); + } + else if (pwr == 4) + { + phy = Utility.RandomMinMax(6, 10); + fire = Utility.RandomMinMax(6, 10); + cold = Utility.RandomMinMax(6, 10); + poison = Utility.RandomMinMax(6, 10); + energy = Utility.RandomMinMax(6, 10); + } + else if (pwr == 5) + { + phy = Utility.RandomMinMax(9, 12); + fire = Utility.RandomMinMax(9, 12); + cold = Utility.RandomMinMax(9, 12); + poison = Utility.RandomMinMax(9, 12); + energy = Utility.RandomMinMax(9, 12); + } + else if (pwr == 6) + { + phy = Utility.RandomMinMax(12, 15); + fire = Utility.RandomMinMax(12, 15); + cold = Utility.RandomMinMax(12, 15); + poison = Utility.RandomMinMax(12, 15); + energy = Utility.RandomMinMax(12, 15); + } + else + { + phy = 0; + fire = 0; + cold = 0; + poison = 0; + energy = 0; + } + } + + protected void GenerateLoot() + { + int dropCount = Utility.RandomMinMax(Math.Max(1, MasterTier -2), MasterTier + 1); + + // Weapons + for (var i = 0; i < dropCount; i++) + { + var weapon = Loot.RandomWeapon(); + int itemPower = Utility.RandomMinMax(0, MasterTier); + GetRandomLevel(itemPower, out var attributeCount, out var min, out var max); + BaseRunicTool.ApplyAttributesTo(weapon, attributeCount, min, max); + DropItem(weapon); + } + + // Armor or Shield + for (var i = 0; i < dropCount; i++) + { + var armor = Loot.RandomArmorOrShield(); + + // Roll #1: Determines the magical properties (Attributes) + int attributePower = Utility.RandomMinMax(0, MasterTier); + GetRandomLevel(attributePower, out var attributeCount, out var min, out var max); + BaseRunicTool.ApplyAttributesTo(armor, attributeCount, min, max); + + // Roll #2: Determines the physical/elemental defense (Resists) + int resistPower = Utility.RandomMinMax(0, MasterTier); + GetRandomResists(resistPower, out var phy, out var fire, out var cold, out var poison, out var energy); + + armor.PhysicalBonus = phy; + armor.FireBonus = fire; + armor.ColdBonus = cold; + armor.PoisonBonus = poison; + armor.EnergyBonus = energy; + DropItem(armor); + } + + // Jewelry + for (var i = 0; i < dropCount; i++) + { + var jewelry = Loot.RandomJewelry(); + int itemPower = Utility.RandomMinMax(0, MasterTier); + GetRandomLevel(itemPower, out var attributeCount, out var min, out var max); + BaseRunicTool.ApplyAttributesTo(jewelry, attributeCount, min, max); + DropItem(jewelry); + } + + // Gems + for (var i = 0; i < dropCount; i++) + { + var gem = Loot.RandomGem(); + gem.Amount = Utility.RandomMinMax(1, dropCount); + DropItem(gem); + } + + // Reagents + for (var i = 0; i < dropCount; i++) + { + var mReagent = Loot.RandomReagent(); + mReagent.Amount = Utility.RandomMinMax(1, dropCount); + DropItem(mReagent); + } + + for (var i = 0; i < dropCount; i++) + { + var nReagent = Loot.RandomNecromancyReagent(); + nReagent.Amount = Utility.RandomMinMax(1, dropCount); + DropItem(nReagent); + } + + // Magic Scrolls + int mlevel = 0; + if (MasterTier >= 4) + { + mlevel = 63; + } + else if (MasterTier >= 2) + { + mlevel = 46; + } + else + { + mlevel = 23; + } + for (var i = 0; i < dropCount; i++) + { + var mscroll = Loot.RandomScroll(0, mlevel, SpellbookType.Regular); + mscroll.Amount = Utility.RandomMinMax(1, 3); + DropItem(mscroll); + } + + int nlevel = 0; + if (MasterTier < 3) + { + nlevel = 7; + } + else + { + nlevel = 15; + } + for (var i = 0; i < dropCount; i++) + { + var nscroll = Loot.RandomScroll(0, nlevel, SpellbookType.Necromancer); + nscroll.Amount = Utility.RandomMinMax(1, 3); + DropItem(nscroll); + } + + // Misc extras bandages/arrows/blankscrolls/potions/ETC + if (Utility.RandomBool()) + { + DropItem(new Arrow(Utility.RandomMinMax(10, dropCount * 10))); + } + else + { + DropItem(new Bolt(Utility.RandomMinMax(10, dropCount * 10))); + } + if (Utility.RandomBool()) + DropItem(new Bandage(Utility.RandomMinMax(10, dropCount * 10))); + if (Utility.RandomBool()) + DropItem(new BlankScroll(Utility.RandomMinMax(1, dropCount))); + for (var i = 0; i < dropCount; i++) + { + var potion = Loot.RandomPotion(); + potion.Amount = Utility.RandomMinMax(1, 3); + DropItem(potion); + } + if (Utility.RandomBool()) + DropItem(new RecallRune()); + + // Gold + int minGold = 100 + (MasterTier * 100); + DropItem(new Gold(Utility.RandomMinMax(minGold, minGold + 99))); + } + } +} diff --git a/Projects/UOContent/Items/TreasureChests/RandomLootBag.cs b/Projects/UOContent/Items/DungeonTreasure/RandomLootBag.cs similarity index 100% rename from Projects/UOContent/Items/TreasureChests/RandomLootBag.cs rename to Projects/UOContent/Items/DungeonTreasure/RandomLootBag.cs diff --git a/Projects/UOContent/Items/Skill Items/Thief/ThiefPedestalLootBag.cs b/Projects/UOContent/Items/Skill Items/Thief/ThiefPedestalLootBag.cs index b22d78ac4..78dcd9701 100644 --- a/Projects/UOContent/Items/Skill Items/Thief/ThiefPedestalLootBag.cs +++ b/Projects/UOContent/Items/Skill Items/Thief/ThiefPedestalLootBag.cs @@ -134,6 +134,7 @@ public partial class ThiefPedestalLootBag : Bag { int bagTier = GetWeightedTier(); + // Weapon int weaponCount = Utility.RandomMinMax(0, bagTier); for (var i = 0; i < weaponCount; i++) { @@ -143,6 +144,7 @@ public partial class ThiefPedestalLootBag : Bag DropItem(weapon); } + // Armor int armorCount = Utility.RandomMinMax(0, bagTier); for (var i = 0; i < armorCount; i++) { @@ -158,6 +160,7 @@ public partial class ThiefPedestalLootBag : Bag DropItem(armor); } + // Jewelry int jewelryCount = Utility.RandomMinMax(0, bagTier); for (var i = 0; i < jewelryCount; i++) { @@ -167,6 +170,16 @@ public partial class ThiefPedestalLootBag : Bag DropItem(jewelry); } + // Gems + int gemCount = Utility.RandomMinMax(0, bagTier); + for (var i = 0; i < gemCount; i++) + { + var gems = Loot.RandomGem(); + gems.Amount = Math.Max(1, bagTier * 2); + DropItem(gems); + } + + // Reagents int reagentCount = Utility.RandomMinMax(0, bagTier); for (var i = 0; i < reagentCount; i++) { @@ -182,25 +195,21 @@ public partial class ThiefPedestalLootBag : Bag DropItem(necroreagents); } - int gemCount = Utility.RandomMinMax(0, bagTier); - for (var i = 0; i < gemCount; i++) - { - var gems = Loot.RandomGem(); - gems.Amount = Math.Max(1, bagTier * 2); - DropItem(gems); - } - + // Magic Scrolls int mageScrollCount = Utility.RandomMinMax(0, bagTier); int mlevel = 0; - if (bagTier < 3) - { - mlevel = 42; - } - else + if (bagTier >= 4) { mlevel = 63; } - + else if (bagTier >= 2) + { + mlevel = 46; + } + else + { + mlevel = 23; + } for (var i = 0; i < mageScrollCount; i++) { var scroll = Loot.RandomScroll(0, mlevel, SpellbookType.Regular); @@ -212,7 +221,7 @@ public partial class ThiefPedestalLootBag : Bag int nlevel = 0; if (bagTier < 3) { - nlevel = 6; + nlevel = 7; } else { @@ -225,6 +234,7 @@ public partial class ThiefPedestalLootBag : Bag DropItem(scroll); } + // Misc extras potions/clothing/arrows/blankscrolls for (var i = Math.Max(1, bagTier); i > 0; i--) { DropItem(Loot.RandomPotion()); @@ -248,6 +258,7 @@ public partial class ThiefPedestalLootBag : Bag DropItem(new BlankScroll(Math.Max(1, GetWeightedTier()))); } + // Gold int minGold = 100 + (bagTier * 100); int maxGold = minGold + 99; DropItem(new Gold(Utility.RandomMinMax(minGold, maxGold))); diff --git a/Projects/UOContent/Items/TreasureChests/BaseTreasureBag.cs b/Projects/UOContent/Items/TreasureChests/BaseTreasureBag.cs deleted file mode 100644 index 67b0ed1ce..000000000 --- a/Projects/UOContent/Items/TreasureChests/BaseTreasureBag.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using ModernUO.Serialization; -using Server.Items; - -namespace Server.Items; - -public abstract class BaseTreasureBag : LockableContainer -{ - public BaseTreasureBag() : base(0xE76) - { - SetBagAppearance(); - Movable = false; - - // Pick a random hue between 1 and 1000 - Hue = Utility.Random(1, 1000); - } - - public BaseTreasureBag(Serial serial) : base(serial) - { - } - - public override bool Decays => true; - public override bool IsDecoContainer => false; - - private readonly TimeSpan _decayTime = TimeSpan.FromMinutes(Utility.Random(15, 60)); - public override TimeSpan DecayTime => _decayTime; - - private static readonly (int, int)[] _bagAppearances = - { - (0xE76, 0x3D), // Bag - (0xE75, 0x3C), // Backpack - (0xE79, 0x41) // Pouch - }; - - private void SetBagAppearance() - { - (ItemID, GumpID) = _bagAppearances.RandomElement(); - } - - public override Rectangle2D Bounds - { - get - { - if (GumpID == 0x3D) return new Rectangle2D(29, 34, 108, 94); // Bag - if (GumpID == 0x3C) return new Rectangle2D(44, 65, 142, 94); // Backpack - return new Rectangle2D(18, 20, 125, 62); // Pouch - } - } -} diff --git a/Projects/UOContent/Items/TreasureChests/TreasureBagLevel1.cs b/Projects/UOContent/Items/TreasureChests/TreasureBagLevel1.cs deleted file mode 100644 index 4d873be23..000000000 --- a/Projects/UOContent/Items/TreasureChests/TreasureBagLevel1.cs +++ /dev/null @@ -1,76 +0,0 @@ -using System; -using ModernUO.Serialization; - -namespace Server.Items; -// ============================================================== -// LEVEL 1: 50% Trapped / 50% Locked -// ============================================================== -[SerializationGenerator(0, false)] -public partial class TreasureBagLevel1 : BaseTreasureBag -{ - [Constructible] - public TreasureBagLevel1() - { - var isTrapped = false; - - Locked = Utility.RandomDouble() < 0.50; // 50% Locked - RequiredSkill = 57; - LockLevel = RequiredSkill - Utility.Random(1, 10); - MaxLockLevel = RequiredSkill + Utility.Random(1, 10); - - if (Utility.RandomDouble() < 0.50) // 50% Trapped - { - TrapType = TrapType.DartTrap; - TrapPower = Utility.Random(1, 25); - isTrapped = true; - } - - if (isTrapped && Locked) - { - DropItem(new Gold(Utility.Random(30, 100))); - if (Utility.RandomBool()) - { - var gems = Loot.RandomGem(); - gems.Amount = Utility.Random(1, 3); - DropItem(gems); - } - if (Utility.RandomBool()) DropItem(Loot.RandomWeapon()); - if (Utility.RandomBool()) DropItem(Loot.RandomArmorOrShield()); - if (Utility.RandomBool()) DropItem(Loot.RandomClothing()); - if (Utility.RandomBool()) DropItem(Loot.RandomJewelry()); - } - else if (isTrapped && !Locked) - { - DropItem(new Gold(Utility.Random(30, 80))); - if (Utility.RandomBool()) - { - var gems = Loot.RandomGem(); - gems.Amount = Utility.Random(1, 3); - DropItem(gems); - } - if (Utility.RandomBool()) DropItem(Loot.RandomWeapon()); - if (Utility.RandomBool()) DropItem(Loot.RandomClothing()); - } - else if (!isTrapped && Locked) - { - DropItem(new Gold(Utility.Random(30, 80))); - if (Utility.RandomBool()) - { - var gems = Loot.RandomGem(); - gems.Amount = Utility.Random(1, 3); - DropItem(gems); - } - if (Utility.RandomBool()) DropItem(Loot.RandomArmor()); - } - else - { - DropItem(new Gold(Utility.Random(30, 50))); - if (Utility.RandomBool()) - { - var gems = Loot.RandomGem(); - gems.Amount = 1; - DropItem(gems); - } - } - } -} diff --git a/Projects/UOContent/Items/TreasureChests/TreasureBagLevel2.cs b/Projects/UOContent/Items/TreasureChests/TreasureBagLevel2.cs deleted file mode 100644 index 7c38ae21c..000000000 --- a/Projects/UOContent/Items/TreasureChests/TreasureBagLevel2.cs +++ /dev/null @@ -1,104 +0,0 @@ -using System; -using ModernUO.Serialization; - -namespace Server.Items; -// ============================================================== -// LEVEL 2: 75% Trapped / 75% Locked -// ============================================================== -[SerializationGenerator(0, false)] -public partial class TreasureBagLevel2 : BaseTreasureBag -{ - [Constructible] - public TreasureBagLevel2() - { - Locked = Utility.RandomDouble() < 0.75; // 75% Locked (25% Unlocked) - RequiredSkill = 72; - LockLevel = RequiredSkill - Utility.Random(1, 10); - MaxLockLevel = RequiredSkill + Utility.Random(1, 10); - var isTrapped = false; - - if (Utility.RandomDouble() < 0.75) // 75% Trapped - { - TrapType = TrapType.ExplosionTrap; - TrapPower = 2 * Utility.Random(1, 25); - isTrapped = true; - } - - if (Locked && isTrapped) - { - DropItem(new Gold(Utility.Random(80, 150))); - for (var i = Utility.Random(3); i > 0; i--) - { - var reagents = Loot.RandomReagent(); - reagents.Amount = Utility.Random(1, 2); - DropItem(reagents); - } - if (Utility.RandomBool()) - { - var scrolls = Loot.RandomScroll(0, 39, SpellbookType.Regular); - scrolls.Amount = Utility.Random(1, 8); - DropItem(scrolls); - } - if (Utility.RandomBool()) - { - var gems = Loot.RandomGem(); - gems.Amount = Utility.Random(1, 6); - DropItem(gems); - } - if (Utility.RandomBool()) DropItem(Loot.RandomPotion()); - } - else if (isTrapped && !Locked) - { - DropItem(new Gold(Utility.Random(80, 120))); - for (var i = Utility.Random(3); i > 0; i--) - { - var reagents = Loot.RandomReagent(); - reagents.Amount = Utility.Random(1, 2); - DropItem(reagents); - } - if (Utility.RandomBool()) - { - var scrolls = Loot.RandomScroll(0, 39, SpellbookType.Regular); - scrolls.Amount = Utility.Random(1, 4); - DropItem(scrolls); - } - if (Utility.RandomBool()) - { - var gems = Loot.RandomGem(); - gems.Amount = Utility.Random(1, 3); - DropItem(gems); - } - if (Utility.RandomBool()) DropItem(Loot.RandomPotion()); - } - else if (!isTrapped && Locked) - { - DropItem(new Gold(Utility.Random(80, 120))); - for (var i = Utility.Random(3); i > 0; i--) - { - var reagents = Loot.RandomReagent(); - reagents.Amount = Utility.Random(1, 2); - DropItem(reagents); - } - if (Utility.RandomBool()) - { - var scrolls = Loot.RandomScroll(0, 39, SpellbookType.Regular); - scrolls.Amount = Utility.Random(1, 4); - DropItem(scrolls); - } - if (Utility.RandomBool()) - { - var gems = Loot.RandomGem(); - gems.Amount = Utility.Random(1, 3); - DropItem(gems); - } - if (Utility.RandomBool()) DropItem(Loot.RandomPotion()); - } - else - { - DropItem(new Gold(Utility.Random(80, 100))); - var gems = Loot.RandomGem(); - gems.Amount = Utility.Random(1, 3); - DropItem(gems); - } - } -} diff --git a/Projects/UOContent/Items/TreasureChests/TreasureBagLevel3.cs b/Projects/UOContent/Items/TreasureChests/TreasureBagLevel3.cs deleted file mode 100644 index 8261dda03..000000000 --- a/Projects/UOContent/Items/TreasureChests/TreasureBagLevel3.cs +++ /dev/null @@ -1,281 +0,0 @@ -using System; -using ModernUO.Serialization; - -namespace Server.Items; - -// ============================================================== -// LEVEL 3: 90% Trapped / 90% Locked -// ============================================================== -[SerializationGenerator(0, false)] -public partial class TreasureBagLevel3 : BaseTreasureBag -{ - [Constructible] - public TreasureBagLevel3() - { - Locked = Utility.RandomDouble() < 0.90; // 90% Locked (10% Unlocked) - RequiredSkill = 84; - LockLevel = RequiredSkill - Utility.Random(1, 10); - MaxLockLevel = RequiredSkill + Utility.Random(1, 10); - var isTrapped = false; - - if (Utility.RandomDouble() < 0.90) // 90% Trapped - { - TrapType = TrapType.PoisonTrap; - TrapPower = 3 * Utility.Random(1, 25); - isTrapped = true; - } - - if (isTrapped && Locked) - { - DropItem(new Gold(Utility.Random(250, 350))); - for (var i = Utility.Random(2); i >= 0; i--) - { - var reagents = Loot.RandomReagent(); - reagents.Amount = Utility.Random(1, 9); - DropItem(reagents); - } - - for (var i = Utility.Random(3); i > 0; i--) - { - var scrolls = Loot.RandomScroll(0, 47, SpellbookType.Regular); - scrolls.Amount = Utility.Random(1, 12); - DropItem(scrolls); - } - - for (var i = Utility.Random(3); i > 0; i--) - { - DropItem(Loot.RandomPotion()); - } - - for (var i = Utility.Random(3); i > 0; i--) - { - var gems = Loot.RandomGem(); - gems.Amount = Utility.Random(1, 9); - DropItem(gems); - } - - for (var i = Utility.Random(3); i > 0; i--) - { - DropItem(Loot.RandomWand()); - } - - for (var i = Utility.Random(3); i > 0; i--) - { - var item = Loot.RandomArmorOrShieldOrWeapon(); - - if (item is BaseWeapon weapon) - { - weapon.DamageLevel = (WeaponDamageLevel)Utility.Random(3); - weapon.AccuracyLevel = (WeaponAccuracyLevel)Utility.Random(3); - weapon.DurabilityLevel = (WeaponDurabilityLevel)Utility.Random(3); - weapon.Quality = WeaponQuality.Regular; - } - else if (item is BaseArmor armor) - { - armor.ProtectionLevel = (ArmorProtectionLevel)Utility.Random(3); - armor.Durability = (ArmorDurabilityLevel)Utility.Random(3); - armor.Quality = ArmorQuality.Regular; - } - - DropItem(item); - } - - for (var i = Utility.Random(3); i > 0; i--) - { - DropItem(Loot.RandomClothing()); - } - - for (var i = Utility.Random(3); i > 0; i--) - { - DropItem(Loot.RandomJewelry()); - } - } - - else if (!isTrapped && Locked) - { - DropItem(new Gold(Utility.Random(250, 300))); - for (var i = Utility.Random(2); i >= 0; i--) - { - var reagents = Loot.RandomReagent(); - reagents.Amount = Utility.Random(1, 9); - DropItem(reagents); - } - - for (var i = Utility.Random(3); i > 0; i--) - { - var scrolls = Loot.RandomScroll(0, 47, SpellbookType.Regular); - scrolls.Amount = Utility.Random(1, 12); - DropItem(scrolls); - } - - for (var i = Utility.Random(3); i > 0; i--) - { - DropItem(Loot.RandomPotion()); - } - - for (var i = Utility.Random(3); i > 0; i--) - { - var gems = Loot.RandomGem(); - gems.Amount = Utility.Random(1, 9); - DropItem(gems); - } - - for (var i = Utility.Random(3); i > 0; i--) - { - DropItem(Loot.RandomWand()); - } - - if (Utility.RandomBool()) - { - for (var i = Utility.Random(3); i > 0; i--) - { - var weapon = Loot.RandomWeapon(); - weapon.DamageLevel = (WeaponDamageLevel)Utility.Random(3); - weapon.AccuracyLevel = (WeaponAccuracyLevel)Utility.Random(3); - weapon.DurabilityLevel = (WeaponDurabilityLevel)Utility.Random(3); - weapon.Quality = WeaponQuality.Regular; - DropItem(weapon); - } - } - - if (Utility.RandomBool()) - { - for (var i = Utility.Random(3); i > 0; i--) - { - var armor = Loot.RandomArmorOrShield(); - armor.ProtectionLevel = (ArmorProtectionLevel)Utility.Random(3); - armor.Durability = (ArmorDurabilityLevel)Utility.Random(3); - armor.Quality = ArmorQuality.Regular; - DropItem(armor); - } - } - - for (var i = Utility.Random(3); i > 0; i--) - { - DropItem(Loot.RandomClothing()); - } - - for (var i = Utility.Random(3); i > 0; i--) - { - DropItem(Loot.RandomJewelry()); - } - } - - else if (isTrapped && !Locked) - { - DropItem(new Gold(Utility.Random(250, 300))); - for (var i = Utility.Random(2); i >= 0; i--) - { - var reagents = Loot.RandomReagent(); - reagents.Amount = Utility.Random(1, 4); - DropItem(reagents); - } - - for (var i = Utility.Random(3); i > 0; i--) - { - var scrolls = Loot.RandomScroll(0, 47, SpellbookType.Regular); - scrolls.Amount = Utility.Random(1, 6); - DropItem(scrolls); - } - - for (var i = Utility.Random(3); i > 0; i--) - { - DropItem(Loot.RandomPotion()); - } - - for (var i = Utility.Random(3); i > 0; i--) - { - var gems = Loot.RandomGem(); - gems.Amount = Utility.Random(1, 4); - DropItem(gems); - } - - for (var i = Utility.Random(3); i > 0; i--) - { - DropItem(Loot.RandomWand()); - } - - if (Utility.RandomBool()) - { - if (Utility.RandomBool()) - { - for (var i = Utility.Random(3); i > 0; i--) - { - var weapon = Loot.RandomWeapon(); - weapon.DamageLevel = (WeaponDamageLevel)Utility.Random(3); - weapon.AccuracyLevel = (WeaponAccuracyLevel)Utility.Random(3); - weapon.DurabilityLevel = (WeaponDurabilityLevel)Utility.Random(3); - weapon.Quality = WeaponQuality.Regular; - DropItem(weapon); - } - } - - if (Utility.RandomBool()) - { - for (var i = Utility.Random(3); i > 0; i--) - { - var armor = Loot.RandomArmorOrShield(); - armor.ProtectionLevel = (ArmorProtectionLevel)Utility.Random(3); - armor.Durability = (ArmorDurabilityLevel)Utility.Random(3); - armor.Quality = ArmorQuality.Regular; - DropItem(armor); - } - } - } - for (var i = Utility.Random(3); i > 0; i--) - { - DropItem(Loot.RandomClothing()); - } - - for (var i = Utility.Random(3); i > 0; i--) - { - DropItem(Loot.RandomJewelry()); - } - } - else - { - DropItem(new Gold(Utility.Random(175, 225))); - for (var i = Utility.Random(2); i >= 0; i--) - { - var reagents = Loot.RandomReagent(); - reagents.Amount = Utility.Random(1, 4); - DropItem(reagents); - } - - for (var i = Utility.Random(3); i > 0; i--) - { - var scrolls = Loot.RandomScroll(0, 47, SpellbookType.Regular); - scrolls.Amount = Utility.Random(1, 6); - DropItem(scrolls); - } - - for (var i = Utility.Random(3); i > 0; i--) - { - DropItem(Loot.RandomPotion()); - } - - for (var i = Utility.Random(3); i > 0; i--) - { - var gems = Loot.RandomGem(); - gems.Amount = Utility.Random(1, 4); - DropItem(gems); - } - - for (var i = Utility.Random(3); i > 0; i--) - { - DropItem(Loot.RandomWand()); - } - if (Utility.RandomBool()) - { - for (var i = Utility.Random(3); i > 0; i--) - { - var armor = Loot.RandomArmorOrShield(); - armor.ProtectionLevel = (ArmorProtectionLevel)Utility.Random(3); - armor.Durability = (ArmorDurabilityLevel)Utility.Random(3); - armor.Quality = ArmorQuality.Regular; - DropItem(armor); - } - } - } - } -} diff --git a/Projects/UOContent/Items/TreasureChests/TreasureBagLevel4.cs b/Projects/UOContent/Items/TreasureChests/TreasureBagLevel4.cs deleted file mode 100644 index f566c16d9..000000000 --- a/Projects/UOContent/Items/TreasureChests/TreasureBagLevel4.cs +++ /dev/null @@ -1,95 +0,0 @@ -using System; -using ModernUO.Serialization; - -namespace Server.Items; - -// ============================================================== -// LEVEL 4: 99% Trapped / 99% Locked (1% Lottery Ticket!) -// ============================================================== -[SerializationGenerator(0, false)] -public partial class TreasureBagLevel4 : BaseTreasureBag -{ - [Constructible] - public TreasureBagLevel4() - { - Locked = Utility.RandomDouble() < 0.95; // 99% Locked (5% Unlocked) - RequiredSkill = 92; - LockLevel = RequiredSkill - Utility.Random(1, 10); - MaxLockLevel = RequiredSkill + Utility.Random(1, 10); - - if (Utility.RandomDouble() < 0.99) // 99% Trapped - { - TrapType = TrapType.ExplosionTrap; - TrapPower = 4 * Utility.Random(10, 25); - } - - // --- UNIFIED LOOT GENERATION --- - // Everyone gets this massive loot pool. The 1% just get to open it for free! - - DropItem(new Gold(Utility.Random(500, 900))); - - for (var i = Utility.Random(4) + 1; i > 0; i--) - { - var reagents = Loot.RandomReagent(); - reagents.Amount = 12; - DropItem(reagents); - } - - for (var i = Utility.Random(4) + 1; i > 0; i--) - { - var scroll = Loot.RandomScroll(0, 47, SpellbookType.Regular); - scroll.Amount = 16; - DropItem(scroll); - } - - DropItem(new BlankScroll(Utility.Random(1, 4))); - - for (var i = Utility.Random(4) + 1; i > 0; i--) - { - DropItem(Loot.RandomPotion()); - } - - for (var i = Utility.Random(4) + 1; i > 0; i--) - { - var gems = Loot.RandomGem(); - gems.Amount = 12; - DropItem(gems); - } - - for (var i = Utility.Random(4) + 1; i > 0; i--) - { - DropItem(Loot.RandomWand()); - } - - for (var i = Utility.Random(4) + 1; i > 0; i--) - { - var item = Loot.RandomArmorOrShieldOrWeapon(); - - if (item is BaseWeapon weapon) - { - weapon.DamageLevel = (WeaponDamageLevel)Utility.Random(4); - weapon.AccuracyLevel = (WeaponAccuracyLevel)Utility.Random(4); - weapon.DurabilityLevel = (WeaponDurabilityLevel)Utility.Random(4); - weapon.Quality = WeaponQuality.Regular; - } - else if (item is BaseArmor armor) - { - armor.ProtectionLevel = (ArmorProtectionLevel)Utility.Random(4); - armor.Durability = (ArmorDurabilityLevel)Utility.Random(4); - armor.Quality = ArmorQuality.Regular; - } - - DropItem(item); - } - - for (var i = Utility.Random(3) + 1; i > 0; i--) - { - DropItem(Loot.RandomClothing()); - } - - for (var i = Utility.Random(3) + 1; i > 0; i--) - { - DropItem(Loot.RandomJewelry()); - } - } -} diff --git a/ToAdd/SackOfHolding.cs b/ToAdd/SackOfHolding.cs new file mode 100644 index 000000000..125402968 --- /dev/null +++ b/ToAdd/SackOfHolding.cs @@ -0,0 +1,196 @@ +using System; +using Server; +using Server.Gumps; +using Server.ContextMenus; +using System.Collections; +using System.Collections.Generic; +using Server.Network; + +namespace Server.Items +{ + public class SackOfHolding : LargeSack + { + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + public Mobile SackOwner; + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Sack_Owner { get{ return SackOwner; } set{ SackOwner = value; } } + + private int m_MaxWeightDefault = 100000; + public override int DefaultMaxWeight{ get{ return m_MaxWeightDefault; } } + + public override bool DisplaysContent{ get{ return false; } } + public override bool DisplayWeight{ get{ return false; } } + + [Constructable] + public SackOfHolding() : base() + { + Weight = 1.0; + MaxItems = 10; + Name = "pack of holding"; + Hue = Utility.RandomColor(0); + + switch( Utility.RandomMinMax( 0, 5 ) ) + { + case 0: Weight = 1.0; MaxItems = 10; ItemID = Utility.RandomList( 0x658D, 0x658E ); break; + case 1: Weight = 1.0; MaxItems = 10; ItemID = Utility.RandomList( 0x658D, 0x658E ); break; + case 2: Weight = 1.0; MaxItems = 10; ItemID = Utility.RandomList( 0x658D, 0x658E ); break; + case 3: Weight = 2.0; MaxItems = 20; ItemID = Utility.RandomList( 0x6568, 0x6569 ); break; + case 4: Weight = 2.0; MaxItems = 20; ItemID = Utility.RandomList( 0x6568, 0x6569 ); break; + case 5: Weight = 3.0; MaxItems = 30; ItemID = Utility.RandomList( 0x6568, 0x6569 ); break; + } + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + list.Add( 1073841, "{0}\t{1}\t{2}", TotalItems, MaxItems, TotalWeight ); // Contents: ~1_COUNT~/~2_MAXCOUNT~ items, ~3_WEIGHT~ stones + } + + public override bool OnDragDropInto( Mobile from, Item dropped, Point3D p ) + { + if ( dropped is Container ) + { + from.SendMessage("You cannot store containers in this bag."); + return false; + } + + return base.OnDragDropInto(from, dropped, p); + } + + public override bool OnDragDrop( Mobile from, Item dropped ) + { + if ( dropped is Container ) + { + from.SendMessage("You cannot store containers in this bag."); + return false; + } + + return base.OnDragDrop(from, dropped); + } + + public class BagGump : Gump + { + public BagGump( Mobile from, Container bag ): base( 50, 50 ) + { + string color = "#b7765d"; + from.SendSound( 0x4A ); + + int hold = bag.MaxItems; + string sText = "This magical bag can hold almost an infinite amount of weight, but it can only hold " + hold + " separate items. Items stacked onto each other count as a single item in this regard. Other containers cannot be placed within the bag. Now that you have read this information about the bag, you can now open the bag as you normally would. To read this information in the future, single click the bag and choose the Look At menu option. Placing items in this bag can be tricky, so be aware of these issues. Items placed into the bag will only be magically affected after being placed within it. This means if your main backpack can only hold 500 stones, and this bag of holding is within your main backpack, then placing 600 stones of weight into this magical bag will not work. You would instead need to place a lesser amount of weight into the bag so the bag can magically reduce that weight. Then you can place a few more items within it. Another method of placing large piles of weight (iron ore for example) into the bag, is to set the bag on the ground and then place items in it."; + + this.Closable=true; + this.Disposable=true; + this.Dragable=true; + this.Resizable=false; + + AddPage(0); + + AddImage(0, 0, 9547, Server.Misc.PlayerSettings.GetGumpHue( from )); + AddHtml( 11, 11, 200, 20, @"BAG OF HOLDING", (bool)false, (bool)false); + AddHtml( 13, 44, 582, 473, @"" + sText + "", (bool)false, (bool)false); + AddButton(568, 9, 4017, 4017, 0, GumpButtonType.Reply, 0); + } + + public override void OnResponse(NetState state, RelayInfo info) + { + Mobile from = state.Mobile; + from.SendSound( 0x4A ); + } + } + + public class BagMenu : ContextMenuEntry + { + private SackOfHolding i_SackOfHolding; + private Mobile m_From; + + public BagMenu( Mobile from, SackOfHolding bag ) : base( 6121, 1 ) + { + m_From = from; + i_SackOfHolding = bag; + } + + public override void OnClick() + { + m_From.CloseGump( typeof( BagGump ) ); + m_From.SendGump( new BagGump( m_From, i_SackOfHolding ) ); + m_From.PlaySound( 0x048 ); + } + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + + if ( from.Alive ) + list.Add( new BagMenu( from, this ) ); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( SackOwner == from ) + { + Open( from ); + from.CloseGump( typeof( BagGump ) ); + } + else + { + SackOwner = from; + from.CloseGump( typeof( BagGump ) ); + from.SendGump( new BagGump( from, this ) ); + from.PlaySound( 0x048 ); + } + } + + public override int GetTotal(TotalType type) + { + if (type != TotalType.Weight) + return base.GetTotal(type); + else + { + return (int)(TotalItemWeights() * (0.0)); + } + } + + public override void UpdateTotal(Item sender, TotalType type, int delta) + { + if (type != TotalType.Weight) + base.UpdateTotal(sender, type, delta); + else + base.UpdateTotal(sender, type, (int)(delta * (0.0))); + } + + private double TotalItemWeights() + { + double weight = 0.0; + + foreach (Item item in Items) + weight += (item.Weight * (double)(item.Amount)); + + return weight; + } + + public SackOfHolding( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + writer.Write( (Mobile)SackOwner); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + SackOwner = reader.ReadMobile(); + Name = "pack of holding"; + if ( Weight == 3.0 ){ MaxItems = 30; if ( ItemID != 0x6568 || ItemID != 0x6569 ){ ItemID = Utility.RandomList( 0x6568, 0x6569 ); } } + else if ( Weight == 2.0 ){ MaxItems = 20; if ( ItemID != 0x6568 || ItemID != 0x6569 ){ ItemID = Utility.RandomList( 0x6568, 0x6569 ); } } + else { MaxItems = 10; if ( ItemID != 0x658D || ItemID != 0x658E ){ ItemID = Utility.RandomList( 0x658D, 0x658E ); } } + m_MaxWeightDefault = 100000; + } + } +} \ No newline at end of file