Achievements

COPPA is something that any new system we developed would have to deal with too.

Not really, COPPA it’s a US federal law that doesn’t apply in EU, so if the achievement server is my own server, we won’t have to deal with it at all; we would have to deal with EU laws though.
If the achievement server ends up being at the US, then yes, we’ll have to deal with COPPA.

On the oter hand, after reading a bit about COPPA, I think having a COPPA compliant site is not difficult for us, specially cause we are not going to ask for any personal infomation, not even the name and even e-mail will be optional, so Children’s Online Privacy is ensured.

The problem with openbadges is not that they support COPPA, is just the opposite: they don’t want to support COPPA so they decided not to admite anyone below the age of 13.

Edit: After reading your post again, I think you were not referring to the achievement service, but about some new site of yours, sorry for the misunderstanting. I’m not deleting the post cause anyway it explain why not openbadges in depth.

My thoughts:

The achievement object can have an optional picture field. That way the server can display a page of achievements with graphical badges. The IF interpreter can display the same thing, using a GET request to fetch the image file. (Have to specify a pixel size.)

The user object has username, email, and userid. I take it the userid will be a generated string and not usually visible to the player? That is, the player will register with a username, password, and (optional) email address.

The interpreter might want to do a query “gameachievements&ifid=…&userid=…” This would return a list of all achievements for that game (completed or not), with a boolean flag for whether that player has completed it or not. This is what you need to display your personal trophy page for the game. (Yes, this information can be extracted from the existing “gameachievements&ifid=…” call, but it’s potentially a much smaller response.)

I like error responses to look like

{"success":"0", "errorcode":"1", "errortext":"Invalid user token"}

That way the client can display a readable message even if it doesn’t recognize the numeric code, or if it doesn’t have a localization/translation table.

On child achievements: this seems like a very fiddly part of the spec. You’ve got special achievements which make another achievement behave differently, and have to be handled differently on both the server and the client side. (The client reports the child is completed and the server responds with the parent’s title and description.) I think this is making life unduly difficult.

I’m hoping for an API where “achieve” actions can be cached locally (for offline use). This means that reporting an achievement should never fail – I mean, it should never report an error saying “Sorry you didn’t really complete that achievement!” It could return an error saying “the server is down” or “you’re not authenticated”, but this implies that the report can be cached and retried later.

Here’s one common case: you launch the game while the net is available. The interpreter does an achievement query and caches the list of all achievement names, descriptions, and badges. The next time you play, you’re offline, so the interpreter checks off achievements locally (and shows them on your trophy page). In a future session, the net is available again, so the interpreter syncs up – it sends its list of checked-off achievements and reads in any that you completed from a different computer.

Another possible case: a game is shipped with a list of achievements. (In a Blorb extension, say.) Now the achievements can be checked off entirely offline; there’s no need for server contact at all.

Obviously it’s not the server API’s job to say what the interpreter can do offline. But all of these cases are made easier if the client can say “I marked achievement X complete, so X is definitely complete, and we will all agree on that.”

In your response yesterday you mention drawbacks of this:

These seem minor. For the first problem, the only failure mode is that the player sees an “You achieved X!” twice on two different machines. This is not wrong, just a little confusing, and then only if you’re not paying attention to your online/offline status.

For the second problem, we could add an optional timestamp=… parameter to the achieve action.

(And, of course, I don’t want to require interpreters to support offline play like this. I just want to make it easy.)

I agree but… we are talking about small images (something like 32x32 or 64x64 foursquare badge icons), aren’t we?

You are right, the userid is sent to client when the user logs in. It may be a UUID like string or just an integer auto-numeric field in the database, but it’s not the username.

You’re right, I’ll add that too.

In fact it was like that when I started, but then I thought achievement libraries would in some cases show that message directly on error, what would lead to english messages in non-english games. On the other hand you are right to say that that would help providing valid messages even for unknown error codes. I think I will add it anyway, cause is probably better to get a detailed message in english that getting a useless “unknow error” message in the game language.

