@@ -18,44 +18,77 @@
#include < string.h>
#include < stdlib.h>
// Load entire questlog for a character
int mapif_quests_fromsql (int char_id, struct quest questlog[])
{
int i;
/* *
* Loads the entire questlog for a character.
*
* @param char_id Character ID
* @param count Pointer to return the number of found entries.
* @return Array of found entries. It has *count entries, and it is care of the
* caller to aFree() it afterwards.
*/
struct quest *mapif_quests_fromsql (int char_id, int *count) {
struct quest *questlog = NULL ;
struct quest tmp_quest;
SqlStmt * stmt;
SqlStmt *stmt;
if ( !count )
return NULL ;
stmt = SqlStmt_Malloc (sql_handle);
if ( stmt == NULL )
{
if ( stmt == NULL ) {
SqlStmt_ShowDebug (stmt);
return 0 ;
*count = 0 ;
return NULL ;
}
memset (&tmp_quest, 0 , sizeof (struct quest));
if ( SQL_ERROR == SqlStmt_Prepare (stmt, " SELECT `quest_id`, `state`, `time`, `count1`, `count2`, `count3` FROM `%s ` WHERE `char_id`=? LIMIT %d " , quest_db, MAX_QUEST_DB )
if ( SQL_ERROR == SqlStmt_Prepare (stmt, " SELECT `quest_id`, `state`, `time`, `count1`, `count2`, `count3` FROM `%s ` WHERE `char_id`=?" , quest_db)
|| SQL_ERROR == SqlStmt_BindParam (stmt, 0 , SQLDT_INT, &char_id, 0 )
|| SQL_ERROR == SqlStmt_Execute (stmt)
|| SQL_ERROR == SqlStmt_BindColumn (stmt, 0 , SQLDT_INT, &tmp_quest.quest_id , 0 , NULL , NULL )
|| SQL_ERROR == SqlStmt_BindColumn (stmt, 1 , SQLDT_INT, &tmp_quest.state , 0 , NULL , NULL )
|| SQL_ERROR == SqlStmt_BindColumn (stmt, 2 , SQLDT_UINT, &tmp_quest.time , 0 , NULL , NULL )
|| SQL_ERROR == SqlStmt_BindColumn (stmt, 3 , SQLDT_INT, &tmp_quest.count [0 ], 0 , NULL , NULL )
|| SQL_ERROR == SqlStmt_BindColumn (stmt, 4 , SQLDT_INT, &tmp_quest.count [1 ], 0 , NULL , NULL )
|| SQL_ERROR == SqlStmt_BindColumn (stmt, 5 , SQLDT_INT, &tmp_quest.count [2 ], 0 , NULL , NULL ) )
|| SQL_ERROR == SqlStmt_BindColumn (stmt, 0 , SQLDT_INT, &tmp_quest.quest_id , 0 , NULL , NULL )
|| SQL_ERROR == SqlStmt_BindColumn (stmt, 1 , SQLDT_INT, &tmp_quest.state , 0 , NULL , NULL )
|| SQL_ERROR == SqlStmt_BindColumn (stmt, 2 , SQLDT_UINT, &tmp_quest.time , 0 , NULL , NULL )
|| SQL_ERROR == SqlStmt_BindColumn (stmt, 3 , SQLDT_INT, &tmp_quest.count [0 ], 0 , NULL , NULL )
|| SQL_ERROR == SqlStmt_BindColumn (stmt, 4 , SQLDT_INT, &tmp_quest.count [1 ], 0 , NULL , NULL )
|| SQL_ERROR == SqlStmt_BindColumn (stmt, 5 , SQLDT_INT, &tmp_quest.count [2 ], 0 , NULL , NULL )
) {
SqlStmt_ShowDebug (stmt);
SqlStmt_Free (stmt);
*count = 0 ;
return NULL ;
}
for ( i = 0 ; i < MAX_QUEST_DB && SQL_SUCCESS == SqlStmt_NextRow (stmt); ++i )
memcpy (&questlog[i], &tmp_quest, sizeof (tmp_quest));
*count = (int )SqlStmt_NumRows (stmt);
if ( *count > 0 ) {
int i = 0 ;
questlog = (struct quest *)aCalloc (*count, sizeof (struct quest));
while ( SQL_SUCCESS == SqlStmt_NextRow (stmt) ) {
if ( i >= *count ) // Sanity check, should never happen
break ;
memcpy (&questlog[i++], &tmp_quest, sizeof (tmp_quest));
}
if ( i < *count ) {
// Should never happen. Compact array
*count = i;
questlog = (struct quest *)aRealloc (questlog, sizeof (struct quest) * i);
}
}
SqlStmt_Free (stmt);
return i ;
return questlog ;
}
// Delete a quest
bool mapif_quest_delete (int char_id, int quest_id)
{
if ( SQL_ERROR == Sql_Query (sql_handle, " DELETE FROM `%s ` WHERE `quest_id` = '%d ' AND `char_id` = '%d '" , quest_db, quest_id, char_id) )
/* *
* Deletes a quest from a character's questlog.
*
* @param char_id Character ID
* @param quest_id Quest ID
* @return false in case of errors, true otherwise
*/
bool mapif_quest_delete (int char_id, int quest_id) {
if ( SQL_ERROR == Sql_Query (sql_handle, " DELETE FROM `%s ` WHERE `quest_id` = '%d ' AND `char_id` = '%d '" , quest_db, quest_id, char_id) )
{
Sql_ShowDebug (sql_handle);
return false ;
@@ -64,10 +97,15 @@ bool mapif_quest_delete(int char_id, int quest_id)
return true ;
}
// Add a quest to a questlog
bool mapif_quest_add (int char_id, struct quest qd)
{
if ( SQL_ERROR == Sql_Query (sql_handle, " INSERT INTO `%s `(`quest_id`, `char_id`, `state`, `time`, `count1`, `count2`, `count3`) VALUES ('%d ', '%d ', '%d ','%d ', '%d ', '%d ', '%d ')" , quest_db, qd.quest_id , char_id, qd.state , qd.time , qd.count [0 ], qd.count [1 ], qd.count [2 ]) )
/* *
* Adds a quest to a character's questlog.
*
* @param char_id Character ID
* @param qd Quest data
* @return false in case of errors, true otherwise
*/
bool mapif_quest_add (int char_id, struct quest qd) {
if ( SQL_ERROR == Sql_Query (sql_handle, " INSERT INTO `%s `(`quest_id`, `char_id`, `state`, `time`, `count1`, `count2`, `count3`) VALUES ('%d ', '%d ', '%d ','%d ', '%d ', '%d ', '%d ')" , quest_db, qd.quest_id , char_id, qd.state , qd.time , qd.count [0 ], qd.count [1 ], qd.count [2 ]) )
{
Sql_ShowDebug (sql_handle);
return false ;
@@ -76,10 +114,15 @@ bool mapif_quest_add(int char_id, struct quest qd)
return true ;
}
// Update a questlog
bool mapif_quest_update (int char_id, struct quest qd)
{
if ( SQL_ERROR == Sql_Query (sql_handle, " UPDATE `%s ` SET `state`='%d ', `count1`='%d ', `count2`='%d ', `count3`='%d ' WHERE `quest_id` = '%d ' AND `char_id` = '%d '" , quest_db, qd.state , qd.count [0 ], qd.count [1 ], qd.count [2 ], qd.quest_id , char_id) )
/* *
* Updates a quest in a character's questlog.
*
* @param char_id Character ID
* @param qd Quest data
* @return false in case of errors, true otherwise
*/
bool mapif_quest_update (int char_id, struct quest qd) {
if ( SQL_ERROR == Sql_Query (sql_handle, " UPDATE `%s ` SET `state`='%d ', `count1`='%d ', `count2`='%d ', `count3`='%d ' WHERE `quest_id` = '%d ' AND `char_id` = '%d '" , quest_db, qd.state , qd.count [0 ], qd.count [1 ], qd.count [2 ], qd.quest_id , char_id) )
{
Sql_ShowDebug (sql_handle);
return false ;
@@ -88,93 +131,95 @@ bool mapif_quest_update(int char_id, struct quest qd)
return true ;
}
// Save quests
int mapif_parse_quest_save (int fd)
{
int i, j, k, num2, num1 = (RFIFOW (fd,2 )-8 )/sizeof (struct quest);
/* *
* Handles the save request from mapserver for a character's questlog.
*
* Received quests are saved, and an ack is sent back to the map server.
*
* @see inter_parse_frommap
*/
int mapif_parse_quest_save (int fd) {
int i, j, k, old_n, new_n = (RFIFOW (fd,2 ) - 8 ) / sizeof (struct quest);
int char_id = RFIFOL (fd,4 );
struct quest qd1[MAX_QUEST_DB],qd2[MAX_QUEST_DB] ;
struct quest *old_qd = NULL , *new_qd = NULL ;
bool success = true ;
memset (qd1, 0 , sizeof (qd1));
memset (qd2, 0 , sizeof (qd2));
if ( num1 ) memcpy (&qd1, RFIFOP (fd,8 ), RFIFOW (fd,2 )-8 );
num2 = mapif_quests_fromsql (char_id, qd2);
for ( i = 0 ; i < num1; i++ )
{
ARR_FIND ( 0 , num2, j, qd1[i].quest_id == qd2[j].quest_id );
if ( j < num2 ) // Update existed quests
{ // Only states and counts are changable.
ARR_FIND ( 0 , MAX_QUEST_OBJECTIVES, k, qd1[i].count [k] != qd2[j].count [k] );
if ( k != MAX_QUEST_OBJECTIVES || qd1[i].state != qd2[j].state )
success &= mapif_quest_update (char_id, qd1[i]);
if ( j < (--num2) )
{
memmove (&qd2[j],&qd2[j+1 ],sizeof (struct quest)*(num2-j));
memset (&qd2[num2], 0 , sizeof (struct quest));
if ( new_n > 0 )
new_qd = (struct quest*)RFIFOP (fd,8 );
old_qd = mapif_quests_fromsql (char_id, &old_n);
for ( i = 0 ; i < new_n; i++ ) {
ARR_FIND (0 , old_n, j, new_qd[i].quest_id == old_qd[j].quest_id );
if ( j < old_n ) { // Update existing quests
// Only states and counts are changable.
ARR_FIND (0 , MAX_QUEST_OBJECTIVES, k, new_qd[i].count [k] != old_qd[j].count [k]);
if ( k != MAX_QUEST_OBJECTIVES || new_qd[i].state != old_qd[j].state )
success &= mapif_quest_update (char_id, new_qd[i]);
if ( j < (--old_n) ) {
// Compact array
memmove (&old_qd[j], &old_qd[j + 1 ], sizeof (struct quest) * (old_n - j));
memset (&old_qd[old_n], 0 , sizeof (struct quest));
}
}
else // Add new quests
success &= mapif_quest_add (char_id, qd1[i]);
} else // Add new quests
success &= mapif_quest_add (char_id, new_qd[i]);
}
for ( i = 0 ; i < num2 ; i++ ) // Quests not in qd1 but in qd2 are to be erased.
success &= mapif_quest_delete (char_id, qd2 [i].quest_id );
for ( i = 0 ; i < old_n ; i++ ) // Quests not in new_qd but in old_qd are to be erased.
success &= mapif_quest_delete (char_id, old_qd [i].quest_id );
if ( old_qd )
aFree (old_qd);
// Send ack
WFIFOHEAD (fd,7 );
WFIFOW (fd,0 ) = 0x3861 ;
WFIFOL (fd,2 ) = char_id;
WFIFOB (fd,6 ) = success? 1 : 0 ;
WFIFOB (fd,6 ) = success ? 1 : 0 ;
WFIFOSET (fd,7 );
return 0 ;
}
// Send questlog to map server
int mapif_parse_quest_load (int fd)
{
/* *
* Sends questlog to the map server
*
* NOTE: Completed quests (state == Q_COMPLETE) are guaranteed to be sent last
* and the map server relies on this behavior (once the first Q_COMPLETE quest,
* all of them are considered to be Q_COMPLETE)
*
* @see inter_parse_frommap
*/
int mapif_parse_quest_load (int fd) {
int char_id = RFIFOL (fd,2 );
struct quest tmp_questlog[MAX_QUEST_DB];
int num_quests, i, num_complete = 0 ;
int complete[MAX_QUEST_DB];
memset (tmp_questlog, 0 , sizeof (tmp_questlog));
memset (complete, 0 , sizeof (complete));
struct quest *tmp_questlog = NULL ;
int num_quests;
num_quests = mapif_quests_fromsql (char_id, tmp_questlog );
tmp_questlog = mapif_quests_fromsql (char_id, &num_quests );
WFIFOHEAD (fd,num_quests* sizeof (struct quest)+ 8 );
WFIFOHEAD (fd,num_quests * sizeof (struct quest) + 8 );
WFIFOW (fd,0 ) = 0x3860 ;
WFIFOW (fd,2 ) = num_quests* sizeof (struct quest)+ 8 ;
WFIFOW (fd,2 ) = num_quests * sizeof (struct quest) + 8 ;
WFIFOL (fd,4 ) = char_id;
// Active and inactive quests
for ( i = 0 ; i < num_quests; i++ )
{
if ( tmp_questlog[i].state == Q_COMPLETE )
{
complete[num_complete++] = i;
continue ;
}
memcpy (WFIFOP (fd,(i-num_complete)*sizeof (struct quest)+8 ), &tmp_questlog[i], sizeof (struct quest));
}
if ( num_quests > 0 )
memcpy (WFIFOP (fd,8 ), tmp_questlog, sizeof (struct quest) * num_quests);
// Completed quests
for ( i = num_quests - num_complete; i < num_quests; i++ )
memcpy (WFIFOP (fd,i*sizeof (struct quest)+8 ), &tmp_questlog[complete[i-num_quests+num_complete]], sizeof (struct quest));
WFIFOSET (fd,num_quests * sizeof (struct quest) + 8 );
WFIFOSET (fd,num_quests*sizeof (struct quest)+8 );
if ( tmp_questlog )
aFree (tmp_questlog);
return 0 ;
}
int inter_quest_parse_frommap (int fd)
{
switch (RFIFOW (fd,0 ))
{
/* *
* Parses questlog related packets from the map server.
*
* @see inter_parse_frommap
*/
int inter_quest_parse_frommap (int fd) {
switch (RFIFOW (fd,0 )) {
case 0x3060 : mapif_parse_quest_load (fd); break ;
case 0x3061 : mapif_parse_quest_save (fd); break ;
default :