diff --git a/Projects/UOContent/Items/Containers/Fillable Containers/FillableContainer.cs b/Projects/UOContent/Items/Containers/Fillable Containers/FillableContainer.cs new file mode 100644 index 000000000..9f035a477 --- /dev/null +++ b/Projects/UOContent/Items/Containers/Fillable Containers/FillableContainer.cs @@ -0,0 +1,254 @@ +using System; +using ModernUO.Serialization; + +namespace Server.Items; + +[SerializationGenerator(2, false)] +public abstract partial class FillableContainer : LockableContainer +{ + [SerializableField(0)] + protected FillableContentType _rawContentType; + + [TimerDrift] + [SerializableField(1)] + private Timer _respawnTimer; + + [DeserializeTimerField(1)] + private void DeserializeRespawnTimer(TimeSpan delay) + { + if (delay > TimeSpan.MinValue) + { + _respawnTimer = Timer.DelayCall(delay, Respawn); + } + } + + public FillableContainer(int itemID) : base(itemID) => Movable = false; + + public virtual int MinRespawnMinutes => 60; + public virtual int MaxRespawnMinutes => 90; + + public virtual bool IsLockable => true; + public virtual bool IsTrappable => IsLockable; + + public virtual int SpawnThreshold => 2; + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime NextRespawnTime => _respawnTimer?.Next ?? DateTime.MinValue; + + [CommandProperty(AccessLevel.GameMaster)] + public FillableContentType ContentType + { + get => _rawContentType; + set + { + if (_rawContentType == value) + { + return; + } + + ClearContents(); + _rawContentType = value; + Respawn(); + } + } + + protected void ClearContents() + { + for (var i = Items.Count - 1; i >= 0; --i) + { + if (i < Items.Count) + { + Items[i].Delete(); + } + } + } + + public override void OnMapChange() + { + base.OnMapChange(); + AcquireContent(); + } + + public override void OnLocationChange(Point3D oldLocation) + { + base.OnLocationChange(oldLocation); + AcquireContent(); + } + + public virtual void AcquireContent() + { + if (_rawContentType != FillableContentType.None) + { + return; + } + + RawContentType = FillableContent.Acquire(GetWorldLocation(), Map); + + if (_rawContentType != FillableContentType.None) + { + Respawn(); + } + } + + public override void OnItemRemoved(Item item) + { + CheckRespawn(); + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + _respawnTimer?.Stop(); + _respawnTimer = null; + } + + public int GetItemsCount() + { + var count = 0; + + foreach (var item in Items) + { + count += item.Amount; + } + + return count; + } + + public void CheckRespawn() + { + var canSpawn = + _rawContentType != FillableContentType.None && + !Deleted && !Movable && Parent == null && !IsLockedDown && !IsSecure && + ( + GetItemsCount() <= SpawnThreshold || + IsLockable && !Locked || + IsTrappable && TrapType == TrapType.None + ); + + if (canSpawn) + { + if (_respawnTimer?.Running != true) + { + var mins = Utility.RandomMinMax(MinRespawnMinutes, MaxRespawnMinutes); + var delay = TimeSpan.FromMinutes(mins); + _respawnTimer = Timer.DelayCall(delay, Respawn); + } + } + else + { + _respawnTimer?.Stop(); + _respawnTimer = null; + } + } + + public void Respawn() + { + _respawnTimer?.Stop(); + _respawnTimer = null; + + if (_rawContentType == FillableContentType.None || Deleted) + { + return; + } + + GenerateContent(); + + var level = FillableContent.Lookup(_rawContentType).Level; + + if (IsLockable) + { + Locked = true; + + var difficulty = (level - 1) * 30; + + LockLevel = difficulty - 10; + MaxLockLevel = difficulty + 30; + RequiredSkill = difficulty; + } + + if (IsTrappable && (level > 1 || Utility.Random(5) < 4)) + { + TrapType = level > Utility.Random(5) ? TrapType.PoisonTrap : TrapType.ExplosionTrap; + TrapPower = level * Utility.RandomMinMax(10, 30); + TrapLevel = level; + } + else + { + TrapType = TrapType.None; + TrapPower = 0; + TrapLevel = 0; + } + + CheckRespawn(); + } + + protected virtual int GetSpawnCount() + { + var itemsCount = GetItemsCount(); + + if (itemsCount > SpawnThreshold) + { + return 0; + } + + var maxSpawnCount = (1 + SpawnThreshold - itemsCount) * 2; + + return Utility.RandomMinMax(0, maxSpawnCount); + } + + public virtual void GenerateContent() + { + if (_rawContentType == FillableContentType.None || Deleted) + { + return; + } + + var content = FillableContent.Lookup(_rawContentType); + + var toSpawn = GetSpawnCount(); + + for (var i = 0; i < toSpawn; ++i) + { + var item = content.Construct(); + + if (item == null) + { + continue; + } + + var list = Items; + + for (var j = 0; j < list.Count; ++j) + { + var subItem = list[j]; + + if (subItem is not Container && subItem.StackWith(null, item, false)) + { + break; + } + } + + if (!item.Deleted) + { + DropItem(item); + } + } + } + + private void Deserialize(IGenericReader reader, int version) + { + _rawContentType = (FillableContentType)reader.ReadInt(); + var respawnTimerNext = reader.ReadDeltaTime(); + DeserializeRespawnTimer(respawnTimerNext == DateTime.MinValue ? TimeSpan.MinValue : respawnTimerNext - Core.Now); + } + + [AfterDeserialization] + private void AfterDeserialization() + { + if (_respawnTimer?.Running != true) + { + CheckRespawn(); + } + } +} diff --git a/Projects/UOContent/Items/Containers/Fillable Containers/FillableContainers.cs b/Projects/UOContent/Items/Containers/Fillable Containers/FillableContainers.cs new file mode 100644 index 000000000..0c3afc853 --- /dev/null +++ b/Projects/UOContent/Items/Containers/Fillable Containers/FillableContainers.cs @@ -0,0 +1,100 @@ +using ModernUO.Serialization; + +namespace Server.Items; + +[Flippable(0xA97, 0xA99, 0xA98, 0xA9A, 0xA9B, 0xA9C)] +[SerializationGenerator(0)] +public partial class LibraryBookcase : FillableContainer +{ + [Constructible] + public LibraryBookcase() : base(0xA97) => Weight = 1.0; + + public override bool IsLockable => false; + public override int SpawnThreshold => 5; + + protected override int GetSpawnCount() => 5 - GetItemsCount(); + + public override void AcquireContent() + { + if (_rawContentType != FillableContentType.None) + { + return; + } + + RawContentType = FillableContentType.Library; + Respawn(); + } +} + +[Flippable(0xE3D, 0xE3C)] +[SerializationGenerator(0)] +public partial class FillableLargeCrate : FillableContainer +{ + [Constructible] + public FillableLargeCrate() : base(0xE3D) => Weight = 1.0; +} + +[Flippable(0x9A9, 0xE7E)] +[SerializationGenerator(0)] +public partial class FillableSmallCrate : FillableContainer +{ + [Constructible] + public FillableSmallCrate() : base(0x9A9) => Weight = 1.0; +} + +[Flippable(0x9AA, 0xE7D)] +[SerializationGenerator(0)] +public partial class FillableWoodenBox : FillableContainer +{ + [Constructible] + public FillableWoodenBox() : base(0x9AA) => Weight = 4.0; +} + +[Flippable(0x9A8, 0xE80)] +[SerializationGenerator(0)] +public partial class FillableMetalBox : FillableContainer +{ + [Constructible] + public FillableMetalBox() : base(0x9A8) + { + } +} + +[SerializationGenerator(0)] +public partial class FillableBarrel : FillableContainer +{ + [Constructible] + public FillableBarrel() : base(0xE77) + { + } +} + +[Flippable(0x9AB, 0xE7C)] +[SerializationGenerator(0, false)] +public partial class FillableMetalChest : FillableContainer +{ + [Constructible] + public FillableMetalChest() : base(0x9AB) + { + } +} + +[Flippable(0xE41, 0xE40)] +[SerializationGenerator(0, false)] +public partial class FillableMetalGoldenChest : FillableContainer +{ + [Constructible] + public FillableMetalGoldenChest() : base(0xE41) + { + } +} + +[Flippable(0xE43, 0xE42)] +[SerializationGenerator(0, false)] +public partial class FillableWoodenChest : FillableContainer +{ + [Constructible] + public FillableWoodenChest() : base(0xE43) + { + } +} diff --git a/Projects/UOContent/Items/Containers/Fillable Containers/FillableContent.ContentTypes.cs b/Projects/UOContent/Items/Containers/Fillable Containers/FillableContent.ContentTypes.cs new file mode 100644 index 000000000..55a7b2ab1 --- /dev/null +++ b/Projects/UOContent/Items/Containers/Fillable Containers/FillableContent.ContentTypes.cs @@ -0,0 +1,810 @@ +using System; +using System.Collections.Generic; +using Server.Mobiles; + +namespace Server.Items; + +public enum FillableContentType +{ + None = -1, + Weaponsmith, + Provisioner, + Mage, + Alchemist, + Armorer, + ArtisanGuild, + Baker, + Bard, + Blacksmith, + Bowyer, + Butcher, + Carpenter, + Clothier, + Cobbler, + Docks, + Farm, + FighterGuild, + Guard, + Healer, + Herbalist, + Inn, + Jeweler, + Library, + Merchant, + Mill, + Mine, + Observatory, + Painter, + Ranger, + Stables, + Tanner, + Tavern, + ThiefGuild, + Tinker, + Veterinarian +} + +public partial class FillableContent +{ + private static readonly FillableContent Alchemist = new( + 1, + new[] + { + typeof(Alchemist) + }, + new[] + { + new FillableEntry(typeof(NightSightPotion)), + new FillableEntry(typeof(LesserCurePotion)), + new FillableEntry(typeof(AgilityPotion)), + new FillableEntry(typeof(StrengthPotion)), + new FillableEntry(typeof(LesserPoisonPotion)), + new FillableEntry(typeof(RefreshPotion)), + new FillableEntry(typeof(LesserHealPotion)), + new FillableEntry(typeof(LesserExplosionPotion)), + new FillableEntry(typeof(MortarPestle)) + } + ); + + private static readonly FillableContent Armorer = new( + 2, + new[] + { + typeof(Armorer) + }, + new[] + { + new FillableEntry(2, typeof(ChainCoif)), + new FillableEntry(1, typeof(PlateGorget)), + new FillableEntry(1, typeof(BronzeShield)), + new FillableEntry(1, typeof(Buckler)), + new FillableEntry(2, typeof(MetalKiteShield)), + new FillableEntry(2, typeof(HeaterShield)), + new FillableEntry(1, typeof(WoodenShield)), + new FillableEntry(1, typeof(MetalShield)) + } + ); + + private static readonly FillableContent ArtisanGuild = new( + 1, + Array.Empty(), + new[] + { + new FillableEntry(1, typeof(PaintsAndBrush)), + new FillableEntry(1, typeof(SledgeHammer)), + new FillableEntry(2, typeof(SmithHammer)), + new FillableEntry(2, typeof(Tongs)), + new FillableEntry(4, typeof(Lockpick)), + new FillableEntry(4, typeof(TinkerTools)), + new FillableEntry(1, typeof(MalletAndChisel)), + new FillableEntry(1, typeof(StatueEast2)), + new FillableEntry(1, typeof(StatueSouth)), + new FillableEntry(1, typeof(StatueSouthEast)), + new FillableEntry(1, typeof(StatueWest)), + new FillableEntry(1, typeof(StatueNorth)), + new FillableEntry(1, typeof(StatueEast)), + new FillableEntry(1, typeof(BustEast)), + new FillableEntry(1, typeof(BustSouth)), + new FillableEntry(1, typeof(BearMask)), + new FillableEntry(1, typeof(DeerMask)), + new FillableEntry(4, typeof(OrcHelm)), + new FillableEntry(1, typeof(TribalMask)), + new FillableEntry(1, typeof(HornedTribalMask)) + } + ); + + private static readonly FillableContent Baker = new( + 1, + new[] + { + typeof(Baker) + }, + new[] + { + new FillableEntry(1, typeof(RollingPin)), + new FillableEntry(2, typeof(SackFlour)), + new FillableEntry(2, typeof(BreadLoaf)), + new FillableEntry(1, typeof(FrenchBread)) + } + ); + + private static readonly FillableContent Bard = new( + 1, + new[] + { + typeof(Bard), + typeof(BardGuildmaster) + }, + new[] + { + new FillableEntry(1, typeof(LapHarp)), + new FillableEntry(2, typeof(Lute)), + new FillableEntry(1, typeof(Drums)), + new FillableEntry(1, typeof(Tambourine)), + new FillableEntry(1, typeof(TambourineTassel)) + } + ); + + private static readonly FillableContent Blacksmith = new( + 2, + new[] + { + typeof(Blacksmith), + typeof(BlacksmithGuildmaster) + }, + new[] + { + new FillableEntry(8, typeof(SmithHammer)), + new FillableEntry(8, typeof(Tongs)), + new FillableEntry(8, typeof(SledgeHammer)), + // new FillableEntry( 8, typeof( IronOre ) ), TODO: Smaller ore + new FillableEntry(8, typeof(IronIngot)), + new FillableEntry(1, typeof(IronWire)), + new FillableEntry(1, typeof(SilverWire)), + new FillableEntry(1, typeof(GoldWire)), + new FillableEntry(1, typeof(CopperWire)), + new FillableEntry(1, typeof(HorseShoes)), + new FillableEntry(1, typeof(ForgedMetal)) + } + ); + + private static readonly FillableContent Bowyer = new( + 2, + new[] + { + typeof(Bowyer) + }, + new[] + { + new FillableEntry(2, typeof(Bow)), + new FillableEntry(2, typeof(Crossbow)), + new FillableEntry(1, typeof(Arrow)) + } + ); + + private static readonly FillableContent Butcher = new( + 1, + new[] + { + typeof(Butcher) + }, + new[] + { + new FillableEntry(2, typeof(Cleaver)), + new FillableEntry(2, typeof(SlabOfBacon)), + new FillableEntry(2, typeof(Bacon)), + new FillableEntry(1, typeof(RawFishSteak)), + new FillableEntry(1, typeof(FishSteak)), + new FillableEntry(2, typeof(CookedBird)), + new FillableEntry(2, typeof(RawBird)), + new FillableEntry(2, typeof(Ham)), + new FillableEntry(1, typeof(RawLambLeg)), + new FillableEntry(1, typeof(LambLeg)), + new FillableEntry(1, typeof(Ribs)), + new FillableEntry(1, typeof(RawRibs)), + new FillableEntry(2, typeof(Sausage)), + new FillableEntry(1, typeof(RawChickenLeg)), + new FillableEntry(1, typeof(ChickenLeg)) + } + ); + + private static readonly FillableContent Carpenter = new( + 1, + new[] + { + typeof(Carpenter), + typeof(Architect), + typeof(RealEstateBroker) + }, + new[] + { + new FillableEntry(1, typeof(ChiselsNorth)), + new FillableEntry(1, typeof(ChiselsWest)), + new FillableEntry(2, typeof(DovetailSaw)), + new FillableEntry(2, typeof(Hammer)), + new FillableEntry(2, typeof(MouldingPlane)), + new FillableEntry(2, typeof(Nails)), + new FillableEntry(2, typeof(JointingPlane)), + new FillableEntry(2, typeof(SmoothingPlane)), + new FillableEntry(2, typeof(Saw)), + new FillableEntry(2, typeof(DrawKnife)), + new FillableEntry(1, typeof(Log)), + new FillableEntry(1, typeof(Froe)), + new FillableEntry(1, typeof(Inshave)), + new FillableEntry(1, typeof(Scorp)) + } + ); + + private static readonly FillableContent Clothier = new( + 1, + new[] + { + typeof(Tailor), + typeof(Weaver), + typeof(TailorGuildmaster) + }, + new[] + { + new FillableEntry(1, typeof(Cotton)), + new FillableEntry(1, typeof(Wool)), + new FillableEntry(1, typeof(DarkYarn)), + new FillableEntry(1, typeof(LightYarn)), + new FillableEntry(1, typeof(LightYarnUnraveled)), + new FillableEntry(1, typeof(SpoolOfThread)), + // Four different types + // new FillableEntry( 1, typeof( FoldedCloth ) ), + // new FillableEntry( 1, typeof( FoldedCloth ) ), + // new FillableEntry( 1, typeof( FoldedCloth ) ), + // new FillableEntry( 1, typeof( FoldedCloth ) ), + new FillableEntry(1, typeof(Dyes)), + new FillableEntry(2, typeof(Leather)) + } + ); + + private static readonly FillableContent Cobbler = new( + 1, + new[] + { + typeof(Cobbler) + }, + new[] + { + new FillableEntry(1, typeof(Boots)), + new FillableEntry(2, typeof(Shoes)), + new FillableEntry(2, typeof(Sandals)), + new FillableEntry(1, typeof(ThighBoots)) + } + ); + + private static readonly FillableContent Docks = new( + 1, + new[] + { + typeof(Fisherman), + typeof(FisherGuildmaster) + }, + new[] + { + new FillableEntry(1, typeof(FishingPole)), + // Two different types + // new FillableEntry( 1, typeof( SmallFish ) ), + // new FillableEntry( 1, typeof( SmallFish ) ), + new FillableEntry(4, typeof(Fish)) + } + ); + + private static readonly FillableContent Farm = new( + 1, + new[] + { + typeof(Farmer), + typeof(Rancher) + }, + new[] + { + new FillableEntry(1, typeof(Shirt)), + new FillableEntry(1, typeof(ShortPants)), + new FillableEntry(1, typeof(Skirt)), + new FillableEntry(1, typeof(PlainDress)), + new FillableEntry(1, typeof(Cap)), + new FillableEntry(2, typeof(Sandals)), + new FillableEntry(2, typeof(GnarledStaff)), + new FillableEntry(2, typeof(Pitchfork)), + new FillableEntry(1, typeof(Bag)), + new FillableEntry(1, typeof(Kindling)), + new FillableEntry(1, typeof(Lettuce)), + new FillableEntry(1, typeof(Onion)), + new FillableEntry(1, typeof(Turnip)), + new FillableEntry(1, typeof(Ham)), + new FillableEntry(1, typeof(Bacon)), + new FillableEntry(1, typeof(RawLambLeg)), + new FillableEntry(1, typeof(SheafOfHay)), + new FillableBvrge(1, typeof(Pitcher), BeverageType.Milk) + } + ); + + private static readonly FillableContent FighterGuild = new( + 3, + new[] + { + typeof(WarriorGuildmaster) + }, + new[] + { + new FillableEntry(12, Loot.ArmorTypes), + new FillableEntry(8, Loot.WeaponTypes), + new FillableEntry(3, Loot.ShieldTypes), + new FillableEntry(1, typeof(Arrow)) + } + ); + + private static readonly FillableContent Guard = new( + 3, + Array.Empty(), + new[] + { + new FillableEntry(12, Loot.ArmorTypes), + new FillableEntry(8, Loot.WeaponTypes), + new FillableEntry(3, Loot.ShieldTypes), + new FillableEntry(1, typeof(Arrow)) + } + ); + + private static readonly FillableContent Healer = new( + 1, + new[] + { + typeof(Healer), + typeof(HealerGuildmaster) + }, + new[] + { + new FillableEntry(1, typeof(Bandage)), + new FillableEntry(1, typeof(MortarPestle)), + new FillableEntry(1, typeof(LesserHealPotion)) + } + ); + + private static readonly FillableContent Herbalist = new( + 1, + new[] + { + typeof(Herbalist) + }, + new[] + { + new FillableEntry(10, typeof(Garlic)), + new FillableEntry(10, typeof(Ginseng)), + new FillableEntry(10, typeof(MandrakeRoot)), + new FillableEntry(1, typeof(DeadWood)), + new FillableEntry(1, typeof(WhiteDriedFlowers)), + new FillableEntry(1, typeof(GreenDriedFlowers)), + new FillableEntry(1, typeof(DriedOnions)), + new FillableEntry(1, typeof(DriedHerbs)) + } + ); + + private static readonly FillableContent Inn = new( + 1, + Array.Empty(), + new[] + { + new FillableEntry(1, typeof(Candle)), + new FillableEntry(1, typeof(Torch)), + new FillableEntry(1, typeof(Lantern)) + } + ); + + private static readonly FillableContent Jeweler = new( + 2, + new[] + { + typeof(Jeweler) + }, + new[] + { + new FillableEntry(1, typeof(GoldRing)), + new FillableEntry(1, typeof(GoldBracelet)), + new FillableEntry(1, typeof(GoldEarrings)), + new FillableEntry(1, typeof(GoldNecklace)), + new FillableEntry(1, typeof(GoldBeadNecklace)), + new FillableEntry(1, typeof(Necklace)), + new FillableEntry(1, typeof(Beads)), + new FillableEntry(9, Loot.GemTypes) + } + ); + + private static readonly FillableContent Library = new( + 1, + new[] + { + typeof(Scribe) + }, + new[] + { + new FillableEntry(8, Loot.LibraryBookTypes), + new FillableEntry(1, typeof(RedBook)), + new FillableEntry(1, typeof(BlueBook)) + } + ); + + private static readonly FillableContent Mage = new( + 2, + new[] + { + typeof(Mage), + typeof(HolyMage), + typeof(MageGuildmaster) + }, + new[] + { + new FillableEntry(16, typeof(BlankScroll)), + new FillableEntry(14, typeof(Spellbook)), + new FillableEntry(12, Loot.RegularScrollTypes, 0, 8), + new FillableEntry(11, Loot.RegularScrollTypes, 8, 8), + new FillableEntry(10, Loot.RegularScrollTypes, 16, 8), + new FillableEntry(9, Loot.RegularScrollTypes, 24, 8), + new FillableEntry(8, Loot.RegularScrollTypes, 32, 8), + new FillableEntry(7, Loot.RegularScrollTypes, 40, 8), + new FillableEntry(6, Loot.RegularScrollTypes, 48, 8), + new FillableEntry(5, Loot.RegularScrollTypes, 56, 8) + } + ); + + private static readonly FillableContent Merchant = new( + 1, + new[] + { + typeof(MerchantGuildmaster) + }, + new[] + { + new FillableEntry(1, typeof(CheeseWheel)), + new FillableEntry(1, typeof(CheeseWedge)), + new FillableEntry(1, typeof(CheeseSlice)), + new FillableEntry(1, typeof(Eggs)), + new FillableEntry(4, typeof(Fish)), + new FillableEntry(2, typeof(RawFishSteak)), + new FillableEntry(2, typeof(FishSteak)), + new FillableEntry(1, typeof(Apple)), + new FillableEntry(2, typeof(Banana)), + new FillableEntry(2, typeof(Bananas)), + new FillableEntry(2, typeof(OpenCoconut)), + new FillableEntry(1, typeof(SplitCoconut)), + new FillableEntry(1, typeof(Coconut)), + new FillableEntry(1, typeof(Dates)), + new FillableEntry(1, typeof(Grapes)), + new FillableEntry(1, typeof(Lemon)), + new FillableEntry(1, typeof(Lemons)), + new FillableEntry(1, typeof(Lime)), + new FillableEntry(1, typeof(Limes)), + new FillableEntry(1, typeof(Peach)), + new FillableEntry(1, typeof(Pear)), + new FillableEntry(2, typeof(SlabOfBacon)), + new FillableEntry(2, typeof(Bacon)), + new FillableEntry(2, typeof(CookedBird)), + new FillableEntry(2, typeof(RawBird)), + new FillableEntry(2, typeof(Ham)), + new FillableEntry(1, typeof(RawLambLeg)), + new FillableEntry(1, typeof(LambLeg)), + new FillableEntry(1, typeof(Ribs)), + new FillableEntry(1, typeof(RawRibs)), + new FillableEntry(2, typeof(Sausage)), + new FillableEntry(1, typeof(RawChickenLeg)), + new FillableEntry(1, typeof(ChickenLeg)), + new FillableEntry(1, typeof(Watermelon)), + new FillableEntry(1, typeof(SmallWatermelon)), + new FillableEntry(3, typeof(Turnip)), + new FillableEntry(2, typeof(YellowGourd)), + new FillableEntry(2, typeof(GreenGourd)), + new FillableEntry(2, typeof(Pumpkin)), + new FillableEntry(1, typeof(SmallPumpkin)), + new FillableEntry(2, typeof(Onion)), + new FillableEntry(2, typeof(Lettuce)), + new FillableEntry(2, typeof(Squash)), + new FillableEntry(2, typeof(HoneydewMelon)), + new FillableEntry(1, typeof(Carrot)), + new FillableEntry(2, typeof(Cantaloupe)), + new FillableEntry(2, typeof(Cabbage)), + new FillableEntry(4, typeof(EarOfCorn)) + } + ); + + private static readonly FillableContent Mill = new( + 1, + Array.Empty(), + new[] + { + new FillableEntry(1, typeof(SackFlour)) + } + ); + + private static readonly FillableContent Mine = new( + 1, + new[] + { + typeof(Miner) + }, + new[] + { + new FillableEntry(2, typeof(Pickaxe)), + new FillableEntry(2, typeof(Shovel)), + new FillableEntry(2, typeof(IronIngot)), + // new FillableEntry( 2, typeof( IronOre ) ), TODO: Smaller Ore + new FillableEntry(1, typeof(ForgedMetal)) + } + ); + + private static readonly FillableContent Observatory = new( + 1, + Array.Empty(), + new[] + { + new FillableEntry(2, typeof(Sextant)), + new FillableEntry(2, typeof(Clock)), + new FillableEntry(1, typeof(Spyglass)) + } + ); + + private static readonly FillableContent Painter = new( + 1, + Array.Empty(), + new[] + { + new FillableEntry(1, typeof(PaintsAndBrush)), + new FillableEntry(2, typeof(PenAndInk)) + } + ); + + private static readonly FillableContent Provisioner = new( + 1, + new[] + { + typeof(Provisioner) + }, + new[] + { + new FillableEntry(1, typeof(CheeseWheel)), + new FillableEntry(1, typeof(CheeseWedge)), + new FillableEntry(1, typeof(CheeseSlice)), + new FillableEntry(1, typeof(Eggs)), + new FillableEntry(4, typeof(Fish)), + new FillableEntry(1, typeof(DirtyFrypan)), + new FillableEntry(1, typeof(DirtyPan)), + new FillableEntry(1, typeof(DirtyKettle)), + new FillableEntry(1, typeof(DirtySmallRoundPot)), + new FillableEntry(1, typeof(DirtyRoundPot)), + new FillableEntry(1, typeof(DirtySmallPot)), + new FillableEntry(1, typeof(DirtyPot)), + new FillableEntry(1, typeof(Apple)), + new FillableEntry(2, typeof(Banana)), + new FillableEntry(2, typeof(Bananas)), + new FillableEntry(2, typeof(OpenCoconut)), + new FillableEntry(1, typeof(SplitCoconut)), + new FillableEntry(1, typeof(Coconut)), + new FillableEntry(1, typeof(Dates)), + new FillableEntry(1, typeof(Grapes)), + new FillableEntry(1, typeof(Lemon)), + new FillableEntry(1, typeof(Lemons)), + new FillableEntry(1, typeof(Lime)), + new FillableEntry(1, typeof(Limes)), + new FillableEntry(1, typeof(Peach)), + new FillableEntry(1, typeof(Pear)), + new FillableEntry(2, typeof(SlabOfBacon)), + new FillableEntry(2, typeof(Bacon)), + new FillableEntry(1, typeof(RawFishSteak)), + new FillableEntry(1, typeof(FishSteak)), + new FillableEntry(2, typeof(CookedBird)), + new FillableEntry(2, typeof(RawBird)), + new FillableEntry(2, typeof(Ham)), + new FillableEntry(1, typeof(RawLambLeg)), + new FillableEntry(1, typeof(LambLeg)), + new FillableEntry(1, typeof(Ribs)), + new FillableEntry(1, typeof(RawRibs)), + new FillableEntry(2, typeof(Sausage)), + new FillableEntry(1, typeof(RawChickenLeg)), + new FillableEntry(1, typeof(ChickenLeg)), + new FillableEntry(1, typeof(Watermelon)), + new FillableEntry(1, typeof(SmallWatermelon)), + new FillableEntry(3, typeof(Turnip)), + new FillableEntry(2, typeof(YellowGourd)), + new FillableEntry(2, typeof(GreenGourd)), + new FillableEntry(2, typeof(Pumpkin)), + new FillableEntry(1, typeof(SmallPumpkin)), + new FillableEntry(2, typeof(Onion)), + new FillableEntry(2, typeof(Lettuce)), + new FillableEntry(2, typeof(Squash)), + new FillableEntry(2, typeof(HoneydewMelon)), + new FillableEntry(1, typeof(Carrot)), + new FillableEntry(2, typeof(Cantaloupe)), + new FillableEntry(2, typeof(Cabbage)), + new FillableEntry(4, typeof(EarOfCorn)) + } + ); + + private static readonly FillableContent Ranger = new( + 2, + new[] + { + typeof(Ranger), + typeof(RangerGuildmaster) + }, + new[] + { + new FillableEntry(2, typeof(StuddedChest)), + new FillableEntry(2, typeof(StuddedLegs)), + new FillableEntry(2, typeof(StuddedArms)), + new FillableEntry(2, typeof(StuddedGloves)), + new FillableEntry(1, typeof(StuddedGorget)), + + new FillableEntry(2, typeof(LeatherChest)), + new FillableEntry(2, typeof(LeatherLegs)), + new FillableEntry(2, typeof(LeatherArms)), + new FillableEntry(2, typeof(LeatherGloves)), + new FillableEntry(1, typeof(LeatherGorget)), + + new FillableEntry(2, typeof(FeatheredHat)), + new FillableEntry(1, typeof(CloseHelm)), + new FillableEntry(1, typeof(TallStrawHat)), + new FillableEntry(1, typeof(Bandana)), + new FillableEntry(1, typeof(Cloak)), + new FillableEntry(2, typeof(Boots)), + new FillableEntry(2, typeof(ThighBoots)), + + new FillableEntry(2, typeof(GnarledStaff)), + new FillableEntry(1, typeof(Whip)), + + new FillableEntry(2, typeof(Bow)), + new FillableEntry(2, typeof(Crossbow)), + new FillableEntry(2, typeof(HeavyCrossbow)), + new FillableEntry(4, typeof(Arrow)) + } + ); + + private static readonly FillableContent Stables = new( + 1, + new[] + { + typeof(AnimalTrainer), + typeof(GypsyAnimalTrainer) + }, + new[] + { + // new FillableEntry( 1, typeof( Wheat ) ), + new FillableEntry(1, typeof(Carrot)) + } + ); + + private static readonly FillableContent Tanner = new( + 2, + new[] + { + typeof(Tanner), + typeof(LeatherWorker), + typeof(Furtrader) + }, + new[] + { + new FillableEntry(1, typeof(FeatheredHat)), + new FillableEntry(1, typeof(LeatherArms)), + new FillableEntry(2, typeof(LeatherLegs)), + new FillableEntry(2, typeof(LeatherChest)), + new FillableEntry(2, typeof(LeatherGloves)), + new FillableEntry(1, typeof(LeatherGorget)), + new FillableEntry(2, typeof(Leather)) + } + ); + + private static readonly FillableContent Tavern = new( + 1, + new[] + { + typeof(TavernKeeper), + typeof(Barkeeper), + typeof(Waiter), + typeof(Cook) + }, + new FillableEntry[] + { + new FillableBvrge(1, typeof(BeverageBottle), BeverageType.Ale), + new FillableBvrge(1, typeof(BeverageBottle), BeverageType.Wine), + new FillableBvrge(1, typeof(BeverageBottle), BeverageType.Liquor), + new FillableBvrge(1, typeof(Jug), BeverageType.Cider) + } + ); + + private static readonly FillableContent ThiefGuild = new( + 1, + new[] + { + typeof(Thief), + typeof(ThiefGuildmaster) + }, + new[] + { + new FillableEntry(1, typeof(Lockpick)), + new FillableEntry(1, typeof(BearMask)), + new FillableEntry(1, typeof(DeerMask)), + new FillableEntry(1, typeof(TribalMask)), + new FillableEntry(1, typeof(HornedTribalMask)), + new FillableEntry(4, typeof(OrcHelm)) + } + ); + + private static readonly FillableContent Tinker = new( + 1, + new[] + { + typeof(Tinker), + typeof(TinkerGuildmaster) + }, + new[] + { + new FillableEntry(1, typeof(Lockpick)), + // new FillableEntry( 1, typeof( KeyRing ) ), + new FillableEntry(2, typeof(Clock)), + new FillableEntry(2, typeof(ClockParts)), + new FillableEntry(2, typeof(AxleGears)), + new FillableEntry(2, typeof(Gears)), + new FillableEntry(2, typeof(Hinge)), + // new FillableEntry( 1, typeof( ArrowShafts ) ), + new FillableEntry(2, typeof(Sextant)), + new FillableEntry(2, typeof(SextantParts)), + new FillableEntry(2, typeof(Axle)), + new FillableEntry(2, typeof(Springs)), + new FillableEntry(5, typeof(TinkerTools)), + new FillableEntry(4, typeof(Key)), + new FillableEntry(1, typeof(DecoArrowShafts)), + new FillableEntry(1, typeof(Lockpicks)), + new FillableEntry(1, typeof(ToolKit)) + } + ); + + private static readonly FillableContent Veterinarian = new( + 1, + new[] + { + typeof(Veterinarian) + }, + new[] + { + new FillableEntry(1, typeof(Bandage)), + new FillableEntry(1, typeof(MortarPestle)), + new FillableEntry(1, typeof(LesserHealPotion)), + // new FillableEntry( 1, typeof( Wheat ) ), + new FillableEntry(1, typeof(Carrot)) + } + ); + + private static readonly FillableContent Weaponsmith = new( + 2, + new[] + { + typeof(Weaponsmith) + }, + new[] + { + new FillableEntry(8, Loot.WeaponTypes), + new FillableEntry(1, typeof(Arrow)) + } + ); + + private static Dictionary _acquireTable; + + // This should match the FillableContentType enum + private static readonly FillableContent[] ContentTypes = + { + Weaponsmith, Provisioner, Mage, + Alchemist, Armorer, ArtisanGuild, + Baker, Bard, Blacksmith, + Bowyer, Butcher, Carpenter, + Clothier, Cobbler, Docks, + Farm, FighterGuild, Guard, + Healer, Herbalist, Inn, + Jeweler, Library, Merchant, + Mill, Mine, Observatory, + Painter, Ranger, Stables, + Tanner, Tavern, ThiefGuild, + Tinker, Veterinarian + }; +} diff --git a/Projects/UOContent/Items/Containers/Fillable Containers/FillableContent.cs b/Projects/UOContent/Items/Containers/Fillable Containers/FillableContent.cs new file mode 100644 index 000000000..f9752d9b7 --- /dev/null +++ b/Projects/UOContent/Items/Containers/Fillable Containers/FillableContent.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections.Generic; + +namespace Server.Items; + +public partial class FillableContent +{ + private readonly FillableEntry[] _entries; + private readonly int _weight; + + public FillableContent(int level, Type[] vendors, FillableEntry[] entries) + { + Level = level; + Vendors = vendors; + _entries = entries; + + for (var i = 0; i < entries.Length; ++i) + { + _weight += entries[i].Weight; + } + } + + public int Level { get; } + + public Type[] Vendors { get; } + + public FillableContentType TypeID => Lookup(this); + + public virtual Item Construct() + { + var index = Utility.Random(_weight); + + for (var i = 0; i < _entries.Length; ++i) + { + var entry = _entries[i]; + + if (index < entry.Weight) + { + return entry.Construct(); + } + + index -= entry.Weight; + } + + return null; + } + + public static FillableContent Lookup(FillableContentType type) + { + var v = (int)type; + + if (v >= 0 && v < ContentTypes.Length) + { + return ContentTypes[v]; + } + + return null; + } + + public static FillableContentType Lookup(FillableContent content) + { + if (content == null) + { + return FillableContentType.None; + } + + return (FillableContentType)Array.IndexOf(ContentTypes, content); + } + + public static FillableContentType Acquire(Point3D loc, Map map) + { + FillableContentType content = FillableContentType.None; + + if (map == null || map == Map.Internal) + { + return content; + } + + if (_acquireTable == null) + { + _acquireTable = new Dictionary(); + + for (var i = 0; i < ContentTypes.Length; ++i) + { + var fill = ContentTypes[i]; + + for (var j = 0; j < fill.Vendors.Length; ++j) + { + _acquireTable[fill.Vendors[j]] = fill.TypeID; + } + } + } + + Mobile nearest = null; + + // TODO: Replace with vendor shop regions and a fallback override. + foreach (var mob in map.GetMobilesInRange(loc, 20)) + { + if (nearest != null && mob.GetDistanceToSqrt(loc) > nearest.GetDistanceToSqrt(loc) && + !(nearest is Mobiles.Cobbler && mob is Mobiles.Provisioner)) + { + continue; + } + + if (_acquireTable.TryGetValue(mob.GetType(), out var check)) + { + nearest = mob; + content = check; + } + } + + return content; + } +} diff --git a/Projects/UOContent/Items/Containers/Fillable Containers/FillableEntry.cs b/Projects/UOContent/Items/Containers/Fillable Containers/FillableEntry.cs new file mode 100644 index 000000000..ee7ca724a --- /dev/null +++ b/Projects/UOContent/Items/Containers/Fillable Containers/FillableEntry.cs @@ -0,0 +1,102 @@ +using System; + +namespace Server.Items; + +public class FillableEntry +{ + protected Type[] _types; + protected int _weight; + + public FillableEntry(Type type) : this(1, new[] { type }) + { + } + + public FillableEntry(int weight, Type type) : this(weight, new[] { type }) + { + } + + public FillableEntry(Type[] types) : this(1, types) + { + } + + public FillableEntry(int weight, Type[] types) + { + _weight = weight; + _types = types; + } + + public FillableEntry(int weight, Type[] types, int offset, int count) + { + _weight = weight; + _types = new Type[count]; + Array.Copy(types, offset, _types, 0, count); + } + + public Type[] Types => _types; + public int Weight => _weight; + + public virtual Item Construct() + { + var item = Loot.Construct(_types); + + if (item is Key key) + { + key.ItemID = Utility.RandomList( + (int)KeyType.Copper, + (int)KeyType.Gold, + (int)KeyType.Iron, + (int)KeyType.Rusty + ); + } + else if (item is Arrow or Bolt) + { + item.Amount = Utility.RandomMinMax(2, 6); + } + else if (item is Bandage or Lockpick) + { + item.Amount = Utility.RandomMinMax(1, 3); + } + + return item; + } +} + +public class FillableBvrge : FillableEntry +{ + public FillableBvrge(Type type, BeverageType content) : this(1, type, content) + { + } + + public FillableBvrge(int weight, Type type, BeverageType content) : base(weight, type) => + Content = content; + + public BeverageType Content { get; } + + public override Item Construct() + { + Item item; + + var index = Utility.Random(_types.Length); + + if (_types[index] == typeof(BeverageBottle)) + { + item = new BeverageBottle(Content); + } + else if (_types[index] == typeof(Jug)) + { + item = new Jug(Content); + } + else + { + item = base.Construct(); + + if (item is BaseBeverage bev) + { + bev.Content = Content; + bev.Quantity = bev.MaxQuantity; + } + } + + return item; + } +} diff --git a/Projects/UOContent/Items/Containers/FillableContainers.cs b/Projects/UOContent/Items/Containers/FillableContainers.cs deleted file mode 100644 index 54ccdd410..000000000 --- a/Projects/UOContent/Items/Containers/FillableContainers.cs +++ /dev/null @@ -1,1612 +0,0 @@ -using System; -using System.Collections.Generic; -using Server.Mobiles; - -namespace Server.Items -{ - public abstract class FillableContainer : LockableContainer - { - protected FillableContent m_Content; - - protected DateTime m_NextRespawnTime; - protected Timer _respawnTimer; - - public FillableContainer(int itemID) : base(itemID) => Movable = false; - - public FillableContainer(Serial serial) - : base(serial) - { - } - - public virtual int MinRespawnMinutes => 60; - public virtual int MaxRespawnMinutes => 90; - - public virtual bool IsLockable => true; - public virtual bool IsTrappable => IsLockable; - - public virtual int SpawnThreshold => 2; - - [CommandProperty(AccessLevel.GameMaster)] - public DateTime NextRespawnTime => m_NextRespawnTime; - - [CommandProperty(AccessLevel.GameMaster)] - public FillableContentType ContentType - { - get => FillableContent.Lookup(m_Content); - set => Content = FillableContent.Lookup(value); - } - - public FillableContent Content - { - get => m_Content; - set - { - if (m_Content == value) - { - return; - } - - m_Content = value; - - for (var i = Items.Count - 1; i >= 0; --i) - { - if (i < Items.Count) - { - Items[i].Delete(); - } - } - - Respawn(); - } - } - - public override void OnMapChange() - { - base.OnMapChange(); - AcquireContent(); - } - - public override void OnLocationChange(Point3D oldLocation) - { - base.OnLocationChange(oldLocation); - AcquireContent(); - } - - public virtual void AcquireContent() - { - if (m_Content != null) - { - return; - } - - m_Content = FillableContent.Acquire(GetWorldLocation(), Map); - - if (m_Content != null) - { - Respawn(); - } - } - - public override void OnItemRemoved(Item item) - { - CheckRespawn(); - } - - public override void OnAfterDelete() - { - base.OnAfterDelete(); - - _respawnTimer?.Stop(); - _respawnTimer = null; - } - - public int GetItemsCount() - { - var count = 0; - - foreach (var item in Items) - { - count += item.Amount; - } - - return count; - } - - public void CheckRespawn() - { - var canSpawn = m_Content != null && !Deleted && GetItemsCount() <= SpawnThreshold && !Movable && - Parent == null && !IsLockedDown && !IsSecure; - - if (canSpawn) - { - if (_respawnTimer?.Running != true) - { - var mins = Utility.RandomMinMax(MinRespawnMinutes, MaxRespawnMinutes); - var delay = TimeSpan.FromMinutes(mins); - - m_NextRespawnTime = Core.Now + delay; - _respawnTimer = Timer.DelayCall(delay, Respawn); - } - } - else - { - _respawnTimer?.Stop(); - _respawnTimer = null; - } - } - - public void Respawn() - { - _respawnTimer?.Stop(); - _respawnTimer = null; - - if (m_Content == null || Deleted) - { - return; - } - - GenerateContent(); - - if (IsLockable) - { - Locked = true; - - var difficulty = (m_Content.Level - 1) * 30; - - LockLevel = difficulty - 10; - MaxLockLevel = difficulty + 30; - RequiredSkill = difficulty; - } - - if (IsTrappable && (m_Content.Level > 1 || Utility.Random(5) < 4)) - { - if (m_Content.Level > Utility.Random(5)) - { - TrapType = TrapType.PoisonTrap; - } - else - { - TrapType = TrapType.ExplosionTrap; - } - - TrapPower = m_Content.Level * Utility.RandomMinMax(10, 30); - TrapLevel = m_Content.Level; - } - else - { - TrapType = TrapType.None; - TrapPower = 0; - TrapLevel = 0; - } - - CheckRespawn(); - } - - protected virtual int GetSpawnCount() - { - var itemsCount = GetItemsCount(); - - if (itemsCount > SpawnThreshold) - { - return 0; - } - - var maxSpawnCount = (1 + SpawnThreshold - itemsCount) * 2; - - return Utility.RandomMinMax(0, maxSpawnCount); - } - - public virtual void GenerateContent() - { - if (m_Content == null || Deleted) - { - return; - } - - var toSpawn = GetSpawnCount(); - - for (var i = 0; i < toSpawn; ++i) - { - var item = m_Content.Construct(); - - if (item == null) - { - continue; - } - - var list = Items; - - for (var j = 0; j < list.Count; ++j) - { - var subItem = list[j]; - - if (subItem is not Container && subItem.StackWith(null, item, false)) - { - break; - } - } - - if (!item.Deleted) - { - DropItem(item); - } - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(1); // version - - writer.Write((int)ContentType); - - if (_respawnTimer?.Running == true) - { - writer.Write(true); - writer.WriteDeltaTime(m_NextRespawnTime); - } - else - { - writer.Write(false); - } - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadEncodedInt(); - - switch (version) - { - case 1: - { - m_Content = FillableContent.Lookup((FillableContentType)reader.ReadInt()); - goto case 0; - } - case 0: - { - if (reader.ReadBool()) - { - m_NextRespawnTime = reader.ReadDeltaTime(); - - var delay = m_NextRespawnTime - Core.Now; - Timer.DelayCall(delay, Respawn); - } - else - { - CheckRespawn(); - } - - break; - } - } - } - } - - [Flippable(0xA97, 0xA99, 0xA98, 0xA9A, 0xA9B, 0xA9C)] - public class LibraryBookcase : FillableContainer - { - [Constructible] - public LibraryBookcase() - : base(0xA97) => - Weight = 1.0; - - public LibraryBookcase(Serial serial) - : base(serial) - { - } - - public override bool IsLockable => false; - public override int SpawnThreshold => 5; - - protected override int GetSpawnCount() => 5 - GetItemsCount(); - - public override void AcquireContent() - { - if (m_Content != null) - { - return; - } - - m_Content = FillableContent.Library; - - if (m_Content != null) - { - Respawn(); - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(1); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadEncodedInt(); - - if (version == 0 && m_Content == null) - { - Timer.StartTimer(AcquireContent); - } - } - } - - [Flippable(0xE3D, 0xE3C)] - public class FillableLargeCrate : FillableContainer - { - [Constructible] - public FillableLargeCrate() - : base(0xE3D) => - Weight = 1.0; - - public FillableLargeCrate(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadEncodedInt(); - } - } - - [Flippable(0x9A9, 0xE7E)] - public class FillableSmallCrate : FillableContainer - { - [Constructible] - public FillableSmallCrate() - : base(0x9A9) => - Weight = 1.0; - - public FillableSmallCrate(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadEncodedInt(); - } - } - - [Flippable(0x9AA, 0xE7D)] - public class FillableWoodenBox : FillableContainer - { - [Constructible] - public FillableWoodenBox() - : base(0x9AA) => - Weight = 4.0; - - public FillableWoodenBox(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadInt(); - } - } - - [Flippable(0x9A8, 0xE80)] - public class FillableMetalBox : FillableContainer - { - [Constructible] - public FillableMetalBox() - : base(0x9A8) - { - } - - public FillableMetalBox(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadEncodedInt(); - - if (version == 0 && Weight == 3) - { - Weight = -1; - } - } - } - - public class FillableBarrel : FillableContainer - { - [Constructible] - public FillableBarrel() - : base(0xE77) - { - } - - public FillableBarrel(Serial serial) - : base(serial) - { - } - - public override bool IsLockable => false; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(1); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadEncodedInt(); - - if (version == 0 && Weight == 25) - { - Weight = -1; - } - } - } - - [Flippable(0x9AB, 0xE7C)] - public class FillableMetalChest : FillableContainer - { - [Constructible] - public FillableMetalChest() - : base(0x9AB) - { - } - - public FillableMetalChest(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadInt(); - - if (version == 0 && Weight == 25) - { - Weight = -1; - } - } - } - - [Flippable(0xE41, 0xE40)] - public class FillableMetalGoldenChest : FillableContainer - { - [Constructible] - public FillableMetalGoldenChest() - : base(0xE41) - { - } - - public FillableMetalGoldenChest(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadInt(); - - if (version == 0 && Weight == 25) - { - Weight = -1; - } - } - } - - [Flippable(0xE43, 0xE42)] - public class FillableWoodenChest : FillableContainer - { - [Constructible] - public FillableWoodenChest() - : base(0xE43) - { - } - - public FillableWoodenChest(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadInt(); - - if (version == 0 && Weight == 2) - { - Weight = -1; - } - } - } - - public class FillableEntry - { - protected Type[] m_Types; - protected int m_Weight; - - public FillableEntry(Type type) - : this(1, new[] { type }) - { - } - - public FillableEntry(int weight, Type type) - : this(weight, new[] { type }) - { - } - - public FillableEntry(Type[] types) - : this(1, types) - { - } - - public FillableEntry(int weight, Type[] types) - { - m_Weight = weight; - m_Types = types; - } - - public FillableEntry(int weight, Type[] types, int offset, int count) - { - m_Weight = weight; - m_Types = new Type[count]; - - for (var i = 0; i < m_Types.Length; ++i) - { - m_Types[i] = types[offset + i]; - } - } - - public Type[] Types => m_Types; - public int Weight => m_Weight; - - public virtual Item Construct() - { - var item = Loot.Construct(m_Types); - - if (item is Key key) - { - key.ItemID = Utility.RandomList( - (int)KeyType.Copper, - (int)KeyType.Gold, - (int)KeyType.Iron, - (int)KeyType.Rusty - ); - } - else if (item is Arrow or Bolt) - { - item.Amount = Utility.RandomMinMax(2, 6); - } - else if (item is Bandage or Lockpick) - { - item.Amount = Utility.RandomMinMax(1, 3); - } - - return item; - } - } - - public class FillableBvrge : FillableEntry - { - public FillableBvrge(Type type, BeverageType content) - : this(1, type, content) - { - } - - public FillableBvrge(int weight, Type type, BeverageType content) - : base(weight, type) => - Content = content; - - public BeverageType Content { get; } - - public override Item Construct() - { - Item item; - - var index = Utility.Random(m_Types.Length); - - if (m_Types[index] == typeof(BeverageBottle)) - { - item = new BeverageBottle(Content); - } - else if (m_Types[index] == typeof(Jug)) - { - item = new Jug(Content); - } - else - { - item = base.Construct(); - - if (item is BaseBeverage bev) - { - bev.Content = Content; - bev.Quantity = bev.MaxQuantity; - } - } - - return item; - } - } - - public enum FillableContentType - { - None = -1, - Weaponsmith, - Provisioner, - Mage, - Alchemist, - Armorer, - ArtisanGuild, - Baker, - Bard, - Blacksmith, - Bowyer, - Butcher, - Carpenter, - Clothier, - Cobbler, - Docks, - Farm, - FighterGuild, - Guard, - Healer, - Herbalist, - Inn, - Jeweler, - Library, - Merchant, - Mill, - Mine, - Observatory, - Painter, - Ranger, - Stables, - Tanner, - Tavern, - ThiefGuild, - Tinker, - Veterinarian - } - - public class FillableContent - { - public static FillableContent Alchemist = new( - 1, - new[] - { - typeof(Alchemist) - }, - new[] - { - new FillableEntry(typeof(NightSightPotion)), - new FillableEntry(typeof(LesserCurePotion)), - new FillableEntry(typeof(AgilityPotion)), - new FillableEntry(typeof(StrengthPotion)), - new FillableEntry(typeof(LesserPoisonPotion)), - new FillableEntry(typeof(RefreshPotion)), - new FillableEntry(typeof(LesserHealPotion)), - new FillableEntry(typeof(LesserExplosionPotion)), - new FillableEntry(typeof(MortarPestle)) - } - ); - - public static FillableContent Armorer = new( - 2, - new[] - { - typeof(Armorer) - }, - new[] - { - new FillableEntry(2, typeof(ChainCoif)), - new FillableEntry(1, typeof(PlateGorget)), - new FillableEntry(1, typeof(BronzeShield)), - new FillableEntry(1, typeof(Buckler)), - new FillableEntry(2, typeof(MetalKiteShield)), - new FillableEntry(2, typeof(HeaterShield)), - new FillableEntry(1, typeof(WoodenShield)), - new FillableEntry(1, typeof(MetalShield)) - } - ); - - public static FillableContent ArtisanGuild = new( - 1, - Array.Empty(), - new[] - { - new FillableEntry(1, typeof(PaintsAndBrush)), - new FillableEntry(1, typeof(SledgeHammer)), - new FillableEntry(2, typeof(SmithHammer)), - new FillableEntry(2, typeof(Tongs)), - new FillableEntry(4, typeof(Lockpick)), - new FillableEntry(4, typeof(TinkerTools)), - new FillableEntry(1, typeof(MalletAndChisel)), - new FillableEntry(1, typeof(StatueEast2)), - new FillableEntry(1, typeof(StatueSouth)), - new FillableEntry(1, typeof(StatueSouthEast)), - new FillableEntry(1, typeof(StatueWest)), - new FillableEntry(1, typeof(StatueNorth)), - new FillableEntry(1, typeof(StatueEast)), - new FillableEntry(1, typeof(BustEast)), - new FillableEntry(1, typeof(BustSouth)), - new FillableEntry(1, typeof(BearMask)), - new FillableEntry(1, typeof(DeerMask)), - new FillableEntry(4, typeof(OrcHelm)), - new FillableEntry(1, typeof(TribalMask)), - new FillableEntry(1, typeof(HornedTribalMask)) - } - ); - - public static FillableContent Baker = new( - 1, - new[] - { - typeof(Baker) - }, - new[] - { - new FillableEntry(1, typeof(RollingPin)), - new FillableEntry(2, typeof(SackFlour)), - new FillableEntry(2, typeof(BreadLoaf)), - new FillableEntry(1, typeof(FrenchBread)) - } - ); - - public static FillableContent Bard = new( - 1, - new[] - { - typeof(Bard), - typeof(BardGuildmaster) - }, - new[] - { - new FillableEntry(1, typeof(LapHarp)), - new FillableEntry(2, typeof(Lute)), - new FillableEntry(1, typeof(Drums)), - new FillableEntry(1, typeof(Tambourine)), - new FillableEntry(1, typeof(TambourineTassel)) - } - ); - - public static FillableContent Blacksmith = new( - 2, - new[] - { - typeof(Blacksmith), - typeof(BlacksmithGuildmaster) - }, - new[] - { - new FillableEntry(8, typeof(SmithHammer)), - new FillableEntry(8, typeof(Tongs)), - new FillableEntry(8, typeof(SledgeHammer)), - // new FillableEntry( 8, typeof( IronOre ) ), TODO: Smaller ore - new FillableEntry(8, typeof(IronIngot)), - new FillableEntry(1, typeof(IronWire)), - new FillableEntry(1, typeof(SilverWire)), - new FillableEntry(1, typeof(GoldWire)), - new FillableEntry(1, typeof(CopperWire)), - new FillableEntry(1, typeof(HorseShoes)), - new FillableEntry(1, typeof(ForgedMetal)) - } - ); - - public static FillableContent Bowyer = new( - 2, - new[] - { - typeof(Bowyer) - }, - new[] - { - new FillableEntry(2, typeof(Bow)), - new FillableEntry(2, typeof(Crossbow)), - new FillableEntry(1, typeof(Arrow)) - } - ); - - public static FillableContent Butcher = new( - 1, - new[] - { - typeof(Butcher) - }, - new[] - { - new FillableEntry(2, typeof(Cleaver)), - new FillableEntry(2, typeof(SlabOfBacon)), - new FillableEntry(2, typeof(Bacon)), - new FillableEntry(1, typeof(RawFishSteak)), - new FillableEntry(1, typeof(FishSteak)), - new FillableEntry(2, typeof(CookedBird)), - new FillableEntry(2, typeof(RawBird)), - new FillableEntry(2, typeof(Ham)), - new FillableEntry(1, typeof(RawLambLeg)), - new FillableEntry(1, typeof(LambLeg)), - new FillableEntry(1, typeof(Ribs)), - new FillableEntry(1, typeof(RawRibs)), - new FillableEntry(2, typeof(Sausage)), - new FillableEntry(1, typeof(RawChickenLeg)), - new FillableEntry(1, typeof(ChickenLeg)) - } - ); - - public static FillableContent Carpenter = new( - 1, - new[] - { - typeof(Carpenter), - typeof(Architect), - typeof(RealEstateBroker) - }, - new[] - { - new FillableEntry(1, typeof(ChiselsNorth)), - new FillableEntry(1, typeof(ChiselsWest)), - new FillableEntry(2, typeof(DovetailSaw)), - new FillableEntry(2, typeof(Hammer)), - new FillableEntry(2, typeof(MouldingPlane)), - new FillableEntry(2, typeof(Nails)), - new FillableEntry(2, typeof(JointingPlane)), - new FillableEntry(2, typeof(SmoothingPlane)), - new FillableEntry(2, typeof(Saw)), - new FillableEntry(2, typeof(DrawKnife)), - new FillableEntry(1, typeof(Log)), - new FillableEntry(1, typeof(Froe)), - new FillableEntry(1, typeof(Inshave)), - new FillableEntry(1, typeof(Scorp)) - } - ); - - public static FillableContent Clothier = new( - 1, - new[] - { - typeof(Tailor), - typeof(Weaver), - typeof(TailorGuildmaster) - }, - new[] - { - new FillableEntry(1, typeof(Cotton)), - new FillableEntry(1, typeof(Wool)), - new FillableEntry(1, typeof(DarkYarn)), - new FillableEntry(1, typeof(LightYarn)), - new FillableEntry(1, typeof(LightYarnUnraveled)), - new FillableEntry(1, typeof(SpoolOfThread)), - // Four different types - // new FillableEntry( 1, typeof( FoldedCloth ) ), - // new FillableEntry( 1, typeof( FoldedCloth ) ), - // new FillableEntry( 1, typeof( FoldedCloth ) ), - // new FillableEntry( 1, typeof( FoldedCloth ) ), - new FillableEntry(1, typeof(Dyes)), - new FillableEntry(2, typeof(Leather)) - } - ); - - public static FillableContent Cobbler = new( - 1, - new[] - { - typeof(Cobbler) - }, - new[] - { - new FillableEntry(1, typeof(Boots)), - new FillableEntry(2, typeof(Shoes)), - new FillableEntry(2, typeof(Sandals)), - new FillableEntry(1, typeof(ThighBoots)) - } - ); - - public static FillableContent Docks = new( - 1, - new[] - { - typeof(Fisherman), - typeof(FisherGuildmaster) - }, - new[] - { - new FillableEntry(1, typeof(FishingPole)), - // Two different types - // new FillableEntry( 1, typeof( SmallFish ) ), - // new FillableEntry( 1, typeof( SmallFish ) ), - new FillableEntry(4, typeof(Fish)) - } - ); - - public static FillableContent Farm = new( - 1, - new[] - { - typeof(Farmer), - typeof(Rancher) - }, - new[] - { - new FillableEntry(1, typeof(Shirt)), - new FillableEntry(1, typeof(ShortPants)), - new FillableEntry(1, typeof(Skirt)), - new FillableEntry(1, typeof(PlainDress)), - new FillableEntry(1, typeof(Cap)), - new FillableEntry(2, typeof(Sandals)), - new FillableEntry(2, typeof(GnarledStaff)), - new FillableEntry(2, typeof(Pitchfork)), - new FillableEntry(1, typeof(Bag)), - new FillableEntry(1, typeof(Kindling)), - new FillableEntry(1, typeof(Lettuce)), - new FillableEntry(1, typeof(Onion)), - new FillableEntry(1, typeof(Turnip)), - new FillableEntry(1, typeof(Ham)), - new FillableEntry(1, typeof(Bacon)), - new FillableEntry(1, typeof(RawLambLeg)), - new FillableEntry(1, typeof(SheafOfHay)), - new FillableBvrge(1, typeof(Pitcher), BeverageType.Milk) - } - ); - - public static FillableContent FighterGuild = new( - 3, - new[] - { - typeof(WarriorGuildmaster) - }, - new[] - { - new FillableEntry(12, Loot.ArmorTypes), - new FillableEntry(8, Loot.WeaponTypes), - new FillableEntry(3, Loot.ShieldTypes), - new FillableEntry(1, typeof(Arrow)) - } - ); - - public static FillableContent Guard = new( - 3, - Array.Empty(), - new[] - { - new FillableEntry(12, Loot.ArmorTypes), - new FillableEntry(8, Loot.WeaponTypes), - new FillableEntry(3, Loot.ShieldTypes), - new FillableEntry(1, typeof(Arrow)) - } - ); - - public static FillableContent Healer = new( - 1, - new[] - { - typeof(Healer), - typeof(HealerGuildmaster) - }, - new[] - { - new FillableEntry(1, typeof(Bandage)), - new FillableEntry(1, typeof(MortarPestle)), - new FillableEntry(1, typeof(LesserHealPotion)) - } - ); - - public static FillableContent Herbalist = new( - 1, - new[] - { - typeof(Herbalist) - }, - new[] - { - new FillableEntry(10, typeof(Garlic)), - new FillableEntry(10, typeof(Ginseng)), - new FillableEntry(10, typeof(MandrakeRoot)), - new FillableEntry(1, typeof(DeadWood)), - new FillableEntry(1, typeof(WhiteDriedFlowers)), - new FillableEntry(1, typeof(GreenDriedFlowers)), - new FillableEntry(1, typeof(DriedOnions)), - new FillableEntry(1, typeof(DriedHerbs)) - } - ); - - public static FillableContent Inn = new( - 1, - Array.Empty(), - new[] - { - new FillableEntry(1, typeof(Candle)), - new FillableEntry(1, typeof(Torch)), - new FillableEntry(1, typeof(Lantern)) - } - ); - - public static FillableContent Jeweler = new( - 2, - new[] - { - typeof(Jeweler) - }, - new[] - { - new FillableEntry(1, typeof(GoldRing)), - new FillableEntry(1, typeof(GoldBracelet)), - new FillableEntry(1, typeof(GoldEarrings)), - new FillableEntry(1, typeof(GoldNecklace)), - new FillableEntry(1, typeof(GoldBeadNecklace)), - new FillableEntry(1, typeof(Necklace)), - new FillableEntry(1, typeof(Beads)), - new FillableEntry(9, Loot.GemTypes) - } - ); - - public static FillableContent Library = new( - 1, - new[] - { - typeof(Scribe) - }, - new[] - { - new FillableEntry(8, Loot.LibraryBookTypes), - new FillableEntry(1, typeof(RedBook)), - new FillableEntry(1, typeof(BlueBook)) - } - ); - - public static FillableContent Mage = new( - 2, - new[] - { - typeof(Mage), - typeof(HolyMage), - typeof(MageGuildmaster) - }, - new[] - { - new FillableEntry(16, typeof(BlankScroll)), - new FillableEntry(14, typeof(Spellbook)), - new FillableEntry(12, Loot.RegularScrollTypes, 0, 8), - new FillableEntry(11, Loot.RegularScrollTypes, 8, 8), - new FillableEntry(10, Loot.RegularScrollTypes, 16, 8), - new FillableEntry(9, Loot.RegularScrollTypes, 24, 8), - new FillableEntry(8, Loot.RegularScrollTypes, 32, 8), - new FillableEntry(7, Loot.RegularScrollTypes, 40, 8), - new FillableEntry(6, Loot.RegularScrollTypes, 48, 8), - new FillableEntry(5, Loot.RegularScrollTypes, 56, 8) - } - ); - - public static FillableContent Merchant = new( - 1, - new[] - { - typeof(MerchantGuildmaster) - }, - new[] - { - new FillableEntry(1, typeof(CheeseWheel)), - new FillableEntry(1, typeof(CheeseWedge)), - new FillableEntry(1, typeof(CheeseSlice)), - new FillableEntry(1, typeof(Eggs)), - new FillableEntry(4, typeof(Fish)), - new FillableEntry(2, typeof(RawFishSteak)), - new FillableEntry(2, typeof(FishSteak)), - new FillableEntry(1, typeof(Apple)), - new FillableEntry(2, typeof(Banana)), - new FillableEntry(2, typeof(Bananas)), - new FillableEntry(2, typeof(OpenCoconut)), - new FillableEntry(1, typeof(SplitCoconut)), - new FillableEntry(1, typeof(Coconut)), - new FillableEntry(1, typeof(Dates)), - new FillableEntry(1, typeof(Grapes)), - new FillableEntry(1, typeof(Lemon)), - new FillableEntry(1, typeof(Lemons)), - new FillableEntry(1, typeof(Lime)), - new FillableEntry(1, typeof(Limes)), - new FillableEntry(1, typeof(Peach)), - new FillableEntry(1, typeof(Pear)), - new FillableEntry(2, typeof(SlabOfBacon)), - new FillableEntry(2, typeof(Bacon)), - new FillableEntry(2, typeof(CookedBird)), - new FillableEntry(2, typeof(RawBird)), - new FillableEntry(2, typeof(Ham)), - new FillableEntry(1, typeof(RawLambLeg)), - new FillableEntry(1, typeof(LambLeg)), - new FillableEntry(1, typeof(Ribs)), - new FillableEntry(1, typeof(RawRibs)), - new FillableEntry(2, typeof(Sausage)), - new FillableEntry(1, typeof(RawChickenLeg)), - new FillableEntry(1, typeof(ChickenLeg)), - new FillableEntry(1, typeof(Watermelon)), - new FillableEntry(1, typeof(SmallWatermelon)), - new FillableEntry(3, typeof(Turnip)), - new FillableEntry(2, typeof(YellowGourd)), - new FillableEntry(2, typeof(GreenGourd)), - new FillableEntry(2, typeof(Pumpkin)), - new FillableEntry(1, typeof(SmallPumpkin)), - new FillableEntry(2, typeof(Onion)), - new FillableEntry(2, typeof(Lettuce)), - new FillableEntry(2, typeof(Squash)), - new FillableEntry(2, typeof(HoneydewMelon)), - new FillableEntry(1, typeof(Carrot)), - new FillableEntry(2, typeof(Cantaloupe)), - new FillableEntry(2, typeof(Cabbage)), - new FillableEntry(4, typeof(EarOfCorn)) - } - ); - - public static FillableContent Mill = new( - 1, - Array.Empty(), - new[] - { - new FillableEntry(1, typeof(SackFlour)) - } - ); - - public static FillableContent Mine = new( - 1, - new[] - { - typeof(Miner) - }, - new[] - { - new FillableEntry(2, typeof(Pickaxe)), - new FillableEntry(2, typeof(Shovel)), - new FillableEntry(2, typeof(IronIngot)), - // new FillableEntry( 2, typeof( IronOre ) ), TODO: Smaller Ore - new FillableEntry(1, typeof(ForgedMetal)) - } - ); - - public static FillableContent Observatory = new( - 1, - Array.Empty(), - new[] - { - new FillableEntry(2, typeof(Sextant)), - new FillableEntry(2, typeof(Clock)), - new FillableEntry(1, typeof(Spyglass)) - } - ); - - public static FillableContent Painter = new( - 1, - Array.Empty(), - new[] - { - new FillableEntry(1, typeof(PaintsAndBrush)), - new FillableEntry(2, typeof(PenAndInk)) - } - ); - - public static FillableContent Provisioner = new( - 1, - new[] - { - typeof(Provisioner) - }, - new[] - { - new FillableEntry(1, typeof(CheeseWheel)), - new FillableEntry(1, typeof(CheeseWedge)), - new FillableEntry(1, typeof(CheeseSlice)), - new FillableEntry(1, typeof(Eggs)), - new FillableEntry(4, typeof(Fish)), - new FillableEntry(1, typeof(DirtyFrypan)), - new FillableEntry(1, typeof(DirtyPan)), - new FillableEntry(1, typeof(DirtyKettle)), - new FillableEntry(1, typeof(DirtySmallRoundPot)), - new FillableEntry(1, typeof(DirtyRoundPot)), - new FillableEntry(1, typeof(DirtySmallPot)), - new FillableEntry(1, typeof(DirtyPot)), - new FillableEntry(1, typeof(Apple)), - new FillableEntry(2, typeof(Banana)), - new FillableEntry(2, typeof(Bananas)), - new FillableEntry(2, typeof(OpenCoconut)), - new FillableEntry(1, typeof(SplitCoconut)), - new FillableEntry(1, typeof(Coconut)), - new FillableEntry(1, typeof(Dates)), - new FillableEntry(1, typeof(Grapes)), - new FillableEntry(1, typeof(Lemon)), - new FillableEntry(1, typeof(Lemons)), - new FillableEntry(1, typeof(Lime)), - new FillableEntry(1, typeof(Limes)), - new FillableEntry(1, typeof(Peach)), - new FillableEntry(1, typeof(Pear)), - new FillableEntry(2, typeof(SlabOfBacon)), - new FillableEntry(2, typeof(Bacon)), - new FillableEntry(1, typeof(RawFishSteak)), - new FillableEntry(1, typeof(FishSteak)), - new FillableEntry(2, typeof(CookedBird)), - new FillableEntry(2, typeof(RawBird)), - new FillableEntry(2, typeof(Ham)), - new FillableEntry(1, typeof(RawLambLeg)), - new FillableEntry(1, typeof(LambLeg)), - new FillableEntry(1, typeof(Ribs)), - new FillableEntry(1, typeof(RawRibs)), - new FillableEntry(2, typeof(Sausage)), - new FillableEntry(1, typeof(RawChickenLeg)), - new FillableEntry(1, typeof(ChickenLeg)), - new FillableEntry(1, typeof(Watermelon)), - new FillableEntry(1, typeof(SmallWatermelon)), - new FillableEntry(3, typeof(Turnip)), - new FillableEntry(2, typeof(YellowGourd)), - new FillableEntry(2, typeof(GreenGourd)), - new FillableEntry(2, typeof(Pumpkin)), - new FillableEntry(1, typeof(SmallPumpkin)), - new FillableEntry(2, typeof(Onion)), - new FillableEntry(2, typeof(Lettuce)), - new FillableEntry(2, typeof(Squash)), - new FillableEntry(2, typeof(HoneydewMelon)), - new FillableEntry(1, typeof(Carrot)), - new FillableEntry(2, typeof(Cantaloupe)), - new FillableEntry(2, typeof(Cabbage)), - new FillableEntry(4, typeof(EarOfCorn)) - } - ); - - public static FillableContent Ranger = new( - 2, - new[] - { - typeof(Ranger), - typeof(RangerGuildmaster) - }, - new[] - { - new FillableEntry(2, typeof(StuddedChest)), - new FillableEntry(2, typeof(StuddedLegs)), - new FillableEntry(2, typeof(StuddedArms)), - new FillableEntry(2, typeof(StuddedGloves)), - new FillableEntry(1, typeof(StuddedGorget)), - - new FillableEntry(2, typeof(LeatherChest)), - new FillableEntry(2, typeof(LeatherLegs)), - new FillableEntry(2, typeof(LeatherArms)), - new FillableEntry(2, typeof(LeatherGloves)), - new FillableEntry(1, typeof(LeatherGorget)), - - new FillableEntry(2, typeof(FeatheredHat)), - new FillableEntry(1, typeof(CloseHelm)), - new FillableEntry(1, typeof(TallStrawHat)), - new FillableEntry(1, typeof(Bandana)), - new FillableEntry(1, typeof(Cloak)), - new FillableEntry(2, typeof(Boots)), - new FillableEntry(2, typeof(ThighBoots)), - - new FillableEntry(2, typeof(GnarledStaff)), - new FillableEntry(1, typeof(Whip)), - - new FillableEntry(2, typeof(Bow)), - new FillableEntry(2, typeof(Crossbow)), - new FillableEntry(2, typeof(HeavyCrossbow)), - new FillableEntry(4, typeof(Arrow)) - } - ); - - public static FillableContent Stables = new( - 1, - new[] - { - typeof(AnimalTrainer), - typeof(GypsyAnimalTrainer) - }, - new[] - { - // new FillableEntry( 1, typeof( Wheat ) ), - new FillableEntry(1, typeof(Carrot)) - } - ); - - public static FillableContent Tanner = new( - 2, - new[] - { - typeof(Tanner), - typeof(LeatherWorker), - typeof(Furtrader) - }, - new[] - { - new FillableEntry(1, typeof(FeatheredHat)), - new FillableEntry(1, typeof(LeatherArms)), - new FillableEntry(2, typeof(LeatherLegs)), - new FillableEntry(2, typeof(LeatherChest)), - new FillableEntry(2, typeof(LeatherGloves)), - new FillableEntry(1, typeof(LeatherGorget)), - new FillableEntry(2, typeof(Leather)) - } - ); - - public static FillableContent Tavern = new( - 1, - new[] - { - typeof(TavernKeeper), - typeof(Barkeeper), - typeof(Waiter), - typeof(Cook) - }, - new FillableEntry[] - { - new FillableBvrge(1, typeof(BeverageBottle), BeverageType.Ale), - new FillableBvrge(1, typeof(BeverageBottle), BeverageType.Wine), - new FillableBvrge(1, typeof(BeverageBottle), BeverageType.Liquor), - new FillableBvrge(1, typeof(Jug), BeverageType.Cider) - } - ); - - public static FillableContent ThiefGuild = new( - 1, - new[] - { - typeof(Thief), - typeof(ThiefGuildmaster) - }, - new[] - { - new FillableEntry(1, typeof(Lockpick)), - new FillableEntry(1, typeof(BearMask)), - new FillableEntry(1, typeof(DeerMask)), - new FillableEntry(1, typeof(TribalMask)), - new FillableEntry(1, typeof(HornedTribalMask)), - new FillableEntry(4, typeof(OrcHelm)) - } - ); - - public static FillableContent Tinker = new( - 1, - new[] - { - typeof(Tinker), - typeof(TinkerGuildmaster) - }, - new[] - { - new FillableEntry(1, typeof(Lockpick)), - // new FillableEntry( 1, typeof( KeyRing ) ), - new FillableEntry(2, typeof(Clock)), - new FillableEntry(2, typeof(ClockParts)), - new FillableEntry(2, typeof(AxleGears)), - new FillableEntry(2, typeof(Gears)), - new FillableEntry(2, typeof(Hinge)), - // new FillableEntry( 1, typeof( ArrowShafts ) ), - new FillableEntry(2, typeof(Sextant)), - new FillableEntry(2, typeof(SextantParts)), - new FillableEntry(2, typeof(Axle)), - new FillableEntry(2, typeof(Springs)), - new FillableEntry(5, typeof(TinkerTools)), - new FillableEntry(4, typeof(Key)), - new FillableEntry(1, typeof(DecoArrowShafts)), - new FillableEntry(1, typeof(Lockpicks)), - new FillableEntry(1, typeof(ToolKit)) - } - ); - - public static FillableContent Veterinarian = new( - 1, - new[] - { - typeof(Veterinarian) - }, - new[] - { - new FillableEntry(1, typeof(Bandage)), - new FillableEntry(1, typeof(MortarPestle)), - new FillableEntry(1, typeof(LesserHealPotion)), - // new FillableEntry( 1, typeof( Wheat ) ), - new FillableEntry(1, typeof(Carrot)) - } - ); - - public static FillableContent Weaponsmith = new( - 2, - new[] - { - typeof(Weaponsmith) - }, - new[] - { - new FillableEntry(8, Loot.WeaponTypes), - new FillableEntry(1, typeof(Arrow)) - } - ); - - private static Dictionary m_AcquireTable; - - private static readonly FillableContent[] m_ContentTypes = - { - Weaponsmith, Provisioner, Mage, - Alchemist, Armorer, ArtisanGuild, - Baker, Bard, Blacksmith, - Bowyer, Butcher, Carpenter, - Clothier, Cobbler, Docks, - Farm, FighterGuild, Guard, - Healer, Herbalist, Inn, - Jeweler, Library, Merchant, - Mill, Mine, Observatory, - Painter, Ranger, Stables, - Tanner, Tavern, ThiefGuild, - Tinker, Veterinarian - }; - - private readonly FillableEntry[] m_Entries; - private readonly int m_Weight; - - public FillableContent(int level, Type[] vendors, FillableEntry[] entries) - { - Level = level; - Vendors = vendors; - m_Entries = entries; - - for (var i = 0; i < entries.Length; ++i) - { - m_Weight += entries[i].Weight; - } - } - - public int Level { get; } - - public Type[] Vendors { get; } - - public FillableContentType TypeID => Lookup(this); - - public virtual Item Construct() - { - var index = Utility.Random(m_Weight); - - for (var i = 0; i < m_Entries.Length; ++i) - { - var entry = m_Entries[i]; - - if (index < entry.Weight) - { - return entry.Construct(); - } - - index -= entry.Weight; - } - - return null; - } - - public static FillableContent Lookup(FillableContentType type) - { - var v = (int)type; - - if (v >= 0 && v < m_ContentTypes.Length) - { - return m_ContentTypes[v]; - } - - return null; - } - - public static FillableContentType Lookup(FillableContent content) - { - if (content == null) - { - return FillableContentType.None; - } - - return (FillableContentType)Array.IndexOf(m_ContentTypes, content); - } - - public static FillableContent Acquire(Point3D loc, Map map) - { - if (map == null || map == Map.Internal) - { - return null; - } - - if (m_AcquireTable == null) - { - m_AcquireTable = new Dictionary(); - - for (var i = 0; i < m_ContentTypes.Length; ++i) - { - var fill = m_ContentTypes[i]; - - for (var j = 0; j < fill.Vendors.Length; ++j) - { - m_AcquireTable[fill.Vendors[j]] = fill; - } - } - } - - Mobile nearest = null; - FillableContent content = null; - - foreach (var mob in map.GetMobilesInRange(loc, 20)) - { - if (nearest != null && mob.GetDistanceToSqrt(loc) > nearest.GetDistanceToSqrt(loc) && - !(nearest is Cobbler && mob is Provisioner)) - { - continue; - } - - if (m_AcquireTable.TryGetValue(mob.GetType(), out var check)) - { - nearest = mob; - content = check; - } - } - - return content; - } - } -} diff --git a/Projects/UOContent/Migrations/Server.Items.FillableBarrel.v0.json b/Projects/UOContent/Migrations/Server.Items.FillableBarrel.v0.json new file mode 100644 index 000000000..755fca3f0 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.FillableBarrel.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.FillableBarrel" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.FillableContainer.v2.json b/Projects/UOContent/Migrations/Server.Items.FillableContainer.v2.json new file mode 100644 index 000000000..bb0c8c156 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.FillableContainer.v2.json @@ -0,0 +1,19 @@ +{ + "version": 2, + "type": "Server.Items.FillableContainer", + "properties": [ + { + "name": "RawContentType", + "type": "Server.Items.FillableContentType", + "rule": "EnumMigrationRule" + }, + { + "name": "RespawnTimer", + "type": "Server.Timer", + "rule": "TimerMigrationRule", + "ruleArguments": [ + "@TimerDrift" + ] + } + ] +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.FillableLargeCrate.v0.json b/Projects/UOContent/Migrations/Server.Items.FillableLargeCrate.v0.json new file mode 100644 index 000000000..55a56b0dc --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.FillableLargeCrate.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.FillableLargeCrate" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.FillableMetalBox.v0.json b/Projects/UOContent/Migrations/Server.Items.FillableMetalBox.v0.json new file mode 100644 index 000000000..7a1fc83d4 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.FillableMetalBox.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.FillableMetalBox" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.FillableMetalChest.v0.json b/Projects/UOContent/Migrations/Server.Items.FillableMetalChest.v0.json new file mode 100644 index 000000000..43282f2ba --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.FillableMetalChest.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.FillableMetalChest" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.FillableMetalGoldenChest.v0.json b/Projects/UOContent/Migrations/Server.Items.FillableMetalGoldenChest.v0.json new file mode 100644 index 000000000..c96422f5f --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.FillableMetalGoldenChest.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.FillableMetalGoldenChest" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.FillableSmallCrate.v0.json b/Projects/UOContent/Migrations/Server.Items.FillableSmallCrate.v0.json new file mode 100644 index 000000000..ad9907a95 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.FillableSmallCrate.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.FillableSmallCrate" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.FillableWoodenBox.v0.json b/Projects/UOContent/Migrations/Server.Items.FillableWoodenBox.v0.json new file mode 100644 index 000000000..c81a4abf8 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.FillableWoodenBox.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.FillableWoodenBox" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.FillableWoodenChest.v0.json b/Projects/UOContent/Migrations/Server.Items.FillableWoodenChest.v0.json new file mode 100644 index 000000000..ec2d74b8d --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.FillableWoodenChest.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.FillableWoodenChest" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.LibraryBookcase.v0.json b/Projects/UOContent/Migrations/Server.Items.LibraryBookcase.v0.json new file mode 100644 index 000000000..3c1812b6f --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.LibraryBookcase.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.LibraryBookcase" +} \ No newline at end of file