I already made Achievement System.

here is my example about this system, but if you want to use this script,
huge modify is necessary.
so I cannot publish this script....

Just see it, and make your own Achievement System.
 

Attachments

  • KakaoTalk_20141105_105756166.png
    KakaoTalk_20141105_105756166.png
    135.1 KB · Views: 322
Looks very nice.

I actually have planned an achievement system myself that I will be releasing here once finished (probably after xmas)
 
Sorry, can't read what's on the gump. What does the system track?
This system track manythings
like hunting monsters, killing bosses, making stuffs, using skills, how many times my char had been dead,
and my shard contains critical system. so it tracks a lot of custom systems...
 
The interface (Gump) is not the problem just the amount of Spots to customize. So i can understand that the Author dont want to publish all files or documentate.
I guess a final solution would be a simple framework, allowing to add new Entries to a generic UI and then let the user do the counting etc. That alone would help a few users i think.
 
That is the plan. It is actually almost finished. It is a fully modular system where you can drop in new achievements and it updates the whole system automatically. It also requires no distro edits!

I have finals in a few weeks so when they are finished then I will get this finished
 
I could just release the original that I had mentioned before everyone started making these new ones lol. Didn't realize the idea would blow up so big :)
 
Go ahead! I am sure people would love to use it :)

Mine was more of an experiment on my part that turned into a pretty big system in the end. Would love to compare with a completed system.

Edit: Didn't mean to thumbs down your post :O misclick!
 
I have been wanting something like this for a while but it is very much outside my abilities. Don't just tease us lol. Any chance of a release of it soon since none other exist in the wild? This is directed at bother dmuprhy and Tresdni. :)
 
I say this almost a joke. every shard is getting one and no one shares the code. Exale I wouldn't expect to see this anytime soon.
 
  • Like
Reactions: ExX
The hard part about sharing an achievement system would be making it easy to install. Achievements can happen all through-out the scripts, so making a system that doesn't require editing of core/script scripts, is pretty much near impossible. This makes supporting a shared Achievement system really difficult. I'll give you an example.

Lets say you wanted to give someone an achievement based on killing a specific mob. Theres really no good way to get notification of this unless you either override OnDeath on that specific Mob, or goto the Mobile.cs script in the Core, and edit OnDeath to notify your Achievement system (which would require your achievement system to reside in the core) or create a new event inside EventSink to allow notification of such events (In either case, a core edit... not advised).

The system itself would be extremely easy to make. Probably a simple script that tracked player achievements by id, could get simple notification with something like:
Code:
Achievements.Push("My Achievement Id", player);
This would either Add the achievement to the player, or up the count for the achievement if its a count based one.

Ideally you want someone to make a simple system that has no scripted achievements, containing Simple Gump setup and a single easy to make call to push and achievement to the player, then you can add the achievements manually as you see fit.
 
I also think the most required thing would be a framework, so you can Push you own content to it. The details like What achievements you have are not necessary, but the framework easy add it.
 
  • Like
Reactions: ExX
The hard part about sharing an achievement system would be making it easy to install. Achievements can happen all through-out the scripts, so making a system that doesn't require editing of core/script scripts, is pretty much near impossible. This makes supporting a shared Achievement system really difficult. I'll give you an example.

Lets say you wanted to give someone an achievement based on killing a specific mob. Theres really no good way to get notification of this unless you either override OnDeath on that specific Mob, or goto the Mobile.cs script in the Core, and edit OnDeath to notify your Achievement system (which would require your achievement system to reside in the core) or create a new event inside EventSink to allow notification of such events (In either case, a core edit... not advised).

The system itself would be extremely easy to make. Probably a simple script that tracked player achievements by id, could get simple notification with something like:
Code:
Achievements.Push("My Achievement Id", player);
This would either Add the achievement to the player, or up the count for the achievement if its a count based one.

Ideally you want someone to make a simple system that has no scripted achievements, containing Simple Gump setup and a single easy to make call to push and achievement to the player, then you can add the achievements manually as you see fit.

Actually, a ton of achievements can be made without having to edit the distro by using the eventsink.

Check out this achievement from my system that requires you to kill x amount of ratmen. The system is not finished or I would share it but I am sure someone can see from this how it is done and work it out them self. If I had time I would and release it.

Code:
using System;
using System.Collections.Generic;
using System.Linq;
using Server.Engines.XmlSpawner2;
using Server.Mobiles;

