/
area/city/
area/crypts/
area/guilds/
area/psuedowild/
area/religion/
data/documents/MPDocs/
data/html/
data/mobprogs/
data/quest/
data/world/
data/world/_utilities/
data/world/images/
design/html/
notes/
player/
// gquest.c
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "merc.h"
#include "mob_cmds.h"
#include "gquest.h"
#include "gdl.h"
#include "interp.h"

DECLARE_DO_FUN( do_say );
ROOM_INDEX_DATA *find_location args( ( CHAR_DATA *ch, char * arg ) );

/*
 * TODO:
 *
 * -    * Make mobprog ifcheck for quest step to prevent multiple messages/rewards
 *      and to make more customized messages for greetings
 * -    * Create OLC for creating a new quest
 * -    * Make quest step text modifyable with text data,no more helps
 */


BEGIN_ELE_LIST(QUEST)
STR(name)
STR(long_name)
STR(description)
INT(min_level)
INT(steps)
INT(reward_qps)
INT(reward_gold)
INT(reward_obj)
INT(number)
END_ELE_LIST

QUEST *quest_list;


/*
 * load_gquest_text()
 *
 * Loads the list into mem
 */
void load_quest()
{
    LOAD_LIST(quest_list, QUEST, QUEST_FILE);
    return;
}



void cmd_gquest(CHAR_DATA * ch, char *argument)
{
    char buf[MSL];
    char bufx[MSL];
    QUEST * p;
    QUEST * g;
    
    stc("You read your joruanal a little...\n\n", ch);
    for (p = quest_list; p ; p = p->next)
    {
        g = quest_lookup(p->name);
        if (ch->gquest[g->number] >= 1)
        {
            sprintf(buf, "--- {w%s{x\n--- {g%s\n",p->long_name, p->description);
            stc(buf, ch);
            if (ch->gquest[g->number] >= 1)
            {
                stc(" {WUpdate{g: ", ch);
                sprintf(bufx, "_%s_%d", p->name, ch->gquest[g->number]);
                do_help(ch, bufx);
                stc("\n", ch);
            }
        }
    }
    return;

}

/*
 * do_mpstartquest()
 *
 * Begins a quest for a character
 *
 * Mobprog keyword: startquest questname $n
 */
void do_mpstartquest(CHAR_DATA * ch, char *argument)
{
    char arg[MAX_INPUT_LENGTH];
    char arg1[MAX_INPUT_LENGTH];
    char buf[MSL];
    CHAR_DATA *victim;
    QUEST * questnum;

    argument = one_argument (argument, arg);
    argument = one_argument (argument, arg1);
    
    log_string("mpstartquest being called");
    
    if (arg[0] == '\0' || arg1[0] == '\0')
    {
        bug ("mpstartquest - Bad syntax from vnum %d. Not enough arguments",
             IS_NPC (ch) ? ch->pIndexData->vnum : 0);
        return;
    }

    questnum = quest_lookup(arg);
    
    if (questnum == NULL)
    {
        bug ("mpstartquest - Bad syntax from vnum %d. Invalid quest",
             IS_NPC (ch) ? ch->pIndexData->vnum : 0);
        return;
    }

    if ((victim = get_char_room (ch, arg1)) == NULL)
    {
        bug ("mpstartquest - Bad syntax from vnum %d. Null Victim",
             IS_NPC (ch) ? ch->pIndexData->vnum : 0);
        return;
    }
    
    sprintf(buf, "mpstartquest: I finished god damn it!");
    log_string(buf);
    
    /* 
     * best way i can cancel it out is to prevent multiple starts...
     */
    if (victim->gquest[questnum->number] != 0)
    {
        do_say(ch, "I'm sorry, but You cannot start this quest agaian.\n");
        return;
    }
    
    victim->gquest[questnum->number] = 1;
}

/*
 * do_mp_queststep()
 *
 * Increment's the steps of the given quest by 1
 *
 * Mobprog keyword: quest_increment questname $n step#
 * 
 * example: quest_step gilly $n 4
 * steps gilly quest to step 4
 */
