TheGodfather

So I am trying to do the following:

Make it so paragon are less frequent with spawning.
I know I need a line that says "ConvertFactor = .X somewhere but I can't figure out where.
I also wanna stop them from spawning NPC paragons and limit it to monsters.

Any help is appreciated.

Code:
using System;
using Server.Items;

namespace Server.Mobiles
{
    public class Paragon
    {
        public static double ChestChance = .25;// Chance that a paragon will carry a paragon chest
        public static double ChocolateIngredientChance = .0001;// Chance that a paragon will drop a chocolatiering ingredient
        public static Map[] Maps = new Map[]                   // Maps that paragons will spawn on
        {
            Map.Felucca
        };
        public static Type[] Artifacts = new Type[]
        {
            typeof(GoldBricks), typeof(PhillipsWoodenSteed),
            typeof(AlchemistsBauble), typeof(ArcticDeathDealer),
            typeof(BlazeOfDeath), typeof(BowOfTheJukaKing),
            typeof(BurglarsBandana), typeof(CavortingClub),
            typeof(EnchantedTitanLegBone), typeof(GwennosHarp),
            typeof(IolosLute), typeof(LunaLance),
            typeof(NightsKiss), typeof(NoxRangersHeavyCrossbow),
            typeof(OrcishVisage), typeof(PolarBearMask),
            typeof(ShieldOfInvulnerability), typeof(StaffOfPower),
            typeof(VioletCourage), typeof(HeartOfTheLion),
            typeof(WrathOfTheDryad), typeof(PixieSwatter),
            typeof(GlovesOfThePugilist)
        };
        public static int Hue = 1209;// Paragon hue

        // Buffs
        public static double HitsBuff = 5.0;
        public static double StrBuff = 1.05;
        public static double IntBuff = 1.20;
        public static double DexBuff = 1.20;
        public static double SkillsBuff = 1.20;
        public static double SpeedBuff = 1.20;
        public static double FameBuff = 1.40;
        public static double KarmaBuff = 1.40;
        public static int DamageBuff = 5;
        public static void Convert(BaseCreature bc)
        {
            if (bc.IsParagon ||
                !bc.CanBeParagon)
                return;

            bc.Hue = Hue;

            if (bc.HitsMaxSeed >= 0)
                bc.HitsMaxSeed = (int)(bc.HitsMaxSeed * HitsBuff);

            bc.RawStr = (int)(bc.RawStr * StrBuff);
            bc.RawInt = (int)(bc.RawInt * IntBuff);
            bc.RawDex = (int)(bc.RawDex * DexBuff);

            bc.Hits = bc.HitsMax;
            bc.Mana = bc.ManaMax;
            bc.Stam = bc.StamMax;

            for (int i = 0; i < bc.Skills.Length; i++)
            {
                Skill skill = (Skill)bc.Skills[i];

                if (skill.Base > 0.0)
                    skill.Base *= SkillsBuff;
            }

            bc.PassiveSpeed /= SpeedBuff;
            bc.ActiveSpeed /= SpeedBuff;
            bc.CurrentSpeed = bc.PassiveSpeed;

            bc.DamageMin += DamageBuff;
            bc.DamageMax += DamageBuff;

            if (bc.Fame > 0)
                bc.Fame = (int)(bc.Fame * FameBuff);

            if (bc.Fame > 32000)
                bc.Fame = 32000;

            // TODO: Mana regeneration rate = Sqrt( buffedFame ) / 4

            if (bc.Karma != 0)
            {
                bc.Karma = (int)(bc.Karma * KarmaBuff);

                if (Math.Abs(bc.Karma) > 32000)
                    bc.Karma = 32000 * Math.Sign(bc.Karma);
            }
        }

