6D/
6D/area/
6D/boards/
6D/city/
6D/color/
6D/corpses/
6D/councils/
6D/htowns/
6D/news/
6D/specials/
6D/src/specials/
6D/src/trades/
/* Volk! 
 * I was getting confused at all the different functions etc we have for 
 * multiclassed players, so I thought i'd just make a new file and put
 * everything in here. */

/* Players that reach a level where they get access to two of the same
 *  * spells/skills from different classes, will want to take the HIGHEST
 *   * adept % from those classes.
 *    * Revamped so if availabletochar is false, it will just return the
 *     * highest adept % from all classes. If TRUE, it will return the highest
 *      * within the player's level range. */
#include <time.h>
#include "h/mud.h"
#include "h/files.h"

extern bool             doubleexp;

// BS function I have to write, because of teacher code
bool IS_UNDERTWENTY(CHAR_DATA *ch, int sn)
{
  if(sn < 0 || sn > top_sn)
  {
    bug("%s: invalid sn [%d]", __FUNCTION__, sn);
    return FALSE;
  }

  if(IS_THIRDCLASS(ch))
  {
    if(skill_table[sn]->skill_level[ch->thirdclass] < 21 || skill_table[sn]->skill_level[ch->secondclass] < 21 || skill_table[sn]->skill_level[ch->Class] < 21)
      return TRUE;
  }
  else if(IS_SECONDCLASS(ch))
  {
    if(skill_table[sn]->skill_level[ch->secondclass] < 21 || skill_table[sn]->skill_level[ch->Class] < 21)
      return TRUE;
  }
  else if(IS_SINGLECLASS(ch))
  {
    if(skill_table[sn]->skill_level[ch->Class] < 21)
      return TRUE;
  }
  else
  {
    return FALSE;
  }
}

/*
 * CanLearnNow: TRUE = see if they can access it now, FALSE = see if they can ever access it.
 */
bool CAN_LEARN(CHAR_DATA *ch, int sn, bool canlearnnow)
{
  if(sn < 0 || sn > top_sn)
  {
    bug("%s: invalid sn [%d]", __FUNCTION__, sn);
    return FALSE;
  }

  if(!IS_NPC(ch))
  {

    if(ch->pcdata->tradeclass == 20 && (sn == gsn_mine || sn == gsn_forge))
    {
      return TRUE;
    }
    if(ch->pcdata->tradeclass == 21 && (sn == gsn_gather || sn == gsn_bake || sn == gsn_mix))
    {
      return TRUE;
    }
    if(ch->pcdata->tradeclass == 22 && (sn == gsn_hunt || sn == gsn_tan))
    {
      return TRUE;
    }
    if(ch->pcdata->tradeclass == 24 && (sn == gsn_mine || sn == gsn_jewelry))
    {
      return TRUE;
    }
    if(ch->pcdata->tradeclass == 25 && (sn == gsn_mill || sn == gsn_fell))
    {
      return TRUE;
    }
    if(ch->pcdata->tradeclass == 26 && (sn == gsn_unearth || sn == gsn_produce))
    {
      return TRUE;
    }

  }

  if(IS_THIRDCLASS(ch) && ch->race != RACE_ANIMAL)
  {
    if(ch->thirdlevel >= skill_table[sn]->skill_level[ch->thirdclass])
      return TRUE;

    if(!canlearnnow && skill_table[sn]->skill_level[ch->thirdclass] < 101 && skill_table[sn]->skill_level[ch->thirdclass] > 0)
      return TRUE;
  }

  if(IS_SECONDCLASS(ch) && ch->race != RACE_ANIMAL)
  {
    if(ch->secondlevel >= skill_table[sn]->skill_level[ch->secondclass])
      return TRUE;

    if(!canlearnnow && skill_table[sn]->skill_level[ch->secondclass] < 101 && skill_table[sn]->skill_level[ch->secondclass] > 0)
      return TRUE;

    if(ch->firstlevel >= skill_table[sn]->skill_level[ch->Class])
      return TRUE;
  }
  else if(ch->level >= skill_table[sn]->skill_level[ch->Class])
    return TRUE;

  if(!canlearnnow && skill_table[sn]->skill_level[ch->Class] < 101 && skill_table[sn]->skill_level[ch->Class] > 0)
    return TRUE;

  return FALSE;
}

