OP
Xeno
ServUO Version
Publish 58
Ultima Expansion
Endless Journey
Ok, I made some custom things and the perfect place is in Ilshenar but I do not want the main guy to be able to become a paragon. Obviously public override bool IsParagon => false; does not work because I would not be here if it did. I also tried public override bool Paragon => false; which gave an error as well. Is there a way to have a mob in Ilshenar but it cannot spawn as a paragon?
 
I am just glad I was in the right ballpark and part of the script. Thank you!!

EDIT: I found something interesting. It is still spawning as a paragon at times (marked as paragon anyways) but it is not getting the properties of a paragon. Skills and stats in normal range.
 
Last edited:
These suggestions were meant for a single mobile script, if you want to remove Paragon stats from all Paragons, you'll need to edit the Paragon.cs in Services
 
Last edited by a moderator:
Nope, just the one mob. I went back to this public override bool CanBeParagon { get { return false; } } to keep him from actually being a paragon. He sometimes spawns with paragon attached to his name but his stats/skills are within the normal standards. When I added IsParagon = False to the construct, he still spawned as a normal paragon at times.
 
Interesting, I'll do some testing and report back what I find after dinner!

My Test Results : By editing a Lich, I made a Test Mob with the Paragon restrictions listed above!

Code:
using System;
using Server.Items;

namespace Server.Mobiles
{
    [CorpseName("a test mob corpse")]
    public class TestMob : BaseCreature
    {
        [Constructable]
        public TestMob() : base(AIType.AI_NecroMage, FightMode.Closest, 10, 1, 0.2, 0.4)
        {
            Name = "a test mob";
            Body = 24;
            BaseSoundID = 0x3E9;

            SetStr(171, 200);
            SetDex(126, 145);
            SetInt(276, 305);

            SetHits(103, 120);

            SetDamage(24, 26);

            SetDamageType(ResistanceType.Physical, 10);
            SetDamageType(ResistanceType.Cold, 40);
            SetDamageType(ResistanceType.Energy, 50);

            SetResistance(ResistanceType.Physical, 40, 60);
            SetResistance(ResistanceType.Fire, 20, 30);
            SetResistance(ResistanceType.Cold, 50, 60);
            SetResistance(ResistanceType.Poison, 55, 65);
            SetResistance(ResistanceType.Energy, 40, 50);

            SetSkill(SkillName.Necromancy, 89, 99.1);
            SetSkill(SkillName.SpiritSpeak, 90.0, 99.0);

            SetSkill(SkillName.EvalInt, 100.0);
            SetSkill(SkillName.Magery, 70.1, 80.0);
            SetSkill(SkillName.Meditation, 85.1, 95.0);
            SetSkill(SkillName.MagicResist, 80.1, 100.0);
            SetSkill(SkillName.Tactics, 70.1, 90.0);

            Fame = 8000;
            Karma = -8000;
            IsParagon = false; //Added to Restrict Paragon
        }

        public TestMob(Serial serial) : base(serial)
        {
        }

        public override TribeType Tribe => TribeType.Undead;

        public override bool CanBeParagon => false; //Added to restrict Paragon

        public override bool CanRummageCorpses => true;
        public override bool BleedImmune => true;
        public override Poison PoisonImmune => Poison.Lethal;
        public override int TreasureMapLevel => 3;
        public override void GenerateLoot()
        {
            AddLoot(LootPack.Rich);
            AddLoot(LootPack.MedScrolls, 2);
            AddLoot(LootPack.NecroRegs, 17, 24);
            AddLoot(LootPack.RandomLootItem(new Type[] { typeof(LichFormScroll), typeof(PoisonStrikeScroll), typeof(StrangleScroll), typeof(VengefulSpiritScroll), typeof(WitherScroll) }, false, true));
        }

        public override void Serialize(GenericWriter writer)
        {
            base.Serialize(writer);
            writer.Write(0);
        }

        public override void Deserialize(GenericReader reader)
        {
            base.Deserialize(reader);
            int version = reader.ReadInt();
        }
    }
}

Spawned 100 normal lich and had about 10 paragon turn
Spawned 100 Test Mobs and had 0 paragon turn
 
Last edited by a moderator:
Interesting, I'll do some testing and report back what I find after dinner!

My Test Results : By editing a Lich, I made a Test Mob with the Paragon restrictions listed above!

Spawned 100 normal lich and had about 10 paragon turn
Spawned 100 Test Mobs and had 0 paragon turn

IsParagon is default false and not initialized to true during construction.
Paragon conversion is checked at spawn time, after object construction.
Therefore adding this change to the constructor will do nothing.

Since paragon conversion relies on RNG seeded by Fame, your tests can't be conclusive without spawning them hundreds or thousands of times.
 
They are both syntactically correct, the lambda expression is newer syntax for short-handing the former example.
Then according to the paragon script...I can't see how his mobile is saying "paragon" and turning gold. As that FALSE setting should have stopped it from happening.

C#:
        public static void Convert(BaseCreature bc)
        {
            if (bc.IsParagon ||
                !bc.CanBeParagon)
                return;
 
Then according to the paragon script...I can't see how his mobile is saying "paragon" and turning gold. As that FALSE setting should have stopped it from happening.

If IsParagon is set to true, the m_Paragon value will still be set to true regardless of whether paragon conversion is successful.
This means that AddNamePrefix will still give them a tag despite them not converting.
This could be considered a bug with the implementation of the IsParagon setter tbh...

So GD's solution is helpful, it just needs to be in an OnAfterSpawn() method override instead of the constructor.
 
Maybe that check should go in here instead? It is what we did similar for modding RunUO long ago.

C#:
        public static bool CheckConvert(BaseCreature bc, Point3D location, Map m)
        {
            if (Array.IndexOf(Maps, m) == -1)
                return false;

            if (bc is BaseChampion || bc is Harrower || bc is BaseVendor || bc is Clone || bc.IsParagon)
                return false;
 
This existing code;
C#:
        [CommandProperty(AccessLevel.GameMaster)]
        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();
			}
		}

Should probably be replaced with;
C#:
        [CommandProperty(AccessLevel.GameMaster)]
        public bool IsParagon
		{
			get{ return m_Paragon; }
			set
			{
				if (m_Paragon == value)
				{
					return;
				}
				else if (value)
				{
					m_Paragon = Paragon.Convert(this);
				}
				else
				{
					m_Paragon = !Paragon.UnConvert(this);
				}

				InvalidateProperties();
			}
		}

And the Paragon.Convert/Unconvert methods should return a bool; true for success and false for failure.
 
If you only have one (or a few) of the custom mobiles then why not control it in the settings of an XML Spawner?

ie. Dragon/IsParagon/false

If your creation will involve many spawners then maybve try adding this to their scripts:

public override void OnAfterSpawn()
{
this.IsParagon = false;
}
 
Last edited:
Back