RunUO 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!

Function Class

Killamus

Knight
Function Class

Yea, I'm looking into making a class with functions that I use very often, however, I can't seem to do it. I have the class, all the functions, etc, but I don't want to inherit said class. Also, interfacing isn't what I'm looking at doing either.

Basically, how can I make a class of functions that I can call the function FROM the class in question, without making a new instance of it and calling the functions from that? Think header files in C++.
 

mordero

Knight
Just make the class and its methods static, then you wont need to initiate it. :)

Edit: Example
Code:
public static class Functions
{
       public static int AFunction()
        {
           //do stuff
           return 0;
         }
}
Then you just need to do Functions.AFunction()
 

daat99

Moderator
Staff member
You should keep in mind that c# is mainly Object Oriented programming language and therefor in most cases it is better to use objects to run these functions.

There are some exceptions (with good reason) out there so there are times where static methods/classes are the solution.

You should think hard before going down that path, maybe your design can be altered a bit and work better as an object (and maybe not ;)).
 

Killamus

Knight
Well, it's a bunch of very commonly used functions, that are being used by items and mobiles alike. But, just a question: Will using static instead of a regular method cause me to lose functionality in said method (Such as I can't pass it variables or some such)?

Thanks again for the help.
 

mordero

Knight
Well since its static, you will need to pass in all the variables that will be used. So, if this function normally references 10 different variables. Then you will need to pass in all 10 variables. What kind of functions are you talking about? If you could break them up into different categories (ie. Functions for items, functions for mobiles, etc), you could just add them into the original classes and use them that way. But if these functions are used for all manner of things and they only work with a few variables, then it shouldnt be any problem using static methods.
 

daat99

Moderator
Staff member
Killamus;745854 said:
Well, it's a bunch of very commonly used functions, that are being used by items and mobiles alike. But, just a question: Will using static instead of a regular method cause me to lose functionality in said method (Such as I can't pass it variables or some such)?

Thanks again for the help.
You won't lose functionality but it might not be "the right tool for the job"
Let me give you a common example:

Consider you program a basketball game.
You have a court with hooks, a ball and players.
Let's say you want to make a player A throw the ball to player B.
In the Object Oriented way (normal people way) you'll simply do this:
A.throwBall(ball, B);
That reads in English like:
A, throw the ball "ball" to "B"

Now in static way (what you want to do) it'll be like this:
StaticClass.throwBall(A, ball, B);
This reads in English like:
StaticClass make A throw the ball "ball" to B.

In the real world it'll be like:
Basketball court make the player A throw the ball "ball" to player B.

Personally that doesn't make much sense to me, why make a machine (StaticClass) that'll make an object (player A) do something (throw the ball "ball" to player B) if you can just tell the object (player A) to do it?


In any case you can go with either way you want.
The end result will work the same, it's only question of how easy it'll be to understand what's going on in there in a few months from now.
Considering Object Oriented programming is a lot closer to Human thinking then procedural programming (static methods), it'll be a lot easier to understand in the future (when your script will get bigger).

Keep in mind that I'm not saying you should never use statics, they do have a lot of useful uses.
All I'm saying is that you should think and see if there's another way before you decide to use it.

Once you've made your decision though, you should go with it whatever it may be.
 

Killamus

Knight
Basically, I have this method, DoHeal. It's called in many items and in many mobiles in many different situations. Sometimes whenever a peice of armor is damaged it's called, in other peices of armor it's not. I figure that adding one-3 lines of code (If (X) Doheal, etc) is much better then adding in 40ish lines of code to every item and monster I want to call it from.

These are very specific kinds of methods, and require very little input do to what they do. Think of something like the Utility class.

I understand what you're saying, that it doesn't make sense at times, but when code is used continuously over a broad range of things to make it into a static class? Mainly I'm doing this because I don't want to edit distro scripts more then nessesary. Obviously, I could just plant these into the item and basecreature distros, but for me, that's a tad much.
 

mordero

Knight
So, these functions take an input and then do something to it? Static would work just fine for that:
Code:
public static Item DoHeal(Item item)
{
     //do stuff to item
     return item;
}

Remember though, you could always just add some of these functions into the Item and Mobile class and call them that way.
 
Killamus;745895 said:
Basically, I have this method, DoHeal. It's called in many items and in many mobiles in many different situations. Sometimes whenever a peice of armor is damaged it's called, in other peices of armor it's not. I figure that adding one-3 lines of code (If (X) Doheal, etc) is much better then adding in 40ish lines of code to every item and monster I want to call it from.

You don't have to add it to every class you want to call it from. If you add the function to a class, every other class that inherits from said class will have this function.

So for example, if you add the function "DoHeal" to BaseArmor, then all the classes that inherit from BaseArmor can call this function.
 

daat99

