using System; using ModernUO.Serialization; using Server.Engines.Craft; namespace Server.Items; [SerializationGenerator(1, false)] public partial class BaseQuiver : Container, ICraftable, IAosItem { private static Type[] m_Ammo = { typeof(Arrow), typeof(Bolt) }; [SerializedIgnoreDupe] [SerializableField(0, setter: "private")] [SerializedCommandProperty(AccessLevel.GameMaster, canModify: true)] private AosAttributes _attributes; [SerializableFieldSaveFlag(0)] private bool ShouldSerializeAosAttributes() => !_attributes.IsEmpty; [SerializableFieldDefault(0)] private AosAttributes AttributesDefaultValue() => new(this); [InvalidateProperties] [SerializableField(1)] [SerializedCommandProperty(AccessLevel.GameMaster)] private int _lowerAmmoCost; [SerializableFieldSaveFlag(1)] private bool ShouldSerializeLowerAmmoCost() => _lowerAmmoCost != 0; [InvalidateProperties] [SerializableField(2)] [SerializedCommandProperty(AccessLevel.GameMaster)] private int _weightReduction; [SerializableFieldSaveFlag(2)] private bool ShouldSerializeWeightReduction() => _weightReduction != 0; [InvalidateProperties] [SerializableField(3)] [SerializedCommandProperty(AccessLevel.GameMaster)] private int _damageIncrease; [SerializableFieldSaveFlag(3)] private bool ShouldSerializeDamageIncrease() => _damageIncrease != 0; [InvalidateProperties] [SerializableField(4)] [SerializedCommandProperty(AccessLevel.GameMaster)] private string _crafter; [SerializableFieldSaveFlag(4)] private bool ShouldSerializeCrafter() => !string.IsNullOrEmpty(_crafter); [InvalidateProperties] [SerializableField(5)] [SerializedCommandProperty(AccessLevel.GameMaster)] private ClothingQuality _quality; [SerializableFieldSaveFlag(5)] private bool ShouldSerializeQuality() => _quality != ClothingQuality.Regular; [SerializableFieldDefault(5)] private ClothingQuality QualityDefaultValue() => ClothingQuality.Regular; [InvalidateProperties] [SerializableField(6)] [SerializedCommandProperty(AccessLevel.GameMaster)] private int _capacity; [SerializableFieldSaveFlag(6)] private bool ShouldSerializeCapacity() => _capacity != 0; public BaseQuiver(int itemID = 0x2FB7) : base(itemID) { Capacity = 500; Layer = Layer.Cloak; Attributes = new AosAttributes(this); DamageIncrease = 10; } public override int DefaultGumpID => 0x108; public override int DefaultMaxItems => 1; public override int DefaultMaxWeight => 50; public override double DefaultWeight => 2.0; public Item Ammo => Items.Count > 0 ? Items[0] : null; public virtual int OnCraft( int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, CraftItem craftItem, int resHue ) { Quality = (ClothingQuality)quality; if (makersMark) { Crafter = from.RawName; } return quality; } public override void OnAfterDuped(Item newItem) { if (newItem is not BaseQuiver quiver) { return; } quiver.Attributes = new AosAttributes(newItem, Attributes); } public override void UpdateTotal(Item sender, TotalType type, int delta) { InvalidateProperties(); base.UpdateTotal(sender, type, delta); } public override int GetTotal(TotalType type) { var total = base.GetTotal(type); if (type == TotalType.Weight) { total -= total * _weightReduction / 100; } return total; } public bool CheckType(Item item) { var type = item.GetType(); var ammo = Ammo; if (ammo != null) { if (ammo.GetType() == type) { return true; } } else { for (var i = 0; i < m_Ammo.Length; i++) { if (type == m_Ammo[i]) { return true; } } } return false; } public override bool CheckHold(Mobile m, Item item, bool message, bool checkItems, int plusItems, int plusWeight) { if (!CheckType(item)) { if (message) { m.SendLocalizedMessage( 1074836 ); // The container can not hold that type of object. } return false; } if (Items.Count < DefaultMaxItems) { return item.Amount <= _capacity && base.CheckHold(m, item, message, checkItems, plusItems, plusWeight); } if (checkItems) { return false; } var ammo = Ammo; return ammo?.Deleted == false && ammo.Amount + item.Amount <= _capacity; } public override void AddItem(Item dropped) { base.AddItem(dropped); InvalidateWeight(); } public override void RemoveItem(Item dropped) { base.RemoveItem(dropped); InvalidateWeight(); } public override void OnAdded(IEntity parent) { if (parent is Mobile mob) { Attributes.AddStatBonuses(mob); } } public override void OnRemoved(IEntity parent) { if (parent is Mobile mob) { Attributes.RemoveStatBonuses(mob); } } public override void GetProperties(IPropertyList list) { base.GetProperties(list); if (_crafter != null) { list.Add(1050043, _crafter); // crafted by ~1_NAME~ } if (_quality == ClothingQuality.Exceptional) { list.Add(1063341); // exceptional } var ammo = Ammo; if (ammo == null) { list.Add(1075265, $"{"0"}\t{Capacity}"); // Ammo: ~1_QUANTITY~/~2_CAPACITY~ arrows } else if (ammo is Arrow) { list.Add(1075265, $"{ammo.Amount}\t{Capacity}"); // Ammo: ~1_QUANTITY~/~2_CAPACITY~ arrows } else if (ammo is Bolt) { list.Add(1075266, $"{ammo.Amount}\t{Capacity}"); // Ammo: ~1_QUANTITY~/~2_CAPACITY~ bolts } int prop; if ((prop = _damageIncrease) != 0) { list.Add(1074762, prop); // Damage modifier: ~1_PERCENT~% } int phys = 0, fire = 0, cold = 0, pois = 0, nrgy = 0, chaos = 0, direct = 0; AlterBowDamage(ref phys, ref fire, ref cold, ref pois, ref nrgy, ref chaos, ref direct); if (phys != 0) { list.Add(1060403, phys); // physical damage ~1_val~% } if (fire != 0) { list.Add(1060405, fire); // fire damage ~1_val~% } if (cold != 0) { list.Add(1060404, cold); // cold damage ~1_val~% } if (pois != 0) { list.Add(1060406, pois); // poison damage ~1_val~% } if (nrgy != 0) { list.Add(1060407, nrgy); // energy damage ~1_val } if (chaos != 0) { list.Add(1072846, chaos); // chaos damage ~1_val~% } if (direct != 0) { list.Add(1079978, direct); // Direct Damage: ~1_PERCENT~% } list.Add(1075085); // Requirement: Mondain's Legacy if ((prop = Attributes.DefendChance) != 0) { list.Add(1060408, prop); // defense chance increase ~1_val~% } if ((prop = Attributes.BonusDex) != 0) { list.Add(1060409, prop); // dexterity bonus ~1_val~ } if ((prop = Attributes.EnhancePotions) != 0) { list.Add(1060411, prop); // enhance potions ~1_val~% } if ((prop = Attributes.CastRecovery) != 0) { list.Add(1060412, prop); // faster cast recovery ~1_val~ } if ((prop = Attributes.CastSpeed) != 0) { list.Add(1060413, prop); // faster casting ~1_val~ } if ((prop = Attributes.AttackChance) != 0) { list.Add(1060415, prop); // hit chance increase ~1_val~% } if ((prop = Attributes.BonusHits) != 0) { list.Add(1060431, prop); // hit point increase ~1_val~ } if ((prop = Attributes.BonusInt) != 0) { list.Add(1060432, prop); // intelligence bonus ~1_val~ } if ((prop = Attributes.LowerManaCost) != 0) { list.Add(1060433, prop); // lower mana cost ~1_val~% } if ((prop = Attributes.LowerRegCost) != 0) { list.Add(1060434, prop); // lower reagent cost ~1_val~% } if ((prop = Attributes.Luck) != 0) { list.Add(1060436, prop); // luck ~1_val~ } if ((prop = Attributes.BonusMana) != 0) { list.Add(1060439, prop); // mana increase ~1_val~ } if ((prop = Attributes.RegenMana) != 0) { list.Add(1060440, prop); // mana regeneration ~1_val~ } if (Attributes.NightSight != 0) { list.Add(1060441); // night sight } if ((prop = Attributes.ReflectPhysical) != 0) { list.Add(1060442, prop); // reflect physical damage ~1_val~% } if ((prop = Attributes.RegenStam) != 0) { list.Add(1060443, prop); // stamina regeneration ~1_val~ } if ((prop = Attributes.RegenHits) != 0) { list.Add(1060444, prop); // hit point regeneration ~1_val~ } if ((prop = Attributes.SpellDamage) != 0) { list.Add(1060483, prop); // spell damage increase ~1_val~% } if ((prop = Attributes.BonusStam) != 0) { list.Add(1060484, prop); // stamina increase ~1_val~ } if ((prop = Attributes.BonusStr) != 0) { list.Add(1060485, prop); // strength bonus ~1_val~ } if ((prop = Attributes.WeaponSpeed) != 0) { list.Add(1060486, prop); // swing speed increase ~1_val~% } if ((prop = _lowerAmmoCost) > 0) { list.Add(1075208, prop); // Lower Ammo Cost ~1_Percentage~% } var weight = ammo != null ? ammo.Weight + ammo.Amount : 0; list.Add( 1072241, // Contents: ~1_COUNT~/~2_MAXCOUNT items, ~3_WEIGHT~/~4_MAXWEIGHT~ stones $"{Items.Count}\t{DefaultMaxItems}\t{(int)weight}\t{DefaultMaxWeight}" ); if ((prop = _weightReduction) != 0) { list.Add(1072210, prop); // Weight reduction: ~1_PERCENTAGE~% } } private void Deserialize(IGenericReader reader, int version) { var flags = reader.ReadEncodedInt(); _attributes = new AosAttributes(this); if ((flags & 0x1) != 0) { _attributes.Deserialize(reader); } if ((flags & 0x4) != 0) { _lowerAmmoCost = reader.ReadInt(); } if ((flags & 0x8) != 0) { _weightReduction = reader.ReadInt(); } if ((flags & 0x80) != 0) { _damageIncrease = reader.ReadInt(); } if ((flags & 0x10) != 0) { Timer.DelayCall((item, crafter) => item._crafter = crafter?.RawName, this, reader.ReadEntity()); } if ((flags & 0x20) != 0) { _quality = (ClothingQuality)reader.ReadInt(); } if ((flags & 0x40) != 0) { _capacity = reader.ReadInt(); } } public virtual void AlterBowDamage( ref int phys, ref int fire, ref int cold, ref int pois, ref int nrgy, ref int chaos, ref int direct ) { } public void InvalidateWeight() { if (RootParent is Mobile m) { m.UpdateTotals(); } } }