arphile
Member
Just see it, and make your own Achievement System.
This system track manythingsSorry, can't read what's on the gump. What does the system track?
Achievements.Push("My Achievement Id", player);
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:
This would either Add the achievement to the player, or up the count for the achievement if its a count based one.Code:Achievements.Push("My Achievement Id", player);
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.
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!");
}
}
}
}
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.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.
I've just noticedServUO 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.
<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>
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.
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>당신이 사냥한 제물은 이 업적의 달성을 도울것이다." ),
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.
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
That's strange, how new is your ServUo copy?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.
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 gatheringlooks like a very nice system. and I totally agree, we do need more eventsinks.
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
StringList list = new StringList("ENU");
string name = list.GetString(itemID+1020000);
We use essential cookies to make this site work, and optional cookies to enhance your experience.