int get_maxadept(CHAR_DATA *ch, int sn, bool availabletochar)
{
  int                     class1 = 0, class2 = 0, class3 = 0, result = 0;

  if(IS_NPC(ch))
    return 80;

  if(IS_IMMORTAL(ch))
    return 100;

  if(sn < 0)
  {
    // this bug has to do with the w_index in fight.c
    // bug( "player %s %s: 'sn is less than 0.", ch->name, __FUNCTION__ );
    return 100;
  }
  if(ch->pcdata->tradeclass == 20 && (sn == gsn_mine || sn == gsn_forge))
  {
    return 95;
  }
  if(ch->pcdata->tradeclass == 21 && (sn == gsn_gather || sn == gsn_bake || sn == gsn_mix))
  {
    return 95;
  }
  if(ch->pcdata->tradeclass == 22 && (sn == gsn_tan || sn == gsn_hunt))
  {
    return 95;
  }
  if(ch->pcdata->tradeclass == 24 && (sn == gsn_mine || sn == gsn_jewelry))
  {
    return 95;
  }
  if(ch->pcdata->tradeclass == 25 && (sn == gsn_mill || sn == gsn_fell))
  {
    return 95;
  }
  if(ch->pcdata->tradeclass == 26 && (sn == gsn_unearth || sn == gsn_produce))
  {
    return 95;
  }
  if(IS_THIRDCLASS(ch) && ch->race != RACE_ANIMAL)
  {
    if(skill_table[sn]->skill_level[ch->thirdclass] < 101)
    {
      class3 = skill_table[sn]->skill_adept[ch->thirdclass];
      if(availabletochar)
        if(skill_table[sn]->skill_level[ch->thirdclass] > ch->thirdlevel)
          class3 = 0; /* Means they can't use it yet, so 0% adept there. */
    }
  }

  if(IS_SECONDCLASS(ch) && ch->race != RACE_ANIMAL)
  {
    if(skill_table[sn]->skill_level[ch->secondclass] < 101)
    {
      class2 = skill_table[sn]->skill_adept[ch->secondclass];
      if(availabletochar)
        if(skill_table[sn]->skill_level[ch->secondclass] > ch->secondlevel)
          class2 = 0; /* Can't use it yet. */
    }
  }

  if(skill_table[sn]->skill_level[ch->Class] < 101)
    class1 = skill_table[sn]->skill_adept[ch->Class];

  if(availabletochar)
  {
    if(IS_SECONDCLASS(ch))
    {
      if(skill_table[sn]->skill_level[ch->Class] > ch->firstlevel)
        class1 = 0;
    }
    else
    {
      if(skill_table[sn]->skill_level[ch->Class] > ch->level)
        class1 = 0;
    }
  }

  class3 = URANGE(0, class3, sysdata.class3maxadept);
  class2 = URANGE(0, class2, sysdata.class2maxadept);
  class1 = URANGE(0, class1, sysdata.class1maxadept);

  result = class1;
  if(class2 > result)
    result = class2;
  if(class3 > result)
    result = class3;

  return result;
}

/* This will find the MAX AVAILABLE SKILL LEVEL for their classes. For example,
 *  * if player gets second attack at level 10 with one class and second
 *   * attack at level 20 with another class, and they are higher than level 20, it
 *    * will return 20. Else if higher than 10, it'll return 10. Else returns 0.
 *     * */
/* Okay, have reworked this now. Use TRUE if you want to check if it's available
 *  * to the player at their current level. Use FALSE if you just want to see what
 *   * level is the highest. :) */
// Volk: Well it should. Seems broken.

