/**
* Top ten player lists - overall and for each guild.
*<p>
* archive and top_ten is of the format:
*<code><p>
* ({ ({ name (guild), rating, level, age }), ... })
*</code><p>
* guild_top_tens is of the format:
*<code><p>
* ([ guild: ({ ({ name, rating, level, age }), ... }), ... ])
* </code>
* @author Deutha
*/
#include <skills.h>
#include <top_ten_tables.h>
#include <clubs.h>
#define SAVE_FILE "/save/top_ten_tables"
#define TOP_TEN_SIZE 15
#define GUILD_TOP_TEN_SIZE 10
#define ARCHIVE_TIME 50 * 24 * 60 * 60
#define ARCHIVE_RATING 30000
/* The Apex Club accepts members with a rating of 10k or greater */
#define APEX_LIMIT 10000
/* Age in days = age in seconds / 86400 */
#define AGE_DIVIDER 100
#define AGE ( -thing->query_time_on() / 86400 )
mapping guild_top_tens;
mixed *archive, *top_ten;
nosave int average;
nosave mixed *skills;
string _family_largest;
int _family_largest_num;
string _family_qp;
int _family_qp_num;
string _family_age;
int _family_age_num;
mapping _family_guilds;
mapping _family_guilds_num;
string _family_pk;
int _family_pk_num;
string _family_single_gender;
int _family_single_gender_num;
string _family_start_time;
int _family_start_time_num;
string _family_relationships;
int _family_relationships_num;
string _club_largest;
int _club_largest_num;
string _club_qp;
int _club_qp_num;
string _club_age;
int _club_age_num;
mapping _club_guilds;
mapping _club_guilds_num;
string _club_pk;
int _club_pk_num;
string _club_single_gender;
int _club_single_gender_num;
string _club_start_time;
int _club_start_time_num;
void calculate_family_and_club_info();
void create() {
seteuid( (string)"/secure/master"->
creator_file( file_name( this_object() ) ) );
guild_top_tens = ([ ]);
_family_guilds = ([ ]);
_club_guilds = ([ ]);
_family_guilds_num = ([ ]);
_club_guilds_num = ([ ]);
archive = ({ });
top_ten = ({ });
call_out( "check_tables", 5 );
call_out( "check_family_and_club_info", 10 );
if ( file_size( SAVE_FILE +".o" ) > 0 ) {
unguarded( (: restore_object, SAVE_FILE :) );
if (!_family_guilds_num) {
_family_guilds_num = ([ ]);
}
if (!_club_guilds_num) {
_club_guilds_num = ([ ]);
}
}
} /* setup() */
private void save_me() {
unguarded( (: save_object, SAVE_FILE :) );
} /* save_me() */
/**
* Some sort of weight average used in the rating calulation.
* @return the weighted average
*/
int query_average() { return average; }
/**
* The skils list with weights. This is used to help generate the
* rating.
* @return the skils list with ratings
*/
mixed *query_skills() { return skills; }
/**
* The mapping which is the guild top ten tables.
* @return the guild top ten mapping
*/
mapping query_guild_top_tens() { return guild_top_tens; }
/** @ignore yes */
void set_guild_top_tens( mapping map ) {
guild_top_tens = map;
save_me();
} /* set_guild_top_tens() */
/**
* Add in a new table. This should be used when a new guild is created
* and their table needs to be defined.
* @param word the name of the table to create
*/
void add_guild_top_ten( string word ) {
if ( guild_top_tens[ word ] ) {
return;
}
guild_top_tens[ word ] = ({ });
save_me();
} /* add_guild_top_ten() */
/**
* The complete archived top ten table.
* @return the archived top ten table
*/
mixed *query_archive() { return archive; }
/** @ignore yes */
void set_archive( mixed *args ) {
archive = args;
save_me();
} /* set_archive() */
/**
* Return the complete list of top ten tables.
* @return the array of arrays being the top ten tab;les
*/
mixed *query_top_ten() { return top_ten; }
/** @ignore yes */
void set_top_ten( mixed *args ) {
top_ten = args;
save_me();
} /* set_top_ten() */
/** @ignore yes */
int check_person( mixed *args, string guild ) {
int i;
string word;
if ( !guild ) {
sscanf( args[ 0 ], "%s (%s)", word, guild );
} else {
word = args[ 0 ];
}
if ( !rank( word ) ||
!PLAYER_H->test_active( word ) ||
creatorp( word ) ||
PLAYER_H->test_property( word, "no_score" ) ||
PLAYER_H->test_property( word, "no score" ) ) {
return 0;
}
if ( ( (int)PLAYER_H->test_last( word ) < time() - ARCHIVE_TIME ) ) {
if ( args[ 1 ] > ARCHIVE_RATING ) {
args[ 0 ] = word +" ("+ guild +")";
for ( i = sizeof( archive ) - 1; i > -1; i-- ) {
if ( archive[ i ][ 0 ] == args[ 0 ] ) {
if ( archive[ i ][ 1 ] > args[ 1 ] )
archive[ i ] = args + ({ time() });
break;
}
}
if ( i == -1 ) {
archive += ({ args + ({ time() }) });
}
}
return 0;
}
return 1;
} /* check_person() */
/**
* Wander over the top ten tables checking to see if everyone
* still exists.
*/
void check_tables() {
int i;
string word;
for ( i = sizeof( top_ten ) - 1; i > -1; i-- ) {
if ( !check_person( copy( top_ten[ i ] ), 0 ) ) {
top_ten = delete( top_ten, i, 1 );
}
}
foreach ( word in keys( guild_top_tens ) ) {
for ( i = sizeof( guild_top_tens[ word ] ) - 1; i > -1; i-- ) {
if ( !check_person( copy( guild_top_tens[ word ][ i ] ), word ) ) {
guild_top_tens[ word ] = delete( guild_top_tens[ word ], i, 1 );
}
}
}
save_me();
} /* check_tables() */
/**
* Returns the ordered list of people on the top ten list. If the table
* name is 0 or it is "main" the main table is checked. If the
* table name is "archive" then the archive is used.
* @param table_name the name of the tanble to check
* @return the array of arrays of the top ten information
* @see /include/top_ten_tables.h
*/
mixed *query_ordered_table( string table_name ) {
int i, highest_loc, highest_num;
mixed *ret, *args;
if ( !table_name || table_name == "main") {
args = top_ten;
} else {
if ( table_name == "archive" ) {
args = archive;
} else {
if ( !guild_top_tens[ table_name ] ) {
return ({ });
}
args = guild_top_tens[ table_name ];
}
}
ret = ({ });
while ( sizeof( args ) ) {
highest_loc = highest_num = 0;
for ( i = 0; i < sizeof( args ); i++ ) {
if ( args[ i ][ TOP_TEN_RATING ] > highest_num ) {
highest_num = args[ i ][ TOP_TEN_RATING ];
highest_loc = i;
}
}
ret += ({ args[ highest_loc] });
args = args[ 0 .. highest_loc - 1 ] + args[ highest_loc + 1 .. ];
}
return ret;
} /* query_orderd_table() */
/** @ignore yes */
mixed *remove_name( string word, mixed *args ) {
int i;
if ( !sizeof( args ) ) {
return ({ });
}
for ( i = sizeof( args ) - 1; i > -1; i-- ) {
if ( word == explode( args[ i ][ TOP_TEN_NAME ], " " )[ 0 ] ) {
args = delete( args, i, 1 );
}
}
return args;
} /* remove_name() */
/** @ignore yes */
int *find_lowest( mixed *args ) {
int i, lowest_loc, lowest_num;
if ( !sizeof( args ) ) {
return ({ 0, 0 });
}
lowest_loc = 0;
lowest_num = args[ 0 ][ TOP_TEN_RATING ];
for ( i = 1; i < sizeof( args ); i++ ) {
if ( lowest_num > args[ i ][ TOP_TEN_RATING ] ) {
lowest_loc = i;
lowest_num = args[ i ][ TOP_TEN_RATING ];
}
}
return ({ lowest_loc, lowest_num });
} /* find_lowest() */
/** @ignore yes */
int query_skill_weight( string skill ) {
int total;
string *next;
next = SKILL_H->query_immediate_children( skill );
if ( !sizeof( next ) ) {
return 1;
}
foreach ( skill in next ) {
total += query_skill_weight( skill );
}
return total;
} /* query_skill_weight() */
/**
* Figure out the rating for the player.
* @param thing the object to get the ratingof
* @return the current rating
*/
int calculate_rating( object thing ) {
int i, j, rating, *bonuses;
rating = (int)thing->query_level();
if ( !skills ) {
skills = ({ });
for ( i = 0; i < sizeof( STD_SKILLS ); i += SKILL_ARR_SIZE ) {
skills += ({ SKILL_H->query_immediate_children( STD_SKILLS[ i ] )
});
skills += ({
sizeof( skills[ <1 ] ),
query_skill_weight( STD_SKILLS[ i ] )
});
average += skills[ <1 ];
}
average /= sizeof( skills ) / 3;
}
bonuses = allocate( sizeof( skills ) / 3 );
for ( i = sizeof( bonuses ) - 1; i > -1; i-- ) {
for ( j = skills[ 3 * i + 1 ] - 3; j > -1; j-- ) {
bonuses[ i ] +=
(int)thing->query_skill_bonus( skills[ 3 * i ][ j ], 1 );
}
bonuses[ i ] = ( ( bonuses[ i ] / skills[ 3 * i + 1 ] ) *
skills[ 3 * i + 2 ] ) / average;
}
bonuses = sort_array( bonuses, -1 );
j = sizeof( bonuses );
for ( i = 0; i < j; i++ ) {
rating = 2 * rating + bonuses[ i ];
if ( !i && userp( thing ) ) {
rating += (int)LIBRARY_H->
query_quest_points( (string)thing->query_name() );
}
}
if( rating > APEX_LIMIT && userp( thing ) ) {
rating = AGE * (rating - APEX_LIMIT) / AGE_DIVIDER + APEX_LIMIT;
}
return rating;
} /* calculate_rating() */
/**
* Called when a player advances their skills.
* @param word the skill being advanced
* @param thing the player which advanced their skils
*/
varargs void player_skill_advance( mixed word, object thing ) {
int rating, *lowest;
string name;
mixed *guild_top_ten;
if( !thing && objectp(word) ) {
thing = word;
word = "I'm broken";
}
if ( creatorp(thing) ) {
return;
}
if ( thing->query_property( "guest" ) ) {
return;
}
if ( thing->query_property( "no_score" ) ) {
return;
}
if ( thing->query_property( "no score" ) ) {
return;
}
guild_top_ten = guild_top_tens[ word ];
if ( !guild_top_ten ) {
return;
}
name = (string)thing->query_name();
rating = calculate_rating( thing );
guild_top_ten = remove_name( name, guild_top_ten );
lowest = find_lowest( guild_top_ten );
if ( sizeof( guild_top_ten ) < GUILD_TOP_TEN_SIZE ) {
guild_top_ten += ({
({ name, rating, (int)thing->query_level(),
-(int)thing->query_time_on() }) });
} else {
if ( rating > lowest[ 1 ] ) {
guild_top_ten[ lowest[ 0 ] ] =
({ name, rating, (int)thing->query_level(),
-(int)thing->query_time_on() });
}
}
guild_top_tens[ word ] = guild_top_ten;
// save_me();
top_ten = remove_name( name, top_ten );
lowest = find_lowest( top_ten );
if ( sizeof( top_ten ) < TOP_TEN_SIZE ) {
top_ten += ({
({ name +" ("+ word +")", rating,
(int)thing->query_level(), -(int)thing->query_time_on() }) });
} else {
if ( rating > lowest[ 1 ] ) {
top_ten[ lowest[ 0 ] ] =
({ name +" ("+ word +")", rating,
(int)thing->query_level(), -(int)thing->query_time_on() });
}
}
// save_me();
} /* player_skill_advance() */
/**
* Remove the named player from the named table.
* @param word1 the name of the player
* @param word2 the name of the table, 0 for the main table
*/
varargs void excise_name( string word1, string word2 ) {
if ( !word2 ) {
top_ten = remove_name( word1, top_ten );
} else {
if ( guild_top_tens[ word2 ] ) {
guild_top_tens[ word2 ] = remove_name( word1,
guild_top_tens[ word2 ] );
}
}
save_me();
} /* excise_name() */
/**
* Stuff to make sure that all the clubs still exist.
*/
void check_family_and_club_info() {
int offset;
string bing;
string guild;
_family_qp_num = 0;
_family_age_num = 0;
_family_largest_num = 0;
if (!mapp(_family_guilds)) {
_family_guilds = ([ ]);
}
if (!mapp(_club_guilds)) {
_club_guilds = ([ ]);
}
// Do these first so that the table is not stuffed up.
if (_family_qp && !CLUB_HANDLER->is_family(_family_qp)) {
_family_qp = 0;
_family_qp_num = 0;
}
if (_family_age && !CLUB_HANDLER->is_family(_family_age)) {
_family_age = 0;
_family_age_num = 0;
}
if (_family_largest && !CLUB_HANDLER->is_family(_family_largest)) {
_family_largest = 0;
_family_largest_num = 0;
}
if (_family_single_gender && !CLUB_HANDLER->is_family(_family_single_gender)) {
_family_single_gender = 0;
_family_single_gender_num = 0;
}
if (_family_pk && !CLUB_HANDLER->is_family(_family_pk)) {
_family_pk = 0;
_family_pk_num = 0;
}
if (_club_qp && !CLUB_HANDLER->is_club(_club_qp)) {
_club_qp = 0;
_club_qp_num = 0;
}
if (_club_age && !CLUB_HANDLER->is_club(_club_age)) {
_club_age = 0;
_club_age_num = 0;
}
if (_club_largest && !CLUB_HANDLER->is_club(_club_largest)) {
_club_largest = 0;
_club_largest_num = 0;
}
if (_club_single_gender && !CLUB_HANDLER->is_club(_club_single_gender)) {
_club_single_gender = 0;
_club_single_gender_num = 0;
}
if (_club_pk && !CLUB_HANDLER->is_club(_club_pk)) {
_club_pk = 0;
_club_pk_num = 0;
}
offset = 3;
foreach (guild, bing in _family_guilds) {
if (stringp(bing)) {
if (!CLUB_HANDLER->is_family(bing)) {
map_delete(_family_guilds, guild);
map_delete(_family_guilds_num, guild);
}
} else {
map_delete(_family_guilds, guild);
map_delete(_family_guilds_num, guild);
}
}
foreach (guild, bing in _club_guilds) {
if (stringp(bing)) {
if (!CLUB_HANDLER->is_club(bing)) {
map_delete(_club_guilds, guild);
map_delete(_club_guilds_num, guild);
}
} else {
map_delete(_club_guilds, guild);
map_delete(_club_guilds_num, guild);
}
}
save_me();
} /* calculate_family_and_club_info() */
void inform_of_club(string club,
int family,
int type,
mixed num) {
string str;
int bing;
if (family) {
switch (type) {
case TOP_TEN_LARGEST_FAMILY:
if (_family_largest_num < num ||
_family_largest == club) {
_family_largest_num = num;
_family_largest = club;
save_me();
}
break;
case TOP_TEN_OLDEST_FAMILY:
if (_family_age_num < num ||
_family_age == club) {
_family_age_num = num;
_family_age = club;
save_me();
}
break;
case TOP_TEN_MOST_QUEST_POINTS:
if (_family_qp_num < num ||
_family_qp == club) {
_family_qp_num = num;
_family_qp = club;
save_me();
}
break;
case TOP_TEN_MOST_GUILD:
foreach (str, bing in num) {
if (_family_guilds_num[str] < bing ||
_family_guilds[str] == club) {
_family_guilds_num[str] = bing;
_family_guilds[str] = club;
save_me();
}
}
break;
case TOP_TEN_MOST_PKS:
if (_family_pk_num < num ||
_family_pk == club) {
_family_pk_num = num;
_family_pk = club;
save_me();
}
break;
case TOP_TEN_SINGLE_GENDER:
if (_family_single_gender_num < num ||
_family_single_gender == club) {
_family_single_gender_num = num;
_family_single_gender = club;
save_me();
}
break;
case TOP_TEN_OLDEST_LOGONS:
if (_family_start_time_num < num ||
_family_start_time == club) {
_family_start_time_num = num;
_family_start_time = club;
save_me();
}
break;
case TOP_TEN_MOST_RELATIONSHIPS:
if (_family_relationships_num < num ||
_family_relationships == club) {
_family_relationships_num = num;
_family_relationships = club;
save_me();
}
break;
}
} else {
switch (type) {
case TOP_TEN_LARGEST_FAMILY:
if (_club_largest_num < num ||
_club_largest == club) {
_club_largest_num = num;
_club_largest = club;
save_me();
}
break;
case TOP_TEN_OLDEST_FAMILY:
if (_club_age_num < num ||
_club_age == club) {
_club_age_num = num;
_club_age = club;
save_me();
}
break;
case TOP_TEN_MOST_QUEST_POINTS:
if (_club_qp_num < num ||
_club_qp == club) {
_club_qp_num = num;
_club_qp = club;
save_me();
}
break;
case TOP_TEN_MOST_GUILD:
foreach (str, bing in num) {
if (_club_guilds_num[str] < bing ||
_club_guilds[str] == club ||
!_club_guilds[str]) {
_club_guilds_num[str] = bing;
_club_guilds[str] = club;
save_me();
}
}
break;
case TOP_TEN_MOST_PKS:
if (_club_pk_num < num ||
_club_pk == club) {
_club_pk_num = num;
_club_pk = club;
save_me();
}
break;
case TOP_TEN_SINGLE_GENDER:
if (_club_single_gender_num < num ||
_club_single_gender == club) {
_club_single_gender_num = num;
_club_single_gender = club;
save_me();
}
break;
case TOP_TEN_OLDEST_LOGONS:
if (_club_start_time_num < num ||
_club_start_time == club) {
_club_start_time_num = num;
_club_start_time = club;
save_me();
}
break;
}
}
} /* inform_of_club() */
mixed *query_family_info() {
return ({ _family_largest,
_family_age,
_family_qp,
_family_guilds,
_family_pk,
_family_single_gender,
_family_start_time,
_family_relationships });
} /* query_family_info() */
mixed *query_club_info() {
return ({ _club_largest,
_club_age,
_club_qp,
_club_guilds,
_club_pk,
_club_single_gender,
_club_start_time });
} /* query_club_info() */
/** @ignore yes */
void dest_me() {
save_me();
destruct(this_object());
} /* dest_me() */
/** @ignore yes */
void reset() {
save_me();
} /* reset() */