/*****************************************************************************
* DikuMUD (C) 1990, 1991 by: *
* Sebastian Hammer, Michael Seifert, Hans Henrik Staefeldt, Tom Madsen, *
* and Katja Nyboe. *
*---------------------------------------------------------------------------*
* MERC 2.1 (C) 1992, 1993 by: *
* Michael Chastain, Michael Quan, and Mitchell Tse. *
*---------------------------------------------------------------------------*
* SMAUG 1.4 (C) 1994, 1995, 1996, 1998 by: Derek Snider. *
* Team: Thoric, Altrag, Blodkai, Narn, Haus, Scryn, Rennard, Swordbearer, *
* gorog, Grishnakh, Nivek, Tricops, and Fireblade. *
*---------------------------------------------------------------------------*
* SMAUG 1.7 FUSS by: Samson and others of the SMAUG community. *
* Their contributions are greatly appreciated. *
*---------------------------------------------------------------------------*
* LoP (C) 2006, 2007 by: the LoP team. *
*---------------------------------------------------------------------------*
* High Scores *
*****************************************************************************/
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include "h/mud.h"
#define HIGHSCORE_FILE SYSTEM_DIR "highscores.dat"
typedef struct highscore_data HIGHSCORE_DATA;
struct highscore_data
{
HIGHSCORE_DATA *next, *prev;
char *name;
int value;
int pos;
};
typedef struct hightable_data HIGHTABLE_DATA;
struct hightable_data
{
HIGHTABLE_DATA *next, *prev;
HIGHSCORE_DATA *first_highscore, *last_highscore;
char *name;
int max;
};
HIGHTABLE_DATA *first_hightable, *last_hightable;
void save_highscore( void )
{
HIGHTABLE_DATA *table;
HIGHSCORE_DATA *score;
FILE *fp;
if( !first_hightable )
{
remove_file( HIGHSCORE_FILE );
return;
}
if( !( fp = fopen( HIGHSCORE_FILE, "w" ) ) )
{
bug( "%s: Can't open %s for writing.", __FUNCTION__, HIGHSCORE_FILE );
perror( HIGHSCORE_FILE );
return;
}
for( table = first_hightable; table; table = table->next )
{
if( !table->name )
continue;
fprintf( fp, "Name %s~\n", table->name );
fprintf( fp, "Max %d\n", table->max );
for( score = table->first_highscore; score; score = score->next )
fprintf( fp, "HighScore %s~ %d\r\n", score->name, score->value );
}
fprintf( fp, "%s", "End\n" );
fclose( fp );
fp = NULL;
}
void free_highscore( HIGHSCORE_DATA *score )
{
if( !score )
return;
STRFREE( score->name );
DISPOSE( score );
}
void free_hightable( HIGHTABLE_DATA *table )
{
HIGHSCORE_DATA *score, *score_next;
if( !table )
return;
STRFREE( table->name );
for( score = table->first_highscore; score; score = score_next )
{
score_next = score->next;
UNLINK( score, table->first_highscore, table->last_highscore, next, prev );
free_highscore( score );
}
DISPOSE( table );
}
void free_hightables( void )
{
HIGHTABLE_DATA *table, *table_next;
for( table = first_hightable; table; table = table_next )
{
table_next = table->next;
UNLINK( table, first_hightable, last_hightable, next, prev );
free_hightable( table );
}
}
void trim_highscore( HIGHTABLE_DATA *table )
{
HIGHSCORE_DATA *score, *score_next;
int count = 0;
for( score = table->first_highscore; score; score = score_next )
{
score_next = score->next;
score->pos = ++count;
if( count >= table->max )
{
UNLINK( score, table->first_highscore, table->last_highscore, next, prev );
free_highscore( score );
}
}
}
void link_highscore( HIGHTABLE_DATA *table, HIGHSCORE_DATA *nscore )
{
HIGHSCORE_DATA *score, *score_next;
char buf[MSL];
int count = 0;
for( score = table->first_highscore; score; score = score_next )
{
score_next = score->next;
++count;
if( nscore->value > score->value )
{
if( nscore->pos > count )
{
snprintf( buf, sizeof( buf ), "%s has obtained position %d on highscore table %s.",
nscore->name, count, table->name );
to_channel( buf, "highscore", PERM_ALL );
}
else if( nscore->pos < count )
{
snprintf( buf, sizeof( buf ), "%s has dropped to position %d on highscore table %s.",
nscore->name, count, table->name );
to_channel( buf, "highscore", PERM_ALL );
}
INSERT( nscore, score, table->first_highscore, next, prev );
trim_highscore( table );
return;
}
}
if( ++count < table->max )
{
if( nscore->pos > count )
{
snprintf( buf, sizeof( buf ), "%s has obtained position %d on highscore table %s.",
nscore->name, count, table->name );
to_channel( buf, "highscore", PERM_ALL );
}
else if( nscore->pos < count )
{
snprintf( buf, sizeof( buf ), "%s has dropped to position %d on highscore table %s.",
nscore->name, count, table->name );
to_channel( buf, "highscore", PERM_ALL );
}
LINK( nscore, table->first_highscore, table->last_highscore, next, prev );
trim_highscore( table );
return;
}
free_highscore( nscore );
trim_highscore( table );
}
HIGHTABLE_DATA *add_hightable( char *name )
{
HIGHTABLE_DATA *table;
if( !name || name[0] == '\0' )
return NULL;
CREATE( table, HIGHTABLE_DATA, 1 );
STRSET( table->name, name );
table->first_highscore = NULL;
table->last_highscore = NULL;
table->max = 20;
LINK( table, first_hightable, last_hightable, next, prev );
return table;
}
void add_highscore( HIGHTABLE_DATA *table, char *name, int value )
{
HIGHSCORE_DATA *score;
if( !table || !name )
return;
CREATE( score, HIGHSCORE_DATA, 1 );
STRSET( score->name, name );
score->value = value;
score->pos = ( table->max + 1 );
link_highscore( table, score );
}
void load_highscores( void )
{
FILE *fp;
HIGHTABLE_DATA *table = NULL;
char *name;
char *sname;
int value;
first_hightable = last_hightable = NULL;
if( !( fp = fopen( HIGHSCORE_FILE, "r" ) ) )
return;
for( ;; )
{
char *word;
if( feof( fp ) )
break;
word = fread_word( fp );
if( word[0] == EOF )
break;
if( !str_cmp( word, "Name" ) )
{
name = fread_flagstring( fp );
if( ( table = add_hightable( name ) ) )
table->max = 20;
continue;
}
else if( !str_cmp( word, "Max" ) )
{
value = fread_number( fp );
if( !table )
continue;
table->max = value;
}
else if( !str_cmp( word, "HighScore" ) )
{
sname = fread_flagstring( fp );
value = fread_number( fp );
if( !table )
continue;
if( valid_pfile( sname ) )
add_highscore( table, sname, value );
continue;
}
else if( !str_cmp( word, "End" ) )
break;
else
{
bug( "%s: bad section (%s).", __FUNCTION__, word );
fread_to_eol( fp );
continue;
}
}
fclose( fp );
fp = NULL;
}
HIGHTABLE_DATA *find_hightable( char *name )
{
HIGHTABLE_DATA *table;
for( table = first_hightable; table; table = table->next )
if( !str_cmp( table->name, name ) )
return table;
return NULL;
}
HIGHSCORE_DATA *find_highscore( HIGHTABLE_DATA *table, char *name )
{
HIGHSCORE_DATA *score;
for( score = table->first_highscore; score; score = score->next )
if( !str_cmp( score->name, name ) )
return score;
return NULL;
}
void check_highscores( HIGHTABLE_DATA *table, HIGHSCORE_DATA *score )
{
if( !table || !score )
return;
if( ( score->prev && score->value > score->prev->value )
|| ( score->next && score->value < score->next->value ) )
{
UNLINK( score, table->first_highscore, table->last_highscore, next, prev );
link_highscore( table, score );
}
}
void update_highscore( CHAR_DATA *ch )
{
HIGHTABLE_DATA *table;
HIGHSCORE_DATA *score;
if( !ch || is_npc( ch ) || is_immortal( ch ) )
return;
if( ( table = find_hightable( "Gold" ) ) )
{
if( ( score = find_highscore( table, ch->name ) ) )
{
score->value = ch->mgold;
check_highscores( table, score );
}
else
add_highscore( table, ch->name, ch->mgold );
}
if( ( table = find_hightable( "SudokuWins" ) ) )
{
if( ( score = find_highscore( table, ch->name ) ) )
{
score->value = ch->pcdata->swins;
check_highscores( table, score );
}
else
add_highscore( table, ch->name, ch->pcdata->swins );
}
if( ( table = find_hightable( "MKills" ) ) )
{
if( ( score = find_highscore( table, ch->name ) ) )
{
score->value = ch->pcdata->mkills;
check_highscores( table, score );
}
else
add_highscore( table, ch->name, ch->pcdata->mkills );
}
if( ( table = find_hightable( "MDeaths" ) ) )
{
if( ( score = find_highscore( table, ch->name ) ) )
{
score->value = ch->pcdata->mdeaths;
check_highscores( table, score );
}
else
add_highscore( table, ch->name, ch->pcdata->mdeaths );
}
if( ( table = find_hightable( "PKills" ) ) )
{
if( ( score = find_highscore( table, ch->name ) ) )
{
score->value = ch->pcdata->pkills;
check_highscores( table, score );
}
else
add_highscore( table, ch->name, ch->pcdata->pkills );
}
if( ( table = find_hightable( "PDeaths" ) ) )
{
if( ( score = find_highscore( table, ch->name ) ) )
{
score->value = ch->pcdata->pdeaths;
check_highscores( table, score );
}
else
add_highscore( table, ch->name, ch->pcdata->pdeaths );
}
save_highscore( );
}
CMDF( do_highscore )
{
HIGHSCORE_DATA *score;
HIGHTABLE_DATA *table;
int cnt = 0, count = 0;
if( !argument || argument[0] == '\0' )
{
for( table = first_hightable; table; table = table->next )
{
count++;
ch_printf( ch, "%20s", table->name );
if( ++cnt >= 4 )
{
cnt = 0;
send_to_char( "\r\n", ch );
}
}
if( cnt != 0 )
send_to_char( "\r\n", ch );
if( !count )
send_to_char( "There are currently no highscore tables.\r\n", ch );
return;
}
if( !( table = find_hightable( argument ) ) )
{
send_to_char( "No such highscore table to look at.\r\n", ch );
send_to_char( "Checking highscore table to see if it matches someone in the lists.\r\n", ch );
count = 0;
for( table = first_hightable; table; table = table->next )
{
cnt = 0;
for( score = table->first_highscore; score; score = score->next )
{
cnt++;
if( str_cmp( score->name, argument ) )
continue;
count++;
ch_printf( ch, "%s is in %3d on highscore table %s.\r\n", score->name, cnt, table->name );
}
}
if( !count )
send_to_char( "Sorry it doesn't look like anyone matching that name is on the list.\r\n", ch );
return;
}
ch_printf( ch, "HighScore Table: %s.\r\n", table->name );
for( score = table->first_highscore; score; score = score->next )
ch_printf( ch, "%3d> %20s %10d\r\n", ++cnt, score->name, score->value );
if( !cnt )
send_to_char( "No one is currently on this highscore table.\r\n", ch );
}
CMDF( do_makehightable )
{
HIGHTABLE_DATA *table;
if( !argument || argument[0] == '\0' )
{
send_to_char( "Usage: makehightable <name>\r\n", ch );
return;
}
argument = capitalize( argument );
if( !( table = add_hightable( argument ) ) )
{
send_to_char( "HighScore Table wasn't created.\r\n", ch );
return;
}
send_to_char( "HighScore Table created.\r\n", ch );
save_highscore( );
}
CMDF( do_deletehightable )
{
HIGHTABLE_DATA *table;
if( !argument || argument[0] == '\0' )
{
send_to_char( "Usage: deletehightable <table>\r\n", ch );
return;
}
if( !( table = find_hightable( argument ) ) )
{
send_to_char( "No such highscore table to delete.\r\n", ch );
return;
}
UNLINK( table, first_hightable, last_hightable, next, prev );
free_hightable( table );
send_to_char( "HighScore Table deleted.\r\n", ch );
save_highscore( );
}