        public static void UnConvert(BaseCreature bc)
        {
            if (!bc.IsParagon)
                return;

            bc.Hue = 0;

            if (bc.HitsMaxSeed >= 0)
                bc.HitsMaxSeed = (int)(bc.HitsMaxSeed / HitsBuff);

            bc.RawStr = (int)(bc.RawStr / StrBuff);
            bc.RawInt = (int)(bc.RawInt / IntBuff);
            bc.RawDex = (int)(bc.RawDex / DexBuff);

            bc.Hits = bc.HitsMax;
            bc.Mana = bc.ManaMax;
            bc.Stam = bc.StamMax;

            for (int i = 0; i < bc.Skills.Length; i++)
            {
                Skill skill = (Skill)bc.Skills[i];

                if (skill.Base > 0.0)
                    skill.Base /= SkillsBuff;
            }

            bc.PassiveSpeed *= SpeedBuff;
            bc.ActiveSpeed *= SpeedBuff;
            bc.CurrentSpeed = bc.PassiveSpeed;

            bc.DamageMin -= DamageBuff;
            bc.DamageMax -= DamageBuff;

            if (bc.Fame > 0)
                bc.Fame = (int)(bc.Fame / FameBuff);
            if (bc.Karma != 0)
                bc.Karma = (int)(bc.Karma / KarmaBuff);
        }

        public static bool CheckConvert(BaseCreature bc)
        {
            return CheckConvert(bc, bc.Location, bc.Map);
        }

        public static bool CheckConvert(BaseCreature bc, Point3D location, Map m)
        {
            if (!Core.AOS)
                return false;

            if (Array.IndexOf(Maps, m) == -1)
                return false;

            if (bc is BaseChampion || bc is Harrower || bc is BaseVendor || bc is BaseEscortable || bc is Clone || bc.IsParagon)
                return false;

            int fame = bc.Fame;

            if (fame > 32000)
                fame = 32000;

            double chance = 1 / Math.Round(20.0 - (fame / 3200));

            return (chance > Utility.RandomDouble());
        }

        public static bool CheckArtifactChance(Mobile m, BaseCreature bc)
        {
            if (!Core.AOS)
                return false;

            double fame = (double)bc.Fame;

            if (fame > 32000)
                fame = 32000;

            double chance = 1 / (Math.Max(10, 100 * (0.83 - Math.Round(Math.Log(Math.Round(fame / 6000, 3) + 0.001, 10), 3))) * (100 - Math.Sqrt(m.Luck)) / 100.0);

            return chance > Utility.RandomDouble();
        }

        public static void GiveArtifactTo(Mobile m)
        {
            Item item = (Item)Activator.CreateInstance(Artifacts[Utility.Random(Artifacts.Length)]);

            if (m.AddToBackpack(item))
                m.SendMessage("As a reward for slaying the mighty paragon, an artifact has been placed in your backpack.");
            else
                m.SendMessage("As your backpack is full, your reward for destroying the legendary paragon has been placed at your feet.");
        }
    }
}
 
bc.CanBeParagon
Some monsters have this method overriden, as it is marked as virtual.
Personally, i'd place the main code in that as it makes sense.

simply doing:
Code:
return Body.IsMonster;
instead of:
Code:
return true;

(Or you could add a "if (Body.IsMonster) return;" somewhere in the CheckConvert method so everything stays related)

Also, Body.IsAnimal and Body.IsHuman are also some other things you can play with, maybe some are more than just monster, so it's probably worth checking.
The things you could use range from: IsHuman, IsFemale, IsMale, IsGhost, IsMonster, IsAnimal, IsEmpty, IsSea, IsEquipment and IsGargoyle (Take a look at the Body class in the server core).

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

As for the spawning rate, i'd look at:
CheckConvert in Paragon.cs

That would be the actual chance code:
Code:
double chance = 1 / (Math.Max(10, 100 * (0.83 - Math.Round(Math.Log(Math.Round(fame / 6000, 3) + 0.001, 10), 3))) * (100 - Math.Sqrt(m.Luck)) / 100.0);
return chance > Utility.RandomDouble();

But i'm bad at maths, so good luck xD
 
Xmlspawner also has an XmlParagon system. You've got quite a bit more control over paragons with that system and you can spawn them on any facet, regardless of core code.
 
