Iomega0318

Vita-Nex Sponsor
ServUO Version
Publish 57
Ultima Expansion
Endless Journey
So I have this in the CanBeHarmful section of BaseCreature, and it seems to work could probably be better but my pets will say they're attacking each other but do no damage. Is there a way to also cancel that command if it meets the criteria? Like set them back to follow or something?

C#:
            if (target is BaseCreature && target is BaseCreature)
            {
                BaseCreature c = (BaseCreature)target;
                BaseCreature d = (BaseCreature)target;

                if (c.Controlled && d.Controlled && c.ControlMaster == d.ControlMaster)
                    return false;
            }

Tried this and it didn't work:
C#:
                if (c.Controlled && d.Controlled && c.ControlMaster == d.ControlMaster)
                    ControlTarget = this.ControlMaster;
                    ControlOrder = OrderType.Follow;
                    Warmode = false;
 
Last edited:

Lemke

Citizen
Maybe you can try to check pet notoriety with if (c.Notoriety.Ally)and change c.Combatant,but somewhere plus CanBeHarmful.
 

UO_Stryder

Citizen
Try changing this:
Your Code:
                if (c.Controlled && d.Controlled && c.ControlMaster == d.ControlMaster)
                    ControlTarget = this.ControlMaster;
                    ControlOrder = OrderType.Follow;
                    Warmode = false;
To this:
New Code:
                if (c.Controlled && d.Controlled && c.ControlMaster == d.ControlMaster)
                {
                    Warmode = false;
                    Combatant = null;
                    ControlTarget = this.ControlMaster;
                    ControlOrder = OrderType.Follow;
                }

You need to have the {} there otherwise it will only set the ControlTarget under the if condition and the others will always happen when it reaches that point in the code. The other thing is setting it's Combatant to null so that it won't start fighting again. If it doesn't work still, I'll look into it more later.

Also not sure why you have "if (target is BaseCreature && target is BaseCreature)" since it's the same thing and does not specify two different targets as BaseCreature, just the one target twice. Should probably make it something like "if (target is BaseCreature && target.Combatant != null && target.Combatant is BaseCreature)" then make it "BaseCreature d = (BaseCreature)target.Combatant;"

Should work anyway, though I haven't tested it.

**Edit**
Place this under OnThink in BaseCreature would be my best guess so that it is always checking to see if it is in combat with a friendly pet.
 
Last edited:

Iomega0318

Vita-Nex Sponsor
Hmm yeah I tried that and still nothing, I haven't had a chance to try putting any edits in the OnThink section..

as for the code I didn't think of it like that so it didn't even occur to me I was just putting the same thing, it makes sense to only use BaseCreature once as they're both BaseCreature's XD..
 

UO_Stryder

Citizen
After thinking about it, here is what you could try. Place this in OnThink.
Your Code:
         if (Combatant != null && Combatant is BaseCreature)
         {
                BaseCreature d = (BaseCreature)Combatant;
                if (Controlled && d.Controlled && ControlMaster == d.ControlMaster)
                {
                    Warmode = false;
                    Combatant = null;
                    d.Warmode = false;
                    d.Combatant = null;
                    ControlTarget = ControlMaster;
                    d.ControlTarget = d.ControlMaster;
                    ControlOrder = OrderType.Follow;
                    d.ControlOrder = OrderType.Follow;
                }
          }
It didn't work before because we were only setting one pet's Combatant null and Warmode false.

Hopefully this will work for you.
 

PyrO

Moderator
I mean since nobody did point it out yet .. you have a copy paste issue going there

