# How should I check if a player has completed an achievement?

I'm making an MMO game and I just got to a point where I need to implement achievements... How do I do that? The most straight forward thing to do would be to run this once every 100ms,:

for a in achievements
for p in players
if a.meetsRequirements(p) then p.completeAchievement(a)


But that just raises even more complications. For example, how do I check if the achievement has actually been completed? Do the players have custom properties on themselves just for a specific achievement? I did this kind of thing with quests, because they are mainly "collect 100 wood", so active quests on a player check that. Also, there must be a better time to check it, this would periodically slow my server down, I think.

• Why not just run pertinent checks as the actions are done? I.e. if the user collects wood, see if they match the "collect 100 wood" specification. – Mike Cluck Dec 24 '11 at 19:55
• That kinda seems too messy... There would be tonnes of checks everywhere. I think I'll stick to the above algorithm because of it's simplicity... – jcora Dec 24 '11 at 20:05
• There are ways of making it less messy: such as having an "OnChange" event handler then attach achievement "objects" to those and handle the logic there. Also understand that with your current setup you have a O(n^2) level of complexity which means your game becomes slower a lot faster with more characters. Kind of a problem for a MMO – Mike Cluck Dec 24 '11 at 20:39
• – Tetrad Dec 24 '11 at 22:29

What you do depends on the nature of the achievement. Unless your achievements all fit a simple pattern (collect X number of Ys), you're going to have to special-case them to some degree.

Using a message-based communication system, you can provide hooks that makes the special-case coding localized. You can have certain actions fire messages to listeners who register themselves. Then your achievement code/script can just register itself with the appropriate listeners and do whatever testing is necessary to fire off the achievement.

You would have messages for the typical events you might want achievements to listen for. Things like "player has acquired item X" or "entity Y killed entity Z". This way, you can track things like how many Z's that the player has killed.

That's probably the best you can do for a system for achievements. It centralizes the code as much as possible, and puts the onus on the listeners for the actual achievement detection.

Also, it should be noted that, for centralized achievement systems (X-Box Live, Steam achievements), progress towards achievements is typically stored on the server. So for accumulation achievements ("perform task X Y number of times"), the achievement script just detects when X has been performed and bumps the server's count. For other kinds of achievements ("perform task X"), the server achievement is binary: either you have done it, or you haven't.

• +1 This is great information. Even useful without me needing to implement achievements at this time. – Joshua Hedges Dec 24 '11 at 21:29
• Thanks! Can't wait to implement this, I wish I had this idea before... – jcora Dec 29 '11 at 22:54

Depending on the nature of your achievements you could also introduce some kind of "marker achievements".

If you have for example 3 consecutive achievements:
Wood 1 - Collect 100 wood
Wood 2 - Collect 500 wood
Wood 3 - Collect 1k wood

Then it would make sense to just register an OnChange event for the first achievement until the player completed it. Upon completion you can register the next achievement object.

This of course requires design (or calculation) of an achievement dependency tree.