#include <sys/types.h> #include <stdio.h> #include <stdlib.h> #include <syslog.h> #include "math.h" #include "define.h" #include "struct.h" int death_exp( char_data* victim, char_data* ) { return exp_for_level( victim )/5; } int exp_for_level( int level ) { int exp; exp = level*(110*level*level+400*level-411); exp += int( pow( level*level*level*level, 1.11 ) ); return exp; } /* * EXP CALCULATION SUB-ROUTINES */ int base_exp( char_data* mob ) { species_data* species = mob->species; double xp; if( species->shdata->deaths == 0 || species->rounds == 0 ) return 0; xp = species->damage*( mob->max_hit +species->damage_taken/species->shdata->deaths )/(2.*species->rounds); xp = int( pow( xp, 1.07 ) )+5.; return (int) xp; } int base_exp( species_data* species ) { double xp; dice_data dice; dice = species->hitdice; if( species->shdata->deaths == 0 || species->rounds == 0 ) return 0; xp = species->damage*( average( dice )+species->damage_taken /species->shdata->deaths )/(2.*species->rounds); xp = pow( double( xp ), double( 1.07 ) )+5.; return (int) xp; } int death_exp( species_data* species, int base ) { float x; x = float( species->shdata->kills/(2+species->shdata->deaths) ); if( x > 1.5 ) return (int) 1.5*base; return (int) x*base; } int special_exp( species_data* species, int base ) { if( species->rounds == 0 ) return 0; return base*species->special/species->rounds/2; } int level_exp( species_data* species, int base ) { return base*species->shdata->level/100; } int modify_exp( species_data* species, int base ) { if( is_set( &species->act_flags, ACT_AGGR_ALL ) ) return base/10; return 0; } int modify_exp( char_data* mob, int base ) { if( is_set( &mob->status, STAT_AGGR_ALL ) ) return base/10; return 0; } /* * EXP DISPLAY FUNCTION */ void do_exp( char_data* ch, char* argument ) { dice_data dice; int base; int death; int spec; int level; int modif; int total; species_data* species; if( ( species = get_species( atoi( argument ) ) ) == NULL ) { send( ch, "No mob has that vnum.\n\r" ); return; } base = base_exp( species ); death = death_exp( species, base ); spec = special_exp( species, base ); modif = modify_exp( species, base ); total = base+death+spec+modif; level = level_exp( species, total ); total += level; page_title( ch, "Exp for %s", species->Name( ) ); if( species->shdata->deaths > 0 ) page( ch, " Ave Exp: %d\n\r", species->exp/species->shdata->deaths ); dice = species->hitdice; page( ch, " Damage: %-10d Rounds: %-11d Dam/Rnd: %.2f\n\r ", species->damage, species->rounds, float( species->damage )/float( species->rounds ) ); page( ch, " Avg. Hp: %-7d Dmg_Taken: %-9d Avg_Taken: ", average( dice ), species->damage_taken ); if( species->shdata->deaths == 0 ) page( ch, "??\n\r" ); else page( ch, "%d\n\r", species->damage_taken/species->shdata->deaths ); page( ch," Kills: %-10d Deaths: %-13d Level: %d\n\r", species->shdata->deaths, species->shdata->kills, species->shdata->level ); page( ch, " Special: %-8d Spec/Rnd: %.2f\n\r\n\r", species->special, float( species->special )/species->rounds ); page( ch, " Base Exp: %7d\n\r", base ); page( ch, " Death Exp: %7d\n\r", death ); page( ch, " Special: %7d\n\r", spec ); page( ch, " Modifiers: %7d\n\r", modif ); page( ch, " Level: %7d\n\r", level ); page( ch, " -------\n\r" ); page( ch, " Total: %7d\n\r", total ); return; } /* * EXP COMPUTATION FUNCTION */ int xp_compute( char_data* victim ) { obj_data* wield; species_data* species = victim->species; int xp; int damage; if( victim->species != NULL ) { xp = base_exp( species ); xp += death_exp( species, xp )+special_exp( species, xp ); xp += level_exp( species, xp ); xp += modify_exp( victim, xp ); } else { if( ( wield = victim->Wearing( WEAR_HELD_R ) ) != NULL && wield->pIndexData->item_type == ITEM_WEAPON ) damage = wield->value[1]*(wield->value[2]+1)/2; else damage = 2; damage += (int) victim->Damroll( wield ); xp = damage*victim->max_hit/2; xp = min( xp, victim->exp/2 ); } xp = max( 0, xp ); return xp; } /* * GROUP EXP FUNCTION */ void gain_exp( char_data* ch, char_data* victim, int gain, const char* msg ) { if( ch->species != NULL ) return; int level = exp_for_level( ch ); if( gain > 0 ) gain = int( gain/sqr(1.+sqrt(1.*gain/level)) ); add_exp( ch, gain, msg ); /* MODIFY REPUTATION */ if( victim == NULL ) return; player_data* pc = (player_data*) ch; pc->reputation.alignment[ victim->shdata->alignment ] += gain; if( victim->species != NULL ) pc->reputation.nation[ victim->species->nation ]++; } void add_exp( char_data* ch, int gain, const char* msg ) { if( ch->species != NULL ) return; if( msg != NULL ) send( ch, msg, abs( gain ), abs( gain ) == 1 ? "" : "s" ); int level = exp_for_level( ch ); ch->exp += gain; for( ; ch->shdata->level > 1 && ch->shdata->level <= LEVEL_HERO && ch->exp < 0; ) { lose_level( ch ); ch->exp += exp_for_level( ch ); } ch->exp = max( 0, ch->exp ); if( ch->exp >= level && ch->shdata->level < LEVEL_HERO && ch->pcdata->quest_pts >= 0 && gain > 0 ) { if( !is_set( ch->pcdata->pfile->flags, PLR_APPROVED ) && ch->shdata->level >= 5 ) { send( ch, "To gain levels past 5th you must have an approved appearance.\n\r" ); } else { ch->exp -= level; advance_level( ch, TRUE ); } } update_score( ch ); } void disburse_exp( char_data* victim ) { char_data* ch; int tot_damage; float xpc; victim->shdata->deaths++; if( victim->pcdata != NULL ) return; xpc = float( xp_compute( victim ) ); if( victim->species != NULL ) victim->species->exp += int( xpc ); tot_damage = 0; for( int i = 0; i < *victim->array; i++ ) { if( ( ch = player( victim->array->list[i] ) ) != NULL && ch != victim ) { remove_bit( &ch->status, STAT_GAINED_EXP ); tot_damage += max( 0, damage_done( ch, victim ) ); } } xpc = xpc/float( max( tot_damage, victim->max_hit ) ); for( int i = 0; i < *victim->array; i++ ) if( ( ch = player( victim->array->list[i] ) ) != NULL && ch != victim && !is_set( &ch->status, STAT_GAINED_EXP ) ) group_gain( victim, ch, xpc ); } void group_gain( char_data* victim, char_data* ch, float xpc ) { player_data* gch; player_array list; int members = 0; int tot_damage = 0; int damage; float xp; for( int i = 0; i < *ch->array; i++ ) { if( ( gch = player( ch->array->list[i] ) ) == NULL || !is_same_group( gch, ch ) ) continue; damage = damage_done( gch, victim ); if( damage >= 0 || gch->fighting != NULL ) { tot_damage += damage; members += cube( gch->shdata->level+5 ); list += gch; } set_bit( &gch->status, STAT_GAINED_EXP ); } for( int i = 0; i < list; i++ ) { if( ( xp = float( tot_damage )*cube( list[i]->shdata->level+5 ) *xpc/members ) > 0 ) { gain_exp( list[i], victim, int( xp ), "You receive %d experience point%s.\n\r" ); } list[i]->shdata->fame = min( list[i]->shdata->fame +victim->shdata->level, 1000 ); } } void zero_exp( species_data* species ) { species->rounds = 1; species->damage = 0; species->damage_taken = 0; species->shdata->deaths = 0; species->shdata->kills = 0; species->exp = 0; species->special = 0; }