void do_mp_queststep(CHAR_DATA * ch, char *argument)
{
    char arg[MAX_INPUT_LENGTH];
    char arg1[MAX_INPUT_LENGTH];
    char arg2[MSL];
    CHAR_DATA *victim;
    QUEST * questnum;
    int step;

    argument = one_argument (argument, arg);
    argument = one_argument (argument, arg1);
    argument = one_argument (argument, arg2);
    
    log_string("do_mp_queststep being called");
    
    if (arg[0] == '\0' || arg1[0] == '\0' || arg2[0] == '\0')
    {
        bug ("do_mp_queststep - Bad syntax from vnum %d. Not enough arguments",
             IS_NPC (ch) ? ch->pIndexData->vnum : 0);
        return;
    }

    questnum = quest_lookup(arg);
    
    if (questnum == NULL )
    {
        bug ("do_mp_queststep - Bad syntax from vnum %d. Invalid quest",
             IS_NPC (ch) ? ch->pIndexData->vnum : 0);
        return;
    }

    if ((victim = get_char_room (ch, arg1)) == NULL)
    {
        bug ("do_mp_queststept - Bad syntax from vnum %d. Null Victim",
             IS_NPC (ch) ? ch->pIndexData->vnum : 0);
        return;
    }
    
    step = atoi(arg2);
    
    victim->gquest[questnum->number] = step;
}

/*
 * do_mp_setquest()
 *
 * Sets mobile's "Quest" to specific quest. This is used for the onstep if check because
 * For the life of me, I couldn't figure out how to add another argument to the
 * if check system. Bleh. So this is a hack. Plain and simple.
 *
 * Syntax:  quest_setquest <quest>
 * Example: quest_setquest gilly
 */
void do_mp_setquest (CHAR_DATA * ch, char *argument)
{
    char arg[MAX_INPUT_LENGTH];
    QUEST * questnum;

    argument = one_argument (argument, arg);
    
    if (arg[0] == '\0')
    {
        bug ("ddo_mp_setquest - Bad syntax from vnum %d. Not enough arguments",
             IS_NPC (ch) ? ch->pIndexData->vnum : 0);
        return;
    }

    questnum = quest_lookup(arg);
    
    if (questnum == NULL )
    {
        bug ("do_mp_queststep - Bad syntax from vnum %d. Invalid quest",
             IS_NPC (ch) ? ch->pIndexData->vnum : 0);
        return;
    }
    
    free_string(ch->quest_number_mp);
    ch->quest_number_mp = str_dup(questnum->name);
}

/*
 * do_mp_questreward()
 *
 * Doles out the quest rewards and ends scripts for given quest
 *
 * Mobprog keyword: questreward questname $n
 * 
 * example: questreward gilly $n
 */
void do_mp_questreward(CHAR_DATA * ch, char *argument)
{
    char arg[MAX_INPUT_LENGTH];
    char arg1[MAX_INPUT_LENGTH];
    CHAR_DATA *victim;
    QUEST * questnum;

    argument = one_argument (argument, arg);
    argument = one_argument (argument, arg1);
    
    log_string("do_mp_questreward being called");
    
    if (arg[0] == '\0' || arg1[0] == '\0')
    {
        bug ("do_mp_questreward - Bad syntax from vnum %d. Not enough arguments",
             IS_NPC (ch) ? ch->pIndexData->vnum : 0);
        return;
    }

    questnum = quest_lookup(arg);
    
    if (questnum == NULL )
    {
        bug ("do_mp_questreward - Bad syntax from vnum %d. Invalid quest",
             IS_NPC (ch) ? ch->pIndexData->vnum : 0);
        return;
    }

    if ((victim = get_char_room (ch, arg1)) == NULL)
    {
        bug ("do_mp_questrewardt - Bad syntax from vnum %d. Null Victim",
             IS_NPC (ch) ? ch->pIndexData->vnum : 0);
        return;
    }
    
    /* TODO: Add in Object reward */
    victim->gold        += questnum->reward_gold;
    victim->quest_curr  += questnum->reward_qps;
    victim->quest_accum += questnum->reward_qps;
    return;
}

/*
 * quest_lookup()
 *
 * Looks up quest based on name.
 * Uses INTERNAL name
 */
QUEST *quest_lookup (char *keyword)
{
    QUEST * pQuest;
    char temp[MIL], argall[MIL];

    argall[0] = '\0';

    while (keyword[0] != '\0')
    {
        keyword = one_argument (keyword, temp);
        if (argall[0] != '\0')
            strcat (argall, " ");
        strcat (argall, temp);
    }

    for (pQuest = quest_list; pQuest; pQuest = pQuest->next)
    {
        if (is_name (argall, pQuest->name))
            return pQuest;
    }

    return NULL;
}

