cdirt/ascii/
cdirt/data/BULL/
cdirt/data/ZONES/PENDING/
cdirt/pending/
cdirt/src/utils/
cdirt/utils/
#include "kernel.h"
#include "locations.h"
#include "objects.h"
#include "mobiles.h"
#include "mudmacros.h"
#include "ctype.h"
#include "bprintf.h"
#include "utils.h"
#include "uaf.h"
#include "mobile.h"
#include "objsys.h"
#include "sendsys.h"
#include "questnames.h"
#include "parse.h"
#include "log.h"
#include "quests.h"
#include "qlevels.h"

int quest_index[][2] = {
  {LOCMIN_EFOREST, LOCMAX_EFOREST},
  {LOCMIN_TOWER, LOCMAX_TOWER},
  {LOCMIN_SEA, LOCMAX_SEA},
  {LOCMIN_CATACOMB, LOCMAX_CATACOMB},
  {LOCMIN_WASTE, LOCMAX_WASTE},
  {LOCMIN_OAKTREE, LOCMAX_OAKTREE},
  {LOCMIN_FROBOZZ, LOCMAX_FROBOZZ},
  {LOCMIN_THYRANNEN, LOCMAX_THYRANNEN},
  {LOCMIN_EVOLUTION, LOCMAX_EVOLUTION},
  {LOCMIN_ZODIAC, LOCMAX_ZODIAC},
  {LOCMIN_ANCIENT, LOCMAX_ANCIENT},
  {LOCMIN_VOLCANO, LOCMAX_VOLCANO},
  {LOCMIN_PIRATE, LOCMAX_PIRATE},
  {LOCMIN_RAINFOREST, LOCMAX_RAINFOREST},
  {LOCMIN_NOXYPICKLE, LOCMAX_NOXYPICKLE},
  {LOCMIN_ABYSS, LOCMAX_ABYSS},
  {LOCMIN_MITHDAN, LOCMAX_MITHDAN},
  {LOCMIN_ORCHOLD, LOCMAX_ORCHOLD}
};

extern int count_players_in_zone(int zone);
extern int count_players_between_locs(int, int);

char *quest_status(int quest) {
  int i = quest;

  if (xtstbit(the_world->q_done, i))
    return("&+RDone ");
  else if (count_players_between_locs(quest_index[i][0], quest_index[i][1]) > 0)
    return("&+YIn Progress");
  else
    return("&+GAvailable");
}

/*
**  To set a quest flag. Makes check to see if gaining quest allows player to
**  level, as well as sets the_world->q_done flags.
*/
void set_quest(int p, int v)
{
  if (mynum < max_players)
    sendf(p, "Congratulations! You have completed the quest %s.\n", 
      Quests[v].name);

  mudlog ("Quest &+M%s&N completed by %s", Quests[v].name, pname(p));

  send_msg(DEST_ALL,MODE_QUIET, LVL_WIZARD,LVL_MAX,NOBODY,NOBODY,
           "&+Y[Quest &+M%s&+Y completed by %s]\n", Quests[v].name, pname(p));

  if (mynum < max_players)
    qsetflg(p, v);
  else
    bprintf("Really useful, completing quests as a mobile..\n");

  xsetbit(the_world->q_done, v);
  return;
}

/*
**  QLIST shows current list of quests and what points they are worth.
**  Points are only appropriate to certain quests systems, as is this command.
*/

