Preamble
I have written an achievement system I want to share with you. It is not the best way to solve achievement systems nor is it very efficient(though it might be more efficient than NPC scripting) and if you already have an achievement system(src or npc) and it's working for you, please don't change to mine. Mine is rather old(about half a year or more) and back then it was the first time I wrote something completly new for eAthena. What I did today was applying the system to rA and create a working diff.
If you are willing to use this system then I beg you to report any bug found.
Also, if there is enough demand, I might consider re-writing it from scratch, because I am overall unhappy with the system, but not really motivated to further work on it in greater detail. Also the code-style I used back then is totally going against the one I am using nowadays... Don't judge me!
Functions
There are pre-defined types of achievements in this system
Monsterkill Achievements
Itemfind Achievements (Only use this for Items NOT trade/drop/storage-able, or else it will result in abuse)
Itemuse Achievements
Explore Achievements
Quest Achievements
Special Achievements
Let me explain them one after another:
Monsterkill Achievements(0):
Well, name says it mostly, but there is a bit more to it. You can define different types per achievement. The types are counting by ID(0), by size(1), by race(2), by element(3) or for all MvPs(4). And if player A has killed X monsters that meet the requirement, then he gets the achievement.
Itemfind Achievements(1):
Again, name says what it does. If you find certain items, you get the achievement. Make sure you only use it on non tradeable etc. items or it will be abused. It can also be filtered into types. They are the following: ID(0), Equip(1)[see item_db->equip), Type(2)[see item_db->type]. It will count if you drop it and pick it up again, so really, only use it on items not storageable, tradeable and dropable!
Itemuse Achievements(2):
Its porpuse is to count every item used. This achievement might be bugged, report anything you find fishy! It uses the same filtering as Itemfind, so please refer to that.
Explore Achievements(3):
When entering a map, the system checks whether the map is inside the database for explore achievements and if so, it sets the count. If the player visited all maps for one achievement, then he receives the achievement.
Quest Achievements(4):
When finishing certain quests, you are able to gain quest achievements. Simple as that!
Special Achievements(5):
This are achievements in the achievement database. But they are only applicable over @achieve from a GM or with the achieve script_command. This achievement has Event porpuses and is only added for a complete database for your website etc.
Now comes the technical stuff...
How to install the achievement system
1. Download the *.diff and the *.sql file(they are in the *.rar provided).
2. Import the *.sql into your rAthena database.
3. Apply the *.diff onto your rAthena server.
4. Check your ./conf/battle/exp.conf and ./conf/battle/misc.conf: Two new configs have been added: achievement_cutin_duration and achievement_exp_rate. Read the conf files for more information and change it to whatever you wish it to be.
5. Add the two new files ./src/map/achievement.c and ./src/map/achievement.h to your MAKEFILE or to your project solution and recompile!
(^ Up to this point, I won't provide ANY support ^)
How to add achievements
Well, that is mainly why I would like to find another way of solving the achievement system. But currently it is like this:
1. Add your achievement to achievement_db. Here is a brief summary of the columns:
If you chose 5 as type, you are nearly done, skip step 2.
If you chose another type, please read on.
2. Go to the respective table of your chosen type:
0->mob_achievement
1->item_achievement
2->itemuse_achievement
3->explore_achievement
4->quest_achievement
Now add an entry for your newly added achievement.
The columns are rather similiar, but I'll explain in greater detail:
mob_achievement:
achievement_id: Set to ID assigned by achievement_db for your new achievement
type: See description of Mobkill Achievements. There are numbers in brackets for each filtering type
valueX: The value for what to filter. I.e. if you chose ID, then place an ID here. If you chose elements, place a number from the element enum here (see script_commands or src for reference)
amountX: How many to kill
itemfind_achievement:
itemuse_achievement:
achievement_id: Set to ID assigned by achievement_db for your new achievement
type: See description of Itemfind Achievements. There are numbers in brackets for each filtering type
valueX: The value for what to filter. I.e. if you chose ID, then place an ID here.
amountX: How many to find/use
explore_achievement:
achievement_id: Set to ID assigned by achievement_db for your new achievement
mapX: Name of the map. I.e. prontera
quest_achievement:
achievement_id: Set to ID assigned by achievement_db for your new achievement
questX: ID of the quest
3. Last step is to reload the AchievementDB ingame via @reloadachievement or restart your server.
Atcommands
So, I added two atcommands working together with this System:
@achieve <Achievement_ID> <Player_Name>. Give <Player_Name> Achievement with <Achievement_ID> as ID. IT DOES NOT CHECK WHETHER HE MEETS THE REQUIREMENTS! Built in for debugging and special achievements
@reloadachievements. Reload the Achievement DBs. Helpfully if you added new achievements and don't want to restart the server.
Scriptcommands
*Achieve( <AchievementID>{, <Account_ID>});
Same as the Atcommand. If no account_id is given, use attached player. Does also not check if player meets requirements. Intended for special achievements
*GetAchievementInfo(<AchievementID>, <flag>);
Flag determines what to return:
0 = type, 1 = bexp, 2 = jexp, 3 = nameid, 4 = points, 5 = status
5 Only works with attached players and returns 1 if the player finished the achievement and 0 otherwise.
*GetAchievementName(<AchievementID>);
Returns the name of the achievement
*GetAchievementCutin(<AchievementID>);
Returns the name of the cutin of the achievement
I think this is about all you need to know. Please report any bugs and post any suggestions. If you overwhelm me enough, I might rework it to be more user-friendly! Only post bugs and suggestions after you've read through the whole article. I will notive if you haven't.
At last Download
achievement.patch
achievement.sql
€dit:
I really want to stress the following facts again:
Read the whole article!
Only use if you are unable to script/code a system that is suficient to suit your needs or this system matches your needs perfectly(well, w/e)!
Report any found bug!
€dit²:
Forgot to mention. The last achievement is stored within the permanent playervariable "LastAchievement" and it stores the ID of the achievement. So you can check it via NPC script etc.
Changelog:
1.0 FIrst version
1.1 Fixxed bug of not deleting the cutins properly [Thanks Dexter]
1.2 Fixxed cutin bug fully, fixxed typos in config