void cmd_gquest2 (CHAR_DATA * ch, char *argument)
{
    QUEST * p; 
    char buf[MSL]; 
    
    if (argument[0] == 'S')
    { 
        for (p = quest_list; p ; p = p->next)
        {
            sprintf(buf, "%s\n", p->name);
            stc(buf, ch);
        }
    }
    
    p = malloc(sizeof(QUEST));
    p->name         = argument;
    p->long_name    = "no long name";
    p->description  = "No description";
    p->min_level    = 1;
    p->steps        = 1; 
    p->reward_qps   = 0;
    p->reward_gold  = 0;
    p->reward_obj   = 0;
    p->next         = quest_list;
    quest_list      = p;
    SAVE_LIST(quest_list, QUEST, QUEST_FILE);
    return;
}


/*
 * check_queststep()
 *
 * Returns true if Queststep == Number
 */
bool check_queststep (CHAR_DATA * ch, CHAR_DATA * mob)
{
    QUEST * qst;
    int quest_number;
    
    qst = quest_lookup(mob->quest_number_mp);
    
    if (qst == NULL)
        return FALSE;
    
    quest_number = qst->number;
    
    if (quest_number == ch->gquest[qst->number])
        return TRUE;
    else
        return FALSE;
    
    return FALSE;
}

/*
 * qedit_new()
 *
 * Creates a new quest
 */
QEDIT (qedit_new)
{
    QUEST   * p;
    char arg[MSL];
    char fullarg[MSL];
    
    strcpy (fullarg, argument);
    argument = one_argument (argument, arg);
    
    p = malloc(sizeof(QUEST));
    p->name         = argument;
    p->long_name    = "none";
    p->min_level    = 0;
    p->steps        = 0;
    p->reward_qps   = 0;
    p->reward_gold  = 0;
    p->reward_obj   = 0;
    p->next         = quest_list;
    quest_list      = p;
    SAVE_LIST(quest_list, QUEST, QUEST_FILE);
    return FALSE;
}



/******************************
* Questmaster
*/

struct reward_type 
{
  char *name;
  char *keyword;
  int cost;
  bool object;
  int value;
  void *      where;
};

struct quest_desc_type {
  char *name;
  char *long_descr;
  char *short_descr;
};

/* Descriptions of quest items go here:
Format is: "keywords", "Short description", "Long description" */
const struct quest_desc_type quest_desc[] =
{
{       "quest vandagard amulet",
        "The amulet of Vandagard is on the ground here, waiting to be returned to its owner."
        "The amulet of Vandagard"},
{       "quest vandagard ring",
        "The ring of Vandagard is on the ground here, waiting to be returned to its owner."
        "The ring of Vandagard"},
{       "quest vandagard bracer",
        "The bracer of Vandagard is on the ground here, waiting to be returned to its owner."
        "The bracer of Vandagard"},
{       "quest vandagard crown",
        "The crown of Vandagard is on the ground here, waiting to be returned to its owner."
        "The crown of Vandagard"},
{       "quest vandagard cloak",
        "The cloak of Vandagard is on the ground here, waiting to be returned to its owner."
        "The cloak of Vandagard"},
{NULL, NULL, NULL}
};

