UOGamers Community

This is a sample guest message. Register a free account today to become a member! Once signed in, you'll be able to participate on this site by adding your own topics and posts, as well as connect with other members through your own private inbox!

  • To obtain new Razor updates, please reinstall Razor from our new website.

runic hammer mods...

mytilus

Sorceror


hammerpick crafted with agapite hammer with only 3 mods, since this one has 46di it can't be explained as < 40di mod....
number of mods should be
gold 3-4
agapite 4-4
verite 4-5
valo 5-5

reference: http://www.uoguide.com/Runic_Tools
 

das3

Sorceror
It's 4 mods. DI (40 DI with arms lore, rolled 46 on the runic), FC1, HML and the elemental damage.
 

Kraz

AssistUO Developer
What if the random elemental damage was applied and it happened to be the same as a standard agapite weapon?
Maybe checking if the item color differs from standard agapite crafted items? Not sure but that random elemental damage may use a different color set.
 

mytilus

Sorceror
if that is even possible then that could explain it i suppose, but i thought it would take some/all out of physical and put it into an elemental? or does that only apply for enhancing?

if anybody can point me in the right direction I would enjoy checking into this myself but so far RunicHammer.cs and a few others i have tried don't seem to be of any help...
 

Kraz

AssistUO Developer
Yes that is weird... anyways right direction would be:
Scripts\Items\Skill Items\Tools\BaseRunicTool.cs
Scripts\Misc\ResourceInfo.cs
 

mytilus

Sorceror
CraftAttributeInfoagapite=Agapite=newCraftAttributeInfo();
agapite.ArmorPhysicalResist = 2;
agapite.ArmorFireResist = 3;
agapite.ArmorColdResist = 2;
agapite.ArmorPoisonResist = 2;
agapite.ArmorEnergyResist = 2;
agapite.WeaponColdDamage = 30;
agapite.WeaponEnergyDamage = 20;
agapite.RunicMinAttributes = 4;
agapite.RunicMaxAttributes = 4;
if ( Core.ML )
{
agapite.RunicMinIntensity = 65;
agapite.RunicMaxIntensity = 100;
}
else
{
agapite.RunicMinIntensity = 40;
agapite.RunicMaxIntensity = 80;
}

Looks like it should be right unless its a strange bug someplace else, I checked color of weapon too and its ordinary agapite, normally elemental change will give weapon a different color. Is there still a test server running someplace in the interwebs? =]
 

kolbycrouch

Knight
I've noticed this several times will all the hammers, however I thought it was a bump in durability that was being considered a mod.
 

MrSunday

Sorceror
I've noticed this several times will all the hammers, however I thought it was a bump in durability that was being considered a mod.

Interesting point there! I still haven't had this happen to me, so I can't give first-hand experience, but this sounds pretty legit.
 

kolbycrouch

Knight
Interesting point there! I still haven't had this happen to me, so I can't give first-hand experience, but this sounds pretty legit.
I remember "losing" a mod several times, but on these occasions I didn't bother to check durability. I also remember glimpsing at freshly crafted items and seeing very high durability.
 

raveX

Page
Looks like it should be right unless its a strange bug someplace else, I checked color of weapon too and its ordinary agapite, normally elemental change will give weapon a different color. Is there still a test server running someplace in the interwebs? =]


So from this code it all looks good, but you obviously have some code elsewhere that is determining what 4 mods to apply. Take a look there (Post it if it is not a lot, I would like to take a look). Make sure the logic for the mod selection isn't bugged where you really did get 4 mods, but 2 of the 4 were Damage Increase..something like DI 22%, DI 24%, FC1, ML 44%. Once a mode is selected, it should be eliminated from the collection of mods to select the next one from. Or perhaps it only applied it once like...first mod DI 38%...code sets property...next mod...DI 46%....code sets property, next mod...FC1...etc.
 

raveX

Page
Well, I thought I found the problem with the code, but after taking a second look, I saw I jumped the gun.

The code I am looking at is in:
Scripts\Items\Skill Items\Tools\BaseRunicTool.cs
Server\Utility.cs

