I've converted my two RunUO scripts to load with ServUO, but I'm wondering if I'm missing anything else I should do due to lack of experience with ServUO's code differences and I could rework some of it to work better with ServUO. Any advice would be appreciated.
The first is a script that creates a replacement framework for OppositionGroup and the other creates more controls for scaling and giving bonuses to secondary stats based on primary stats, along with some paragon and breath damage controls.
Both are partial replacements and additions to basecreatures.cs (only the relevant modules and properties are here)

Opposition List:

Code:
Version S1.01
Opposition List is intended as a replacement for Opposition Group. It is both greatly simplified and more dynamic than the existing Opposition Group.
As far as I know, it is only used in basecreature.cs in the IsFriend(m) and IsEnemy(m) modules.
Please inform if I'm incorrect.

First, this is all done in BaseCreature.cs, but the OppositionList is overridden in individual creature files.

Nothing changes by default. This is a framework intended to provide additional options and controls when making creatures.

I do not have Opposition Group functionality removed in the provided modules. Opposition Group references should not be removed unless all creatures are converted to use Opposition List.

Which OppositionLists a unit's OppositionList is hostile against are declare in each OppositionList's module, and can have multiple targeted enemies. However, I advise to take care to ensure that all aggression is reciprocated.

More OppositionTypes can be declared easily in the OppositionType enum and adding appropriate case in OppositonListEnemy(m) module and adding a module for the OppositionType.

Input of individual creature types into an index is not required, as it simply checks the OppositionList of each creature involved.
These properties are virtual flags, which means they are set by creature type, and are not serialized.

The below cs file contains the modules. It is NOT a loadable .cs file itself, and the modules must be manually edited into basecreature.cs, replacing or merging with existing ones.

I suggest pasting the first, non-replacement section (property virtual flags) just below AlwaysAttackable property virtual flag.