/* Local functions */
/* The main quest function */
void do_quest(CHAR_DATA *ch, char *argument)
{
    CHAR_DATA *questman;
    OBJ_DATA *obj=NULL, *obj_next;
    OBJ_INDEX_DATA *questinfoobj;
    MOB_INDEX_DATA *questinfo;
    char buf [MAX_STRING_LENGTH];
    char arg1 [MAX_INPUT_LENGTH];
    char arg2 [MAX_INPUT_LENGTH];
    int i;

/* Add your rewards here.  Works as follows:
"Obj name shown when quest list is typed", "keywords for buying",
"Amount of quest points",  Does it load an object?,  IF it loads an
object, then the vnum, otherwise a value to set in the next thing,  This
is last field is a part of the char_data to be modified */ 

const struct reward_type reward_table[]= 
{
  { "350,000 Gold Pieces",              "500,000 gold",         50,     FALSE, 500000,  &ch->gold},
  { "1 Practice",                       "practice",             50,     FALSE, 1,       &ch->practice},
  { NULL, NULL, 0, FALSE, 0, 0  } /* Never remove this!!! */
};


    argument = one_argument(argument, arg1);
    argument = one_argument(argument, arg2);

    if(IS_NPC(ch))
        { send_to_char("NPC's can't quest.\n\r",ch); return; }

    if (arg1[0] == '\0')
    {
        send_to_char("Quest commands: Info, Time, Resign, Request, Complete, Quit, List, and Buy.\n\r",ch);
        send_to_char("For more information, type 'Help Quest'.\n\r",ch);
        return;
    }

    
    if (!strcmp(arg1, "info"))
    {
        if (IS_SET(ch->act,PLR_QUESTING))
        {
            if (ch->questmob == -1 && ch->questgiver->short_descr != NULL) {
                sprintf(buf,"Your quest is ALMOST complete!\n\rGet back to %s before your time runs out!\n\r",ch->questgiver->short_descr);
                send_to_char(buf, ch);
            }
            else if (ch->questobj > 0)
            { 
                questinfoobj = get_obj_index(ch->questobj);
                if (questinfoobj != NULL) {
                    sprintf(buf,"You are on a quest to recover the fabled %s!\n\r",questinfoobj->name);                
                    send_to_char(buf, ch);
                }
                else send_to_char("You aren't currently on a quest.\n\r",ch);
                return;
            }
            else if (ch->questmob > 0)
            {
                questinfo = get_mob_index(ch->questmob);
                if (questinfo != NULL) {
                    sprintf(buf,"You are on a quest to slay the dreaded %s!\n\r",questinfo->short_descr);
                    send_to_char(buf, ch);
                }
                else send_to_char("You aren't currently on a quest.\n\r",ch);
                return;
            }
        }
        else
            send_to_char("You aren't currently on a quest.\n\r",ch);
        return;
    }
    else if (!strcmp(arg1, "time"))
    {
        if (!IS_SET(ch->act,PLR_QUESTING))
        {
            send_to_char("You aren't currently on a quest.\n\r",ch);
            if (ch->nextquest > 1) {
                sprintf(buf,"There are %d minutes remaining until you can go on another quest.\n\r",ch->nextquest);
                send_to_char(buf, ch);
            }
            else if (ch->nextquest == 1) {
                sprintf(buf, "There is less than a minute remaining until you can go on another quest.\n\r");
                send_to_char(buf, ch);
            }
        }
        else if (ch->countdown > 0)
        {
            sprintf(buf, "Time left for current quest: %d\n\r",ch->countdown);
            send_to_char(buf, ch);
        }
        return;
    }
    
    else if (!strcmp(arg1, "resign"))
    {
        if (!IS_SET(ch->act,PLR_QUESTING))
        {
            stc("You are not currently on a quest!\n", ch);
        }
        else
        {
            stc("You hang your head in failure.\n", ch);
            REMOVE_BIT(ch->act,PLR_QUESTING);
            ch->nextquest   = 3;
            ch->questgiver  = NULL;
            ch->countdown   = 0;
            ch->questmob    = 0;
            ch->questobj    = 0;
            return;
        }
        return;
    }

    for ( questman = ch->in_room->people; questman != NULL; questman = questman->next_in_room )
    {
        if (!IS_NPC(questman)) continue;
        if (questman->spec_fun == spec_lookup( "spec_quest_master" )) break;
    }

    if (questman == NULL || questman->spec_fun != spec_lookup("spec_quest_master" ))
    {
        send_to_char("You can't do that here.\n\r",ch);
        return;
    }

    if ( questman->fighting != NULL)
    {
        send_to_char("Wait until the fighting stops.\n\r",ch);
        return;
    }

    ch->questgiver = questman;

    if (!strcmp(arg1, "list"))
    {
        act("$n asks $N for a list of quest items.", ch, NULL, questman, TO_ROOM); 
        act ("You ask $N for a list of quest items.",ch, NULL, questman, TO_CHAR);
        send_to_char("Current Quest Items available for Purchase:\n\r", ch);
        if(reward_table[0].name == NULL)
          send_to_char("  Nothing.\n\r",ch);
        else {
        send_to_char("  [{WCost{w]     [{BName{w]\n\r",ch);
        for(i=0;reward_table[i].name != NULL;i++) {
              sprintf(buf,"   {W%-4d{w       {b%s{w\n\r"
                        ,reward_table[i].cost,reward_table[i].name);
              send_to_char(buf, ch);
        }
             }
        send_to_char("\n\rTo buy an item, type 'Quest buy <item>'.\n\r",ch);
        return;
    }

    else if (!strcmp(arg1, "buy"))
    {
        bool found=FALSE;
        if (arg2[0] == '\0')
        {
            send_to_char("To buy an item, type 'Quest buy <item>'.\n\r",ch);
            return;
        }
        /* Use keywords rather than the name listed in qwest list */
        /* Do this to avoid problems with something like 'qwest buy the' */
        /* And people getting things they don't want... */
      for(i=0;reward_table[i].name != NULL;i++)
        if (is_name(arg2, reward_table[i].keyword))
        { found = TRUE;
            if (ch->quest_curr >= reward_table[i].cost)
            {
                ch->quest_curr -= reward_table[i].cost;
                if(reward_table[i].object)
                    obj = create_object(get_obj_index(reward_table[i].value),ch->level);
                else
                   {
                   sprintf(buf,"In exchange for %d quest points, %s gives you %s.\n\r",
                        reward_table[i].cost, questman->short_descr, reward_table[i].name );
                   send_to_char(buf, ch);
                   *(int *)reward_table[i].where += reward_table[i].value;
                   }
                break;
            }
            else
            {
                sprintf(buf, "Sorry, %s, but you don't have enough quest points for that.",ch->name);
                do_say(questman,buf);
                return;
            }
        }
        if(!found)
        {
            sprintf(buf, "I don't have that item, %s.",ch->name);
            do_say(questman, buf);
        }
        if (obj != NULL)
        {
            sprintf(buf,"In exchange for %d quest points, %s gives you %s.\n\r",
                    reward_table[i].cost, questman->short_descr, obj->short_descr);
            send_to_char(buf, ch);
            obj_to_char(obj, ch);
        }
        return;
    }
    else if (!strcmp(arg1, "request"))
    {
        act("$n asks $N for a quest.", ch, NULL, questman, TO_ROOM); 
        act("You ask $N for a quest.",ch, NULL, questman, TO_CHAR);
        if (IS_SET(ch->act,PLR_QUESTING))
        {
            sprintf(buf, "But you're already on a quest!");
            do_say(questman, buf);
            return;
        }
        if (ch->nextquest > 0)
        {
            sprintf(buf, "You're very brave, %s, but let someone else have a chance.",ch->name);
            do_say(questman, buf);
            sprintf(buf, "Come back later.");
            do_say(questman, buf);
            return;
        }

        sprintf(buf, "Thank you, brave %s!",ch->name);
        if (!IS_SET(ch->act,PLR_QUESTING))
        do_say(questman, buf);
        ch->questmob = 0;
        ch->questobj = 0;
        generate_quest(ch, questman);

        if (ch->questmob > 0 || ch->questobj > 0)
        {
            ch->countdown = number_range(5,10);
            SET_BIT(ch->act,PLR_QUESTING);
            sprintf(buf, "You have %d minutes to complete this quest.",ch->countdown);
            do_say(questman, buf);
            sprintf(buf, "May the gods go with you!");
            do_say(questman, buf);
        }
        return;
    }

    else if (!strcmp(arg1, "complete"))
    {
        act("$n informs $N $e has completed $s quest.", ch, NULL, questman, TO_ROOM); 
        act("You inform $N you have completed $s quest.",ch, NULL, questman, TO_CHAR);
        if (ch->questgiver != questman)
        {
            sprintf(buf, "I never sent you on a quest! Perhaps you're thinking of someone else.");
            do_say(questman,buf);
            return;
        }

        if (IS_SET(ch->act,PLR_QUESTING))
        {
        bool obj_found = FALSE;
            if (ch->questobj > 0 && ch->countdown > 0)
            {
                    for (obj = ch->carrying; obj != NULL; obj= obj_next)
                    {
                    obj_next = obj->next_content;
        
                    if (obj != NULL && obj->pIndexData->vnum == ch->questobj)
                    {
                        obj_found = TRUE;
                            break;
                    }
                }
            }

     if ((ch->questmob == -1 || (ch->questobj && obj_found)) 
        && ch->countdown > 0)
        {
        int reward, pointreward;
                    reward = number_range(50,100);
                    pointreward = number_range(20,30);

                sprintf(buf, "Congratulations on completing your quest!");
                do_say(questman,buf);
                sprintf(buf,"As a reward, I am giving you %d quest points, and %d gold.",pointreward,reward);
                do_say(questman,buf);

                REMOVE_BIT(ch->act,PLR_QUESTING);
                ch->questgiver = NULL;
                ch->countdown = 0;
                ch->questmob = 0;
                ch->questobj = 0;
                ch->nextquest = number_range(3, 6);
                ch->gold += reward;
                ch->quest_curr += pointreward;
                ch->quest_accum += pointreward;
                if(obj_found) extract_obj(obj);
         return;
        }
     else if((ch->questmob > 0 || ch->questobj > 0)
          && ch->countdown > 0)
            {
                sprintf(buf, "You haven't completed the quest yet, but there is still time!");
                do_say(questman, buf);
                return;
            }
     }
        if (ch->nextquest > 0)
        {
            sprintf(buf,"But you didn't complete your quest in time!");
        }
        else sprintf(buf, "You have to request a quest first, %s.",ch->name);
        do_say(questman, buf);
        return;
    }

    else if (!strcmp(arg1, "quit"))
    {
        act("$n informs $N $e wishes to quit $s quest.", ch, NULL,questman, TO_ROOM); 
        act ("You inform $N you wish to quit $s quest.",ch, NULL, questman, TO_CHAR);
        if (ch->questgiver != questman)
        {
            sprintf(buf, "I never sent you on a quest! Perhaps you're thinking of someone else.");
            do_say(questman,buf);
            return;
        }

        if (IS_SET(ch->act,PLR_QUESTING))
        {
            REMOVE_BIT(ch->act,PLR_QUESTING);
            ch->questgiver = NULL;
            ch->countdown = 0;
            ch->questmob = 0;
            ch->questobj = 0;
            ch->nextquest = 30;

            sprintf(buf, "Your quest is over, but for your cowardly behavior, you may not quest again for 30 minutes.");
            do_say(questman,buf);
                    return;
        }
        else
        {
        send_to_char("You aren't on a quest!",ch);
        return;
        } 
    }


    send_to_char("Quest commands: Info, Time, Request, Complete, Quit, List, and Buy.\n\r",ch);
    send_to_char("For more information, type 'Help Quest'.\n\r",ch);
    return;
}

