Basically I'm tired of stats like Hit Fireball on weapons being complete %'s. So what I am wondering is how can I change it to be something like 23.4% chance. I'd also like to experiment with skills going to the hundredth's place to see how it is.
 
Start here; (Line 3,347)
https://github.com/ServUO/ServUO/blob/master/Scripts/Misc/AOS.cs#L3347

Change 'int' to 'double' and be prepared to fix about 500 compile errors. :/

If you do decide to go through with it, you also need to update the Deserialize method to be sure it's using ReadDouble(). It currently uses ReadInt() which is implicitly convertible to double and won't give you any errors or hints about it, causing world load errors.
 
I'm curious when this comes up. In looking at how properties are distributed, there aren't many (any?) times where the prop is first generated as a double.

I suppose this could apply to some of the skill generated property buffs, but that seems like a corner case in the grand scheme of properties.

Any insight as to when you find properties as rounded doubles?
 
I'll give it a shot, I love tearing my server a new one. I'll update on my findings.


Code:
public int GetValue(int bitmask)
        {
            if (!Core.AOS)
                return 0;
          
            uint mask = (uint)bitmask;
      
            if ((this.m_Names & mask) == 0)
                return 0;

            int index = this.GetIndex(mask);
      
            if (index >= 0 && index < this.m_Values.Length)
                return this.m_Values[index];<-----------

            return 0;
        }

My last error that I have for right now is this line, Cannot implicitly convert type 'double' to 'int'. An explicit conversion exists (are you missing a cast?). So far what i have done is change

private int[] m_Values; to public double[] m_Values;

I feel the error lies somewhere within the index (or the uint mask). Somehow i feel like if I could get it to be a double it would then generate a new list of errors that'll need to be ironed out. Any help with this one to assist me in moving forward would be much appreciated.


