First off, I'm going to point out that module is only called in:
BaseAI.cs's AcquireFocusMob module
SpellHelper.cs's ValidIndirectTarget module (This use happens when both attacker and target are creatures, to see if AOE spells should cause damage)
MeerMage's OnThink module (used to change target for summoning rabid animals and to target stinging insects)
MeerEternal's DoAreaLeech_Finish (used to check for valid targets to steal life from)
Betrayer's OnActionCombat (used for valid targets to area poison)

Next, the following checks have become redundant because both checks are now made in AcquireFocusMob for all FightModes:
line 1017.
Code:
            if (m is PlayerMobile && ((PlayerMobile)m).HonorActive)
            {
                return false;
            }
line 1027:
Code:
if (TransformationSpellHelper.UnderTransformation(m, typeof(EtherealVoyageSpell)))
{
return false;
}
It should have no effect on mobile-to-mobile AOE damage, but in theory, some mobiles might be struck inadvertantly that weren't before. Is this issue relevant enough to block their removal?

Next, is a little more theoretical: Should ALL AIs have their enemy determinations moved to BaseCreature.cs?
For reference, that's all the 'bValid' checks in AcquireFocusMob: the positive check on enemy factions/ethic, the positive check on Good and Evil karma enemy checks, and the summoned creature check.

Have a separate IsSpecialEnemy sub-module in BaseCreature.cs for evaluating passive/karma specific enemies. (including the positive faction/ethic enemy check). This would be referenced immediately after the XML check at the beginning of IsEnemy. Summoned Creatures would also use this module directly instead of the normal IsEnemy module.

Result would be that IsEnemy would more accurately represent enemy target determination(e.g. when a FightMode Evil mob uses an AOE spell, it would also hit negative karma mobiles), while AcquireFocusMob would grow correspondingly shorter and be simplified.


New module in BaseCreature.cs would be IsSpecialEnemy:
Code:
     public virtual bool IsSpecialEnemy(Mobile m)
     {
       // We want a faction/ethic enemy
       if (GetFactionAllegiance(m) == BaseCreature.Allegiance.Enemy || GetEthicAllegiance(m) == BaseCreature.Allegiance.Enemy)
       {
         return true;
       }

       BaseCreature c = m as BaseCreature;

       // We want a karma enemy
       if (FightMode == FightMode.Evil)
       {
         if (c != null && c.Controlled && c.ControlMaster != null)
         {
           if (c.ControlMaster.Karma < 0)
           {
             return true;
           }
         }
         else if (m.Karma < 0)
         {
           return true;
         }
       }
       // We want a karma enemy
       else if (FightMode == FightMode.Good)
       {
         if (c != null && c.Controlled && c.ControlMaster != null)
         {
           if (c.ControlMaster.Karma > 0)
           {
             return true;
           }
         }
         else if (m.Karma > 0)
         {
           return true;
         }
       }

       return false;
     }

Then, in BaseCreature.cs's IsEnemy, right below the XML check, the following check would be added:
Code:
  if (IsSpecialEnemy(m)))
  {
  return true;
  }


Then, in BaseAI's AcquireFocusMob, the the checks would also be changed. (relevant section only)
Code:
             if (!IsHostile(m))
             {
               // Ignore anyone if we don't want enemies
               if (!bFacFoe)
               {
                 continue;
               }

               //Ignore anyone under EtherealVoyage
               if (TransformationSpellHelper.UnderTransformation(m, typeof(EtherealVoyageSpell)))
               {
                 continue;
               }

               // Ignore players with activated honor
               if (m is PlayerMobile && ((PlayerMobile)m).HonorActive && !(m_Mobile.Combatant == m))
               {
                 continue;
               }

               // Xmlspawner faction check
               // Ignore mob faction ranked players, more highly more often
               //if (!Server.Engines.XmlSpawner2.XmlMobFactions.CheckAcquire(this.m_Mobile, m))
               //continue;

               // Ignore anyone who is not a Special Enemy (We are a Passive FightMode)
               if (acqType == FightMode.Good || acqType == FightMode.Evil || acqType == FightMode.Aggressor)
               {
                 if (!m_Mobile.IsSpecialEnemy(m))
                 {
                   continue;
                 }
               }
               // Ignore anyone who is not a Special Enemy (We are an Uncontrolled Summon)
               else if (c != null && c.Summoned)
               {
                 if (!m_Mobile.IsSpecialEnemy(m))
                 {
                   continue;
                 }
               }
               // Ignore anyone who is not an Enemy (We are an Aggressive FightMode)
               else if (!m_Mobile.IsEnemy(m))
               {
                 continue;
               }
             }

