If you're having trouble or run into any bugs with the code, post a comment here! I will try to get back to you within a few days.
In-depth ingame achievement support for Ren'Py that plugs into the Steam backend. · By
Hello! In Steamworks, you can go to Technical Tools > Edit Steamworks Settings > Stats & Achievements > Achievements and add a new achievement. The first column, called API Name, is the ID for the achievement. This should be the same ID as you set when you make your Achievement objects in-game using the system. You can then add the locked/unlocked images in Steamworks as per usual. The only important thing is that the achievement has the same ID as the in-game one! Aside from that, the backend of registering and granting the achievement for Steam is all taken care of via the system. Hope that helps!
Thanks for the quick response! I added an achievement with the same ID as in your Example 1 to Steamworks. I also added a steam_appid.txt file with the game id near the .exe file. The in-game achievement works (using $ sample_achievement.grant() ), but it is not granted at Steam. I run the game through Steam and the overlay (Shift+tab) works.
Did you install the Steam support from the Ren'Py launcher? That's required for any Steam integration. Remember also that you'll have to go through Steam to clear any achievements if you'd like to re-see the popup, as the clear method only clears it on Ren'Py's end. You can install the Steam support via the launcher Preferences -> Install Libraries -> Install Steam Support. The overlay isn't related to whether Steam support is installed or not, just if you're playing it through Steam. Let me know if that fixes it for you!
If I understood your question - you can declare the achievements in whichever rpy file in your project you like. The included achievements.rpy file has several example achievements, so it probably makes sense to declare your own achievements there. Be sure to read the included README for more instructions on what details you can provide to each achievement as well! You might consider reading https://feniksdev.com/organizing-a-renpy-project/ if you're new to Ren'Py project organization in general.
So if I understood, you just want a notification screen? You certainly don't need to go through the achievement system for that; just make yourself a screen and show it with your desired notification. You can copy the general format of the achievement popup screen and methods for that, but I'm afraid that would be out of the scope of things I can help with for this system.
Hi, I was having difficulties accessing the achievement screen on my main menu so I looked around and found that deleting the second datetime (line 131 and 148) in the achievements backend solved it. I do not know if it's a bug on my end or my game but thought I'd let you know! Fanatastic asset, very excited to customise it!
The current achievement code is correct! But sometimes other people import the datetime module separately, which could cause this conflict. It usually looks like from datetime import datetime instead of just import datetime. I would check your project for other places where the datetime module is used to see what's causing that. If you've imported datetime differently, then your fix will work.
Glad you like the system! I hope you find it useful :)
Hello! Thank you very much for the great feature!
As I was testing out the achievement pop-ups I saw that the name of the achievements and descriptions were not showing up, then I realized I set gui.text_color in gui.rpy to black, is there a way to make the achievement text not rely on the same gui type as that of dialogue? Or is there a way to change the color of the popup box to white?
I sincerely apologize for any inconvenience :c
Sure! You can change the text colour of any of the screens however you like by adjusting the styles; all of the existing styling is meant to be changed to suit your project. I suggest you hover over the text in question and hit shift+i to find which styles are affecting it, or you can find the lines in achievements.rpy and just add color "#fff" or similar to whichever line of text you need. For example, you can change the line text a.description size 25 to text a.description size 25 color "#fff" to make the text white. Hope that helps!
the problem is that the minigame uses that time variable to countdown to the end of each phase. im not entirely sure what to change in order to separate the countdown time from the default time https://imgur.com/ZxmZGCv
It's not a requirement or anything! That's just an example of a button you can make so players can see your achievement gallery. In a standard Ren'Py project, that would go on screen navigation in the same pattern as all the other buttons there. But you can create whatever kind of button or method to access the achievement gallery that you want.
You can look up regular screen language in Ren'Py for more information on how UI works in Ren'Py. I have some tutorials on my website also https://feniksdev.com/navigation/
Hello, my friend. Just one stupid question.
In achievement_backend.rpy, line 457:
ACHIEVEMENT_SOUND = "audio/interface/ach.ogg"
I got the right path and there's no problem with this sound, but in-game granting going without any sound. I really don't know, why, mb I need to change smth, not the only one line?
Sound channel is also correct
btw sry my english is bad and im drunk a little
You're meant to change the sound with your own define statement, not in the backend file! For example,
define myconfig.ACHIEVEMENT_SOUND = "audio/interface/ach.ogg"
The achievements.rpy file has examples of that. If you're only changing it in the backend, then the redeclaration in achievements.rpy will be overwriting it with None. The backend file has an early initialization order so it can be set up early before it's used and modified with a regular define statement.
So, in short, change it in achievements.rpy not in the backend file :) Hope that helps!
Hello! You have to make a button to lead to the achievement gallery yourself - it's not built into your project or the tool because I don't know how your main menu screen is set up. That's what this bit of code in the instructions is for:
textbutton _("Achievements") action ShowMenu("achievement_gallery")
You need to add that or something similar to your project to access the achievement gallery. Don't delete datetime either - that was a very specific case where another bit of code had imported datetime already in a different way. I suggest not changing anything in the backend unless you understand what you're doing.
So my game has 15 achievements (14 dis-including Platinum Achievement) sorry if this is a lot
This is what I've coded every time an achievement is unlocked
These are my "if"s I've set up
(The 8th achievement is the bar one, I've already done coding for that one)
And this is the Platinum Achievement code on the achievement script
So what I'm understanding based on the code you've posted is that you're very new to coding. That's all right, but you will need to have a basic grasp of how variables (getting and setting them) work in order to understand how to use the achievement code. I really recommend you begin with https://feniksdev.com/a-quick-primer-on-variables-in-renpy/ and go through the rest of the tutorials in that series to see how to declare variables and update them. Then I recommend you read over the examples included with the achievements - you should follow the example very closely and just tweak things until they work how you want. A better understanding of variables will help you see what the system is doing and how you can follow the examples to do what you want. Good luck!
If you want to check if the player is skipping a specific section of dialogue, you can check for if renpy.is_skipping(): (https://www.renpy.org/doc/html/other.html#renpy.is_skipping) at the start of that dialogue, and if it's true, grant your achievement. Otherwise, you can also add an achievement action to the Skip button on the quick menu (e.g. action [skip_achievement.Grant(), Skip()] on the quick menu button). The latter suggestion will *not* cover the case if the player uses a keyboard key like CTRL or Tab to start skipping; the best way to handle that more general case would be through a callback https://www.renpy.org/doc/html/config.html#var-config.interact_callbacks. If you're new to coding, I would wait to implement the last option until you're a bit more comfortable with Python! I hope that helps :)
Hello! I'm having a strange issue with granting achievements during the game.
Here's one achievement as an example:
define ACHex = Achievement( name = _("EXTERMINATOR"), id = "Exterminator", description = _("Get the good ending to the RATS scenario after choosing to kill them."), unlocked_image = "gui/ach/Exterminatora.png", locked_image = "locked_achievement", hidden = False, hide_description=True, )
My issue lies with the [achievementName].grant() function. It's very strange, because while some instances of the function work, others (and the ones I need most) don't seem to. For example, when I grant the achievement as a screen function like this (for testing purposes only):
textbutton "GET" action Function(ACHex.grant)
It works! The art and description show up, which is what I want. But the problem is that I want to grant the achievements in the game itself as you play. But, when I do so by putting this in the actual scene of the game:
$ ACHex.grant()
Nothing happens. I've toggled all of my achievements to hide and unhide them while testing, so I can confirm that they all have the proper art, title, and description once their achievements are granted. I've also made sure to restart the game, and double check that Steams support is up to date (My game is already on Steam so this was just to be sure).
The main thing I want to know is how I can get the achievements to be granted in real time as you play like in the example above (only functional lol). Any help would be awesome, this is a neat tool and I'd like to get it working! ✌✨
So, when you say nothing happens - does it not grant the achievement at all, or are you just not seeing the popup? You can watch the status of the achievement by bringing up the console with shift+o and typing watch ACHex.has() for example. If you already have the achievement, it won't re-grant it. If proceeding past that line in your script does not change the achievement to being unlocked, then that's a different issue from it changing it and you not seeing the popup screen. If you're testing on Steam, you may need to clear the achievements from their backend as well. See the bottom of this article: https://partner.steamgames.com/doc/features/achievements/ach_guide
Thanks! As it turns out, it was actually an issue with how I was calling the achievements menu (I had a feature that was able to delete all achievements after clicking another confirmation box) that was clearing the achievements as the menu was called for some reason. The good news is that I found this out by using the shift+o console method which I actually didn't know about before, so thanks for the help! I used this to test all of my achievements and if they were being granted correctly, and it's been a big help! ✌✨
Hi there! In-script, you can grant achievements with
$ achievement_you_made.grant()
Remember it'll only show a popup if you've got the configuration options set to allow them + you haven't gotten that achievement before. You can use the Delete Persistent option in the Ren'Py launcher to fully reset all achievements.
Hello! Can you please explain this part in a bit more detail. I am trying to make an achievement that is granted once player tries all 4 options of something.
# $ persistent.seen_endings.add("end1")
# $ ending_achievement.progress(len(persistent.seen_endings))
## This will prevent the achievement from being added to multiple times if the
## player sees the same ending multiple times.
I tried to do my own version and keep getting the error
```
AttributeError: 'int' object has no attribute 'add'
or
AttributeError: 'NoneType' object has no attribute 'add'
Do we need to define the class somewhere? I'm also severely sleep deprived so may be making simple mistake. Overall love this code a lot though!
You need to create a persistent set, e.g.
default persistent.seen_endings = set()
and then you will add to that set when you reach a relevant part in the game (that's this part:)
$ persistent.seen_endings.add("end1")
and in order to record that progress for an achievement, you can set the progress to the length of the list e.g.
$ ending_achievement.progress(len(persistent.seen_endings))
Sets are used because they can't have duplicates, so the length of the list will be the number of unique endings the player has seen, and it won't matter if they go through the same ending multiple times/it won't count them more than once towards the achievement.
Thank you for the speedy response! I really appreciate the breakdown.
I discovered that the issue was actually with the name I was giving my variable...I'm still not sure why it was happening but I suspect it was too similar to the name of something else in my project. Once I followed your code with a different name it worked!
Thanks again for your contributions as I'm really excited to have this feature and I will be crediting you in the final release!