View Single Post
Xellath
Veteran Member
Join Date: Dec 2007
Location: Sweden
Old 09-19-2011 , 12:35   Re: Achievements API
Reply With Quote #29

HOW TO: Create a custom achievement (plus a webstats snippet!)

NOTE: It is important to understand that this tutorial assumes you know the basics about Pawn (syntactically and the implementation of it in AMXX). You should be at least an intermediate level scripter with relatively much or some knowledge of APIs.

The following snippets are only commented, well commented, but for those whom does not understand a thing; it is best just to let someone else do the work. Post a request in the request forum instead of struggling with this API.

For multiple achievements in the same plugin, I refer you to look at the achievement_example.sma in the main thread.


achievement_grenade_kills:
An achievement that counts your grenade kills and when the max value (objective) is reached, client is rewarded with completion of the achievement.
Code:
// includes, duh... #include < amxmodx > #include < csx > #include < achievement_api > // declaring the max client size const MaxClients = 32; // max steamid characters const MaxSteamIdChars = 35; // random number for the set_task const TaskIdDelayConnect = 3799; // to make it easier to retrieve the achievement data, we make an enumeration; making it a "structure" enum _:AchievementDataStruct {     _Name[ MaxClients ], // the name of the achievement     _Description[ 256 ], // the description of the achievement (cannot exceed 255 chars - limit set in api)     _Save_Name[ MaxClients ], // the save key of the achievement     _Max_Value // and finally the max value (also referred to as objective value in other achievement plugins) }; // an array built from the struct new const AchievementInfo[ AchievementDataStruct ] = {     "Grenade Kills", // the name of the achievement     "Kill an enemy with a Grenade 50 times", // the description of the achievement (cannot exceed 255 chars - limit set in api)     "progress_grenade", // the save key of the achievement     50 // and finally the max value (also referred to as objective value in other achievement plugins) }; // create a variable new AchievementPointer; // this variable will hold the unique index that the achievement has in the API, allowing you to use it to retrieve data // variable to hold the steamid of a client // 33 cells (for the 32 users) and 35 cells (for the steamid) // const MaxClients = 32; // const MaxSteamIdChars = 35; new SteamId[ MaxClients + 1 ][ MaxSteamIdChars ]; // our objective counter, will hold the current kills of a client // 33 cells (for all the 32 users) new GrenadeKills[ MaxClients + 1 ]; // variable holding the max players (not max slots) new MaxPlayers; public plugin_init( ) // self explanatory {     // register plugin     register_plugin( "Achievement API: Grenade Kills", "0.0.1", "Xellath" );         // register achievement to api     // in the order: Achievement Name, Description, Save Key and Max Value     AchievementPointer = RegisterAchievement( AchievementInfo[ _Name ], AchievementInfo[ _Description ], AchievementInfo[ _Save_Name ], AchievementInfo[ _Max_Value ] );     // will return index of achievement (stored in AchievementPointer)     // assign max players (not max slots)     MaxPlayers = get_maxplayers( );         // the achievement is now registered to the API, lets start with the grenade kill thingy } public client_connect( Client ) // called when client connects {     // set a 10 sec task to check if user has completed or has data for the achievement     set_task( 10.0, "TaskDelayConnect", Client + TaskIdDelayConnect ); } public TaskDelayConnect( TaskId ) {     // our client id (Client) = (TaskId - TaskIdDelayConnect (3799))     new Client = TaskId - TaskIdDelayConnect;         // get steamid of client     get_user_authid( Client, SteamId[ Client ], charsmax( SteamId ) );         // check if our client has objective data     GrenadeKills[ Client ] = GetAchievementData( SteamId[ Client ] /* our key */, AchievementInfo[ _Save_Name ] /* save name for achievement (declared in the array) */ );         // check if client already completed achievement     if( GetClientAchievementStatus( AchievementPointer, GrenadeKills[ Client ] ) == _In_Progress )     {         // achievement not completed                 // save objective data to clients steamid         SetAchievementData( SteamId[ Client ] /* our key */, AchievementInfo[ _Save_Name ] /* save name for achievement */, GrenadeKills[ Client ] /* data */ );     }     else //if( GetClientAchievementStatus( AchievementPointer, Connections[ Client ] ) == _Unlocked )     {         // client has completed achievement already         // send completed to api, but don't announce (or else every client would get all achievements everytime the connect)         ClientAchievementCompleted( Client, AchievementPointer, .Announce = false );     }         // remove task     remove_task( Client + TaskIdDelayConnect ); } public client_disconnect( Client ) {     // reset variable in case played indexes are magically switched and another client gets another set of connections     GrenadeKills[ Client ] = 0; } public client_death( Killer, Victim, WeaponIndex, Hitplace, TeamKill ) // called when a client dies {     // check whether victim and killer are actual players (index above or equal 1 but lower or equal to 32)     if( 1 <= Victim <= MaxPlayers     && 1 <= Killer <= MaxPlayers )     {         // victim did not kill himself         if( Victim != Killer )         {             // was the weapon a hegrenade?             if( WeaponIndex == CSW_HEGRENADE )             {                 // yes it was                 // check if client has unlocked the achievement                 if( GetClientAchievementStatus( AchievementPointer, GrenadeKills[ Killer ] ) == _In_Progress )                 {                     // increment the objective value                     GrenadeKills[ Killer ]++;                     // save data                     SetAchievementData( SteamId[ Killer ] /* our key */, AchievementInfo[ _Save_Name ] /* save name for achievement */, GrenadeKills[ Killer ] /* data */ );                                         // check if client just unlocked the achievement                     if( GetClientAchievementStatus( AchievementPointer, GrenadeKills[ Killer ] ) == _In_Progress )                     {                         // client unlocked the achievement                                                 // send completed to api, and announce                         ClientAchievementCompleted( Killer, AchievementPointer, .Announce = true ); // true is default, but just to clarify                         // the forward below is now called, so to award extra stuff, do something in the forward                     }                 }             }         }     } } public Forward_ClientEarnedAchievement( const AchiPointer, const Client ) // called when client earned the achievement {     if( AchiPointer == AchievementPointer )     {         // this forward can be used to reward people stuff         // perhaps a model or just something extra (like ie. cash from cashmod, pointsystem etc.)     } }


