From 128bececce34bcfd337d397d0366bb4bbdec3057 Mon Sep 17 00:00:00 2001 From: WarrentyExpired Date: Sun, 11 Oct 2026 16:08:46 -0400 Subject: [PATCH] #W# Added: Treasure bags are like treasure chests but theres a chance they may not be locked or trapped for less loot. --- .../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 ++++++ .../TreasureChests/TreasureChestLevel2.cs | 2 +- .../TreasureChests/TreasureChestLevel3.cs | 2 +- .../TreasureChests/TreasureChestLevel4.cs | 2 +- 8 files changed, 608 insertions(+), 3 deletions(-) create mode 100644 Projects/UOContent/Items/TreasureChests/BaseTreasureBag.cs create mode 100644 Projects/UOContent/Items/TreasureChests/TreasureBagLevel1.cs create mode 100644 Projects/UOContent/Items/TreasureChests/TreasureBagLevel2.cs create mode 100644 Projects/UOContent/Items/TreasureChests/TreasureBagLevel3.cs create mode 100644 Projects/UOContent/Items/TreasureChests/TreasureBagLevel4.cs diff --git a/Projects/UOContent/Items/TreasureChests/BaseTreasureBag.cs b/Projects/UOContent/Items/TreasureChests/BaseTreasureBag.cs new file mode 100644 index 000000000..67b0ed1ce --- /dev/null +++ b/Projects/UOContent/Items/TreasureChests/BaseTreasureBag.cs @@ -0,0 +1,49 @@ +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 new file mode 100644 index 000000000..4d873be23 --- /dev/null +++ b/Projects/UOContent/Items/TreasureChests/TreasureBagLevel1.cs @@ -0,0 +1,76 @@ +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 new file mode 100644 index 000000000..7c38ae21c --- /dev/null +++ b/Projects/UOContent/Items/TreasureChests/TreasureBagLevel2.cs @@ -0,0 +1,104 @@ +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 new file mode 100644 index 000000000..8261dda03 --- /dev/null +++ b/Projects/UOContent/Items/TreasureChests/TreasureBagLevel3.cs @@ -0,0 +1,281 @@ +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 new file mode 100644 index 000000000..f566c16d9 --- /dev/null +++ b/Projects/UOContent/Items/TreasureChests/TreasureBagLevel4.cs @@ -0,0 +1,95 @@ +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/Projects/UOContent/Items/TreasureChests/TreasureChestLevel2.cs b/Projects/UOContent/Items/TreasureChests/TreasureChestLevel2.cs index f212d3e71..7cf8e1276 100644 --- a/Projects/UOContent/Items/TreasureChests/TreasureChestLevel2.cs +++ b/Projects/UOContent/Items/TreasureChests/TreasureChestLevel2.cs @@ -29,7 +29,7 @@ public partial class TreasureChestLevel2 : LockableContainer // Gems // Gold - DropItem(new Gold(Utility.Random(70, 100))); + DropItem(new Gold(Utility.Random(80, 150))); // Drop bolts // DropItem( new Arrow( 10 ) ); diff --git a/Projects/UOContent/Items/TreasureChests/TreasureChestLevel3.cs b/Projects/UOContent/Items/TreasureChests/TreasureChestLevel3.cs index 04b4577c9..72233ec0d 100644 --- a/Projects/UOContent/Items/TreasureChests/TreasureChestLevel3.cs +++ b/Projects/UOContent/Items/TreasureChests/TreasureChestLevel3.cs @@ -34,7 +34,7 @@ public partial class TreasureChestLevel3 : LockableContainer // Magic jewelry (not implemented) // Gold - DropItem(new Gold(Utility.Random(180, 240))); + DropItem(new Gold(Utility.Random(250, 350))); // Drop bolts // DropItem( new Arrow( 10 ) ); diff --git a/Projects/UOContent/Items/TreasureChests/TreasureChestLevel4.cs b/Projects/UOContent/Items/TreasureChests/TreasureChestLevel4.cs index 12639638d..2cacf4cdc 100644 --- a/Projects/UOContent/Items/TreasureChests/TreasureChestLevel4.cs +++ b/Projects/UOContent/Items/TreasureChests/TreasureChestLevel4.cs @@ -35,7 +35,7 @@ public partial class TreasureChestLevel4 : LockableContainer // Crystal ball (not implemented) // Gold - DropItem(new Gold(Utility.Random(200, 400))); + DropItem(new Gold(Utility.Random(500, 900))); // Reagents for (var i = Utility.Random(4); i > 0; i--)