/*
I worked on this code for Merc 2.2 with some changes from
Rom24B6. So this code should be simular to use for any diku
deriv codebase. The base working code below is exactly as
it was when I pulled it from my codebase on Feb 11th, 2009. 
It's been tested and works.

The idea came a few years ago from Avatar Mud. Basicly, this
is just a general sublevel system that doesn't rely on Remort
code, multiclassing or anything else. It just adds to the 
existing mud.

Mortals = Levels 1 - 50
Heros = Level 51 (sublevels 1 - 999)
Lords = Level 125 (sublevels 1 - 999)

Basicly, this gives your mud an additional 2000 levels while
all mobiles for heros and lords only need to be real levels
51 - 55 or so. Since sublevels have nothing to do with the
actual levels, you don't need to create level 600 mobs.

You can have a builder create a new hero area with all mobs
set to level 51. All hero's no matter what thier sublevel is
will gain exp from them.

There are many other things that can be added such as the do_who
command, adding the sublevels to the do_score, seperate spell/skills
lists such as do_slist for mortals, do_hlist for heros and so on.

To try out the hero code, make sure level_hero is set to 51, then
advance a char to level 50, upon leveling, they will become a
hero (level 51 )with a sublevel of 1. 

----------------------------------------
Questions or Comments? Send me an email!
Chris Bunting - cbunting99@gmail.com
----------------------------------------

Changes made to this version of Merc 2.2
----------------------------------------
*/
// * merc.h add...
#define MAX_SUBLEVEL 999
#define MIN_SUBLEVEL 1 /* never set to 0 */

//-- added to char_data struct
sh_int sublevel;

// Others you may need..
#define LEVEL_HERO 51
#define LEVEL_LORD 125

//* comm.c find ch->level = 1; and add
ch->sublevel = 0;

/* EG:
      ch->level = 1;
      ch->sublevel = 0;
      ch->train = 21;
      ch->practice = 6;
*/

//* save.c
//-- added to fwrite_char the line below:
fprintf (fp, "SubLevel     %d\n", ch->sublevel);

//-- added to fread_char under CASE 'S' the line below:
KEY ("SubLevel", ch->sublevel, fread_number (fp));

//* update.c
//-- Took existing code in update.c gain_exp and reworked it for sublevels.

/////////// Modified do_gain in update.c ///////////

/*
 * Modified do_gain for lots of sublevels.. Chris
 */
void gain_exp (CHAR_DATA * ch, int gain)
{
    char buf[MAX_STRING_LENGTH];

    if (IS_NPC (ch) || ch->level >= LEVEL_IMMORTAL)
        return;

    // ch->exp = ch->exp + gain;
    ch->exp = UMAX (exp_per_level (ch, ch->pcdata->exp_lvl), ch->exp + gain);

    while (ch->level < LEVEL_IMMORTAL && ch->exp >= exp_per_level (ch, ch->pcdata->exp_lvl) * (ch->level + 1))
    {
        /*
         * Mortals Level 1 - 50
         */
        while (ch->level < LEVEL_HERO)
        {
            send_to_char ("{MYou raise a level!!{x  ", ch);
            ch->level += 1;
            advance_level (ch);
            sprintf (buf, "{wThe Mayor Yells, %s has now raised in power to level %d!{x", ch->name, ch->level);
            do_function (ch, &do_iecho, buf);
            sprintf (buf, "%s is now mortal level %d.", ch->name, ch->level);
            wiznet (ch, WIZ_LEVELS, get_trust (ch), buf);
            return;
        }

        /*
         * Heros Level 51, Sublevels 1 - 999
         */
        while (ch->level == LEVEL_HERO
                && ch->sublevel >= MIN_SUBLEVEL < MAX_SUBLEVEL)
        {
            send_to_char ("{MYou raise a sublevel!!{x  ", ch);
            ch->exp = ch->exp - exp_per_level (ch, ch->pcdata->exp_lvl);
            ch->sublevel += 1;
            advance_level (ch);
            sprintf (buf, "{wThe Mayor Yells, %s has now raised in power to hero level %d!{x", ch->name, ch->sublevel);
            do_function (ch, &do_iecho, buf);
            sprintf (buf, "%s is now hero level %d.", ch->name, ch->sublevel);
            wiznet (ch, WIZ_LEVELS, get_trust (ch), buf);
            return;
        }

        /*
         * Lords Level 125, Sublevels 1 - 999
         */
        while (ch->level == LEVEL_LORD && ch->sublevel >= MIN_SUBLEVEL < MAX_SUBLEVEL)
        {
            send_to_char ("{MYou raise a sublevel!!{x  ", ch);
            ch->exp = ch->exp - exp_per_level (ch, ch->pcdata->exp_lvl);
            ch->sublevel += 1;
            advance_level (ch);
            sprintf (buf, "{wThe Mayor Yells, %s has now raised in power to lord level %d!{x", ch->name, ch->sublevel);
            do_function (ch, &do_iecho, buf);
            sprintf (buf, "%s is now lord level %d.", ch->name, ch->sublevel);
            wiznet (ch, WIZ_LEVELS, get_trust (ch), buf);
            return;
        }
    }
    return;
}

