using System; using Server.Engines.Craft; namespace Server.Items { public class BaseQuiver : Container, ICraftable { private static readonly Type[] m_Ammo = { typeof(Arrow), typeof(Bolt) }; private int m_Capacity; private Mobile m_Crafter; private int m_DamageIncrease; private int m_LowerAmmoCost; private ClothingQuality m_Quality; private int m_WeightReduction; public BaseQuiver(int itemID = 0x2FB7) : base(itemID) { Weight = 2.0; Capacity = 500; Layer = Layer.Cloak; Attributes = new AosAttributes(this); DamageIncrease = 10; } public BaseQuiver(Serial serial) : base(serial) { } public override int DefaultGumpID => 0x108; public override int DefaultMaxItems => 1; public override int DefaultMaxWeight => 50; public override double DefaultWeight => 2.0; [CommandProperty(AccessLevel.GameMaster, canModify: true)] public AosAttributes Attributes { get; private set; } [CommandProperty(AccessLevel.GameMaster)] public int Capacity { get => m_Capacity; set { m_Capacity = value; InvalidateProperties(); } } [CommandProperty(AccessLevel.GameMaster)] public int LowerAmmoCost { get => m_LowerAmmoCost; set { m_LowerAmmoCost = value; InvalidateProperties(); } } [CommandProperty(AccessLevel.GameMaster)] public int WeightReduction { get => m_WeightReduction; set { m_WeightReduction = value; InvalidateProperties(); } } [CommandProperty(AccessLevel.GameMaster)] public int DamageIncrease { get => m_DamageIncrease; set { m_DamageIncrease = value; InvalidateProperties(); } } [CommandProperty(AccessLevel.GameMaster)] public Mobile Crafter { get => m_Crafter; set { m_Crafter = value; InvalidateProperties(); } } [CommandProperty(AccessLevel.GameMaster)] public ClothingQuality Quality { get => m_Quality; set { m_Quality = value; InvalidateProperties(); } } 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; } return quality; } public override void OnAfterDuped(Item newItem) { if (!(newItem is 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 * m_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)) { return Items.Count >= DefaultMaxItems && !checkItems && Ammo?.Deleted == false && Ammo.Amount + item.Amount <= m_Capacity || item.Amount <= m_Capacity && base.CheckHold(m, item, message, checkItems, plusItems, plusWeight); } if (message) { m.SendLocalizedMessage(1074836); // The container can not hold that type of object. } return false; } 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(ObjectPropertyList list) { base.GetProperties(list); if (m_Crafter != null) { list.Add(1050043, m_Crafter.Name); // crafted by ~1_NAME~ } if (m_Quality == ClothingQuality.Exceptional) { list.Add(1063341); // exceptional } var ammo = Ammo; if (ammo != null) { if (ammo is Arrow) { list.Add(1075265, "{0}\t{1}", ammo.Amount, Capacity); // Ammo: ~1_QUANTITY~/~2_CAPACITY~ arrows } else if (ammo is Bolt) { list.Add(1075266, "{0}\t{1}", ammo.Amount, Capacity); // Ammo: ~1_QUANTITY~/~2_CAPACITY~ bolts } } else { list.Add(1075265, "{0}\t{1}", 0, Capacity); // Ammo: ~1_QUANTITY~/~2_CAPACITY~ arrows } int prop; if ((prop = m_DamageIncrease) != 0) { list.Add(1074762, prop.ToString()); // Damage modifier: ~1_PERCENT~% } AlterBowDamage( out var phys, out var fire, out var cold, out var pois, out var nrgy, out var chaos, out var direct ); if (phys != 0) { list.Add(1060403, phys.ToString()); // physical damage ~1_val~% } if (fire != 0) { list.Add(1060405, fire.ToString()); // fire damage ~1_val~% } if (cold != 0) { list.Add(1060404, cold.ToString()); // cold damage ~1_val~% } if (pois != 0) { list.Add(1060406, pois.ToString()); // poison damage ~1_val~% } if (nrgy != 0) { list.Add(1060407, nrgy.ToString()); // energy damage ~1_val } if (chaos != 0) { list.Add(1072846, chaos.ToString()); // chaos damage ~1_val~% } if (direct != 0) { list.Add(1079978, direct.ToString()); // Direct Damage: ~1_PERCENT~% } list.Add(1075085); // Requirement: Mondain's Legacy if ((prop = Attributes.DefendChance) != 0) { list.Add(1060408, prop.ToString()); // defense chance increase ~1_val~% } if ((prop = Attributes.BonusDex) != 0) { list.Add(1060409, prop.ToString()); // dexterity bonus ~1_val~ } if ((prop = Attributes.EnhancePotions) != 0) { list.Add(1060411, prop.ToString()); // enhance potions ~1_val~% } if ((prop = Attributes.CastRecovery) != 0) { list.Add(1060412, prop.ToString()); // faster cast recovery ~1_val~ } if ((prop = Attributes.CastSpeed) != 0) { list.Add(1060413, prop.ToString()); // faster casting ~1_val~ } if ((prop = Attributes.AttackChance) != 0) { list.Add(1060415, prop.ToString()); // hit chance increase ~1_val~% } if ((prop = Attributes.BonusHits) != 0) { list.Add(1060431, prop.ToString()); // hit point increase ~1_val~ } if ((prop = Attributes.BonusInt) != 0) { list.Add(1060432, prop.ToString()); // intelligence bonus ~1_val~ } if ((prop = Attributes.LowerManaCost) != 0) { list.Add(1060433, prop.ToString()); // lower mana cost ~1_val~% } if ((prop = Attributes.LowerRegCost) != 0) { list.Add(1060434, prop.ToString()); // lower reagent cost ~1_val~% } if ((prop = Attributes.Luck) != 0) { list.Add(1060436, prop.ToString()); // luck ~1_val~ } if ((prop = Attributes.BonusMana) != 0) { list.Add(1060439, prop.ToString()); // mana increase ~1_val~ } if ((prop = Attributes.RegenMana) != 0) { list.Add(1060440, prop.ToString()); // mana regeneration ~1_val~ } if (Attributes.NightSight != 0) { list.Add(1060441); // night sight } if ((prop = Attributes.ReflectPhysical) != 0) { list.Add(1060442, prop.ToString()); // reflect physical damage ~1_val~% } if ((prop = Attributes.RegenStam) != 0) { list.Add(1060443, prop.ToString()); // stamina regeneration ~1_val~ } if ((prop = Attributes.RegenHits) != 0) { list.Add(1060444, prop.ToString()); // hit point regeneration ~1_val~ } if ((prop = Attributes.SpellDamage) != 0) { list.Add(1060483, prop.ToString()); // spell damage increase ~1_val~% } if ((prop = Attributes.BonusStam) != 0) { list.Add(1060484, prop.ToString()); // stamina increase ~1_val~ } if ((prop = Attributes.BonusStr) != 0) { list.Add(1060485, prop.ToString()); // strength bonus ~1_val~ } if ((prop = Attributes.WeaponSpeed) != 0) { list.Add(1060486, prop.ToString()); // swing speed increase ~1_val~% } if ((prop = m_LowerAmmoCost) > 0) { list.Add(1075208, prop.ToString()); // Lower Ammo Cost ~1_Percentage~% } var weight = ammo != null ? ammo.Weight + ammo.Amount : 0; list.Add( 1072241, "{0}\t{1}\t{2}\t{3}", Items.Count, DefaultMaxItems, (int)weight, DefaultMaxWeight ); // Contents: ~1_COUNT~/~2_MAXCOUNT items, ~3_WEIGHT~/~4_MAXWEIGHT~ stones if ((prop = m_WeightReduction) != 0) { list.Add(1072210, prop.ToString()); // Weight reduction: ~1_PERCENTAGE~% } } private static void SetSaveFlag(ref SaveFlag flags, SaveFlag toSet, bool setIf) { if (setIf) { flags |= toSet; } } private static bool GetSaveFlag(SaveFlag flags, SaveFlag toGet) => (flags & toGet) != 0; public override void Serialize(IGenericWriter writer) { base.Serialize(writer); writer.Write(0); // version var flags = SaveFlag.None; SetSaveFlag(ref flags, SaveFlag.Attributes, !Attributes.IsEmpty); SetSaveFlag(ref flags, SaveFlag.LowerAmmoCost, m_LowerAmmoCost != 0); SetSaveFlag(ref flags, SaveFlag.WeightReduction, m_WeightReduction != 0); SetSaveFlag(ref flags, SaveFlag.DamageIncrease, m_DamageIncrease != 0); SetSaveFlag(ref flags, SaveFlag.Crafter, m_Crafter != null); SetSaveFlag(ref flags, SaveFlag.Quality, true); SetSaveFlag(ref flags, SaveFlag.Capacity, m_Capacity > 0); writer.WriteEncodedInt((int)flags); if (GetSaveFlag(flags, SaveFlag.Attributes)) { Attributes.Serialize(writer); } if (GetSaveFlag(flags, SaveFlag.LowerAmmoCost)) { writer.Write(m_LowerAmmoCost); } if (GetSaveFlag(flags, SaveFlag.WeightReduction)) { writer.Write(m_WeightReduction); } if (GetSaveFlag(flags, SaveFlag.DamageIncrease)) { writer.Write(m_DamageIncrease); } if (GetSaveFlag(flags, SaveFlag.Crafter)) { writer.Write(m_Crafter); } if (GetSaveFlag(flags, SaveFlag.Quality)) { writer.Write((int)m_Quality); } if (GetSaveFlag(flags, SaveFlag.Capacity)) { writer.Write(m_Capacity); } } public override void Deserialize(IGenericReader reader) { base.Deserialize(reader); var version = reader.ReadInt(); var flags = (SaveFlag)reader.ReadEncodedInt(); Attributes = new AosAttributes(this); if (GetSaveFlag(flags, SaveFlag.Attributes)) { Attributes.Deserialize(reader); } if (GetSaveFlag(flags, SaveFlag.LowerAmmoCost)) { m_LowerAmmoCost = reader.ReadInt(); } if (GetSaveFlag(flags, SaveFlag.WeightReduction)) { m_WeightReduction = reader.ReadInt(); } if (GetSaveFlag(flags, SaveFlag.DamageIncrease)) { m_DamageIncrease = reader.ReadInt(); } if (GetSaveFlag(flags, SaveFlag.Crafter)) { m_Crafter = reader.ReadEntity(); } if (GetSaveFlag(flags, SaveFlag.Quality)) { m_Quality = (ClothingQuality)reader.ReadInt(); } if (GetSaveFlag(flags, SaveFlag.Capacity)) { m_Capacity = reader.ReadInt(); } } public virtual void AlterBowDamage( out int phys, out int fire, out int cold, out int pois, out int nrgy, out int chaos, out int direct ) { phys = fire = cold = pois = nrgy = chaos = direct = 0; } public void InvalidateWeight() { if (RootParent is Mobile m) { m.UpdateTotals(); } } [Flags] private enum SaveFlag { None = 0x00000000, Attributes = 0x00000001, DamageModifier = 0x00000002, LowerAmmoCost = 0x00000004, WeightReduction = 0x00000008, Crafter = 0x00000010, Quality = 0x00000020, Capacity = 0x00000040, DamageIncrease = 0x00000080 } } }