Thoughts? Criticisms? Approval? Please discuss :)
 
Last edited:
Splitting the IsEnemy function in two will add more complexity to the whole thing.
All what relies on IsEnemy currently would have to override the IsEnemy but also the IsSpecialEnemy.
Those who won't know about that change or having a custom npc script risk to see their things behaving wrongly.
 
Indeed, it adds more complexity, but I was unable to divine a way to both prevent a loss of current functionality and increase of current functionality without it. Of the extant uses, BaseAI gains simplicity, and the rest gain function (They positively find Faction/Ethic enemies and Karma enemies)
Is the improved function worth it?
Edit: I suppose the IsSpecialEnemy stuff could also be added directly into IsEnemy instead of using the check.
 
Last edited:
I'm not coding that much on servuo, so i guess that's up to those who code the most to provide some feedback on it, and if you add it, don't link it in the IsEnemy, i think it would be better to separate both functions to be sure each one does it's job regardless of the other so the overrides have no consequence on the other one's execution. Otherwise we would be forced to execute the base.IsEnemy or calling the IsSpecialEnemy everywhere in the override functions, which would be even harder to maintain afterward.
 
Alright, this version works a little differently. It maintains the redundant honor/ethereal voyage checks since they may be required for non-BaseAI uses, but moves the ethereal voyage check ABOVE the attack all players check. Also maintained in the BaseAI check.

Added the positive faction enemy, positive ethic enemy, and positive karma enemy checks into IsEnemy, just after the XML check.

Question, should the BaseGuard check before moved to first position? Is there ever a situation where it's okay for a creature to attack a BaseGuard? (Or maybe to just below XML check, and above these checks) I left it below faction enemy and opposition group checks as before.

Then, in BaseAI, the passive fightmodes/target is a summon once again have their own separate checks, while aggressive fightmodes only check IsEnemy. (IsHostile, bFacFoe, XMLSpawner faction, Ethereal Voyage, and Honor checks are still carried out before this split)

Also, I just realized I failed a reading-comprehension check in BaseAI: It isn't using the 'passive' check when the CHECKER is a summon, it's doing it when the TARGET is a summon. Mind, I kept the functionality the same even if I put an incorrect note on it.

Anyhow, here's a revised version of the !IsHostile check in AcquireFocusMob in BaseAI:
Code:
            // Don't ignore hostile mobiles
             if (!IsHostile(m))
             {
               // Ignore anyone if we don't want enemies
               if (!bFacFoe)
               {
                 continue;
               }

               // Xmlspawner faction check
               // Ignore mob faction ranked players, more highly more often
               //if (!Server.Engines.XmlSpawner2.XmlMobFactions.CheckAcquire(this.m_Mobile, m))
               //continue;

               //Ignore anyone under EtherealVoyage
               if (TransformationSpellHelper.UnderTransformation(m, typeof(EtherealVoyageSpell)))
               {
                 continue;
               }

               // Ignore players with activated honor
               if (m is PlayerMobile && ((PlayerMobile)m).HonorActive && !(m_Mobile.Combatant == m))
               {
                 continue;
               }

               // We are a Passive FightMode or they are a summon
               if (acqType == FightMode.Good || acqType == FightMode.Evil || acqType == FightMode.Aggressor ||
                 ((m is BaseCreature) && ((BaseCreature)m).Summoned))
               {
                 // We want a faction/ethic enemy
                 bool bValid = (m_Mobile.GetFactionAllegiance(m) == BaseCreature.Allegiance.Enemy ||
                        m_Mobile.GetEthicAllegiance(m) == BaseCreature.Allegiance.Enemy);

                 // We want a special FightMode enemy
                 if (!bValid)
                 {
                   BaseCreature c = m as BaseCreature;

                   // We want a karma enemy
                   if (acqType == FightMode.Evil)
                   {
                     if (c != null && c.Controlled && c.ControlMaster != null)
                     {
                       bValid = (c.ControlMaster.Karma < 0);
                     }
                     else
                     {
                       bValid = (m.Karma < 0);
                     }
                   }
                   // We want a karma enemy
                   else if (acqType == FightMode.Good)
                   {
                     if (c != null && c.Controlled && c.ControlMaster != null)
                     {
                       bValid = (c.ControlMaster.Karma > 0);
                     }
                     else
                     {
                       bValid = (m.Karma > 0);
                     }
                   }
                 }

                 // Ignore invalid targets
                 if (!bValid)
                 {
                   continue;
                 }
               }
               // Ignore any non-enemy (We are an Aggressive FightMode)
               else if (!m_Mobile.IsEnemy(m))
               {
                 continue;
               }
             }