namespace Server.Achievements.MonsterHunt
{
    class ratmen
    {
        public static int ID = 0;// MUST BE UNIQUE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

        public static string category = "Monster Hunter";

        private static int[] levelAmounts = {100, 500, 1000, 5000, 10000};

        private static string[,] rewards =
        {
            {"Gold", "500"},
            {"Gold", "10000"},
            {"Gold", "20000"},
            {"Gold", "30000"},
            {"Gold", "60000"}
        };

      

        private static readonly AchievementInfo m_Info = new AchievementInfo(
            "Ratmen",
            "Prove yourself as a true RatMan slayer and slay the required amount of ratmen warriors, mages and archers!",
            levelAmounts.Length,
            levelAmounts, rewards, ID, category);


        public static void Initialize()
        {
            EventSink.OnKilledBy += EventSinkOnOnKilledBy;
            AchievementInfo.aList.Add(m_Info);
            if (!AchievementInfo.categories.Exists(e => e == category))
                AchievementInfo.categories.Add(category);

        }

        private static void EventSinkOnOnKilledBy(OnKilledByEventArgs e)
        {
            Mobile pm = e.KilledBy;
            Mobile m = e.Killed;


            var a = (AchievementAttachment)XmlAttach.FindAttachment(pm, typeof(AchievementAttachment));
            List<int> dvalue = a.data[ID];
            if (((BaseCreature)m).ControlMaster != null || ((BaseCreature)m).Summoned) return;
            if ((!(m is Ratman) && !(m is RatmanArcher) && !(m is RatmanMage)) || dvalue[0] > 10000) return;
            dvalue[0]++;

            foreach (int t in levelAmounts.Where(t => dvalue[0] == t))
            {

                dvalue[1]++;
                pm.SendMessage(50, "Achievement Unlocked!");
            }
        }
    }


}

I have made other achievement types too such as enter a certain location and all without having to edit the distro.

EDIT. It needs some work even in that script, initially I was using an array to hold all the achievement information but because there was so many achievments the array got quite large and as it was an object added to each playermobile object it would end up using a lot of resources on some shards, I was working on that problem the last time I was working on it, i had it almost cracked. I might get back to it soon and release what I have.
 
Last edited:
Actually, a ton of achievements can be made without having to edit the distro by using the eventsink.

Check out this achievement from my system that requires you to kill x amount of ratmen. The system is not finished or I would share it but I am sure someone can see from this how it is done and work it out them self. If I had time I would and release it.

Code:
using System;
using System.Collections.Generic;
using System.Linq;
using Server.Engines.XmlSpawner2;
using Server.Mobiles;

namespace Server.Achievements.MonsterHunt
{
    class ratmen
    {
        public static int ID = 0;// MUST BE UNIQUE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

        public static string category = "Monster Hunter";

        private static int[] levelAmounts = {100, 500, 1000, 5000, 10000};

        private static string[,] rewards =
        {
            {"Gold", "500"},
            {"Gold", "10000"},
            {"Gold", "20000"},
            {"Gold", "30000"},
            {"Gold", "60000"}
        };

     

        private static readonly AchievementInfo m_Info = new AchievementInfo(
            "Ratmen",
            "Prove yourself as a true RatMan slayer and slay the required amount of ratmen warriors, mages and archers!",
            levelAmounts.Length,
            levelAmounts, rewards, ID, category);


        public static void Initialize()
        {
            EventSink.OnKilledBy += EventSinkOnOnKilledBy;
            AchievementInfo.aList.Add(m_Info);
            if (!AchievementInfo.categories.Exists(e => e == category))
                AchievementInfo.categories.Add(category);

        }

        private static void EventSinkOnOnKilledBy(OnKilledByEventArgs e)
        {
            Mobile pm = e.KilledBy;
            Mobile m = e.Killed;


            var a = (AchievementAttachment)XmlAttach.FindAttachment(pm, typeof(AchievementAttachment));
            List<int> dvalue = a.data[ID];
            if (((BaseCreature)m).ControlMaster != null || ((BaseCreature)m).Summoned) return;
            if ((!(m is Ratman) && !(m is RatmanArcher) && !(m is RatmanMage)) || dvalue[0] > 10000) return;
            dvalue[0]++;

            foreach (int t in levelAmounts.Where(t => dvalue[0] == t))
            {

                dvalue[1]++;
                pm.SendMessage(50, "Achievement Unlocked!");
            }
        }
    }


}