Code:
 [PropertyObject]
    public abstract class BaseAttributes
    {
        private readonly Item m_Owner;
        private uint m_Names;
        public double[] m_Values;

        private static readonly double[] m_Empty = new double[0];

        public bool IsEmpty
        {
            get
            {
                return (this.m_Names == 0);
            }
        }
        public Item Owner
        {
            get
            {
                return this.m_Owner;
            }
        }

        public BaseAttributes(Item owner)
        {
            this.m_Owner = owner;
            this.m_Values = m_Empty;
        }

        public BaseAttributes(Item owner, BaseAttributes other)
        {
            this.m_Owner = owner;
            this.m_Values = new double[other.m_Values.Length];
            other.m_Values.CopyTo(this.m_Values, 0);
            this.m_Names = other.m_Names;
        }

        public BaseAttributes(Item owner, GenericReader reader)
        {
            this.m_Owner = owner;

            int version = reader.ReadByte();

            switch (version)
            {
                case 1:
                    {
                        this.m_Names = reader.ReadUInt();
                        this.m_Values = new double[reader.ReadEncodedInt()];

                        for (int i = 0; i < this.m_Values.Length; ++i)
                            this.m_Values[i] = reader.ReadEncodedInt();

                        break;
                    }
                case 0:
                    {
                        this.m_Names = reader.ReadUInt();
                        this.m_Values = new double[reader.ReadInt()];

                        for (int i = 0; i < this.m_Values.Length; ++i)
                            this.m_Values[i] = reader.ReadInt();

                        break;
                    }
            }
        }

        public void Serialize(GenericWriter writer)
        {
            writer.Write((byte)1); // version;

            writer.Write((uint)this.m_Names);
            writer.WriteEncodedInt((int)this.m_Values.Length);

            for (int i = 0; i < this.m_Values.Length; ++i)
                writer.WriteEncodedInt((int)this.m_Values[i]);
        }

        public int GetValue(int bitmask)
        {
            if (!Core.AOS)
                return 0;
           
            uint mask = (uint)bitmask;
       
            if ((this.m_Names & mask) == 0)
                return 0;

            int index = this.GetIndex(mask);
       
            if (index >= 0 && index < this.m_Values.Length)
                return this.m_Values[index];

            return 0;
        }

        public void SetValue(int bitmask, int value)
        {
            if ((bitmask == (int)AosWeaponAttribute.DurabilityBonus) && (this is AosWeaponAttributes))
            {
                if (this.m_Owner is BaseWeapon)
                    ((BaseWeapon)this.m_Owner).UnscaleDurability();
            }
            else if ((bitmask == (int)AosArmorAttribute.DurabilityBonus) && (this is AosArmorAttributes))
            {
                if (this.m_Owner is BaseArmor)
                    ((BaseArmor)this.m_Owner).UnscaleDurability();
                else if (this.m_Owner is BaseClothing)
                    ((BaseClothing)this.m_Owner).UnscaleDurability();
            }
            else if (Core.SA && bitmask == (int)AosAttribute.WeaponSpeed && m_Owner is BaseWeapon)
            {
                ((BaseWeapon)m_Owner).WeaponAttributes.ScaleLeech((BaseWeapon)m_Owner, value);
            }

            uint mask = (uint)bitmask;

            if (value != 0)
            {
                if ((this.m_Names & mask) != 0)
                {
                    int index = this.GetIndex(mask);

                    if (index >= 0 && index < this.m_Values.Length)
                        this.m_Values[index] = value;
                }
                else
                {
                    int index = this.GetIndex(mask);

                    if (index >= 0 && index <= this.m_Values.Length)
                    {
                        double[] old = this.m_Values;
                        this.m_Values = new double[old.Length + 1];

                        for (int i = 0; i < index; ++i)
                            this.m_Values[i] = old[i];

                        this.m_Values[index] = value;

                        for (int i = index; i < old.Length; ++i)
                            this.m_Values[i + 1] = old[i];

                        this.m_Names |= mask;
                    }
                }
            }
            else if ((this.m_Names & mask) != 0)
            {
                int index = this.GetIndex(mask);

                if (index >= 0 && index < this.m_Values.Length)
                {
                    this.m_Names &= ~mask;

                    if (this.m_Values.Length == 1)
                    {
                        this.m_Values = m_Empty;
                    }
                    else
                    {
                        double[] old = this.m_Values;
                        this.m_Values = new double[old.Length - 1];

                        for (int i = 0; i < index; ++i)
                            this.m_Values[i] = old[i];

                        for (int i = index + 1; i < old.Length; ++i)
                            this.m_Values[i - 1] = old[i];
                    }
                }
            }

            if ((bitmask == (int)AosWeaponAttribute.DurabilityBonus) && (this is AosWeaponAttributes))
            {
                if (this.m_Owner is BaseWeapon)
                    ((BaseWeapon)this.m_Owner).ScaleDurability();
            }
            else if ((bitmask == (int)AosArmorAttribute.DurabilityBonus) && (this is AosArmorAttributes))
            {
                if (this.m_Owner is BaseArmor)
                    ((BaseArmor)this.m_Owner).ScaleDurability();
                else if (this.m_Owner is BaseClothing)
                    ((BaseClothing)this.m_Owner).ScaleDurability();
            }

            if (this.m_Owner != null && this.m_Owner.Parent is Mobile)
            {
                Mobile m = (Mobile)this.m_Owner.Parent;

                m.CheckStatTimers();
                m.UpdateResistances();
                m.Delta(MobileDelta.Stat | MobileDelta.WeaponDamage | MobileDelta.Hits | MobileDelta.Stam | MobileDelta.Mana);

                if (this is AosSkillBonuses)
                {
                    ((AosSkillBonuses)this).Remove();
                    ((AosSkillBonuses)this).AddTo(m);
                }
            }

            if (this.m_Owner != null)
                this.m_Owner.InvalidateProperties();
        }

        private int GetIndex(uint mask)
        {
            int index = 0;
            uint ourNames = this.m_Names;
            uint currentBit = 1;

            while (currentBit != mask)
            {
                if ((ourNames & currentBit) != 0)
                    ++index;

                if (currentBit == 0x80000000)
                    return -1;

                currentBit <<= 1;
            }

            return index;
        }
    }
}

This is what I have done so far to get to where I am, I know it's not finished but it may come in handy in helping solve how to get non-complete percentages on items.
 
Last edited:
Back