Code:
        public static void ApplyAttributesTo( BaseWeapon weapon, bool isRunicTool, int luckChance, int attributeCount, int min, int max )
        {
            m_IsRunicTool = isRunicTool;
            m_LuckChance = luckChance;
 
            AosAttributes primary = weapon.Attributes;
            AosWeaponAttributes secondary = weapon.WeaponAttributes;
 
            m_Props.SetAll( false );
 
            if ( weapon is BaseRanged )
                m_Props.Set( 2, true ); // ranged weapons cannot be ubws or mageweapon
 
            for ( int i = 0; i < attributeCount; ++i )
            {
                int random = GetUniqueRandom( 25 );
 
                if ( random == -1 )
                    break;
 
                switch ( random )
                {
                    case 0:
                    {
                        switch ( Utility.Random( 5 ) )
                        {
                            case 0: ApplyAttribute( secondary, min, max, AosWeaponAttribute.HitPhysicalArea,2, 50, 2 ); break;
                            case 1: ApplyAttribute( secondary, min, max, AosWeaponAttribute.HitFireArea,    2, 50, 2 ); break;
                            case 2: ApplyAttribute( secondary, min, max, AosWeaponAttribute.HitColdArea,    2, 50, 2 ); break;
                            case 3: ApplyAttribute( secondary, min, max, AosWeaponAttribute.HitPoisonArea,    2, 50, 2 ); break;
                            case 4: ApplyAttribute( secondary, min, max, AosWeaponAttribute.HitEnergyArea,    2, 50, 2 ); break;
                        }
 
                        break;
                    }
                    case 1:
                    {
                        switch ( Utility.Random( 4 ) )
                        {
                            case 0: ApplyAttribute( secondary, min, max, AosWeaponAttribute.HitMagicArrow,    2, 50, 2 ); break;
                            case 1: ApplyAttribute( secondary, min, max, AosWeaponAttribute.HitHarm,        2, 50, 2 ); break;
                            case 2: ApplyAttribute( secondary, min, max, AosWeaponAttribute.HitFireball,    2, 50, 2 ); break;
                            case 3: ApplyAttribute( secondary, min, max, AosWeaponAttribute.HitLightning,    2, 50, 2 ); break;
                        }
 
                        break;
                    }
                    case 2:
                    {
                        switch ( Utility.Random( 2 ) )
                        {
                            case 0: ApplyAttribute( secondary, min, max, AosWeaponAttribute.UseBestSkill,    1, 1 ); break;
                            case 1: ApplyAttribute( secondary, min, max, AosWeaponAttribute.MageWeapon,        1, 10 ); break;
                        }
 
                        break;
                    }
                    case  3: ApplyAttribute( primary,    min, max, AosAttribute.WeaponDamage,                1, 50 ); break;
                    case  4: ApplyAttribute( primary,    min, max, AosAttribute.DefendChance,                1, 15 ); break;
                    case  5: ApplyAttribute( primary,    min, max, AosAttribute.CastSpeed,                    1, 1 ); break;
                    case  6: ApplyAttribute( primary,    min, max, AosAttribute.AttackChance,                1, 15 ); break;
                    case  7: ApplyAttribute( primary,    min, max, AosAttribute.Luck,                        1, 100 ); break;
                    case  8: ApplyAttribute( primary,    min, max, AosAttribute.WeaponSpeed,                    5, 30, 5 ); break;
                    case  9: ApplyAttribute( primary,    min, max, AosAttribute.SpellChanneling,                1, 1 ); break;
                    case 10: ApplyAttribute( secondary, min, max, AosWeaponAttribute.HitDispel,                2, 50, 2 ); break;
                    case 11: ApplyAttribute( secondary,    min, max, AosWeaponAttribute.HitLeechHits,            2, 50, 2 ); break;
                    case 12: ApplyAttribute( secondary,    min, max, AosWeaponAttribute.HitLowerAttack,        2, 50, 2 ); break;
                    case 13: ApplyAttribute( secondary,    min, max, AosWeaponAttribute.HitLowerDefend,        2, 50, 2 ); break;
                    case 14: ApplyAttribute( secondary,    min, max, AosWeaponAttribute.HitLeechMana,            2, 50, 2 ); break;
                    case 15: ApplyAttribute( secondary,    min, max, AosWeaponAttribute.HitLeechStam,            2, 50, 2 ); break;
                    case 16: ApplyAttribute( secondary,    min, max, AosWeaponAttribute.LowerStatReq,            10, 100, 10 ); break;
                    case 17: ApplyAttribute( secondary,    min, max, AosWeaponAttribute.ResistPhysicalBonus,    1, 15 ); break;
                    case 18: ApplyAttribute( secondary,    min, max, AosWeaponAttribute.ResistFireBonus,        1, 15 ); break;
                    case 19: ApplyAttribute( secondary,    min, max, AosWeaponAttribute.ResistColdBonus,        1, 15 ); break;
                    case 20: ApplyAttribute( secondary,    min, max, AosWeaponAttribute.ResistPoisonBonus,        1, 15 ); break;
                    case 21: ApplyAttribute( secondary,    min, max, AosWeaponAttribute.ResistEnergyBonus,        1, 15 ); break;
                    case 22: ApplyAttribute( secondary, min, max, AosWeaponAttribute.DurabilityBonus,        10, 100, 10 ); break;
                    case 23: weapon.Slayer = GetRandomSlayer(); break;
                    case 24: GetElementalDamages( weapon ); break;
                }
            }
        }