int get_maxskill(CHAR_DATA *ch, int sn, bool availabletochar)
{
  int                     sklvl1 = skill_table[sn]->skill_level[ch->Class];
  int                     sklvl2 = skill_table[sn]->skill_level[ch->secondclass];
  int                     sklvl3 = skill_table[sn]->skill_level[ch->thirdclass];
  int                     result = 0;
  bool                    one = FALSE, two = FALSE, three = FALSE;

  if(sklvl1 == 0)
    sklvl1 = 101;
  if(sklvl2 == 0)
    sklvl2 = 101;
  if(sklvl3 == 0)
    sklvl3 = 101;

/* Means players have access to said sn */
  if(availabletochar)
  {
    if(sklvl3 <= ch->thirdlevel)
      three = TRUE;
    if(sklvl2 <= ch->secondlevel)
      two = TRUE;
    if(IS_SECONDCLASS(ch))
    {
      if(sklvl1 <= ch->firstlevel)
        one = TRUE;
    }
    else
    {
      if(sklvl1 <= ch->Class)
        one = TRUE;
    }
  }
  else
  {
    three = TRUE;
    two = TRUE;
    one = TRUE;
  }

  if(three)
  {
    if(two)
    {
      if(one)
      {
        /*
         * All three are valid!! 
         */
        result = sklvl3 > sklvl2 ? UMAX(sklvl3, sklvl1) : UMAX(sklvl2, sklvl1);
      }
      else  /* Only three and two! */
        result = UMAX(sklvl3, sklvl2);
    }
    if(one) /* Might still be three and one */
      result = UMAX(sklvl3, sklvl1);
  }
  else if(two)
    result = UMAX(sklvl2, sklvl1);
  else
    result = sklvl1;

  return result;
}

void advance_class_level(CHAR_DATA *ch)
{ /* ONLY called for multiclasses */
  int                     level = 0;

  if(ch->firstexp >= exp_class_level(ch, ch->firstlevel + 1, ch->Class))
  { /* Levelled */
    ch_printf(ch, "\r\n&WYou have now obtained %s level %d!&D\r\n", class_table[ch->Class]->who_name, ++ch->firstlevel);
    ch->firstexp = URANGE(0, (ch->firstexp - exp_class_level(ch, ch->firstlevel, ch->Class)), ch->firstexp);
    advance_level(ch);
  }

  if(IS_SECONDCLASS(ch) && ch->secondexp >= exp_class_level(ch, ch->secondlevel + 1, ch->secondclass))
  { /* Again */
    ch_printf(ch, "\r\n&WYou have now obtained %s level %d!&D\r\n", class_table[ch->secondclass]->who_name, ++ch->secondlevel);
    ch->secondexp = URANGE(0, (ch->secondexp - exp_class_level(ch, ch->secondlevel, ch->secondclass)), ch->secondexp);
    advance_level(ch);
  }

  if(IS_THIRDCLASS(ch) && ch->thirdexp >= exp_class_level(ch, ch->thirdlevel + 1, ch->thirdclass))
  { /* Made a level! */
    ch_printf(ch, "\r\n&WYou have now obtained %s level %d!&D\r\n", class_table[ch->thirdclass]->who_name, ++ch->thirdlevel);
    ch->thirdexp = URANGE(0, (ch->thirdexp - exp_class_level(ch, ch->thirdlevel, ch->thirdclass)), ch->thirdexp);
    advance_level(ch);
  }

  if(IS_THIRDCLASS(ch))
    level = ((ch->firstlevel + 1 + ch->secondlevel + ch->thirdlevel) / 3);
  else if(IS_SECONDCLASS(ch))
    level = ((ch->firstlevel + 1 + ch->secondlevel) / 2);
  else
    level = (ch->firstlevel + 1);

  if(level > ch->level)
  { /* Should have gained! */
    char                    buf[MSL];

    if(xIS_SET(ch->act, PLR_EXTREME))
    {
      ch_printf(ch, "&GPlaying 6D EXTREME you gain 5 glory!&D\r\n");
      ch->quest_curr += 5;
    }

    ch_printf(ch, "\r\n&WYou have now obtained an overall experience level %d!&D\r\n", ++ch->level);
    restore_char(ch);
    send_to_char_color("&YYou have gained insight in the realms, and have been restored!\r\n", ch);
    snprintf(buf, MSL, "The realms rejoice as %s has just achieved level %d!&D", ch->name, ch->level);
    announce(buf);
    snprintf(buf, MSL, "%24.24s: %s obtained level %d!%s%s&D", ctime(&current_time), ch->name, ch->level, (doubleexp ? " (Double)" : ""), (happyhouron ? " (HappyHour)" : ""));
    append_to_file(PLEVEL_FILE, buf);
  }
}