void generate_quest(CHAR_DATA *ch, CHAR_DATA *questman)
{
    CHAR_DATA *victim;
    MOB_INDEX_DATA *vsearch;
    ROOM_INDEX_DATA *room;
    OBJ_DATA *questitem;
    char buf [MAX_STRING_LENGTH];
    long mcounter;
    int mob_vnum;

    for (mcounter = 0; mcounter < 99999; mcounter ++)
    {
        mob_vnum = number_range(50, 32600);

        if ( (vsearch = get_mob_index(mob_vnum) ) != NULL )
        {
            if (quest_level_diff(ch->level, vsearch->level) == TRUE
                && vsearch->pShop == NULL
                    && !IS_SET(vsearch->act, ACT_TRAIN)
                    && !IS_SET(vsearch->act, ACT_PRACTICE)
                    && !IS_SET(vsearch->act, ACT_IS_HEALER)
                && !IS_SET(vsearch->act, ACT_PET)
                && !IS_SET(vsearch->affected_by, AFF_CHARM)
                && !IS_SET(vsearch->affected_by, AFF_INVISIBLE)
                && number_percent() < 40) break;
                else vsearch = NULL;
        }
    }

    if ( vsearch == NULL || ( victim = get_char_world( ch, vsearch->player_name ) ) == NULL )
    {
        sprintf(buf, "I'm sorry, but I don't have any quests for you at this time.");
        do_say(questman, buf);
        sprintf(buf, "Try again later.");
        do_say(questman, buf);
        ch->nextquest = 2;
        return;
    }

    if ( ( room = find_location( ch, victim->name ) ) == NULL )
    {
        sprintf(buf, "I'm sorry, but I don't have any quests for you at this time.");
        do_say(questman, buf);
        sprintf(buf, "Try again later.");
        do_say(questman, buf);
        ch->nextquest = 2;
        return;
    }

    /*  40% chance it will send the player on a 'recover item' quest. */

    if (number_percent() < 40) 
    {
        int numobjs=0;
        int descnum = 0;

        for(numobjs=0; quest_desc[numobjs].name != NULL; numobjs++)
            ;
        numobjs--;
        descnum = number_range(0,numobjs);
        questitem = create_object( get_obj_index(number_range(40, 44)), ch->level );

        obj_to_room(questitem, room);
        ch->questobj = questitem->pIndexData->vnum;

        sprintf(buf, "Vile pilferers have stolen %s from the royal treasury!",questitem->short_descr);
        do_say(questman, buf);
        do_say(questman, "My court wizardess, with her magic mirror, has pinpointed its location.");

        sprintf(buf, "Look in the general area of %s for %s!",room->area->name, room->name);
        do_say(questman, buf);

        return;
    }

    /* Quest to kill a mob */

    else 
    {
    switch(number_range(0,1))
    {
        case 0:
        sprintf(buf, "An enemy of mine, %s, is making vile threats against the crown.",victim->short_descr);
        do_say(questman, buf);
        sprintf(buf, "This threat must be eliminated!");
        do_say(questman, buf);
        break;

        case 1:
        sprintf(buf, "Vandagard's most heinous criminal, %s, has escaped from the dungeon!",victim->short_descr);
        do_say(questman, buf);
        sprintf(buf, "Since the escape, %s has murdered %d civillians!",victim->short_descr, number_range(2,20));
        do_say(questman, buf);
        do_say(questman,"The penalty for this crime is death, and you are to deliver the sentence!");

        break;
    }

    if (room->name != NULL)
    {
        sprintf(buf, "Seek %s out somewhere in the vicinity of %s!",victim->short_descr,room->name);
        do_say(questman, buf);

        sprintf(buf, "That location is in the general area of %s.",room->area->name);
        do_say(questman, buf);
    }
    ch->questmob = victim->pIndexData->vnum;
    }

    return;
}

