#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;
}