Yes, this part is not the easiest one. Maybe if the API respondes with the parent’s title, description, and ID it would be better, as the client always does the same, mark the responded achievement as completed. So “the conversation” is not like:

C: Achievement X has been completed.
S: OK, yes, it has been completed.
C: To player: [Achievement X has been completed]

but

C: This action has happened.
S: OK, [achievement ID X has been completed].
C: To player:  [Achievement X has been completed]

I mean that you don’t ask for achievement completion or not, you just report an event and server tells you if any achievement has been completed. In fact, I have just realized that the same event may lead to the completion of two or more achievements, so the answer may have to be an array. But this changes everything a lot… time to think about it.

Example:

>KILL ORC CAPTAIN
You kill the Orc Dark lord.                                            (event is sent, two achievements returned)
[You've completed the achievement "Kill 100 orcs"]
[You've completed the achievement "Kill all the orc council members"]
>

Yes , that would be the best implementation possible, something I would like to recommend but not enforce.

In that case your achievements will never be visible in game “hall of fame”, nor in the achievements site, but it may work.

Yes, as I tell to Peter Piers, I think that will eventually happen in all clients, but not specifying that in the protocol/API will just make easier for all game engine authors to adopt it, then I’m sure 90% of them will add support for offline gaming.

Having the achievement shown twice (or more times) is not a big issue, but the timestamp parameter is an awesome method of cheating achievement time, and game-wide, first achiever is allways first achiever (in fact that lead to other type of achievements we have not considered yet, the “world first” achievements).

Would the achievements be listable in a given game with a user command like score or would they be entirely in the interpreter’s scope (available via a tab / menu selection or whatnot)?

Two minor comments to the spec based on Apple’s Game Center deals with achievements:

If the list of achievements is indeed available to the player, a subset of the achievements could be “hidden”. Thus some achievements would be revealed only as the user triggers the conditions. Prior to that the list of achievements would state that there are X hidden achievements available as well as the normally listed ones. This might be the same as “isPublic”, but I can’t parse its definition: exactly how would the non-public achievements be utilized.

Also, there might be two descriptions for an achievement - one displayed prior to getting it and the other displayed after earning it. The former might be a gentle hint towards the conditions, whereas the latter could use more concrete (i.e. spoilery) language.

I would like to keep the game code’s API as simple as possible – just “achieve X” – and let the interpreter do all the work of listing and displaying achievements.

I agree on that, for authoring systems like Inform and any other were interpreter and game are clearly separated, it should be like that. For other authoring systems were the frontier is not that clear (i.e. ngpwas), is still the better approach.

My only doubt at this moment is what I exposed above, if the game should signal an achievement or just signal a milestone, and the interpreter (connecting to server if needed) would then return zero, one or more achivements.

The second way is more complicated, and forces to change the spec draft a lot, but I think it would lead much better with the multipart-achievements, and would make possible the same milestone completing more than one achievement, leaving that login in hands of interpreter/server too, and not in the game.

I see that as an interpreter task.

Well, the non-public achivements were described to be part of a multipart-achivement, but is not exactly a “hidden” achievement. They can be used for that purpose though.

Yes, sounds good, I think an achiement can have an optional “after-complete-description” (if it is not defined, then the normal one would be shown).

You’ve probably already done this research, but since it hasn’t been mentioned in this thread yet (unless I’ve managed to miss something, in which case I apologize to the poster I didn’t notice), here’s how Steam does it (the link is not the official Valve docs, because I couldn’t find it easily there):

There are get/set achievement functions (that take a string as an argument), accompanied by get/set stat functions. Here’s a quote from the page I linked to:

Example code from the same site:

xp += 100;
steam_set_stat_int("Total_XP", steam_get_stat_int("Total_XP") + 100);
if steam_get_stat_int("Total_XP") > 1000
   {
   if !steam_get_achievement("Ach_1000XP") steam_set_achievement("Ach_1000XP");
   }

I like the way that looks.