void qlistcom() {
  int i = 0;
  int qpoints = 0;
  Boolean nl;

  nl = False;
  bprintf("                     &-BQuest Status for This Reset\n\n");
  bprintf("&+WQUEST        PTS  CRIT  STATUS            "
             "QUEST        PTS  CRIT  STATUS\n");
  while(Quests[i].name != TABLE_END) {
    if( Quests[i].name[0] ) {
      bprintf("%-13s %-4d%s  %-14s&N",
              Quests[i].name, Quests[i].pnt, 
              (Quests[i].crit ? "&+WYes&N " : "No  "), quest_status(i));
      qpoints += Quests[i].pnt;
      bprintf( "%s", nl ? "\n" : "       &N" );
      if( !nl ) 
        nl = True;
      else
        nl = False;
    }
    i++;
  }
  if( nl )
    bprintf( "\n" );
#if QTYPE <= 1
  bprintf("\nPoints, and critical have no meaning, please ignore.\n");
#elif QTYPE == 2
  bprintf("\nCritical has no meaning, please ignore\n");
#elif QTYPE == 4
bprintf( "\nYou must have %d (of %d) quest points and all the critical quests done to wiz.\n",
         WIZ_QPOINTS, qpoints );
#endif
  bprintf("\n");
  return;
}

/*
 *  Returns level a player could have according to quests/quest points they 
 *  have. qpoints() decides if it is dependent on points or just number of
 *  quests.
 */

int qcheck(int pl) {
  int pnt, i;

  i = -1;

  if ((plev(pl) >= LVL_WIZARD) || (plev(pl) < 1))
    return plev(pl);

#if QTYPE == 0
  if (!tstbits(qflags(pl), Q_ALL))
    return LVL_WIZARD - 1;
  else
    return LVL_WIZARD;

#elif (QTYPE == 1 || QTYPE == 2)
  pnt = qpoints(pl);
  for(i = LVL_WIZARD; i > 0; i--) {
    if (pnt >= qlevels[i])
      return i;
  }

#elif QTYPE == 3
  pnt = qpoints(pl);
  if (pnt >= WIZ_QPOINTS  && crit_qtest(pl))
    return LVL_WIZARD;
  else
    for(i = LVL_WIZARD; i > 0; i--) {
     if (pnt >= qlevels[i])
       return i;
   }

#elif QTYPE == 4
  pnt = qpoints(pl);
  if(pnt >= WIZ_QPOINTS  && crit_qtest(pl))
    return LVL_WIZARD;
  else
    return LVL_WIZARD - 1;
#endif
}

/*
**  For quests systems with critical quests, that is ones players MUST do
*/
Boolean crit_qtest(int pl)
{
  int i = 0;

  while(Quests[i].name != TABLE_END)
  {
    if (Quests[i].crit && !qtstflg(pl, i))
      return False;
    i++;
  }
  return True;
}

/*
**  Depending on the QTYPE defined, this function returns either the number
**  of quests done, or number of quest points obtained, which ever is 
**  appropriate to the quest system. Default is number of quests
*/
int qpoints(int pl)
{
  int pnt = 0;
  int i = 0;
  int num = 0;
  
  while(Quests[i].name != TABLE_END)
  {
    if (qtstflg(pl, i))
    {
      num++;
      pnt += Quests[i].pnt;
    }
    i++;
  }
#if ((QTYPE == 2) || (QTYPE == 3) || (QTYPE == 4))
  return pnt;
#else
  return num;
#endif
}