The comment tags themselves mark the beginning (//GS) and end (//GS//) of each section (either whole modules or a list of virtual flags and modules). I advise including them for future reference.

Use Ctrl+F and paste in the module names to quickly search for the modules in basecreature.cs.

Contains the following existing modules that need merged/replaced:
IsEnemy()
IsFriend()
Code:
//GS
     // Opposition List stuff
     public virtual OppositionType OppositionList{ get{ return OppositionType.None ; } }       // What opposition list am I in?
     public virtual bool OppositionPet{ get{ return false ; } }                   // Do I attack tame members of my opposition?

     public enum OppositionType
     {
       None,
       Juka,
       Meer,
       Terathan,
       Ophidian,
       Savage,
       Orc,
       BlackSolen,
       RedSolen,
       Fey,
       Undead,
       Daemon,
       Dragon,
       Exodus,
       Elemental
     }

     public virtual bool OppositionListEnemy( Mobile m )
     {
       BaseCreature c = m as BaseCreature;
       
       if ( c == null )
       {
         return false;
       }

       if ( OppositionPet && c.ControlMaster != null )
       {
         return false;
       }
       
       switch ( OppositionList )
       {
         case OppositionType.Juka: return JukaEnemy(c.OppositionList);
         case OppositionType.Meer: return MeerEnemy(c.OppositionList);
         case OppositionType.Terathan: return TerathanEnemy(c.OppositionList);
         case OppositionType.Ophidian: return OphidianEnemy(c.OppositionList);
         case OppositionType.Savage: return SavageEnemy(c.OppositionList);
         case OppositionType.Orc: return OrcEnemy(c.OppositionList);
         case OppositionType.BlackSolen: return BlackSolenEnemy(c.OppositionList);
         case OppositionType.RedSolen: return RedSolenEnemy(c.OppositionList);
         case OppositionType.Fey: return FeyEnemy(c.OppositionList);
         case OppositionType.Undead: return UndeadEnemy(c.OppositionList);
         case OppositionType.Daemon: return DaemonEnemy(c.OppositionList);
         case OppositionType.Dragon: return DragonEnemy(c.OppositionList);
         case OppositionType.Exodus: return ExodusEnemy(c.OppositionList);
         case OppositionType.Elemental: return ElementalEnemy(c.OppositionList);
         default: return false;
       }
     }
     
     private bool JukaEnemy( OppositionType egroup )
     {
       switch ( egroup )
       {
         case OppositionType.Meer: return true;
         default: return false;
       }
     }

     private bool MeerEnemy( OppositionType egroup )
     {
       switch ( egroup )
       {
         case OppositionType.Juka: return true;
         default: return false;
       }
     }

     private bool TerathanEnemy( OppositionType egroup )
     {
       switch ( egroup )
       {
         case OppositionType.Ophidian: return true;
         default: return false;
       }
     }

     private bool OphidianEnemy( OppositionType egroup )
     {
       switch ( egroup )
       {
         case OppositionType.Terathan: return true;
         default: return false;
       }
     }

     private bool SavageEnemy( OppositionType egroup )
     {
       switch ( egroup )
       {
         case OppositionType.Orc: return true;
         default: return false;
       }
     }

     private bool OrcEnemy( OppositionType egroup )
     {
       switch ( egroup )
       {
         case OppositionType.Savage: return true;
         default: return false;
       }
     }

     private bool BlackSolenEnemy( OppositionType egroup )
     {
       switch ( egroup )
       {
         case OppositionType.RedSolen: return true;
         default: return false;
       }
     }

     private bool RedSolenEnemy( OppositionType egroup )
     {
       switch ( egroup )
       {
         case OppositionType.BlackSolen: return true;
         default: return false;
       }
     }

     private bool FeyEnemy( OppositionType egroup )
     {
       switch ( egroup )
       {
         case OppositionType.Undead: return true;
         default: return false;
       }
     }

     private bool UndeadEnemy( OppositionType egroup )
     {
       switch ( egroup )
       {
         case OppositionType.Fey: return true;
         default: return false;
       }
     }

     private bool DaemonEnemy( OppositionType egroup )
     {
       switch ( egroup )
       {
         default: return false;
       }
     }

     private bool DragonEnemy( OppositionType egroup )
     {
       switch ( egroup )
       {
         default: return false;
       }
     }

     private bool ExodusEnemy( OppositionType egroup )
     {
       switch ( egroup )
       {
         default: return false;
       }
     }

     private bool ElementalEnemy( OppositionType egroup )
     {
       switch ( egroup )
       {
         default: return false;
       }
     }
//GS//

//GS
     public virtual bool IsFriend( Mobile m )
     {
       if (OppositionListEnemy(m))
  {
  return false;
  }

  OppositionGroup g = OppositionGroup;

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

  if (!(m is BaseCreature))
  {
  return false;
  }

  BaseCreature c = (BaseCreature)m;

  return (m_iTeam == c.m_iTeam && ((m_bSummoned || m_bControlled) == (c.m_bSummoned || c.m_bControlled))
  /* && c.Combatant != this */);
     }

//GS//

//GS
     public virtual bool IsEnemy( Mobile m )
     {
  XmlIsEnemy a = (XmlIsEnemy)XmlAttach.FindAttachment(this, typeof(XmlIsEnemy));

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

       if (OppositionListEnemy(m))
  {
         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 (!(m is BaseCreature) || m is MilitiaFighter)
  {
  return true;
  }

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

  BaseCreature c = (BaseCreature)m;
  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;

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

Patchnotes:
vS1.01 - 10/26/2016
fixed elemental OT to use elemental module, rather than exodus

Stat Scalars & Bonuses

Code:
Version S1.02
This thread is about how to make creatures' secondary stats (hits, mana, stamina, breath damage) directly correlate to primary stats (strength, intellect, dexterity) along with how to add an additional bonus instead of using arbitrary secondary stat declarations.

I've also added two additional things to this list:
A 'never paragon' property virtual flag, so one can set special (eg: boss) monsters to never spawn as paragons.
Additional breath damage controls.

First, this is all done in BaseCreature.cs, but the individual scalars and bonuses can be overridden in individual creature files, allowing type by type control of their stats. For example, a humanoid creature might be desirable to receive 50% of strength plus 50 hits to mimic the scale of a player.

These scaled stats will also be affected by status effects such as bless and curse.

They are, however, overridden if the arbitrary secondary stats are set.

Almost nothing changes by default. (creatures converting to/from being a paragon are restored to full) These are intended as tools to provide additional options and controls when making creatures.

These properties are virtual flags, which means they are set by type, and are not serialized.

The below cs file contains the modules. It is [b][u]NOT[/u][/b] a loadable .cs file itself, and the modules must be manually edited into basecreature.cs, replacing or merging with existing ones.

I suggest pasting the first, non-replacement section (property virtual flags) just below AlwaysAttackable property virtual flag.

The comment tags themselves mark the beginning (//GS) and end (//GS//) of each section (either whole modules or a list of virtual flags). I advise including them for future reference.

Use Ctrl+F and paste in the module names to quickly search for the modules in basecreature.cs.

Contains the following existing modules that need merged/replaced:
HitsMax
StamMax
ManaMax
IsParagon
OnBeforeSpawn( Point3D location, Map m )
BreathComputeDamage()
Code:
//GS
     // Stat multipliers
     public virtual long HitScale{ get{ return 1; } }         // Multiplies hitpoints from strength
     public virtual long StamScale{ get{ return 1; } }         // Multiplies stamina from dexterity
     public virtual long ManaScale{ get{ return 1; } }         // Multiplies manapoints from intelligence
     public virtual long ParagonHitScale{ get{ return 5; } }       // Multiplies hitpoints from strength for paragons
     public virtual long ParagonStamScale{ get{ return 1; } }     // Multiplies stamina from dexterity for paragons
     public virtual long ParagonManaScale{ get{ return 1; } }     // Multiplies manapoints from intelligence for paragons

     // Stat bonuses
     public virtual int HitBonus{ get{ return 0; } }           // Adds hitpoints to scaled total
     public virtual int StamBonus{ get{ return 0; } }         // Adds stamina to scaled total
     public virtual int ManaBonus{ get{ return 0; } }         // Adds manapoints to scaled total
     public virtual int ParagonHitBonus{ get{ return 0; } }       // Adds hitpoints to scaled total for paragons
     public virtual int ParagonStamBonus{ get{ return 0; } }       // Adds stamina to scaled total for paragons
     public virtual int ParagonManaBonus{ get{ return 0; } }       // Adds manapoints to scaled total for paragons

     // Breath Damage Controllers
     public virtual int BreathDamageMin{ get{ return 1; } }       // Minimum breath damage
     public virtual int BreathDamageMax{ get{ return 200; } }     // Maximum breath damage
     public virtual int BreathDamageBonus{ get{ return 0; } }     // Adds damage to breath attack total
     public virtual int ParagonBreathMin{ get{ return 1; } }       // Minimum breath damage for paragons
     public virtual int ParagonBreathMax{ get{ return 200; } }     // Maximum breath damage for paragons
     public virtual int ParagonBreathBonus{ get{ return 0; } }     // Adds damage to breath attack total for paragons
     public virtual long ParagonBreathScalar{ get{ return 1; } }     // Multiplies breath damage for paragons

     public virtual bool NeverParagon{ get{ return false; } }     // This unit will never spawn as a paragon; for bosses
//GS//

//GS
  [CommandProperty(AccessLevel.GameMaster)]
  public override int HitsMax
  {
  get
  {
  if (m_HitsMax > 0)
  {
  int value = m_HitsMax + GetStatOffset(StatType.Str);

  if (value < 1)
  {
  value = 1;
  }
  else if (value > 1000000)
  {
  value = 1000000;
  }

  return value;
  }
         
         if ( IsParagon )
  {
           return (int)(Str * ParagonHitScale + ParagonHitBonus);
  }

         return (int)(Str * HitScale + HitBonus);
       }
     }
//GS//

//GS
     [CommandProperty( AccessLevel.GameMaster )]
     public override int StamMax
     {
       get
       {
  if (m_StamMax > 0)
  {
  int value = m_StamMax + GetStatOffset(StatType.Dex);

  if (value < 1)
  {
  value = 1;
  }
  else if (value > 1000000)
  {
  value = 1000000;
  }

  return value;
  }

         if ( IsParagon )
  {
           return (int)(Dex * ParagonStamScale + ParagonStamBonus);
  }

         return (int)(Dex * StamScale + StamBonus);
       }
     }
//GS//

//GS
     [CommandProperty( AccessLevel.GameMaster )]
     public override int ManaMax
     {
       get
       {
  if (m_ManaMax > 0)
  {
  int value = m_ManaMax + GetStatOffset(StatType.Int);

  if (value < 1)
  {
  value = 1;
  }
  else if (value > 1000000)
  {
  value = 1000000;
  }

  return value;
  }

         if ( IsParagon )
  {
           return (int)(Int * ParagonManaScale + ParagonManaBonus);
  }

         return (int)(Int * ManaScale + ManaBonus);
       }
     }
//GS//

//GS
     [CommandProperty( AccessLevel.GameMaster )]
     public bool IsParagon
     {
       get{ return m_Paragon; }
       set
       {
         if ( NeverParagon )
         {
           m_Paragon = false;
           return;
         }

         if ( m_Paragon == value )
  {
           return;
  }
         else if ( value )
  {
  XmlParagon.Convert(this);
  }
         else
  {
  XmlParagon.UnConvert(this);
  }

         m_Paragon = value;
         Hits = HitsMax;
         Mana = ManaMax;
         Stam = StamMax;
         InvalidateProperties();
       }
     }
//GS//

//GS
     public override void OnBeforeSpawn( Point3D location, Map m )
     {
       if ( !NeverParagon && XmlParagon.CheckConvert(this, location, m) )
  {
  IsParagon = true;
  }

       base.OnBeforeSpawn( location, m );
     }
//GS//

//GS
     public virtual int BreathComputeDamage()
     {
       int damage;

       if ( IsParagon )
       {
         damage = (int)(Hits * BreathDamageScalar * ParagonBreathScalar);

         if ( m_HitsMax > 0 )
         {
           damage = (int)(damage / XmlParagon.GetHitsBuff(this) + ParagonBreathBonus);
         }
         else if ( IsParagon )
         {
           damage = (int)(damage * HitScale / ParagonHitScale + ParagonBreathBonus);
         }

         if ( damage < ParagonBreathMin )
         {
           damage = ParagonBreathMin;
         }
         else if ( damage > ParagonBreathMax )
         {
           damage = ParagonBreathMax;
         }

         return damage;
       }

       damage = (int)(Hits * BreathDamageScalar + BreathDamageBonus);

       if ( damage < BreathDamageMin )
       {
         damage = BreathDamageMin;
       }
       else if ( damage > BreathDamageMax )
       {
         damage = BreathDamageMax;
       }

       return damage;
     }
//GS//

Patchnotes:
vS1.02 - 10/25/2016
Small formatting changes
vS1.01 - 10/23/2016
Fixed paragons' breath damage to multiply by base hitscale, then divide by paragonhitscale, because paragonhitscale completely replaces hitscale for paragons
 
We use a lot of Runuo JustUo and Serveuo scripts it mostly minor changes for some and some are drag and drop no problem
 
Back