/********************************************************************************
* Stat List code copyright 1999-2001 *
* Markanth : markanth@spaceservices.net *
* Devil's Lament : spaceservices.net port 3778 *
* Web Page : http://spaceservices.net/~markanth/ *
* *
* All I ask in return is that you give me credit on your mud somewhere *
* or email me if you use it. *
********************************************************************************/
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if !defined(WIN32)
#include <unistd.h>
#endif
#include "merc.h"
#include "interp.h"
#include "recycle.h"
STAT_DATA *stat_list;
long TopGameStat[MAX_GAMESTAT];
void save_statlist ( void )
{
STAT_DATA *pstat;
FILE *fp;
bool found = FALSE;
int i;
if ( ( fp = file_open ( STAT_FILE, "w" ) ) == NULL )
{
perror ( STAT_FILE );
}
fprintf ( fp, "TOPSTATS %d ", MAX_GAMESTAT );
for ( i = 0; i < MAX_GAMESTAT; i++ )
fprintf ( fp, "%ld ", TopGameStat[i] );
fprintf ( fp, "\n" );
for ( pstat = stat_list; pstat != NULL; pstat = pstat->next )
{
found = TRUE;
fprintf ( fp, "%s ", pstat->name );
for ( i = 0; i < MAX_GAMESTAT; i++ )
fprintf ( fp, "%ld ", pstat->gamestat[i] );
fprintf ( fp, "\n" );
}
file_close ( fp );
if ( !found )
unlink ( STAT_FILE );
}
void load_statlist ( void )
{
FILE *fp;
STAT_DATA *stat_last;
int i, maxStat = 0;
if ( ( fp = file_open ( STAT_FILE, "r" ) ) == NULL )
return;
if ( !str_cmp ( fread_word ( fp ), "TOPSTATS" ) );
{
maxStat = fread_number ( fp );
for ( i = 0; i < maxStat; i++ )
TopGameStat[i] = fread_number ( fp );
}
stat_last = NULL;
for ( ;; )
{
STAT_DATA *pstat;
if ( feof ( fp ) )
{
file_close ( fp );
return;
}
pstat = new_stat_data ( );
pstat->name = str_dup ( fread_word ( fp ) );
for ( i = 0; i < maxStat; i++ )
pstat->gamestat[i] = fread_number ( fp );
fread_to_eol ( fp );
if ( stat_list == NULL )
stat_list = pstat;
else
stat_last->next = pstat;
stat_last = pstat;
}
}
void update_statlist ( CHAR_DATA * ch, bool pdelete )
{
STAT_DATA *prev;
STAT_DATA *curr;
int i;
if ( IS_NPC ( ch ) || IS_IMMORTAL ( ch ) )
return;
prev = NULL;
for ( curr = stat_list; curr != NULL; prev = curr, curr = curr->next )
{
if ( !str_cmp ( ch->name, curr->name ) )
{
if ( prev == NULL )
stat_list = stat_list->next;
else
prev->next = curr->next;
free_stat_data ( curr );
save_statlist ( );
}
}
if ( pdelete )
{
return;
}
curr = new_stat_data ( );
curr->name = str_dup ( ch->name );
for ( i = 0; i < MAX_GAMESTAT; i++ )
{
curr->gamestat[i] = ch->pcdata->gamestat[i];
if ( curr->gamestat[i] > TopGameStat[i] )
TopGameStat[i] = curr->gamestat[i];
}
curr->next = stat_list;
stat_list = curr;
save_statlist ( );
return;
}
CH_CMD ( do_showstats )
{
int option;
char arg[MIL];
argument = one_argument ( argument, arg );
if ( arg[0] == '\0' )
{
chsend ( " {ROPTIONS AVAILABLE:{x\n\r", ch );
chsend ( " {G1{x - Ranking of Player Killers (pkills)\n\r", ch );
chsend ( " {G2{x - Ranking of Player Deaths (pdeaths)\n\r", ch );
chsend ( " {G3{x - Ranking of Mob Kills (mkills)\n\r", ch );
chsend ( " {G4{x - Ranking of Mob Deaths (mdeaths)\n\r", ch );
if ( IS_IMMORTAL ( ch ) )
chsend ( " {Gdelete <name>{x - deletes from statlist\n\r",
ch );
return;
}
option = atoi ( arg );
if ( !str_cmp ( arg, "delete" ) && IS_IMMORTAL ( ch ) )
{
STAT_DATA *prev = NULL;
STAT_DATA *curr = NULL;
bool found = FALSE;
for ( curr = stat_list; curr != NULL; prev = curr, curr = curr->next )
{
if ( !str_cmp ( argument, curr->name ) )
{
if ( prev == NULL )
stat_list = stat_list->next;
else
prev->next = curr->next;
free_stat_data ( curr );
save_statlist ( );
found = TRUE;
}
}
if ( !found )
chprintf ( ch, "Error deleting %s.\n\r", argument );
}
else if ( option == 1 || !str_prefix ( arg, "pkills" ) )
show_game_stats ( ch, PK_KILLS );
else if ( option == 3 || !str_prefix ( arg, "mkills" ) )
show_game_stats ( ch, MOB_KILLS );
else if ( option == 2 || !str_prefix ( arg, "pdeaths" ) )
show_game_stats ( ch, PK_DEATHS );
else if ( option == 4 || !str_prefix ( arg, "mdeaths" ) )
show_game_stats ( ch, MOB_DEATHS );
else
do_showstats ( ch, "" );
return;
}
int compare_stats args ( ( const void *v1, const void *v2 ) );
int compare_stats ( const void *v1, const void *v2 )
{
return *( long * ) v2 - *( long * ) v1;
}
void show_game_stats ( CHAR_DATA * ch, int type )
{
STAT_DATA *curr;
BUFFER *output;
char buf[MSL];
/* max 2000 entries?
old entries will be shoved to the end anyways
*/
long top[2000];
int count, pos, loop, dcount;
bool found = FALSE;
const char *stat_name[MAX_GAMESTAT] = {
"PLAYER KILLERS",
"MOB KILLERS",
"PK DEATHS",
"MOB DEATHS",
};
output = new_buf ( );
count = 0;
pos = 0;
dcount = 0;
sprintf ( buf, "{CRANKING OF %s{x", stat_name[type] );
add_buf ( output, buf );
add_buf ( output, "\n\r" );
loop = 0;
for ( curr = stat_list; curr != NULL; curr = curr->next )
{
if ( count >= 2000 )
break;
if ( curr->gamestat[type] > 0 )
{
top[count] = curr->gamestat[type];
count++;
found = TRUE;
}
}
qsort ( top, count, sizeof ( long ), compare_stats );
for ( loop = 0; loop < count; loop++ )
{
if ( loop >= 49 )
break;
for ( curr = stat_list; curr != NULL; curr = curr->next )
{
if ( curr->gamestat[type] != top[loop] )
continue;
if ( dcount++ >= 50 )
break;
sprintf ( buf, "{G%2d{w){W %-20s {w[{R%8ld{W]{x ", dcount,
curr->name, top[loop] );
add_buf ( output, buf );
if ( ++pos % 2 == 0 )
{
add_buf ( output, "\n\r" );
pos = 0;
}
}
}
if ( !found )
add_buf ( output, "\n\rNo one found yet.\n\r" );
else if ( pos % 2 != 0 )
add_buf ( output, "\n\r" );
page_to_char ( buf_string ( output ), ch );
free_buf ( output );
return;
}