LOP/
LOP/area/
LOP/boards/
LOP/channels/
LOP/clans/
LOP/classes/
LOP/color/
LOP/councils/
LOP/deity/
LOP/races/
LOP/src/specials/
/*****************************************************************************
 * 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, 2008 by: the LoP team.                                *
 *****************************************************************************/

#include <stdio.h>
#include <string.h>
#include <math.h>
#include "h/mud.h"

/* Calculate roughly how much experience a character is worth */
double get_exp_worth( CHAR_DATA *ch )
{
   double wexp;

   wexp = ( ch->level * ch->level * UMAX( 1, ch->level / 2 ) );
   return durange( MIN_EXP_WORTH, wexp, MAX_EXP_WORTH );
}

double exp_level( CHAR_DATA *ch, int level )
{
   double lvl;

   lvl = durange( 1, level, MAX_LEVEL );
   return ( 20 + ( lvl * lvl * lvl ) );
}

double xp_compute( CHAR_DATA *gch, CHAR_DATA *victim )
{
   double xp;

   if( ( victim->level - gch->level ) > 10 )
      return 0;
   if( ( gch->level - victim->level ) > 10 )
      return 0;

   xp = get_exp_worth( victim );

   if( !is_npc( gch ) && is_npc( victim ) )
   {
      int times = times_killed( gch, victim );

      if( times >= 20 )
         xp = 0;
      else if( times )
      {
         xp = ( xp * ( 20 - times ) ) / 20;
         if( times > 15 )
            xp /= 3;
         else if( times > 10 )
            xp /= 1.5;
      }
   }

   return durange( 0, xp, exp_level( gch, gch->level ) );
}

/* Advancement stuff. */
void advance_level( CHAR_DATA *ch )
{
   if( !is_npc( ch ) )
   {
      set_char_color( AT_WHITE, ch );
      if( ( ch->level % 2 ) == 1 )
      {
         send_to_char( "You have gained another practice session.\r\n", ch );
         ch->practice += 1;
      }
      /* Restore them if needed */
      if( ch->hit < ch->max_hit )
         ch->hit = ch->max_hit;
      if( ch->mana < ch->max_mana )
         ch->mana = ch->max_mana;
      if( ch->move < ch->max_move )
         ch->move = ch->max_move;
      if( ch->level == MAX_LEVEL )
      {
         playing_printf( ch, "&[immortal]%s has just achieved Avatarhood!&[white]\r\n", ch->name );
         do_help( ch, "M_ADVHERO_" );
         ch->exp = 0.0;
      }
   }
}

void gain_exp( CHAR_DATA *ch, double gain )
{
   double modgain, oldexp, gained;

   if( is_npc( ch ) )
      return;
   if( ch->level >= MAX_LEVEL )
   {
      ch->exp = 0.0;
      return;
   }

   modgain = gain;

   /* No one goes below current exp for the level they are */
   if( ( ch->exp + modgain ) < 0 )
      modgain = ch->exp;

   modgain = dumin( modgain, exp_level( ch, ch->level ) );

   oldexp = ch->exp;
   ch->exp = dumax( 0, ch->exp + ( int )modgain );
   gained = ( ch->exp - oldexp );

   if( not_authed( ch ) && ch->exp >= exp_level( ch, ch->level ) )
   {
      send_to_char( "You can't ascend to a higher level until you are authorized.\r\n", ch );
      ch->exp = ( exp_level( ch, ch->level ) - 1 );
      return;
   }

   if( gained != 0 )
      ch_printf( ch, "You %s %s experience points.\r\n", gained > 0 ? "received" : "lost",
      double_punct( fabs( gained ) ) );

   while( ch->level < MAX_LEVEL && ch->exp >= exp_level( ch, ( ch->level + 1 ) ) )
   {
      set_char_color( AT_WHITE + AT_BLINK, ch );
      ch->level += 1;
      ch->exp -= exp_level( ch, ch->level );
      ch_printf( ch, "You have obtained level %d!\r\n", ch->level );
      advance_level( ch );
      set_char_color( AT_PLAIN, ch );
   }
}

/* Display your current exp, level, and surrounding level exp requirements - Thoric */
CMDF( do_level )
{
   int x, lowlvl, hilvl;
   char arg[MIL], *s1, *s2;

   s1 = color_str( AT_SCORE, ch );
   s2 = color_str( AT_SCORE2, ch );

   lowlvl = UMAX( 1, ch->level - 5 );
   if( argument && argument[0] != '\0' )
   {
      argument = one_argument( argument, arg );
      lowlvl = URANGE( 1, ( atoi( arg ) - 5 ), MAX_LEVEL );
   }
   hilvl = URANGE( lowlvl, ( lowlvl + 10 ), MAX_LEVEL );

   ch_printf( ch, "\r\n%sExperience required from level %s%d %sto %s%d%s:\r\n", s1, s2, lowlvl, s1, s2, hilvl, s1 );
   ch_printf( ch, "%s.~`~.~`~.~`~.~`~.~`~.~`~.~`~.~`~.~`~.~`~.~`~.~`~.\r\n", s1 );
   for( x = lowlvl; x <= hilvl; x++ )
   {
      ch_printf( ch, "%s%s%s%5d%s> %s%12s %sexp", s1, x == ch->level ? "*" : " ", s2, x, s1, s2,
         double_punct( exp_level( ch, x ) ), s1 );
      if( x == ch->level )
         ch_printf( ch, " %s(Current: %s%12s%s)", s1, s2, double_punct( ch->exp ), s1 );
      else if( x == ( ch->level + 1 ) )
         ch_printf( ch, " %s(Needed:  %s%12s%s)", s1, s2, double_punct( exp_level( ch, ch->level + 1 ) - ch->exp ), s1 );
      send_to_char( "\r\n", ch );
   }
   ch_printf( ch, "%s.~`~.~`~.~`~.~`~.~`~.~`~.~`~.~`~.~`~.~`~.~`~.~`~.\r\n", s1 );
}