I have made other achievement types too such as enter a certain location and all without having to edit the distro.

EDIT. It needs some work even in that script, initially I was using an array to hold all the achievement information but because there was so many achievments the array got quite large and as it was an object added to each playermobile object it would end up using a lot of resources on some shards, I was working on that problem the last time I was working on it, i had it almost cracked. I might get back to it soon and release what I have.
Wasn't saying its not possible without distro edits. But there are some big obvious achievements where distro/core edits are needed. OnKilledBy on eventsink, thats not stock RunUO and I wasnt aware ServUO had it. I suppose ServUO might have a lot of core edits that make this possible which is nice. :)
 
Wasn't saying its not possible without distro edits. But there are some big obvious achievements where distro/core edits are needed. OnKilledBy on eventsink, thats not stock RunUO and I wasnt aware ServUO had it. I suppose ServUO might have a lot of core edits that make this possible which is nice. :)

Oh for sure there a ton of nice things that you can do for an achievement system that would definitely require you to edit the distro. I was just showing that you could get a bunch of things done without any distro edits by using the eventsink.

ServUO core is definitely a lot different than the runuo core, sometimes not for the best though. A lot has to be sorted out.
 
Actually, a ton of achievements can be made without having to edit the distro by using the eventsink.

Check out this achievement from my system that requires you to kill x amount of ratmen. The system is not finished or I would share it but I am sure someone can see from this how it is done and work it out them self. If I had time I would and release it.

Code:
using System;
using System.Collections.Generic;
using System.Linq;
using Server.Engines.XmlSpawner2;
using Server.Mobiles;

namespace Server.Achievements.MonsterHunt
{
    class ratmen
    {
        public static int ID = 0;// MUST BE UNIQUE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

        public static string category = "Monster Hunter";

        private static int[] levelAmounts = {100, 500, 1000, 5000, 10000};

        private static string[,] rewards =
        {
            {"Gold", "500"},
            {"Gold", "10000"},
            {"Gold", "20000"},
            {"Gold", "30000"},
            {"Gold", "60000"}
        };

    

        private static readonly AchievementInfo m_Info = new AchievementInfo(
            "Ratmen",
            "Prove yourself as a true RatMan slayer and slay the required amount of ratmen warriors, mages and archers!",
            levelAmounts.Length,
            levelAmounts, rewards, ID, category);


        public static void Initialize()
        {
            EventSink.OnKilledBy += EventSinkOnOnKilledBy;
            AchievementInfo.aList.Add(m_Info);
            if (!AchievementInfo.categories.Exists(e => e == category))
                AchievementInfo.categories.Add(category);

        }

        private static void EventSinkOnOnKilledBy(OnKilledByEventArgs e)
        {
            Mobile pm = e.KilledBy;
            Mobile m = e.Killed;


            var a = (AchievementAttachment)XmlAttach.FindAttachment(pm, typeof(AchievementAttachment));
            List<int> dvalue = a.data[ID];
            if (((BaseCreature)m).ControlMaster != null || ((BaseCreature)m).Summoned) return;
            if ((!(m is Ratman) && !(m is RatmanArcher) && !(m is RatmanMage)) || dvalue[0] > 10000) return;
            dvalue[0]++;

            foreach (int t in levelAmounts.Where(t => dvalue[0] == t))
            {

                dvalue[1]++;
                pm.SendMessage(50, "Achievement Unlocked!");
            }
        }
    }


}

I have made other achievement types too such as enter a certain location and all without having to edit the distro.

EDIT. It needs some work even in that script, initially I was using an array to hold all the achievement information but because there was so many achievments the array got quite large and as it was an object added to each playermobile object it would end up using a lot of resources on some shards, I was working on that problem the last time I was working on it, i had it almost cracked. I might get back to it soon and release what I have.


Looks cool. The achievement system we use uses XML to load achievements in. Can be done at any time. The whole thing is completed and we used it on Shadow Age and most likely on Shards too. We have the the code automatically check where any monster killed, if it is something you need to kill on an achievement will increment. Basically, whatever monsters is in the description of the achievement, it'll know that thats the monster it needs to increment for the achievement. Same thing goes with crafting anything, casting any spells, consuming reagents, gold available, house placement sizes, gametime, etc. We pretty much have all things covered.