/* 
**  The QUESTS-Command. Mortals may find out which quests they have
**  comleted and which are left. Arch-Wizards may in addition set or
**  clear quests for a mortal, Wizards only for themselves.
**  Usage: QUESTS <player> <questname> <true/false>
**  (Moved over from commands.c file to keep quest code together)
*/
void questcom(void)
{
  int a, b, c, l;
  char *n;
  Boolean f, all;
  QFLAGS q, *p;
  PERSONA d;

  f = False;

  if (brkword() == -1) 
  {
    a = mynum;
    p = &(qflags(a));
    n = pname(a);
    l = plev(a);
  } 
  else if ((a = fpbn(wordbuf)) != -1) 
  {
    if (a != mynum && plev(mynum) < LVL_WIZARD) 
    {
      bprintf("You can only check your own Quest-stats.\n");
      return;
    }
    p = &(qflags(a));
    n = pname(a);
    l = plev(a);
  } 
  else if (!getuaf(wordbuf,&d)) 
  {
    bprintf("No such persona in system.\n");
    return;
  } 
  else if (plev(mynum) < LVL_WIZARD) 
  {
    bprintf("You can only check your own Quest-stats.\n");
    return;
  } 
  else 
  {
    f = True;
    p = &(d.player.pquests);
    n = d.ublock.pname;
    l = d.ublock.plev;
  }

  if (brkword() == -1) 
  {
    all = False;
    if ((*p & Q_ALL) == Q_ALL) 
    {
      bprintf("&+C%s has completed all quests!\n", n);
      all = True;
    } 
    else if ((*p & Q_ALL) != 0) 
    {
      bprintf("\n&+c----------------------------------"
              "--------------------------------------------\n");
      bprintf("                                &+MQUESTS COMPLETED\n\n");
      show_quests((int *)p, sizeof(QFLAGS)/sizeof(int));
      bprintf("&+c----------------------------------"
              "--------------------------------------------\n");
    } 
    else 
    {
      bprintf("&+W%s has completed no quests!\n", n);
    }
    if (!all) 
    {
      bprintf("\n&+c----------------------------------"
              "--------------------------------------------\n");
      bprintf("                               &+YQUESTS NOT COMPLETED\n\n");
      q = (~*p & Q_ALL);
      show_quests((int *)&q, sizeof(QFLAGS)/sizeof(int));
      bprintf("&+c----------------------------------"
              "--------------------------------------------\n");
    }
    return;
  } 
  else if ((b = qlookup(wordbuf)) == -1) 
  {
    bprintf("%s: No such Quest.\n", wordbuf);
    return;
  } 
  else if (brkword() == -1 || plev(mynum) < LVL_WIZARD) 
  {
    c = xtstbit(*p,b)?1:0;
    bprintf("Value of %s is %s\n", Quests[b].name, TF[c]);
    return;
  } 
  else if (plev(mynum) < LVL_ARCHWIZARD && !EQ(n, pname(mynum)) ) 
  {
    bprintf("You can't change other players Quest-stats.\n");
    return;
  } 
  else if ((c = tlookup(wordbuf,TF)) == -1) 
  {
    bprintf("Value must be True or False.\n");
    return;
  }

  mudlog("Quest: %s by %s, %s := %s", n, pname(mynum), Quests[b].name, TF[c]);

  if (c == 0) 
    xclrbit(*p,b);
  else 
    xsetbit(*p,b);
  if (f) 
    putuaf(&d);
}

/*
**  Basically just show_bits, modified to deal with just the Quests[] struct
*/
void show_quests(int *bits, int n)
{
  int *b;
  int bno;
  int xno;
  int cno;
  int c2;
  char *p;
  Boolean t_end;
  char buff[16];
  int t;

  cno = n;
  b = bits + n - 1;
  bno = 0;
  xno = 0;
  c2 = 0;
  t = 0;
  t_end = False;
  for (;b >= bits; --b, ++cno) 
  {
    for (bno = 0; bno < 32; bno++, xno++, t++) 
    {
      if (((*b) & (1<<bno)) != 0) 
      {
        if (t_end)
          p = NULL;
        else if ((p = Quests[t].name) == TABLE_END) 
        {
          t_end = True;
          p = NULL;
        }
        if (p == NULL) 
        {
          sprintf(buff,"<Spare%d>", xno);
          p = buff;
        }
        if (++c2 == 6) {
          bprintf("\n");
          c2 = 1;
        }
        if (c2 > 1)
          bprintf("\t");

        bprintf("%-14s", p);
      }
    }
  }
  bprintf("\n");
  return;
}

/*
**  Return array index for name in Quests[].name struct
*/
int qlookup(char *name)
{
  int i = 0;

  while(Quests[i].name != TABLE_END)
  {
    if (strncasecmp(Quests[i].name, name, strlen(name)) == 0)
    {
      return i;
    }
    i++;
  }
  return -1;
}