C#:
            if (target is BaseCreature && target is BaseCreature)
            {
                BaseCreature c = (BaseCreature)target;
                BaseCreature d = (BaseCreature)target;

So I will just leave it at that for now :D
 

Iomega0318

Vita-Nex Sponsor
After thinking about it, here is what you could try. Place this in OnThink.
Your Code:
         if (Combatant != null && Combatant is BaseCreature)
         {
                BaseCreature d = (BaseCreature)Combatant;
                if (Controlled && d.Controlled && ControlMaster == d.ControlMaster)
                {
                    Warmode = false;
                    Combatant = null;
                    d.Warmode = false;
                    d.Combatant = null;
                    ControlTarget = ControlMaster;
                    d.ControlTarget = d.ControlMaster;
                    ControlOrder = OrderType.Follow;
                    d.ControlOrder = OrderType.Follow;
                }
          }
It didn't work before because we were only setting one pet's Combatant null and Warmode false.

Hopefully this will work for you.
This does appear to be working now, they do occasionally still hit each other before stopping, threw the other code out lol, still a little wonky but requires more testing..
 

UO_Stryder

Citizen
This does appear to be working now, they do occasionally still hit each other before stopping, threw the other code out lol, still a little wonky but requires more testing..
I was literally just writing an edit for that very reason. If you don't want it to do any damage still as a result of delays where OnThink will not stop them from hitting one another or remaining in combat under rare occurrences, do this:


BaseCreature.cs - OnDamageChange:
public override bool CanBeHarmful(IDamageable damageable, bool message, bool ignoreOurBlessedness)
        {
            Mobile target = damageable as Mobile;
   
            if (Controlled && target is BaseCreature)
            {
                BaseCreature bc = target as BaseCreature;
               
                if (bc.Controlled && ControlMaster == bc.ControlMaster)
                {
                    Combatant = null;
                    bc.Combatant = null;
                    Warmode = false;
                    bc.Warmode = false;
                    ControlTarget = ControlMaster;
                    bc.ControlTarget = bc.ControlMaster;
                    ControlOrder = OrderType.Follow;
                    bc.ControlOrder = OrderType.Follow;
                   
                    return false;
                }
            }

            if (RecentSetControl && GetMaster() == target)
            {
                return false;
            }

            if (target is BaseFactionGuard)
            {
                return false;
            }

            if ((target is BaseVendor && ((BaseVendor)target).IsInvulnerable) || target is PlayerVendor || target is TownCrier)
            {
                return false;
            }

            if (damageable is IDamageableItem && !((IDamageableItem)damageable).CanDamage)
            {
                return false;
            }

            return base.CanBeHarmful(damageable, message, ignoreOurBlessedness);
        }
 

PyrO

Moderator
I actually already did point that out haha :p Which is why I recommended using target.Combatant.
Oh ... didnt read that right, you are right you did :D

And yes there is no need to cast both, the attacked and the attacker, attacked / target ist fine.

Also you should be fine to shorten the if to

Controlled && ControlMaster == d.ControlMaster)

since at that pont you know that this creature is controlled, and if the controlmaster is the same you know that target is controlled as well.


Additionally, I would probably go and write a method like

C#:
public void ResetTamedCombattant(BaseCreature creature)
{  
    creature.Warmode = false;
    creature.Combatant = null;
    creature.ControlTarget = creature.ControlMaster;
    creature.ControlOrder = OrderType.Follow;
    }

And just call it for both

Still works with both your edits :D

-- Edit

Well you also shortend the if in the edit ;)
You got this I am out :D
 

UO_Stryder

Citizen
C#:
public void ResetTamedCombattant(BaseCreature creature)
{
    creature.Warmode = false;
    creature.Combatant = null;
    creature.ControlTarget = creature.ControlMaster;
    creature.ControlOrder = OrderType.Follow;
    }
This could still be beneficial to do for other specific situations as well, though I would also create one for any BaseCreature or Mobile for that matter to set their Warmode false and Combatant null so that you could end combat for any Mobile at any time, even if only briefly.

**Edit**
I mean an Untamed version that is.

**Edit 2**
I guess the shorter/easier thing to do would actually be to make it:
New::
public void ResetCombatant(Mobile mobile)
{
    mobile.Warmode = false;
    mobile.Combatant = null;
    
    if (mobile is BaseCreature)
    {
        BaseCreature creature = mobile as BaseCreature;
        if (creature.Controlled)
        {
            creature.ControlTarget = creature.ControlMaster;
            creature.ControlOrder = OrderType.Follow;
        }
    }
}
 
Last edited:

Iomega0318

Vita-Nex Sponsor
Very nice, thank you for all your help, does exactly what I need it to do.. been working on getting them to not attack you as your pet and to stop them from attacking each other when they use AOE haha..
 

UO_Stryder

Citizen
To make them not attack the owner or the owner's pets at all just add an addition spot to check if Combatant is ControlMaster so something like this:

ControlMaster Update:
            if (Controlled)
            {
                if (target is BaseCreature)
                {
                    BaseCreature bc = target as BaseCreature;

                    if (bc.Controlled && ControlMaster == bc.ControlMaster)
                    {
                        Combatant = null;
                        bc.Combatant = null;
                        Warmode = false;
                        bc.Warmode = false;
                        ControlTarget = ControlMaster;
                        bc.ControlTarget = bc.ControlMaster;
                        ControlOrder = OrderType.Follow;
                        bc.ControlOrder = OrderType.Follow;

                        return false;
                    }
                }
                else if (target is PlayerMobile)
                {
                    PlayerMobile pm = target as PlayerMobile;
                   
                    if (ControlMaster == pm)
                    {
                        Combatant = null;
                        Warmode = false;
                        ControlTarget = ControlMaster;
                        ControlOrder = OrderType.Follow;

                        return false;
                    }
                }
            }
 

Iomega0318

Vita-Nex Sponsor
Very nice, this is actually what I had haha in the canbeharmful section
C#:
            if (this.Controlled && this.ControlMaster != null && this.ControlMaster == target)
            {
                return false;
            }
 

PyrO

Moderator
**Edit 2**
I guess the shorter/easier thing to do would actually be to make it:
New::
public void ResetCombatant(Mobile mobile)
{
    mobile.Warmode = false;
    mobile.Combatant = null;
   
    if (mobile is BaseCreature)
    {
        BaseCreature creature = mobile as BaseCreature;
        if (creature.Controlled)
        {
            creature.ControlTarget = creature.ControlMaster;
            creature.ControlOrder = OrderType.Follow;
        }
    }
}

sure would work as a generel purpose method for all Mobiles.

But at the same time you wouldnt need to check for controlled.
If Controlled is false, ControlMaster would be null.
Setting ControlTarget to null should also cause no issues, since it should be null at that point anyway.

New::
public void ResetCombatant(Mobile mobile)
{
    mobile.Warmode = false;
    mobile.Combatant = null;
   
    if (mobile is BaseCreature)
    {
        BaseCreature creature = mobile as BaseCreature;
        creature.ControlTarget = creature.ControlMaster;
        creature.ControlOrder = OrderType.Follow;
    }
}

or depending on the C# Version you are using yo could use the if to also set the creature variable in the same check.

New::
public void ResetCombatant(Mobile mobile)
{
    mobile.Warmode = false;
    mobile.Combatant = null;
   
    if (mobile is BaseCreature creature)
    {
        creature.ControlTarget = creature.ControlMaster;
        creature.ControlOrder = OrderType.Follow;
    }
}
 

UO_Stryder

Citizen
sure would work as a generel purpose method for all Mobiles.

But at the same time you wouldnt need to check for controlled.
If Controlled is false, ControlMaster would be null.
Setting ControlTarget to null should also cause no issues, since it should be null at that point anyway.

New::
public void ResetCombatant(Mobile mobile)
{
    mobile.Warmode = false;
    mobile.Combatant = null;
 
    if (mobile is BaseCreature)
    {
        BaseCreature creature = mobile as BaseCreature;
        creature.ControlTarget = creature.ControlMaster;
        creature.ControlOrder = OrderType.Follow;
    }
}
You're right. Even in this particular case with the tamed mobiles, it was unnecessary under that context as it already checks if the this.BaseCreature is Controlled as well as it's target. You could take it one step further and add a variable for OrderType. Also reminds me, should we be checking for BardProvoked, BardTarget and BardMaster? I guess that could be a simple bool.
OrderType:
        public void ResetCombatant(Mobile mobile, OrderType order, bool provo)
        {
            mobile.Warmode = false;
            mobile.Combatant = null;

            if (mobile is BaseCreature)
            {
                if (provo)
                {
                    BardProvoked = false;
                    BardTarget = null;
                    BardMaster = null;
                }
                BaseCreature creature = mobile as BaseCreature;
                creature.ControlTarget = creature.ControlMaster;
                creature.ControlOrder = order;
            }
        }

Then call it using ResetCombatant(this, OrderType.None, true);
Just an idea and further completes the resetting of combat a bit more.

or depending on the C# Version you are using yo could use the if to also set the creature variable in the same check.