Moderator
Staff member
Killamus;745895 said:
Basically, I have this method, DoHeal. It's called in many items and in many mobiles in many different situations. Sometimes whenever a peice of armor is damaged it's called, in other peices of armor it's not. I figure that adding one-3 lines of code (If (X) Doheal, etc) is much better then adding in 40ish lines of code to every item and monster I want to call it from.

These are very specific kinds of methods, and require very little input do to what they do. Think of something like the Utility class.

I understand what you're saying, that it doesn't make sense at times, but when code is used continuously over a broad range of things to make it into a static class? Mainly I'm doing this because I don't want to edit distro scripts more then nessesary. Obviously, I could just plant these into the item and basecreature distros, but for me, that's a tad much.
Like TheOutkastDev already stated you could just add it to the base class.
As to your concern about editing the base classes from the RunUO distribution you should know that as long as you don't touch the serialise and deserialize method there is no risk at all.

Let's look at BaseCreature Dispel function:
Code:
public virtual void Dispel( Mobile m )
{
	Effects.SendLocationParticles( EffectItem.Create( m.Location, m.Map, EffectItem.DefaultDuration ), 0x3728, 8, 20, 5042 );
	Effects.PlaySound( m, m.Map, 0x201 );

	m.Delete();
}
This function make one mobile dispel another summon.
First it get the summon as a mobile parameter.
Next it plays the animation and sound effects and lastly it deletes it.

You can add your own "heal" method like that (to both BaseCreature and BaseArmor):
Code:
public virtual void healMobile( Mobile healMe )
{
	healMe.Heal(10); //heal 10 points of damage on the mobile sent as a parameter
}

Or if you want more control you can do:
Code:
public virtual void healMobile( Mobile healMe, int amount )
{
	healMe.Heal(amount); //heal "amount" points of damage on the mobile sent as a parameter
}

I assume you already know how to use those methods since you're here and not in the script support forum so I won't elaborate on that.

P.S.
You are aware of the Mobile class Heal function right?
 

Killamus