// advance_level (update.c) add these above the last return;
// These two bits are only used once per player. Upon reaching
// Level 51 and 125

  if (ch->sublevel < 1 && ch->level == LEVEL_HERO)
  {
    sprintf (buf, "{cWelcome to Hero %s!!{x\n\r", ch->name);
    send_to_char (buf, ch);
    ch->sublevel++;		
    do_function (ch, &do_help, "GRATS_HERO");
  }

  if (ch->sublevel >= 1 && ch->level == LEVEL_LORD)
  {
    sprintf (buf, "{cWelcome to Lord %s!!{x\n\r", ch->name);
    send_to_char (buf, ch);
    ch->sublevel = 1;		
    do_function (ch, &do_help, "GRATS_LORD");
  }

/*
	This is just the basics of the system. do_slist can show all spells and skills
	for mortal levels 1 - 50. Rename do_slist to do_hlist for heros showing all
	level 51 or Hero skills spells. You can check for ch->level == LEVEL_HERO && sublevel 10
	to give a new skill/spell to a hero at sublevel 10 and so on.

 */

///// You may want this too.. do_advance

void do_advance (CHAR_DATA * ch, char *argument)
{
  char buf[MAX_STRING_LENGTH];
  char arg1[MAX_INPUT_LENGTH];
  bool sublevel = FALSE;
  CHAR_DATA *victim;
  int level;
  int iLevel;

  argument = one_argument (argument, arg1);

  if (arg1[0] == '\0' || argument[0] == '\0')
  {
    send_to_char ("Syntax: advance <character> [sublevel|level] <level>\n\r", ch);
    return;
  }

  if ((victim = get_char_world (ch, arg1)) == NULL)
  {
    send_to_char ("That player is not here.\n\r", ch);
    return;
  }

  if (IS_NPC (victim))
  {
    send_to_char ("Not on NPC's.\n\r", ch);
    return;
  }

  if (victim->sublevel)
  {
    argument = one_argument (argument, arg1);
    if (argument[0] == '\0' || !is_number (argument)
	|| (str_cmp (arg1, "level") && str_cmp (arg1, "sublevel")))
    {
      send_to_char
	("For chars that are heros/lords, please specify level or sublevel.\n\r",
	 ch);
      return;
    }
    if (!str_cmp (arg1, "sublevel"))
      sublevel = TRUE;
  }

  if (!is_number (argument))
  {
    send_to_char
      ("Usage: advance <character> [sublevel|level] <level>\n\r", ch);
    return;
  }

  level = atoi (argument);

  if (level <= 0 || level > MAX_LEVEL)
  {
    sprintf (buf, "Advance within range 1 to %d.\n\r", MAX_SUBLEVEL);
    send_to_char (buf, ch);
    return;
  }
  if (victim->sublevel && (level > victim->level
			   || (sublevel && level <= victim->sublevel)))
  {
    send_to_char
      ("For hero or lords, you may only demote them to a\n\r"
       "lower level, or promote them sublevels.\n\r", ch);
    return;
  }

  /*
   * Lower level:
   *   Reset to level 1.
   *   Then raise again.
   *   Currently, an imp can lower another imp.
   *   -- Swiftest
   */
  if (!sublevel && level <= victim->level)
  {
    int temp_prac;
    int temp_train;

    send_to_char ("Lowering a player's level!\n\r", ch);
    send_to_char ("**** OOOOHHHHHHHHHH  NNNNOOOO ****\n\r", victim);
    temp_prac = victim->practice;
    temp_train = victim->train;
    victim->level = 1;
    victim->sublevel = 0;
    victim->exp = exp_per_level (victim, victim->pcdata->exp_lvl);
    victim->max_hit = 20;
    victim->max_mana = 100;
    victim->max_move = 100;
    victim->hit = victim->max_hit;
    victim->mana = victim->max_mana;
    victim->move = victim->max_move;
    advance_level (victim);
    victim->practice = temp_prac;
    victim->train = temp_train;
  }
  else
  {
    send_to_char ("Raising a player's level!\n\r", ch);
    send_to_char ("**** OOOOHHHHHHHHHH  YYYYEEEESSS ****\n\r", victim);
  }

  if (victim->sublevel > 0)
  {
    for (iLevel = victim->sublevel; iLevel < level; iLevel++)
    {
      victim->sublevel += 1;
      advance_level (victim);
    }
  }
  else
  {
    for (iLevel = victim->level; iLevel < level; iLevel++)
    {
      victim->level += 1;
      advance_level (victim);
    }
  }
  sprintf (buf, "You are now level %d.\n\r", victim->level);
  send_to_char (buf, victim);
  victim->exp =
    exp_per_level (victim, victim->pcdata->exp_lvl) * UMAX (1, victim->level);
  victim->trust = 0;
  save_char_obj (victim);
  return;
}