bool quest_level_diff(int clevel, int mlevel)
{
    if (clevel < 9 && mlevel < clevel + 2) return TRUE;
    else if (clevel <= 9 && mlevel < clevel + 3 
          && mlevel > clevel - 5) return TRUE;
    else if (clevel <= 14 && mlevel < clevel + 4 
          && mlevel > clevel - 5) return TRUE;
    else if (clevel <= 21 && mlevel < clevel + 5 
          && mlevel > clevel - 4) return TRUE;
    else if (clevel <= 29 && mlevel < clevel + 6 
          && mlevel > clevel - 3) return TRUE;
    else if (clevel <= 37 && mlevel < clevel + 7 
          && mlevel > clevel - 2) return TRUE;
    else if (clevel <= 55 && mlevel < clevel + 8 
          && mlevel > clevel - 1) return TRUE;
    else if (clevel <= 65 && mlevel < clevel + 9
          && mlevel > clevel - 1) return TRUE;
    else if (clevel <= 75 && mlevel < clevel + 10 
          && mlevel > clevel - 1) return TRUE;
    else if (clevel <= 85 && mlevel < clevel + 11
          && mlevel > clevel - 1) return TRUE;
    else if (clevel <= 95 && mlevel < clevel + 12
          && mlevel > clevel - 1) return TRUE;
    else if (clevel <= 100 && mlevel < clevel + 13 
          && mlevel > clevel - 1) return TRUE;
    else if(clevel > 106) return TRUE; /* Imms can get anything :) */
    else return FALSE;
}
                