Knight
Yea, this method that I created.. Well, here it is, as well as a few others:
Code:
        public static void DoHeal ( Mobile creature )
        {
            DoHeal( creature, false, 10 );
        }

        public static void DoHeal ( Mobile creature, int percentToHeal )
        {
            DoHeal( creature, false, percentToHeal );
        }

        public static void DoHeal ( Mobile creature, bool checkBandages )
        {
            DoHeal( creature, checkBandages, 10 );
        }

        public static void DoHeal ( Mobile creature, bool checkBandages, int percentToHeal )
        {
            BaseCreature c = null;
            if ( creature is BaseCreature )
                c = (BaseCreature)creature;

            if ( percentToHeal <= 0 || percentToHeal >= 100 ) //No weird percentages
            {
                percentToHeal = 10;
            }
            int percent = creature.HitsMax / percentToHeal; //We need to find the number of hits
            if ( creature.Hits < creature.HitsMax - percent ) //If they're below that number
            {
                if ( BandageContext.GetContext( creature ) == null ) //Checks to see if healing
                {
                    if ( !checkBandages ) //Do we need bandages?
                    {
                        if ( c != null )
                            c.DebugSay( "I'm healing without bandages" );
                        BandageContext.BeginHeal( creature, creature ); //Start the healing process
                        return;
                    }
                    if ( creature.FindItemOnLayer( Layer.Backpack ) != null) //Check for a backpack
                    {
                        Bandage bandage = (Bandage)creature.Backpack.FindItemByType( typeof( Bandage ) ); //Are there even bandages?
                        if ( bandage != null )
                        {
                            if ( c != null )
                                c.DebugSay( "I'm healing with bandages!" );
                            BandageContext.BeginHeal( creature, creature ); //Start the healing process
                            return;
                        }
                        if ( c != null )
                            c.DebugSay( "I'm out of bandages!" );
                    }
                }
            }
        }

        public static void suckBlood ( Mobile creature )
        {
            suckBlood( creature, 10, 20, 2 );
        }

        public static void suckBlood ( Mobile creature, int range )
        {
            suckBlood (creature, 10, 20, range);
        }

        public static void suckBlood ( Mobile creature, int min, int max )
        {
            suckBlood( creature, min, max, 2 );
        }

        public static void suckBlood ( Mobile creature, int min, int max, int range )
        {
            BaseCreature c = null;
            if ( creature is BaseCreature )
                c = (BaseCreature)creature;
            ArrayList list = new ArrayList();

            foreach ( Mobile m in creature.GetMobilesInRange( range ) )
            {
                if ( m == creature || !creature.CanBeHarmful( m ) )
                    continue;

                if ( m is BaseCreature && ( ( (BaseCreature)m ).Controlled || ( (BaseCreature)m ).Summoned ) )
                    list.Add( m );
                else if ( c != null && m is BaseCreature && ( (BaseCreature)m ).Team != c.Team )
                    list.Add( m );
                else if ( m.Player )
                    list.Add( m );
            }

            foreach ( Mobile m in list )
            {
                creature.DoHarmful( m );

                m.FixedParticles( 0x374A, 10, 15, 5013, 0x496, 0, EffectLayer.Waist );
                m.PlaySound( 0x231 );

                m.SendMessage( "You feel the life drain out of you!" );

                int toDrain = Utility.RandomMinMax( min, max );

                creature.Hits += toDrain;
                m.Damage( toDrain, creature );
            }
        }

        public static void equipWeapon ( Mobile creature )
        {
            equipWeapon( creature, false, false );
        }

        public static void equipWeapon ( Mobile creature, bool constantCheck )
        {
            equipWeapon( creature, false, constantCheck);
        }

        public static void equipWeapon ( Mobile creature, bool createWeapon, bool constantCheck )
        {
            BaseCreature c = null;
            if ( creature is BaseCreature )
                c = (BaseCreature)creature;
            List<BaseWeapon> weps = new List<BaseWeapon>();
            BaseWeapon wep = creature.Weapon as BaseWeapon;
            if ( constantCheck || wep != null ) //Do we always check for a weapon? Do we even have a weapon?
            {
                float total = 0;//Which of the weapon skills is highest?
                short holder = 0;//Hold the value

                double[] skillz = new double[6];
                skillz[0] = ( creature.Skills[SkillName.Wrestling].Value );//Value, because skill bonus items have an effect             
                skillz[1] = ( creature.Skills[SkillName.Archery].Value ); //Change to 0 for no archery support
                skillz[2] = ( creature.Skills[SkillName.Swords].Value );
                skillz[3] = ( creature.Skills[SkillName.Fencing].Value );
                skillz[4] = ( creature.Skills[SkillName.Macing].Value );


                for ( short i = 0; i < 5; i++ )
                    if ( skillz[i] > total )
                    {
                        total = (float)skillz[i];
                        holder = i;
                    }

                if ( total == 0 || holder == 0 ) //Don't equip a weapon if every skill is at 0 or wrestling is highest
                {
                    if ( c != null )
                        c.DebugSay( "My fists are my weapons!" );

                    return;
                }

                if ( creature.Backpack != null ) //Backpack check
                {
                    foreach ( Item i in creature.Backpack.Items )
                        if ( i is BaseWeapon )
                            weps.Add( (BaseWeapon)i );

                    if ( weps.Count == 0 ) //No weapons, no need to waste CPU cycles
                    {
                        if ( c != null )
                            c.DebugSay( "I have no weapons!" );
                        return;
                    }

                    List<int> wepRanks = new List<int>();

                    for ( int i = 0; i < weps.Count; i++ )
                    {
                        if ( c != null )
                            wepRanks[i] = doRank( weps[i], c.AI, holder );
                        else
                            wepRanks[i] = doRank( weps[i], AIType.AI_Melee, holder );
                    }
                        

                    total = 0; //Reset the total

                    for ( short i = 0; i < wepRanks.Count; i++ )
                        if ( wepRanks[i] > total )
                        {
                            total = wepRanks[i];
                            holder = i;
                        }

                    creature.EquipItem( weps[holder] );//And FINALLY equip it.

                }
                    if ( c != null )
                        c.DebugSay( "I have no backpack!" );
                return;
            }
        }

The equipWeapon method is called by an item (Ironically) whenever a playermobile casts a spell or unequips it's weapon and it has a bool to equip weapons on. The heal method is called by a special type of bracelet that while it's equipped uses this method so that the person in question doesn't have to worry about keeping the bandages there. It's also used on the OnHit of a few weapons, as well as the bleed attack script whenever a basecreature is bleeding, and the list goes on. This isn't by far done, I just need to test it now.

Thanks again for all the help.

Also, Outkast, I know how to inherit classes, but like I said, I don't like modifying the distro, because I have to send these to someone who doesn't know the difference between inheriting and an instance. Alas.
 

daat99

Moderator
Staff member
In my humble opinion you should add those to the BaseCreature class.
I think it'll make a lot more sense if you do.