This is an example on how a achievement would look like if you are creating it with ours:
Code:
<category uid="11" name="Chivalry">
      <achievement uid="111" name="Tithe Lord" points="100" goal="1000000" enabled="True">
        <art artid="0" arthue="0" artx="0" arty="0" />
        <desc>Consume 1,000,000 Tithing Points.</desc>
      </achievement>

This basically means in the Category, Chivalry, we add this achievement called Tithe Lord, which awards 100 achievement points, and needs to consume 1,000,000 tithing to complete. Itll also track progress in the gump.

You could also add an art ID, hue, and the x,y coordinates of it for the gump.

Once you get comfortable with it, you can throw out hundreds of achievements a day. I think we had like 700+ at one point.
 
Looks cool. The achievement system we use uses XML to load achievements in. Can be done at any time. The whole thing is completed and we used it on Shadow Age and most likely on Shards too. We have the the code automatically check where any monster killed, if it is something you need to kill on an achievement will increment. Basically, whatever monsters is in the description of the achievement, it'll know that thats the monster it needs to increment for the achievement. Same thing goes with crafting anything, casting any spells, consuming reagents, gold available, house placement sizes, gametime, etc. We pretty much have all things covered.

This is an example on how a achievement would look like if you are creating it with ours:
Code:
<category uid="11" name="Chivalry">
      <achievement uid="111" name="Tithe Lord" points="100" goal="1000000" enabled="True">
        <art artid="0" arthue="0" artx="0" arty="0" />
        <desc>Consume 1,000,000 Tithing Points.</desc>
      </achievement>

This basically means in the Category, Chivalry, we add this achievement called Tithe Lord, which awards 100 achievement points, and needs to consume 1,000,000 tithing to complete. Itll also track progress in the gump.

You could also add an art ID, hue, and the x,y coordinates of it for the gump.

Once you get comfortable with it, you can throw out hundreds of achievements a day. I think we had like 700+ at one point.

Awesome. I should get back to that system :p It was almost finished.
 
few days ago, I uploaded my achievement script on this site.

Now a days, I remade this system and also works well!

here's an example of database script.
new AchievementDatabase(
/* Name */ "Monster Hunter",
/* Code Number */ 000 ,
/* Aim Array[] */ new uint[] { 500, 1000, 2500, 5000, 10000, 100000, 500000, 1000000, 5000000, 10000000, 50000000, 100000000 } ,
/* Point Array[] */ new int[] { 10, 10, 10, 10, 15, 15, 15, 20, 20, 30, 30, 40 } ,
/* Rewards[] */ new Type[] { typeof(BankCheck), typeof(BankCheck), typeof(BankCheck), typeof(BankCheck), typeof(BankCheck), typeof(BankCheck), typeof(BankCheck), typeof(BankCheck), typeof(BankCheck), typeof(BankCheck), typeof(BankCheck), typeof(BankCheck) } ,
/* Rew_Amounts[] */ new int[] { 1000, 2000, 4000, 8000, 16000, 32000, 64000, 128000, 256000, 512000, 1024000, 2048000 } ,
/* Information */ "어떠한 타입이든 사냥을 하라!<BR>당신이 사냥한 제물은 이 업적의 달성을 도울것이다." ),

Here's an image of Achievements Gump.

acontinentarsene.uorefresh.net_files_attach_images_1605_607_001_9ac5703701f4971e289391193fd7b8a0.jpg

Maybe somedays, I think I'll share this code. lol...
 
Looks cool. The achievement system we use uses XML to load achievements in. Can be done at any time. The whole thing is completed and we used it on Shadow Age and most likely on Shards too. We have the the code automatically check where any monster killed, if it is something you need to kill on an achievement will increment. Basically, whatever monsters is in the description of the achievement, it'll know that thats the monster it needs to increment for the achievement. Same thing goes with crafting anything, casting any spells, consuming reagents, gold available, house placement sizes, gametime, etc. We pretty much have all things covered.

This is an example on how a achievement would look like if you are creating it with ours:
Code:
<category uid="11" name="Chivalry">
      <achievement uid="111" name="Tithe Lord" points="100" goal="1000000" enabled="True">
        <art artid="0" arthue="0" artx="0" arty="0" />
        <desc>Consume 1,000,000 Tithing Points.</desc>
      </achievement>

This basically means in the Category, Chivalry, we add this achievement called Tithe Lord, which awards 100 achievement points, and needs to consume 1,000,000 tithing to complete. Itll also track progress in the gump.