Xmlspawner also has an XmlParagon system. You've got quite a bit more control over paragons with that system and you can spawn them on any facet, regardless of core code.

So is this the one where you have to edit "basecreatures.xml"?
 
Yes, BaseCreature.cs
Code:
XmlParagon v1.00
updated 2/25/08
ArteGordon

SUMMARY
An Xmlspawner attachment that can be applied to individual xmlspawners to customize paragon spawns from that spawner.  Various paragon spawning properties can be set such as buff factors, conversion rate, artifact drop rate, chest drop rate, hue, labels.  Paragon spawning on the spawner can also be entirely disabled.


DESCRIPTION
To use this system, add the XmlParagon attachment to any xmlspawner by using the command 

[addatt xmlparagon

and then targeting an xmlspawner. You can then edit the xmlparagon properties by using the command

[getatt

and targeting the xmlspawner to open the attachments gump and then selecting the properties button on the XmlParagon attachment.
Paragon spawning on any spawner with this attachment will be controlled by the attachment settings.  Normal paragon settings such as map restrictions will not apply.  This means that you can enable paragon spawning on any spawner on any map regardless of the default Paragon settings by adding the attachment to the spawner.

To disable paragon spawning on any spawner, just set the EnableParagon property on the attachment to false.

Custom paragon attachments can also be scripted with different default behavior.  Some simple examples have been included.  MLParagon.cs changes the artifact drops to ML artifacts.  WeakParagon.cs is an XmlParagon attachment with weaker default buff factors.
Custom attachments derived from the XmlParagon attachment can also be scripted and with the following methods that can be overridden for further customization

        public virtual void XmlAddChest(BaseCreature bc, int treasureLevel)
        public virtual double XmlChestChance(BaseCreature bc)
        public virtual string XmlGetParagonLabel(BaseCreature bc)
        public virtual void XmlConvert(BaseCreature bc)
        public virtual void XmlUnConvert(BaseCreature bc)
        public virtual bool XmlCheckConvert(BaseCreature bc, Point3D location, Map m)
        public virtual bool XmlCheckArtifactChance(Mobile m, BaseCreature bc)
        public virtual void XmlGiveArtifactTo(Mobile m, BaseCreature bc)


INSTALLATION
This system involves making six modifications to the BaseCreature script.  No other scripts are affected.  No changes to any serialization are made so the system can be safely added and removed at any time.  Standard paragon spawning on spawners that do not have this attachment is not affected by this system.

STEP 1:
Install the latest XmlSpawner2 package.  This system only works with xmlspawners. Other spawning systems will not be affected.

STEP 2:
Add the following line at the top of Scripts/Engines/AI/Creature/BaseCreature.cs

using Server.Engines.XmlSpawner2;

and make the following additional modifications

around line 368 change this

		public bool IsParagon
		{
			get{ return m_Paragon; }
			set
			{
				if ( m_Paragon == value )
					return;
				else if ( value )
					Paragon.Convert( this );
				else
					Paragon.UnConvert( this );

				m_Paragon = value;

				InvalidateProperties();
			}
		}

to this

        public bool IsParagon
        {
            get { return m_Paragon; }
            set
            {
                // ARTEGORDONMOD
                // add custom paragon conversion support
                if (m_Paragon == value)
                    return;
                else if (value)
                    XmlParagon.Convert(this);
                else
                    XmlParagon.UnConvert(this);
                // end custom paragon conversion support

                m_Paragon = value;

                InvalidateProperties();
            }
        }


STEP 3:
around line 542 change this

		public virtual int BreathComputeDamage()
		{
			int damage = (int)(Hits * BreathDamageScalar);

			if ( IsParagon )
				damage = (int)(damage / Paragon.HitsBuff);

			return damage;
		}

to this

        public virtual int BreathComputeDamage()
        {
            int damage = (int)(Hits * BreathDamageScalar);

            // ARTEGORDONMOD
            // custom paragon support
            if (IsParagon)
                damage = (int)(damage / XmlParagon.GetHitsBuff(this));

            return damage;
        }



STEP 4:
around line 770 change this

		public override string ApplyNameSuffix( string suffix )
		{
			if ( IsParagon )
			{
				if ( suffix.Length == 0 )
					suffix = "(Paragon)";
				else
					suffix = String.Concat( suffix, " (Paragon)" );
			}

			return base.ApplyNameSuffix( suffix );
		}

to this

        public override string ApplyNameSuffix(string suffix)
        {
            if (IsParagon)
            {
                // ARTEGORDONMOD
                // allow custom paragon labels
                if (suffix.Length == 0)
                    suffix = XmlParagon.GetParagonLabel(this);
                else
                    suffix = String.Concat(suffix, " " + XmlParagon.GetParagonLabel(this));
                // end mod to allow custom paragon labels
            }

            return base.ApplyNameSuffix(suffix);
        }

STEP 5:
around line 915 change this

		public override void OnBeforeSpawn( Point3D location, Map m )
		{
			if ( Paragon.CheckConvert( this, location, m ) )
				IsParagon = true;

			base.OnBeforeSpawn( location, m );
		}

to this

        public override void OnBeforeSpawn(Point3D location, Map m)
        {
            // ARTEGORDONMOD
            // add custom paragon conversion support
            if (XmlParagon.CheckConvert(this, location, m))
                IsParagon = true;

            base.OnBeforeSpawn(location, m);
        }

STEP 6:
around line 3903 in the OnBeforeDeath method change this

			if ( !Summoned && !NoKillAwards && !IsBonded && treasureLevel >= 0 )
			{
				if ( m_Paragon && Paragon.ChestChance > Utility.RandomDouble() )
					PackItem( new ParagonChest( this.Name, treasureLevel ) );
				else if ( (Map == Map.Felucca || Map == Map.Trammel) && TreasureMap.LootChance >= Utility.RandomDouble() )
					PackItem( new TreasureMap( treasureLevel, Map ) );
			}	

to this

            if (!Summoned && !NoKillAwards && !IsBonded && treasureLevel >= 0)
            {
                //ARTEGORDONMOD
                // mod to allow custom paragon chest drops
                if (m_Paragon && XmlParagon.GetChestChance(this) > Utility.RandomDouble())
                    XmlParagon.AddChest(this,treasureLevel);
                    // end mod to allow custom paragon chest drops
                else if ((Map == Map.Felucca || Map == Map.Trammel) && TreasureMap.LootChance >= Utility.RandomDouble())
                    PackItem(new TreasureMap(treasureLevel, Map));
            }

STEP 7:
around line 4324 change this

		public virtual void OnKilledBy( Mobile mob )
		{
			if ( m_Paragon && Paragon.CheckArtifactChance( mob, this ) )
				Paragon.GiveArtifactTo( mob );
		}

to this

        public virtual void OnKilledBy(Mobile mob)
        {
            // ARTEGORDONMOD
            // begin custom paragon artifact drops
            if (m_Paragon && XmlParagon.CheckArtifactChance(mob, this))
                XmlParagon.GiveArtifactTo(mob, this);
            // end custom paragon artifact drops
        }
 
Unfortunately no, because my BaseCreature.cs has hundreds of custom edits. The XmlParagon package is installed on ServUO by default though. If that's what you're using, it should already be installed.
 
Unfortunately no, because my BaseCreature.cs has hundreds of custom edits. The XmlParagon package is installed on ServUO by default though. If that's what you're using, it should already be installed.

Is there a way to attach these to all monster spawners without doing it manually? Maybe even by Fame?
 
You would have to code it that way, but yes. Alternatively, you could use XmlFind to locate all the Xmlspawners within a facet, or by name, etc, until you only have the Xmlspawner(s) you want to be paragons.
 
You would have to code it that way, but yes. Alternatively, you could use XmlFind to locate all the Xmlspawners within a facet, or by name, etc, until you only have the Xmlspawner(s) you want to be paragons.
That is kinda genius.
 
Back