In any case they should like something like this if you want them Object Oriented:
Code:
        public void DoHeal ()
        {
            DoHeal( false, 10 );
        }

        public void DoHeal ( int percentToHeal )
        {
            DoHeal( false, percentToHeal );
        }

        public void DoHeal ( bool checkBandages )
        {
            DoHeal( checkBandages, 10 );
        }

        public void DoHeal ( bool checkBandages, int percentToHeal )
        {
            if ( percentToHeal <= 0 || percentToHeal >= 100 ) //No weird percentages
            {
                percentToHeal = 10;
            }
            int percent = HitsMax / percentToHeal; //We need to find the number of hits
            if ( Hits < HitsMax - percent ) //If they're below that number
            {
                if ( BandageContext.GetContext( this ) == null ) //Checks to see if healing
                {
                    if ( !checkBandages ) //Do we need bandages?
                    {
                        DebugSay( "I'm healing without bandages" );
                        BandageContext.BeginHeal( this, this ); //Start the healing process
                        return;
                    }
                    if ( FindItemOnLayer( Layer.Backpack ) != null) //Check for a backpack
                    {
                        Bandage bandage = (Bandage)Backpack.FindItemByType( typeof( Bandage ) ); //Are there even bandages?
                        if ( bandage != null )
                        {
                            DebugSay( "I'm healing with bandages!" );
                            BandageContext.BeginHeal( this, this ); //Start the healing process
                            return;
                        }
                        DebugSay( "I'm out of bandages!" );
                    }
                }
            }
        }

        public void suckBlood ()
        {
            suckBlood( 10, 20, 2 );
        }

        public void suckBlood ( int range )
        {
            suckBlood (10, 20, range);
        }

        public void suckBlood ( int min, int max )
        {
            suckBlood( min, max, 2 );
        }

        public void suckBlood ( int min, int max, int range )
        {
            ArrayList list = new ArrayList();

            foreach ( Mobile m in GetMobilesInRange( range ) )
            {
                if ( m == this || !CanBeHarmful( m ) )
                    continue;

                if ( m is BaseCreature && ( ((BaseCreature)m).Controlled || ( (BaseCreature)m).Summoned ) )
                    list.Add( m );
                else if ( m is BaseCreature && ( (BaseCreature)m).Team != Team )
                    list.Add( m );
                else if ( m.Player )
                    list.Add( m );
            }

            foreach ( Mobile m in list )
            {
                DoHarmful( m );

                m.FixedParticles( 0x374A, 10, 15, 5013, 0x496, 0, EffectLayer.Waist );
                m.PlaySound( 0x231 );

                m.SendMessage( "You feel the life drain out of you!" );

                int toDrain = Utility.RandomMinMax( min, max );

                Hits += toDrain;
                m.Damage( toDrain, this );
            }
        }

        public void equipWeapon ()
        {
            equipWeapon( false, false );
        }

        public void equipWeapon ( bool constantCheck )
        {
            equipWeapon( false, constantCheck);
        }

        public void equipWeapon ( bool createWeapon, bool constantCheck )
        {
            List<BaseWeapon> weps = new List<BaseWeapon>();
            BaseWeapon wep = Weapon as BaseWeapon;
            if ( constantCheck || wep != null ) //Do we always check for a weapon? Do we even have a weapon?
            {
                float total = 0;//Which of the weapon skills is highest?
                short holder = 0;//Hold the value

                double[] skillz = new double[6];
                skillz[0] = ( Skills[SkillName.Wrestling].Value );//Value, because skill bonus items have an effect             
                skillz[1] = ( Skills[SkillName.Archery].Value ); //Change to 0 for no archery support
                skillz[2] = ( Skills[SkillName.Swords].Value );
                skillz[3] = ( Skills[SkillName.Fencing].Value );
                skillz[4] = ( Skills[SkillName.Macing].Value );

                for ( short i = 0; i < 5; i++ )
                    if ( skillz[i] > total )
                    {
                        total = (float)skillz[i];
                        holder = i;
                    }

                if ( total == 0 || holder == 0 ) //Don't equip a weapon if every skill is at 0 or wrestling is highest
                {
                    DebugSay( "My fists are my weapons!" );
                    return;
                }

                if ( Backpack != null ) //Backpack check
                {
                    foreach ( Item i in Backpack.Items )
                        if ( i is BaseWeapon )
                            weps.Add( (BaseWeapon)i );
                    if ( weps.Count == 0 ) //No weapons, no need to waste CPU cycles
                    {
                        DebugSay( "I have no weapons!" );
                        return;
                    }

                    List<int> wepRanks = new List<int>();
                    for ( int i = 0; i < weps.Count; i++ )
                    {
                        wepRanks[i] = doRank( weps[i], AI, holder );
                    }

                    total = 0; //Reset the total
                    for ( short i = 0; i < wepRanks.Count; i++ )
                        if ( wepRanks[i] > total )
                        {
                            total = wepRanks[i];
                            holder = i;
                        }
                    EquipItem( weps[holder] );//And FINALLY equip it.
                }
                DebugSay( "I have no backpack!" );
                return;
            }
        }
Notice how I removed all the "Mobile creature" from everywhere and removed the null checks (the "this" object can never be null).
Also by inserting the code inside BaseCreature itself you make sure that it'll be used only by objects that inherit from BaseCreature, so you don't need to check for that either.


In any case, like I said before.
This is just my opinion, you can do whatever you think is best in your particular situation.
 
Top