New::
public void ResetCombatant(Mobile mobile)
{
    mobile.Warmode = false;
    mobile.Combatant = null;
 
    if (mobile is BaseCreature creature)
    {
        creature.ControlTarget = creature.ControlMaster;
        creature.ControlOrder = OrderType.Follow;
    }
}
I keep forgetting ServUO uses a later version of .NET than I am used to haha :D I've tried to use this so many times on an old server of mine using RunUO 2.2 and an older .NET. I'll have to remember I can use that for when I'm writing something for a server that uses a later version.

**Edit**
At least the most recent ServUO pubs are able to use it. I suppose it doesn't hurt to write it the old way for those who can't use it since it works in the newer versions as well.
 
Last edited:

PyrO

Moderator
Well yea, the method could be expanded further, since it is called Reset, it could also include removing paralyzed, heals, refreshes stamina and fills mana as well, removing debuffs and so on.

In that case I would probably not go with just bools each, but rather an flag type enum, so you can pass just one value.

Additionally optional parameter would work.

so going with
public void ResetCombatant(Mobile mobile, OrderType order = OrderType.Follow, bool provo = true)

would still allow for short calls.

and if you add something like this:

C#:
[flag]
public enum ResetCombatStatus : byte
{
    None = 0,
    Health = 1 << 0,
    Stamina = 1 << 1,
    Mana = 1 << 2,
    AllStats = Health | Stamina | Mana,
    Provocation = 1 << 3,
    Peace = 1 << 4,
    Discord = 1 << 5,
    Barding = Provocation | Peace | Discord,
    Buffs = 1 << 6,
    Debuffs = 1 << 7,
    Alterations = Buffs | Debuffs,
    All = AllStats | Barding | Alterations
}

You could cherry pick what you want to reset or you dont want to reset. For that the method header could look like
public void ResetCombatant(Mobile mobile, OrderType order = OrderType.Follow, ResetCombatStatus resetflags = ResetCombatStatus.All)
 

UO_Stryder

Citizen
Well yea, the method could be expanded further, since it is called Reset, it could also include removing paralyzed, heals, refreshes stamina and fills mana as well, removing debuffs and so on.

In that case I would probably not go with just bools each, but rather an flag type enum, so you can pass just one value.

Additionally optional parameter would work.

so going with
public void ResetCombatant(Mobile mobile, OrderType order = OrderType.Follow, bool provo = true)

would still allow for short calls.

and if you add something like this:

C#:
[flag]
public enum ResetCombatStatus : byte
{
    None = 0,
    Health = 1 << 0,
    Stamina = 1 << 1,
    Mana = 1 << 2,
    AllStats = Health | Stamina | Mana,
    Provocation = 1 << 3,
    Peace = 1 << 4,
    Discord = 1 << 5,
    Barding = Provocation | Peace | Discord,
    Buffs = 1 << 6,
    Debuffs = 1 << 7,
    Alterations = Buffs | Debuffs,
    All = AllStats | Barding | Alterations
}

You could cherry pick what you want to reset or you dont want to reset. For that the method header could look like
public void ResetCombatant(Mobile mobile, OrderType order = OrderType.Follow, ResetCombatStatus resetflags = ResetCombatStatus.All)

Aye, I was going to say there is a ton more you could do to make it a complete and total reset with any number of ways one could go about doing it haha. Great example though and I do like the idea of using the flags for this purpose.

Maybe we went a bit off-topic? Not really though? It still has to do with the original question at least even if it is far more than originally requested. You're the Moderator, you tell me haha Either way some good information I'm sure some will find very useful.

Last thing I'll add to it just because people already get the general idea I'm sure haha, is adding in home spawn location and things of that nature as well as converting it into a staff command able to be used on the fly.

I will probably make a command for it another day or soon since there is no telling when it might be a useful command to have. If I do, I'll upload it here and give you both credit unless one of you want to release your own or do it before I do. If that's the case, no need to give me any credit, just happy to help. I enjoyed the brainstorming and collaboration.
 
Last edited:

Iomega0318

Vita-Nex Sponsor
I've definitely enjoyed the conversation even if I wasn't fully involved it it haha, some really great stuff, a command would be interesting for sure but I'm not skilled enough to create one :)