The first time I went through this, I saw a bunch of calls like 'Utility.Random( 5 )' and thought "these are not unique". Skimming the code I thought all of the calls were the same, but the code is actually getting a Unique value each time it tries to figure out a mod to apply to the weapon with the following method call.

Code:
private const int MaxProperties = 32;
        private static BitArray m_Props = new BitArray( MaxProperties );
        private static int[] m_Possible = new int[MaxProperties];
 
        public static int GetUniqueRandom( int count )
        {
            int avail = 0;
 
            for ( int i = 0; i < count; ++i )
            {
                if ( !m_Props[i] )
                    m_Possible[avail++] = i;
            }
 
            if ( avail == 0 )
                return -1;
 
            int v = m_Possible[Utility.Random( avail )];
 
            m_Props.Set( v, true );
 
            return v;
        }

I ran the logic of this GetUniqueRandom method several million times in a quick test harness and never got a duplicate number, so there doesn't appear to be any issues with it, meaning, it shouldn't pull the same mod twice when determining which ones to apply, assuming we are running through it synchronously.

I certainly need to get more familiarized with this code base, though , because there are static variables in here that normally would not make sense being static. The fact that we have a static array which is modified when we calculate our unique random numbers just doesn't seem right (m_props and m_possible) especially if this code runs multi-threaded.

What happens if we have two people making items with runic hammers at the same time? Static variables are shared, and our array is now being modified by perhaps two separate threads running asynchronously. Now that seems like a logical case where we can pull the same mod twice.

The first thread clears m_props and we start to select random numbers, second thread comes in and clears m_props again before the first thread is done, and now we lost what numbers we were no longer suppose to select in the first thread.

I guess I am done looking for now. Time to actually play the game :)
 

Eos

Demise Administrator
Staff member
Some ways in which mods go "missing" are:
  • You roll the durability bonus, which is invisible.
  • You roll the undead slayer, but fail the super slayer roll -- no slayer is applied.
Both issues have been addressed. Durability bonus is now visible on weapons, and the random slayer property will no longer roll no slayer.

Please post if mods still go missing. :)
 

Kallitcha

Squire
Just looking at the code you posted, could it be re-applying the same mod? Hence over writing a mod.

Ie 1st roll : you get life leech 30%
2nd roll : you get life leech 50%

Item appears with 1 mod with life leech 50%.

Just reading what's coded there, I didn't see an obvious check to see if a specific mod was already given. Please note it's been many many years since I wrote code.
 

raveX

Page
Just looking at the code you posted, could it be re-applying the same mod? Hence over writing a mod.

Ie 1st roll : you get life leech 30%
2nd roll : you get life leech 50%

Item appears with 1 mod with life leech 50%.

Just reading what's coded there, I didn't see an obvious check to see if a specific mod was already given. Please note it's been many many years since I wrote code.


No, the mods pulled will be unique as a list is maintained for what random numbers you already rolled. I tested that just to be sure it was working correctly. I think Eos got the problems that occurred with any regularity. My only concern left would be the use of static objects to track all of this, but on the scale of operations completing in milliseconds, it would take absolute perfect timing to see lost mods due to that. That is also assuming these operations are running in multiple threads, of which I cannot be sure. This was my first look at RunUO code.
 
Top