/* Called from update_handler() by pulse_area */

void quest_update(void)
{
    DESCRIPTOR_DATA *d;
    CHAR_DATA *ch;
    char buf[MAX_STRING_LENGTH]; 

    for ( d = descriptor_list; d != NULL; d = d->next )
    {
        if (d->character != NULL && d->connected == CON_PLAYING)
        {
        ch = d->character;
        if(IS_NPC(ch))
        continue; 
        if (ch->nextquest > 0)
        {
            ch->nextquest--;
            if (ch->nextquest == 0)
            {
                send_to_char("You may now quest again.\n\r",ch);
                return;
            }
        }
        else if (IS_SET(ch->act,PLR_QUESTING))
        {
            if (--ch->countdown <= 0)
            {
                ch->nextquest = 3;
                sprintf(buf,"You have run out of time for your quest!\n\rYou may quest again in %d minutes.\n\r",ch->nextquest);
                send_to_char(buf, ch);
                REMOVE_BIT(ch->act,PLR_QUESTING);
                ch->questgiver = NULL;
                ch->countdown = 0;
                ch->questmob = 0;
                ch->questobj = 0;
            }
            if (ch->countdown > 0 && ch->countdown < 6)
            {
                send_to_char("Better hurry, you're almost out of time for your quest!\n\r",ch);
                return;
            }
        }
        }
    }
    return;
}