And here's the revised IsEnemy check in BaseCreature:
[code]
    public virtual bool IsEnemy(Mobile m)
     {
       XmlIsEnemy a = (XmlIsEnemy)XmlAttach.FindAttachment(this, typeof(XmlIsEnemy));

       if (a != null)
       {
         return a.IsEnemy(m);
       }

       // We want a faction enemy
       if (GetFactionAllegiance(m) == BaseCreature.Allegiance.Enemy);
       {
         return true;
       }

       // We want an ethic enemy
       if (GetEthicAllegiance(m) == BaseCreature.Allegiance.Enemy);
       {
         return true;
       }

       BaseCreature c = m as BaseCreature;

       // We want a karma enemy
       if (FightMode == FightMode.Evil)
       {
         if (c != null && c.Controlled && c.ControlMaster != null)
         {
           if (c.ControlMaster.Karma < 0)
           {
             return true;
           }
         }
         else if (m.Karma < 0)
         {
           return true;
         }
       }
       // We want a karma enemy
       else if (FightMode == FightMode.Good)
       {
         if (c != null && c.Controlled && c.ControlMaster != null)
         {
           if (c.ControlMaster.Karma > 0)
           {
             return true;
           }
         }
         else if (m.Karma > 0)
         {
           return true;
         }
       }

       OppositionGroup g = OppositionGroup;

       if (g != null && g.IsEnemy(this, m))
       {
         return true;
       }

       if (m is BaseGuard)
       {
         return false;
       }

       if (GetFactionAllegiance(m) == Allegiance.Ally)
       {
         return false;
       }

       Ethic ourEthic = EthicAllegiance;
       Player pl = Ethics.Player.Find(m, true);

       if (pl != null && pl.IsShielded && (ourEthic == null || ourEthic == pl.Ethic))
       {
         return false;
       }

       if (m is PlayerMobile && ((PlayerMobile)m).HonorActive)
       {
         return false;
       }

       if (TransformationSpellHelper.UnderTransformation(m, typeof(EtherealVoyageSpell)))
       {
         return false;
       }

       if (!(m is BaseCreature) || m is MilitiaFighter)
       {
         return true;
       }

       BaseCreature t = this;

       // Summons should have same rules as their master
       if (c.Summoned && c.SummonMaster != null && c.SummonMaster is BaseCreature)
         c = c.SummonMaster as BaseCreature;

       if (t.Summoned && t.SummonMaster != null && t.SummonMaster is BaseCreature)
         t = t.SummonMaster as BaseCreature;

       if (t.m_iTeam != c.m_iTeam)
       {
         return true;
       }

       return ((t.m_bSummoned || t.m_bControlled) != (c.m_bSummoned || c.m_bControlled));
//  return ((t.m_bSummoned || t.m_bControlled) != (c.m_bSummoned || c.m_bControlled) || c.Combatant == this );
     }
 
Back