You could also add an art ID, hue, and the x,y coordinates of it for the gump.

Once you get comfortable with it, you can throw out hundreds of achievements a day. I think we had like 700+ at one point.

If you don't mind me asking which xml attachment does it use. I have been attempting to build a achievement system based on the current quest system, I also am attempting to use the eventsink, can't figure it out either. Any help would be appreciated.
 
If you don't mind me asking which xml attachment does it use. I have been attempting to build a achievement system based on the current quest system, I also am attempting to use the eventsink, can't figure it out either. Any help would be appreciated.

It doesn't use an XmlAttachment like in XmlSpawner.
It's our custom built achievement system using the Xml language to load the achievements into the game.
 
Arphile can you post your complete Achievement System Plz ?

Or post Playermobile for First ?

Thanks a Lot
 
Last edited:
I've been working on an achievement system too since no one has released one publicly. Img
Discovery, Kill/Hunting, and resource gathering achieve types so far, other types need more eventsink options.

I've got a pull request in for servuo as well as i noticed OnEnterRegion only ever got null regions while testing.
 
I've been working on an achievement system too since no one has released one publicly. Img
Discovery, Kill/Hunting, and resource gathering achieve types so far, other types need more eventsink options.

looks like a very nice system. and I totally agree, we do need more eventsinks.
 
looks like a very nice system. and I totally agree, we do need more eventsinks.
If you have any suggestions on what events should be added let me know. I have recently added a few. Before save, after save, while gathering and after gathering
 
One for CraftItem.cs under method CompleteCraft

right after from.AddToBackpack(item);

Adding this:
OnCraft( int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, Item item )

This would allow an event for any item crafted and ability to check the resource type, quality, and if it had a maker's mark; among other things.

Note: Still trying to get it to display the item's name in a string. CraftItem has m_NameString / NameString / name but none of them seem to pass to a string to display to the player

Edit: I don't mean "add" that line directly - but something like it for an eventsink
 
Last edited:
One for CraftItem.cs under method CompleteCraft

right after from.AddToBackpack(item);

Adding this:
OnCraft( int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, Item item )

This would allow an event for any item crafted and ability to check the resource type, quality, and if it had a maker's mark; among other things.

Note: Still trying to get it to display the item's name in a string. CraftItem has m_NameString / NameString / name but none of them seem to pass to a string to display to the player

Edit: I don't mean "add" that line directly - but something like it for an eventsink

Added an event at successful crafting. There is not need to pass in a lot of that info to the event since it can be gotten from the item already such as a the makers mark.

In order to get the name of an item that does not implicitly have one assigned to it (Most are set to null) you will need to read the client files using Ultima.dll. This is because the client is what decides what the name of the item is using the cliloc files. This means it is multilingual unless you assign a custom name.

It's been a long time since I have done it but I think it is something like this.

Code:
			StringList list = new StringList("ENU");
			string name = list.GetString(itemID+1020000);
 
I tested ServUO latest GIT before making a pull request with my fix, You can reproduce by creating an OnEnterRegion eventsink, then viewing the output while zoning to an area like yew or minoc. No Region is set in the Args in stock servuo.
https://github.com/ServUO/ServUO/pull/841/commits/9daffe5445abd7472a9cb1fce58f3f90a6d51157
As you can see newR gets set to newR.Parent in stock servuo before calling the eventsink.


Im personally working on runuo 2.3 with lots of servuo changes backported, but i test my scripts against the latest ServUO GIT as well.

WiP Code if anyone wants to have a play with it Untested in production so far, and only the 3 achievement types still.

Should be as simple as drop it in your custom scripts folder, than login and type [feats to display the gump, It's setup to store data on an item, rather than the playermobile to keep things drag and drop without any edits required.


As for Eventsink's I'm planning to add the following to support more achievement types, ill do a PR for servuo as well for these
Item Crafted
Skill Gain
Skill Used
House Placed
Maybe UseObject as well
 
Thank you for sharing your code will need to look at it more when I can get to my comp

Why not use XML attachment on player to store data?
 
Because for my own version as you see im doing standard serialization, just storing int,int,timestamp for each achieve to keep memory usage low.
I've also never looked into XML attachments or seen their use, I've only just got into scripting for runuo/servo a few weeks ago.

The code to support non modified playermobiles was just quickly hacked together, if you want to improve it / swap it over to XML attachment, throw a PR my way and ill check it out
 
Back