Now for the Webstats snippet. It was done quickly and may not be optimized to it's best, it works as an example however.

Live example here: http://testmepls.hostoi.com/web_stat...ats_index.html
Enter my Steam ID to test: STEAM_0:1:20366487

NOTE: The snippet is very basic; just data fetched through SQL and put into a table. Uses the table design as seen in achievement_motd. Achievements information (in the array) needs to be sorted in alphabetical order to work correctly (meaning numbers first, then a, b, c etc.)
PHP Code:
<?php

// multi-dimensional array holding info for achievements
$data = array
(
    
0=>array
    (
        
"1337"// achievement name
        
"Be online at 13:37"// description
        
// objective value (value set at completion)
    
),
    
1=>array
    (
        
"Addict",
        
"Connect 500 times",
        
500
    
)
);

// mysql initzializing variables
$hostname "localhost";
$username "root";
$password "pass";
$database "achievement_api";

// connect to mysql
$connection mysql_connect$hostname$username$password );
if( !
$connection )
{
    
// could not connect; throw error

    
die( 'Could not connect: ' mysql_error( ) );
}

// check if steamid was entered
$steamid $_GET['steamid'];
if( !
$steamid )
{
    
// no steamid; throw error

    
die( 'No steamid entered!' );
}

// html body / style
echo "<html>";
echo 
"<style>";
echo 
"body{margin:0;padding:0;font-family:Tahoma,Helvetica,Arial,sans-serif;}table,tr,td{align:center;color:#222;background:#fff;margin:1;padding:1;border:solid #eee 1px;}";
echo 
"</style>";
echo 
"<body>";
// table (for the sake of simplicity)
echo "<table width=600>";
echo 
"<tr><td><b>Achievement Name</b></td><td><b>Description</b></td><td><b>Earned</b></td></tr>";

// select database in sql
mysql_select_db$database$connection );

// make the query
$query "SELECT `data`, `key2` FROM `achievement_api_ex` WHERE `key1` = '$steamid';";
// send query
$result mysql_query$query$connection );
// check if query picked up any data
if( !$result )
{
    
// no data found

    
die( 'No data found!' );
}

// achievement counter
$achievement 0;

// achievements earned
$achievements 0;

// fetch data from query
while( $row mysql_fetch_array$result ) )
{
    
// convert data to an int
    
$number = (int)$row['data'];
    
// check if data is more or equal to the max value (assigned in multi-dimensional array above)
    
$earned = ( ( $number >= $data[$achievement][2] ) ? "Yes" "No" ); // "Yes" if more or equal, otherwise "No"
    // check if client has earned
    
if( $earned == "Yes" )
    {
        
$achievements++;
    }
    
    
// print the data into the table
    
echo "<tr><td>"$data[$achievement][0] ."</td><td>" $data[$achievement][1] . "</td><td>" $earned "</td></tr>";
    
    
// increment the achievement variable
    
$achievement++;
}

// total achievements earned
echo "Achievements Earned: " $achievements ."<br>";
echo 
"Max Achievements: " $achievement "";

// close
echo "</table>";
echo 
"</body>";

?>
And a HTML file for you to enter the steamid:
PHP Code:
<html>
    <
body>
        <!-- 
Make them enter a steamid and send them to php script with steamid input -->
        <
form action="web_stats_example.php" method="get">
        
Steam ID: <input type="text" name="steamid" />
        <
input type="submit" />
        </
form>
    </
body>
</
html
__________________
Achievements API - a simple way for you to create your OWN custom achievements!

Last edited by Xellath; 11-28-2011 at 11:09. Reason: Fixed typo
Xellath is offline