drm/player/
/****************************************************************************
*  Automated Quest code written by Vassago of MOONGATE, moongate.ams.com    *
*  4000. Copyright (c) 1996 Ryan Addams, All Rights Reserved. Use of this   *
*  code is allowed provided you add a credit line to the effect of:         *
*  "Quest Code (c) 1996 Ryan Addams" to your logon screen with the rest     *
*  of the standard diku/rom credits. If you use this or a modified version  *
*  of this code, let me know via email: moongate@moongate.ams.com. Further  *
*  updates will be posted to the rom mailing list. If you'd like to get     *
*  the latest version of quest.c, please send a request to the above add-   *
*  ress. Quest Code v2.03. Please do not remove this notice from this file. *
****************************************************************************/

/********************************************************************************
 * Updated Quest Code copyright 1999-2001                                       *
 * Markanth : markanth@hotpop.com or rjenn78@home.com                           *
 * Devil's Lament : spaceservices.net port 3778                                 *
 * Web Page : http://spaceservices.net/~markanth/                               *
 *                                                                              *
 * Quest objects are now updated by owner's level, code is more dynamic.        *
 *                                                                              *
 * All I ask in return is that you give me credit on your mud somewhere         *
 * or email me if you use it.                                                   *
 ********************************************************************************/

#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "merc.h"
#include "recycle.h"

struct quest_type
{
    char *name;
    char *who_name;
    long vnum;
    int cost;
};

/* Quest Prizes */
#define QUEST_BLADE       501   /* Blade     */
#define QUEST_ARMOR       502   /* Armor     */
#define QUEST_LEGGING     505   /* Leggings  */
#define QUEST_GAUNTLET    503   /* Gauntlets */
#define QUEST_BOOT        512   /* Boots     */
#define QUEST_HELM        514   /* Helm      */
#define QUEST_RING        506   /* Ring      */
#define QUEST_ORB         516   /* Orb       */
#define QUEST_NECKLACE    517   /* Necklace  */
#define QUEST_MASK        508   /* Mask      */
#define QUEST_BELT        511   /* Belt      */
#define QUEST_CLOAK       507   /* Cloak     */
#define QUEST_BRACER      509   /* Bracelet  */
#define QUEST_EARRING     518   /* Earring   */
#define QUEST_ANKLET      513   /* Anklet    */
#define QUEST_SHIELD      510   /* Shield    */
#define QUEST_AURA        515   /* Aura      */
#define QUEST_TATTOO      504   /* Tattoo    */
#define QUEST_SLEEVE      519   /* Sleeves   */
#define QUEST_FLAME       520   /* Flame     */
#define QUEST_STRINGTICK  548   /* Restring Ticket */
#define QUEST_WHOTICK     549   /* Whostring Ticket */
/*#define QUEST_TRIVIA      OBJ_VNUM_TRIVIA_PILL*/

/*
 * Quest Reward Table.
 */
const struct quest_type quest_table[] = {
    {"blade", "{BB{blad{Be{x of the {YA{yn{Yc{yi{Ye{yn{Yt{y's{x", QUEST_BLADE,
     20000},
    {"protection", "{RP{rrotectio{Rn {xof the {YA{yn{Yc{yi{Ye{yn{Yt{y's{x",
     QUEST_ARMOR, 15000},
    {"gauntlets", "{GG{gauntlet{Gs{x of the {YA{yn{Yc{yi{Ye{yn{Yt{y's",
     QUEST_GAUNTLET, 9000},
    {"tattoo", "{RT{ratto{Ro{x of the {YA{yn{Yc{yi{Ye{yn{Yt{y's{x",
     QUEST_TATTOO, 5000},
    {"leggings", "{WL{Degging{Ws{x of the {YA{yn{Yc{yi{Ye{yn{Yt{y's{x",
     QUEST_LEGGING, 5000},
    {"boots", "{DB{moot{Ds {xof the {YA{yn{Yc{yi{Ye{yn{Yt{y's{x", QUEST_BOOT,
     5000},
    {"mask", "{CM{cas{Ck{x of the {YA{yn{Yc{yi{Ye{yn{Yt{y's{x", QUEST_MASK,
     5000},
    {"helm", "{YH{yel{Ym{x of the {YA{yn{Yc{yi{Ye{yn{Yt{y's{x", QUEST_HELM,
     5000},
    {"belt", "{BB{gel{Bt{x of the {YA{yn{Yc{yi{Ye{yn{Yt{y's{x", QUEST_BELT,
     5000},
    {"orb", "{CO{Br{Cb{x of the {YA{yn{Yc{yi{Ye{yn{Yt{y's{x", QUEST_ORB,
     5000},
    {"earring", "{ME{Darrin{Mg{x of the {YA{yn{Yc{yi{Ye{yn{Yt{y's{x",
     QUEST_EARRING, 5000},
    {"shield", "{DS{Ghiel{Dd{x of the {YA{yn{Yc{yi{Ye{yn{Yt{y's{x",
     QUEST_SHIELD, 5000},
    {"ring", "{MR{min{Mg{x of the {YA{yn{Yc{yi{Ye{yn{Yt{y's{x", QUEST_RING,
     5000},
    {"cloak", "{DC{gloa{Dk {xof the {YA{yn{Yc{yi{Ye{yn{Yt{y's{x", QUEST_CLOAK,
     5000},
    {"neckguard", "{WN{Deckguar{Wd {xof the {YA{yn{Yc{yi{Ye{yn{Yt{y's{x",
     QUEST_NECKLACE, 5000},
    {"anklet", "{gA{cnkle{gt{x of the {YA{yn{Yc{yi{Ye{yn{Yt{y's{x",
     QUEST_ANKLET, 5000},
    {"bracer", "{BB{Drace{Br{x of the {YA{yn{Yc{yi{Ye{yn{Yt{y's{x",
     QUEST_BRACER, 5000},
    {"aura", "{CA{Wu{Cr{Wa{x of the {YA{yn{Yc{yi{Ye{yn{Yt{ys{x", QUEST_AURA,
     5000},
    {"sleeves", "{RS{cl{Re{ce{Rv{ce{Rs{x of the {YA{yn{Yc{yi{Ye{yn{Yt{ys{x",
     QUEST_SLEEVE, 5000},
    {"flame", "{RF{Yl{Ra{Ym{Re{x of the {YA{yn{Yc{yi{Ye{yn{Yt{ys{x",
     QUEST_FLAME, 5000},
    {"wticket", "{wA {WW{ghostrin{Wg{G Ticket (Quest Buy WTicket){x",
     QUEST_WHOTICK, 3000},
    {"sticket", "{wA {WR{gestrin{Wg {GTicket (Quest Buy STicket){x",
     QUEST_STRINGTICK, 2000},
    {NULL, 0, 0}
};

/* Quests to find objects */
#define QUEST_OBJQUEST1 3315
#define QUEST_OBJQUEST2 3316
#define QUEST_OBJQUEST3 3317
#define QUEST_OBJQUEST4 3318

/*
 * CHANCE function. I use this everywhere in my code, very handy :> 
 */
bool chance ( int num )
{
    if ( number_range ( 1, 100 ) <= num )
        return TRUE;
    else
        return FALSE;
}

/* is object in quest table? */
int is_qobj ( OBJ_DATA * obj )
{
    int i;

    if ( !obj || !obj->pIndexData )
        return -1;

    for ( i = 0; quest_table[i].name != NULL; i++ )
    {
        if ( obj->pIndexData->vnum == quest_table[i].vnum )
            return i;
    }
    return -1;
}

/* get the cost of an object in questpoints */
int qobj_cost ( OBJ_DATA * obj )
{
    int i;

    if ( !obj || !obj->pIndexData )
        return 0;

    for ( i = 0; quest_table[i].name != NULL; i++ )
    {
        if ( obj->pIndexData->vnum == quest_table[i].vnum )
            return quest_table[i].cost;
    }
    return 0;
}

/*
 * * Add or enhance an obj affect. 
 */
void affect_join_obj ( OBJ_DATA * obj, AFFECT_DATA * paf )
{
    AFFECT_DATA *paf_old;
    bool found;

    found = FALSE;
    for ( paf_old = obj->affected; paf_old != NULL; paf_old = paf_old->next )
    {
        if ( paf_old->location == paf->location )
        {
            paf_old->level = paf->level;
            paf_old->modifier = paf->modifier;
            found = TRUE;
        }
    }
    if ( !found )
        affect_to_obj ( obj, paf );
    return;
}

/* Nice little addapply function */
void add_apply ( OBJ_DATA * obj, int loc, int mod, int where, int type,
                 int dur, long bit, int level )
{
    AFFECT_DATA pAf;

    if ( obj == NULL )
        return;

    if ( !obj->enchanted )
        affect_enchant ( obj );

    pAf.location = loc;
    pAf.modifier = mod;
    pAf.where = where;
    pAf.type = type;
    pAf.duration = dur;
    pAf.bitvector = bit;
    pAf.level = level;
    affect_join_obj ( obj, &pAf );

    return;
}

/* Update a questobject */
void update_questobjs ( CHAR_DATA * ch, OBJ_DATA * obj )
{
    int bonus, pbonus, cost;

    if ( obj == NULL || obj->pIndexData == NULL )
    {
        bug ( "update_questobjs: NULL obj", 0 );
        return;
    }
    if ( ch == NULL )
    {
        bug ( "update_questobjs: NULL ch", 0 );
        return;
    }

    if ( !IS_OBJ_STAT ( obj, ITEM_QUEST ) && is_qobj ( obj ) == -1 )
        return;

    bonus = UMAX ( 5, ch->level / 2 );
    pbonus = UMAX ( 5, ch->level / 2 );
    cost = qobj_cost ( obj );

    if ( obj->level != ch->level )
        obj->level = ch->level;
    if ( obj->condition != -1 )
        obj->condition = -1;
    if ( obj->cost != cost )
        obj->cost = cost;
    if ( !CAN_WEAR ( obj, ITEM_NO_SAC ) )
        SET_BIT ( obj->wear_flags, ITEM_NO_SAC );
    if ( !IS_OBJ_STAT ( obj, ITEM_BURN_PROOF ) )
        SET_BIT ( obj->extra_flags, ITEM_BURN_PROOF );

    if ( obj->pIndexData->vnum == QUEST_ARMOR )
    {
        add_apply ( obj, APPLY_DAMROLL, pbonus, TO_OBJECT, 0, -1, 0,
                    ch->level );
        add_apply ( obj, APPLY_HITROLL, pbonus, TO_OBJECT, 0, -1, 0,
                    ch->level );
        add_apply ( obj, APPLY_HIT, UMAX ( 50, ch->level * 7 ), TO_OBJECT, 0,
                    -1, 0, ch->level );
        add_apply ( obj, APPLY_MANA, UMAX ( 50, ch->level * 7 ), TO_OBJECT, 0,
                    -1, 0, ch->level );
        add_apply ( obj, APPLY_MOVE, UMAX ( 50, ch->level * 7 ), TO_OBJECT, 0,
                    -1, 0, ch->level );
    }
    else if ( obj->pIndexData->vnum == QUEST_SHIELD )
    {
        add_apply ( obj, APPLY_DAMROLL, pbonus, TO_OBJECT, 0, -1, 0,
                    ch->level );
        add_apply ( obj, APPLY_HITROLL, pbonus, TO_OBJECT, 0, -1, 0,
                    ch->level );
        add_apply ( obj, APPLY_HIT, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
        add_apply ( obj, APPLY_MANA, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
        add_apply ( obj, APPLY_MOVE, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
    }
    else if ( obj->pIndexData->vnum == QUEST_TATTOO )
    {
        add_apply ( obj, APPLY_DAMROLL, pbonus, TO_OBJECT, 0, -1, 0,
                    ch->level );
        add_apply ( obj, APPLY_HITROLL, pbonus, TO_OBJECT, 0, -1, 0,
                    ch->level );
        add_apply ( obj, APPLY_HIT, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
        add_apply ( obj, APPLY_MANA, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
        add_apply ( obj, APPLY_MOVE, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
    }
    else if ( obj->pIndexData->vnum == QUEST_MASK )
    {
        add_apply ( obj, APPLY_DAMROLL, pbonus, TO_OBJECT, 0, -1, 0,
                    ch->level );
        add_apply ( obj, APPLY_HITROLL, pbonus, TO_OBJECT, 0, -1, 0,
                    ch->level );
        add_apply ( obj, APPLY_HIT, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
        add_apply ( obj, APPLY_MANA, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
        add_apply ( obj, APPLY_MOVE, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
    }
    else if ( obj->pIndexData->vnum == QUEST_EARRING )
    {
        add_apply ( obj, APPLY_DAMROLL, pbonus, TO_OBJECT, 0, -1, 0,
                    ch->level );
        add_apply ( obj, APPLY_HITROLL, pbonus, TO_OBJECT, 0, -1, 0,
                    ch->level );
        add_apply ( obj, APPLY_HIT, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
        add_apply ( obj, APPLY_MANA, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
        add_apply ( obj, APPLY_MOVE, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
    }
    else if ( obj->pIndexData->vnum == QUEST_AURA )
    {
        add_apply ( obj, APPLY_DAMROLL, pbonus, TO_OBJECT, 0, -1, 0,
                    ch->level );
        add_apply ( obj, APPLY_HITROLL, pbonus, TO_OBJECT, 0, -1, 0,
                    ch->level );
        add_apply ( obj, APPLY_HIT, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
        add_apply ( obj, APPLY_MANA, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
        add_apply ( obj, APPLY_MOVE, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
    }
    else if ( obj->pIndexData->vnum == QUEST_BRACER )
    {
        add_apply ( obj, APPLY_DAMROLL, pbonus, TO_OBJECT, 0, -1, 0,
                    ch->level );
        add_apply ( obj, APPLY_HITROLL, pbonus, TO_OBJECT, 0, -1, 0,
                    ch->level );
        add_apply ( obj, APPLY_HIT, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
        add_apply ( obj, APPLY_MANA, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
        add_apply ( obj, APPLY_MOVE, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
    }
    else if ( obj->pIndexData->vnum == QUEST_NECKLACE )
    {
        add_apply ( obj, APPLY_DAMROLL, pbonus, TO_OBJECT, 0, -1, 0,
                    ch->level );
        add_apply ( obj, APPLY_HITROLL, pbonus, TO_OBJECT, 0, -1, 0,
                    ch->level );
        add_apply ( obj, APPLY_HIT, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
        add_apply ( obj, APPLY_MANA, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
        add_apply ( obj, APPLY_MOVE, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
    }
    else if ( obj->pIndexData->vnum == QUEST_ORB )
    {
        add_apply ( obj, APPLY_DAMROLL, pbonus, TO_OBJECT, 0, -1, 0,
                    ch->level );
        add_apply ( obj, APPLY_HITROLL, pbonus, TO_OBJECT, 0, -1, 0,
                    ch->level );
        add_apply ( obj, APPLY_HIT, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
        add_apply ( obj, APPLY_MANA, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
        add_apply ( obj, APPLY_MOVE, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
    }
    else if ( obj->pIndexData->vnum == QUEST_ANKLET )
    {
        add_apply ( obj, APPLY_DAMROLL, pbonus, TO_OBJECT, 0, -1, 0,
                    ch->level );
        add_apply ( obj, APPLY_HITROLL, pbonus, TO_OBJECT, 0, -1, 0,
                    ch->level );
        add_apply ( obj, APPLY_HIT, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
        add_apply ( obj, APPLY_MANA, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
        add_apply ( obj, APPLY_MOVE, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
    }
    else if ( obj->pIndexData->vnum == QUEST_BELT )
    {
        add_apply ( obj, APPLY_DAMROLL, pbonus, TO_OBJECT, 0, -1, 0,
                    ch->level );
        add_apply ( obj, APPLY_HITROLL, pbonus, TO_OBJECT, 0, -1, 0,
                    ch->level );
        add_apply ( obj, APPLY_HIT, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
        add_apply ( obj, APPLY_MANA, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
        add_apply ( obj, APPLY_MOVE, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
    }
    else if ( obj->pIndexData->vnum == QUEST_CLOAK )
    {
        add_apply ( obj, APPLY_DAMROLL, pbonus, TO_OBJECT, 0, -1, 0,
                    ch->level );
        add_apply ( obj, APPLY_HITROLL, pbonus, TO_OBJECT, 0, -1, 0,
                    ch->level );
        add_apply ( obj, APPLY_HIT, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
        add_apply ( obj, APPLY_MANA, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
        add_apply ( obj, APPLY_MOVE, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
    }
    else if ( obj->pIndexData->vnum == QUEST_RING )
    {
        add_apply ( obj, APPLY_DAMROLL, pbonus, TO_OBJECT, 0, -1, 0,
                    ch->level );
        add_apply ( obj, APPLY_HITROLL, pbonus, TO_OBJECT, 0, -1, 0,
                    ch->level );
        add_apply ( obj, APPLY_HIT, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
        add_apply ( obj, APPLY_MANA, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
        add_apply ( obj, APPLY_MOVE, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
    }
    else if ( obj->pIndexData->vnum == QUEST_HELM )
    {
        add_apply ( obj, APPLY_DAMROLL, pbonus, TO_OBJECT, 0, -1, 0,
                    ch->level );
        add_apply ( obj, APPLY_HITROLL, pbonus, TO_OBJECT, 0, -1, 0,
                    ch->level );
        add_apply ( obj, APPLY_HIT, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
        add_apply ( obj, APPLY_MANA, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
        add_apply ( obj, APPLY_MOVE, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
    }
    else if ( obj->pIndexData->vnum == QUEST_GAUNTLET )
    {
        add_apply ( obj, APPLY_DAMROLL, pbonus, TO_OBJECT, 0, -1, 0,
                    ch->level );
        add_apply ( obj, APPLY_HITROLL, pbonus, TO_OBJECT, 0, -1, 0,
                    ch->level );
        add_apply ( obj, APPLY_HIT, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
        add_apply ( obj, APPLY_MANA, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
        add_apply ( obj, APPLY_MOVE, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
    }
    else if ( obj->pIndexData->vnum == QUEST_BOOT )
    {
        add_apply ( obj, APPLY_DAMROLL, pbonus, TO_OBJECT, 0, -1, 0,
                    ch->level );
        add_apply ( obj, APPLY_HITROLL, pbonus, TO_OBJECT, 0, -1, 0,
                    ch->level );
        add_apply ( obj, APPLY_HIT, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
        add_apply ( obj, APPLY_MANA, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
        add_apply ( obj, APPLY_MOVE, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
    }
    else if ( obj->pIndexData->vnum == QUEST_LEGGING )
    {
        add_apply ( obj, APPLY_DAMROLL, pbonus, TO_OBJECT, 0, -1, 0,
                    ch->level );
        add_apply ( obj, APPLY_HITROLL, pbonus, TO_OBJECT, 0, -1, 0,
                    ch->level );
        add_apply ( obj, APPLY_HIT, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
        add_apply ( obj, APPLY_MANA, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
        add_apply ( obj, APPLY_MOVE, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
    }

    else if ( obj->pIndexData->vnum == QUEST_SLEEVE )
    {
        add_apply ( obj, APPLY_DAMROLL, pbonus, TO_OBJECT, 0, -1, 0,
                    ch->level );
        add_apply ( obj, APPLY_HITROLL, pbonus, TO_OBJECT, 0, -1, 0,
                    ch->level );
        add_apply ( obj, APPLY_HIT, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
        add_apply ( obj, APPLY_MANA, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
        add_apply ( obj, APPLY_MOVE, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level );
    }

    else if ( obj->pIndexData->vnum == QUEST_FLAME )
    {
        add_apply ( obj, APPLY_DAMROLL, pbonus, TO_OBJECT, 0, -1, 0,
                    ch->level / 2 );
        add_apply ( obj, APPLY_HITROLL, pbonus, TO_OBJECT, 0, -1, 0,
                    ch->level / 2 );
        add_apply ( obj, APPLY_HIT, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level * 2 );
        add_apply ( obj, APPLY_MANA, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level * 2 );
        add_apply ( obj, APPLY_MOVE, UMAX ( 50, ch->level ), TO_OBJECT, 0, -1,
                    0, ch->level * 2 );
    }

    else if ( obj->item_type == ITEM_CONTAINER )
    {
        obj->weight = -1 * ( 50 + ( ch->level * 1.5 ) );
        obj->value[0] = 1000 + ( 20 * ch->level );
        obj->value[3] = 1000 + ( 20 * ch->level );
    }

    if ( obj->item_type == ITEM_WEAPON )
    {
        obj->value[1] = UMAX ( 15, ch->level );
        obj->value[2] = ch->level < 80 ? 6 : 8;
        add_apply ( obj, APPLY_DAMROLL, pbonus, TO_OBJECT, 0, -1, 0,
                    ch->level );
        add_apply ( obj, APPLY_HITROLL, pbonus, TO_OBJECT, 0, -1, 0,
                    ch->level );
        add_apply ( obj, APPLY_HIT, UMAX ( 50, ch->level * 4 ), TO_OBJECT, 0,
                    -1, 0, ch->level );
        add_apply ( obj, APPLY_MANA, UMAX ( 50, ch->level * 4 ), TO_OBJECT, 0,
                    -1, 0, ch->level );
        add_apply ( obj, APPLY_MOVE, UMAX ( 50, ch->level * 4 ), TO_OBJECT, 0,
                    -1, 0, ch->level );
    }
    else if ( obj->item_type == ITEM_ARMOR )
    {
        obj->value[0] = UMAX ( 20, ch->level * 4 / 3 );
        obj->value[1] = UMAX ( 20, ch->level * 4 / 3 );
        obj->value[2] = UMAX ( 20, ch->level * 4 / 3 );
        obj->value[3] = ( 5 * UMAX ( 20, ch->level * 4 / 3 ) ) / 6;
    }
    else if ( obj->item_type == ITEM_STAFF )
        obj->value[0] = UMAX ( 40, ch->level / 3 );
    return;
}

/* Usage info on the QUEST commands*/
/* Keep this in line with the do_quest function's keywords */
void quest_usage ( CHAR_DATA * ch )
{
    send_to_char
        ( "{YQUEST commands: POINTS INFO TIME REQUEST COMPLETE LIST BUY QUIT SELL REPLACE.{x\n\r",
          ch );
    send_to_char ( "{YFor more information, type 'HELP QUEST'.{x\n\r", ch );
    return;
}

/* Obtain additional location information about sought item/mob */
void quest_where ( CHAR_DATA * ch, char *what )
{
    char buf[MAX_INPUT_LENGTH];
    ROOM_INDEX_DATA *room;

    if ( !ch || IS_NPC ( ch ) )
        return;

    if ( ch->pcdata->questloc <= 0 )
    {
        bug ( "QUEST INFO: ch->questloc = %ld", ch->pcdata->questloc );
        return;
    }
    if ( ch->in_room == NULL )
        return;

    room = get_room_index ( ch->pcdata->questloc );
    if ( room->area == NULL )
    {
        bug ( "QUEST INFO: room(%ld)->area == NULL", ch->pcdata->questloc );
        return;
    }
    if ( room->area->name == NULL )
    {
        bug ( "QUEST INFO: area->name == NULL", 0 );
        return;
    }
    sprintf ( buf,
              "{RRumor has it this %s was last seen in the area known as %s,{x\n\r",
              what, room->area->name );
    send_to_char ( buf, ch );
    if ( room->name == NULL )
    {
        bug ( "QUEST INFO: room(%ld)->name == NULL", ch->pcdata->questloc );
        return;
    }
    sprintf ( buf, "{Rnear %s.{x\n\r", room->name );
    send_to_char ( buf, ch );

}                               /* end quest_where() */

/* Does player have thier target object? */
OBJ_DATA *has_questobj ( CHAR_DATA * ch )
{
    OBJ_DATA *obj;
    OBJ_INDEX_DATA *pObj;

    if ( !ch || IS_NPC ( ch ) || ch->pcdata->questobj <= 0 )
        return NULL;

    if ( ( pObj = get_obj_index ( ch->pcdata->questobj ) ) == NULL )
        return NULL;

    for ( obj = ch->carrying; obj != NULL; obj = obj->next_content )
        if ( obj != NULL && obj->pIndexData == pObj )
            return obj;

    return NULL;
}

/*
 * The main quest function 
 */
CH_CMD ( do_quest )
{
    CHAR_DATA *questman;
    OBJ_DATA *obj = NULL;
//    EXTRA_DESCR_DATA *ed;
    OBJ_INDEX_DATA *questinfoobj;
    MOB_INDEX_DATA *questinfo;
    char buf[MSL];
    char arg1[MIL];
    char arg2[MIL];
    int i = 0;

    if ( !ch )
        return;
    if ( IS_NPC ( ch ) )
    {
        send_to_char ( "I'm sorry, you can't quest.\n\r", ch );
        return;
    }

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

    if ( arg1[0] == '\0' )
    {
        quest_usage ( ch );
        return;
    }

    if ( !str_cmp ( arg1, "info" ) )
    {
        MOB_INDEX_DATA *qm_mobindex;

        if ( !IS_QUESTOR ( ch ) )
        {
            send_to_char ( "You aren't currently on a quest.\n\r", ch );
            return;
        }
        send_to_char ( "\n\r", ch );
        if ( ch->pcdata->questgiver <= 0 )
        {
            bug ( "QUEST INFO: quest giver = %d", ch->pcdata->questgiver );
            send_to_char
                ( "{RIt seems your quest master died of old age waiting for you.{x\n\r",
                  ch );
            end_quest ( ch, 5 );
            return;
        }
        qm_mobindex = get_mob_index ( ch->pcdata->questgiver );
        if ( qm_mobindex == NULL )
        {
            bug ( "QUEST INFO: quest giver %d has no MOB_INDEX_DATA!",
                  ch->pcdata->questgiver );
            send_to_char
                ( "{RYour quest master has fallen very ill. Please contact an imm!{x\n\r",
                  ch );
            end_quest ( ch, 5 );
            return;
        }
        if ( ch->pcdata->questmob == -1 || has_questobj ( ch ) )    /* killed target mob */
        {
            send_to_char ( "{RYour quest is {fALMOST{x{R complete!{x\n\r",
                           ch );
            sprintf ( buf,
                      "{RGet back to %s{R before your time runs out!{x\n\r",
                      ( qm_mobindex->short_descr ==
                        NULL ? "your quest master" : qm_mobindex->
                        short_descr ) );
            send_to_char ( buf, ch );
            return;
        }
        else if ( ch->pcdata->questobj > 0 )    /* questing for an object */
        {
            questinfoobj = get_obj_index ( ch->pcdata->questobj );
            if ( questinfoobj != NULL )
            {
                printf_to_char ( ch,
                                 "{RYou recall the quest which the %s{R gave you.{x\n\r",
                                 ( qm_mobindex->short_descr ==
                                   NULL ? "your quest master" : qm_mobindex->
                                   short_descr ) );
                sprintf ( buf,
                          "{RYou are on a quest to recover the fabled %s{R!{x\n\r",
                          questinfoobj->name );
                send_to_char ( buf, ch );
                quest_where ( ch, "treasure" );
                return;
            }
            /* quest object not found! */
            bug ( "No info for quest object %d", ch->pcdata->questobj );
            ch->pcdata->questobj = 0;
            REMOVE_BIT ( ch->act, PLR_QUESTOR );
            /* no RETURN -- fall thru to 'no quest', below */
        }
        else if ( ch->pcdata->questmob > 0 )    /* questing for a mob */
        {
            questinfo = get_mob_index ( ch->pcdata->questmob );
            if ( questinfo != NULL )
            {
                sprintf ( buf,
                          "{RYou are on a quest to slay the dreaded %s{R!{x\n\r",
                          questinfo->short_descr );
                send_to_char ( buf, ch );
                quest_where ( ch, "fiend" );
                return;
            }
            /* quest mob not found! */
            bug ( "No info for quest mob %d", ch->pcdata->questmob );
            ch->pcdata->questmob = 0;   /* Changed to mob instead of obj - Lotus */
            REMOVE_BIT ( ch->act, PLR_QUESTOR );
            /* no RETURN -- fall thru to 'no quest', below */
        }
        /* we shouldn't be here */
        bug ( "QUEST INFO: Questor with no kill, mob or obj", 0 );
        return;
    }
    if ( !str_cmp ( arg1, "points" ) )
    {
        sprintf ( buf,
                  "{WYou have {r%-8ld{W AQP{x\n\r{WYou have {r%-8d {WIQP{x\n\r",
                  ch->pcdata->questpoints, ch->qps );
        send_to_char ( buf, ch );
        return;
    }
    else if ( !str_cmp ( arg1, "time" ) )
    {
        if ( !IS_SET ( ch->act, PLR_QUESTOR ) )
        {
            send_to_char ( "You aren't currently on a quest.\n\r", ch );
            if ( ch->pcdata->nextquest > 1 )
            {
                sprintf ( buf,
                          "There are %d minutes remaining until you can go on another quest.\n\r",
                          ch->pcdata->nextquest );
                send_to_char ( buf, ch );
            }
            else if ( ch->pcdata->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->pcdata->countdown > 0 )
        {
            sprintf ( buf, "Time left for current quest: %d\n\r",
                      ch->pcdata->countdown );
            send_to_char ( buf, ch );
        }
        return;
    }

    /*
     * Checks for a character in the room with spec_questmaster set. This
     * special procedure must be defined in special.c. You could instead use
     * an ACT_QUESTMASTER flag instead of a special procedure. 
     */

    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_questmaster" ) )
            break;
    }

    if ( questman == NULL ||
         questman->spec_fun != spec_lookup ( "spec_questmaster" ) )
    {
        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;
    }

    /*
     * And, of course, you will need to change the following lines for YOUR
     * quest item information. Quest items on Moongate are unbalanced, very
     * very nice items, and no one has one yet, because it takes awhile to
     * build up quest points :> Make the item worth their while. 
     */

    if ( !str_cmp ( arg1, "list" ) )
    {
        act ( "$n asks $N for a list of quest items.", ch, NULL, questman,
              TO_ROOM );
        send_to_char
            ( "\t{YCurrent Quest Items available for Purchase:{x\n\r", ch );
        for ( i = 0; quest_table[i].who_name != NULL; i++ )
            printf_to_char ( ch, "\t%-5dqp ........ %s{x\n\r",
                             quest_table[i].cost, quest_table[i].who_name );
//        printf_to_char(ch,"        500  qp ........ {R25 {WI{wqp ({Wquest buy iqp{x){x\n\r");  
        send_to_char ( "\tTo buy an item, type 'QUEST BUY <item>'.\n\r", ch );
        send_to_char
            ( "\tFor more info on quest items type 'help questitems'\n\r",
              ch );
        return;
    }

    else if ( !str_cmp ( arg1, "buy" ) )
    {

        if ( arg2[0] == '\0' )
        {
            send_to_char ( "To buy an item, type 'QUEST BUY <item>'.\n\r",
                           ch );
            return;
        }
        if ( !str_cmp ( arg1, "iqp" ) )
        {
            if ( ch->pcdata->questpoints >= 500 )
            {
                ch->pcdata->questpoints -= 500;
                ch->qps += 25;
            }
            else
            {
                sprintf ( buf,
                          "Sorry, %s, but you don't have enough quest points for that.",
                          ch->name );
                do_mob_tell ( ch, questman, buf );
                return;
            }
        }

        for ( i = 0; quest_table[i].name != NULL; i++ )
        {
            if ( is_name ( arg2, quest_table[i].name ) )
            {
                if ( ch->pcdata->questpoints >= quest_table[i].cost )
                {
                    if ( quest_table[i].vnum == 0 )
                    {
                        ch->pcdata->questpoints -= quest_table[i].cost;
                        ch->pcdata->condition[COND_FULL] = -51;
                        ch->pcdata->condition[COND_THIRST] = -51;
                        act ( "$N calls upon the power of the gods to relieve your mortal burdens.", ch, NULL, questman, TO_CHAR );
                        act ( "$N calls upon the power of the gods to relieve $n' mortal burdens.", ch, NULL, questman, TO_ROOM );
                        return;
                    }
                    else if ( ( obj =
                                create_object ( get_obj_index
                                                ( quest_table[i].vnum ),
                                                ch->level ) ) == NULL )
                    {
                        send_to_char
                            ( "That object could not be found, contact an immortal.\n\r",
                              ch );
                        return;
                    }
                    else
                    {
                        ch->pcdata->questpoints -= quest_table[i].cost;
                        if ( !IS_IMMORTAL ( ch ) )
                        {
                            sprintf ( buf, "Bought %s for %d questpoints.",
                                      quest_table[i].name,
                                      quest_table[i].cost );
                            append_file ( ch, QUEST_FILE, buf );
                        }
                    }
                    /* this is my object owner code 

                       ed = new_extra_descr();
                       ed->keyword = str_dup(KEYWD_OWNER);
                       ed->description = str_dup(ch->name);
                       ed->next = obj->extra_descr;
                       obj->extra_descr = ed; */

                    if ( !IS_SET
                         ( obj->pIndexData->extra_flags, ITEM_QUEST ) )
                    {
                        SET_BIT ( obj->pIndexData->extra_flags, ITEM_QUEST );
                        SET_BIT ( obj->extra_flags, ITEM_QUEST );
                        SET_BIT ( obj->pIndexData->area->area_flags,
                                  AREA_CHANGED );
                    }
                    act ( "$N gives $p to $n.", ch, obj, questman, TO_ROOM );
                    act ( "$N gives you $p.", ch, obj, questman, TO_CHAR );
                    obj_to_char ( obj, ch );
                    save_char_obj ( ch );
                    return;
                }
                else
                {
                    sprintf ( buf,
                              "Sorry, %s, but you need %d quest points for that.",
                              ch->name, quest_table[i].cost );
                    do_mob_tell ( ch, questman, buf );
                    return;
                }
            }
        }
        sprintf ( buf, "I don't have that item, %s.", ch->name );
        do_mob_tell ( ch, questman, buf );
        return;
    }

    else if ( !str_cmp ( arg1, "sell" ) )
    {
        if ( arg2[0] == '\0' )
        {
            send_to_char ( "To sell an item, type 'QUEST SELL <item>'.\n\r",
                           ch );
            return;
        }
        if ( ( obj = get_obj_carry ( ch, arg2 ) ) == NULL )
        {
            send_to_char ( "Which item is that?\n\r", ch );
            return;
        }

        if ( !IS_OBJ_STAT ( obj, ITEM_QUEST ) )
        {
            sprintf ( buf, "That is not a quest item, %s.", ch->name );
            do_mob_tell ( ch, questman, buf );
            return;
        }

        for ( i = 0; quest_table[i].name != NULL; i++ )
        {
            if ( quest_table[i].vnum <= 0 )
                continue;
            if ( quest_table[i].vnum == obj->pIndexData->vnum )
            {
                ch->pcdata->questpoints += quest_table[i].cost / 3;
                act ( "$N takes $p from $n.", ch, obj, questman, TO_ROOM );
                sprintf ( buf, "$N takes $p from you for %d quest points.",
                          quest_table[i].cost / 3 );
                act ( buf, ch, obj, questman, TO_CHAR );
                extract_obj ( obj );
                save_char_obj ( ch );
                return;
            }
        }
        sprintf ( buf, "I only take items I sell, %s.", ch->name );
        do_mob_tell ( ch, questman, buf );
        return;
    }
    else if ( !str_cmp ( arg1, "replace" ) )
    {
        if ( arg2[0] == '\0' )
        {
            send_to_char
                ( "To replace an item, type 'QUEST REPLACE <item>'.\n\r",
                  ch );
            return;
        }
        if ( ( obj = get_obj_carry ( ch, arg2 ) ) == NULL )
        {
            send_to_char ( "Which item is that?\n\r", ch );
            return;
        }

        if ( !IS_OBJ_STAT ( obj, ITEM_QUEST ) )
        {
            sprintf ( buf, "That is not a quest item, %s.", ch->name );
            do_mob_tell ( ch, questman, buf );
            return;
        }
        if ( ch->pcdata->questpoints < 75 )
        {
            do_mob_tell ( ch, questman,
                          "It costs 75 questpoints to replace an item." );
            return;
        }
        for ( i = 0; quest_table[i].name != NULL; i++ )
        {
            if ( quest_table[i].vnum <= 0 )
                continue;
            if ( quest_table[i].vnum == obj->pIndexData->vnum )
            {
                OBJ_DATA *newobj;

                if ( ( newobj =
                       create_object ( get_obj_index ( quest_table[i].vnum ),
                                       ch->level ) ) == NULL )
                {
                    sprintf ( buf,
                              "I could not find a new quest item for you %s.",
                              ch->name );
                    do_mob_tell ( ch, questman, buf );
                }
                else
                {
                    /* this is my object owner code 

                       ed = new_extra_descr();
                       ed->keyword = str_dup(KEYWD_OWNER);
                       ed->description = str_dup(ch->name);
                       ed->next = obj->extra_descr;
                       obj->extra_descr = ed; */

                    obj_to_char ( newobj, ch );
                    extract_obj ( obj );
                    ch->pcdata->questpoints -= 75;
                    act ( "$N takes $p from $n and gives $m a new one.", ch,
                          obj, questman, TO_ROOM );
                    act ( "$N replaces $p with a new one for 75 quest points.", ch, obj, questman, TO_CHAR );
                    save_char_obj ( ch );
                }
                return;
            }
        }
        sprintf ( buf, "I only replace items I sell, %s.", ch->name );
        do_mob_tell ( ch, questman, buf );
        return;
    }

    else if ( !str_cmp ( 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_QUESTOR ) )
        {
            do_mob_tell ( ch, questman, "But you're already on a quest!" );
            return;
        }
        if ( ch->pcdata->nextquest > 0 )
        {
            sprintf ( buf,
                      "You're very brave, %s, but let someone else have a chance.",
                      ch->name );
            do_mob_tell ( ch, questman, buf );
            do_mob_tell ( ch, questman, "Come back later." );
            return;
        }

        sprintf ( buf, "Thank you, brave %s!", ch->name );
        do_mob_tell ( ch, questman, buf );
        ch->pcdata->questmob = 0;
        ch->pcdata->questobj = 0;

        generate_quest ( ch, questman );
        return;
    }
    else if ( !str_cmp ( arg1, "complete" ) )
    {
        if ( ch->pcdata->questgiver != questman->pIndexData->vnum )
        {
            do_mob_tell ( ch, questman,
                          "I never sent you on a quest! Perhaps you're thinking of someone else." );
            return;
        }

        if ( IS_SET ( ch->act, PLR_QUESTOR ) )
        {
            int reward, pracreward, points;

            if ( ch->pcdata->questmob == -1 && ch->pcdata->countdown > 0 )
            {
                reward = number_range ( 100, 800 );
                points = number_range ( 25, 75 );
                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 );

                do_mob_tell ( ch, questman,
                              "Congratulations on completing your quest!" );

                sprintf ( buf,
                          "As a reward, I am giving you %d quest points, and %d gold.",
                          points, reward );
                do_mob_tell ( ch, questman, buf );

                if ( double_qp )
                {
                    sprintf ( buf,
                              "You recive an extra %d quest points due to doubleqp!!",
                              points );
                    do_mob_tell ( ch, questman, buf );
                }
                if ( chance ( 15 ) )
                {
                    pracreward = number_range ( 1, 6 );
                    sprintf ( buf, "You gain %d practices!\n\r", pracreward );
                    send_to_char ( buf, ch );
                    ch->practice += pracreward;
                }
                end_quest ( ch, 8 );
                add_cost ( ch, reward, VALUE_GOLD );
                ch->pcdata->questpoints += points;
                if ( double_qp )
                {
                    ch->pcdata->questpoints += points;
                }
                save_char_obj ( ch );
                return;
            }
            else if ( ch->pcdata->questobj > 0 && ch->pcdata->countdown > 0 )
            {
                if ( ( obj = has_questobj ( ch ) ) != NULL )
                {
                    reward = number_range ( 150, 1250 );
                    points = number_range ( 50, 100 );
                    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 );

                    act ( "You hand $p to $N.", ch, obj, questman, TO_CHAR );
                    act ( "$n hands $p to $N.", ch, obj, questman, TO_ROOM );

                    do_mob_tell ( ch, questman,
                                  "Congratulations on completing your quest!" );
                    sprintf ( buf,
                              "As a reward, I am giving you %d quest points, and %d gold.",
                              points, reward );
                    do_mob_tell ( ch, questman, buf );
                    if ( double_qp )
                    {
                        sprintf ( buf,
                                  "You recive an extra %d quest points due to doubleqp!!",
                                  points );
                        do_mob_tell ( ch, questman, buf );
                    }
                    if ( chance ( 15 ) )
                    {
                        pracreward = number_range ( 1, 6 );
                        sprintf ( buf, "You gain %d practices!\n\r",
                                  pracreward );
                        send_to_char ( buf, ch );
                        ch->practice += pracreward;
                    }
                    end_quest ( ch, 8 );
                    add_cost ( ch, reward, VALUE_GOLD );
                    ch->pcdata->questpoints += points;
                    if ( double_qp )
                    {
                        ch->pcdata->questpoints += points;
                    }
                    extract_obj ( obj );
                    save_char_obj ( ch );
                    return;
                }
                else
                {
                    do_mob_tell ( ch, questman,
                                  "You haven't completed the quest yet, but there is still time!" );
                    return;
                }
                return;
            }
            else if ( ( ch->pcdata->questmob > 0 || ch->pcdata->questobj > 0 )
                      && ch->pcdata->countdown > 0 )
            {
                do_mob_tell ( ch, questman,
                              "You haven't completed the quest yet, but there is still  time!" );
                return;
            }
        }
        if ( ch->pcdata->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_mob_tell ( ch, questman, buf );
        return;
    }

    else if ( !str_cmp ( arg1, "quit" ) || !str_cmp ( arg1, "fail" ) )
    {
        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->pcdata->questgiver != questman->pIndexData->vnum )
        {
            do_mob_tell ( ch, questman,
                          "I never sent you on a quest! Perhaps you're thinking of someone else." );
            return;
        }

        if ( IS_SET ( ch->act, PLR_QUESTOR ) )
        {
            end_quest ( ch, 30 );
            do_mob_tell ( ch, questman,
                          "Your quest is over, but for your cowardly behavior, you may not quest again for 30 minutes." );

            return;
        }
        else
        {
            send_to_char ( "You aren't on a quest!", ch );
            return;
        }
    }

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

#define MAX_QMOB_COUNT mobile_count /* do all mobs what the heck */

void generate_quest ( CHAR_DATA * ch, CHAR_DATA * questman )
{
    CHAR_DATA *victim = NULL;
    ROOM_INDEX_DATA *room = NULL;
    CHAR_DATA *mobs[MAX_QMOB_COUNT];
    size_t mob_count;
    OBJ_DATA *questitem = NULL;
    char buf[MSL];
    int mrange;

    /*
     * * find MAX_QMOB_COUNT quest mobs and store their vnums in mob_buf 
     */

    mob_count = 0;
    for ( victim = char_list; victim; victim = victim->next )
    {

        if ( !IS_NPC ( victim ) || !quest_level_diff ( ch, victim ) ||
             ( victim->pIndexData == NULL || victim->in_room == NULL ||
               victim->pIndexData->pShop != NULL ) || ( IS_EVIL ( victim ) &&
                                                        IS_EVIL ( ch ) &&
                                                        chance ( 50 ) ) ||
             ( IS_GOOD ( victim ) && IS_GOOD ( ch ) && chance ( 50 ) ) ||
             victim->pIndexData->vnum < 100 ||
             IS_SET ( victim->imm_flags, IMM_WEAPON | IMM_MAGIC ) ||
             IS_SET ( victim->act,
                      ACT_TRAIN | ACT_PRACTICE | ACT_IS_HEALER | ACT_PET |
                      ACT_IS_PRIEST | ACT_PET | ACT_GAIN ) ||
             IS_SET ( victim->affected_by, AFF_CHARM ) ||
             questman->pIndexData == victim->pIndexData ||
             ( ( IS_SET ( victim->act, ACT_SENTINEL ) ) &&
               IS_SET ( victim->in_room->room_flags,
                        ROOM_PRIVATE | ROOM_SOLITARY | ROOM_SAFE ) ) )
            continue;
        mobs[mob_count++] = victim;
        if ( mob_count >= MAX_QMOB_COUNT )
            break;
    }

    if ( mob_count == 0 )
    {
        do_mob_tell ( ch, questman,
                      "I'm sorry, but I don't have any quests for you at this time." );
        do_mob_tell ( ch, questman, "Try again later." );
        end_quest ( ch, 2 );
        return;
    }

    /*
     * at this point the player is sure to get a quest 
     */
    ch->pcdata->questgiver = questman->pIndexData->vnum;
    mrange = number_range ( 0, mob_count - 1 );
    while ( ( victim = mobs[mrange] ) == NULL )
        mrange = number_range ( 0, mob_count - 1 );
    room = victim->in_room;
    ch->pcdata->questloc = room->vnum;

    ch->pcdata->countdown = number_range ( 12, 30 );

    /*
     * 20% chance it will send the player on a 'recover item' quest. Changed
     * to 15 by Markanth 
     */

    if ( chance ( 20 ) )
    {
        long objvnum = 0;

        switch ( number_range ( 0, 3 ) )
        {
            case 0:
                objvnum = QUEST_OBJQUEST1;
                break;

            case 1:
                objvnum = QUEST_OBJQUEST2;
                break;

            case 2:
                objvnum = QUEST_OBJQUEST3;
                break;

            case 3:
                objvnum = QUEST_OBJQUEST4;
                break;
        }

        questitem = create_object ( get_obj_index ( objvnum ), ch->level );
        obj_to_room ( questitem, room );
        REMOVE_BIT ( ch->act, PLR_CANLOOT );
        free_string ( questitem->owner );
        questitem->owner = str_dup ( ch->name );
        questitem->cost = 0;
        questitem->timer = ( 4 * ch->pcdata->countdown + 10 ) / 3;
        ch->pcdata->questobj = questitem->pIndexData->vnum;

        switch ( number_range ( 0, 1 ) )
        {
            default:
            case 0:
                sprintf ( buf,
                          "Vile pilferers have stolen %s from the royal treasury!",
                          questitem->short_descr );
                do_mob_tell ( ch, questman, buf );
                do_mob_tell ( ch, questman,
                              "My court wizardess, with her magic mirror, has pinpointed its location." );
                break;
            case 1:
                sprintf ( buf,
                          "A powerful wizard has stolen %s for his personal power!",
                          questitem->short_descr );
                do_mob_tell ( ch, questman, buf );
                break;
        }

        if ( room->name != NULL )
        {
            sprintf ( buf, "Look for %s somewhere in the vicinity of %s!",
                      questitem->short_descr, room->name );
            do_mob_tell ( ch, questman, buf );
            sprintf ( buf, "That location is in the general area of %s.",
                      room->area->name );
            do_mob_tell ( ch, questman, buf );
        }
    }

    /*
     * Quest to kill a mob 
     */

    else
    {
        switch ( number_range ( 0, 3 ) )
        {
            default:
            case 0:
                sprintf ( buf,
                          "An enemy of mine, %s, is making vile threats against the crown.",
                          victim->short_descr );
                do_mob_tell ( ch, questman, buf );
                do_mob_tell ( ch, questman,
                              "This threat must be eliminated!" );
                break;
            case 1:
                sprintf ( buf,
                          "Thera's most heinous criminal, %s, has escaped from the dungeon!",
                          victim->short_descr );
                do_mob_tell ( ch, questman, buf );
                sprintf ( buf,
                          "Since the escape, %s has murdered %d civillians!",
                          victim->short_descr, number_range ( 2, 20 ) );
                do_mob_tell ( ch, questman, buf );
                do_mob_tell ( ch, questman,
                              "The penalty for this crime is death, and you are to deliver the sentence!" );
                break;
            case 2:
                sprintf ( buf,
                          "The King of Gaalstrom has recently been attacked by %s.  This is an act of war!",
                          victim->short_descr );
                do_mob_tell ( ch, questman, buf );
                sprintf ( buf,
                          "%s must be severly dealt with for this injustice.",
                          victim->short_descr );
                do_mob_tell ( ch, questman, buf );
                break;
            case 3:
                sprintf ( buf,
                          "%s has been stealing valuables from the citizens of Gaalstrom.",
                          victim->short_descr );
                do_mob_tell ( ch, questman, buf );
                sprintf ( buf,
                          "Make sure that %s never has the chance to steal again.",
                          victim->short_descr );
                do_mob_tell ( ch, questman, buf );
                break;
        }

        if ( room->name != NULL )
        {
            sprintf ( buf, "Seek %s out somewhere in the vicinity of %s!",
                      victim->short_descr, room->name );
            do_mob_tell ( ch, questman, buf );
            sprintf ( buf, "That location is in the general area of %s.",
                      room->area->name );
            do_mob_tell ( ch, questman, buf );
        }
        ch->pcdata->questmob = victim->pIndexData->vnum;
    }
    if ( ch->pcdata->questmob > 0 || ch->pcdata->questobj > 0 )
    {
        SET_BIT ( ch->act, PLR_QUESTOR );
        sprintf ( buf, "You have %d minutes to complete this quest.",
                  ch->pcdata->countdown );
        do_mob_tell ( ch, questman, buf );
        do_mob_tell ( ch, questman, "May the gods go with you!" );
    }
    else
        end_quest ( ch, 2 );
    return;
}

bool quest_level_diff ( CHAR_DATA * ch, CHAR_DATA * mob )
{
    int bonus = 20 + ch->level;
    if ( IS_IMMORTAL ( ch ) )
        return TRUE;
    else if ( ch->level > ( mob->level + bonus ) ||
              ch->level < ( mob->level - bonus ) )
        return FALSE;
    else
        return TRUE;
}

void quest_update ( void )
{
    DESCRIPTOR_DATA *d;
    CHAR_DATA *ch;
    for ( d = descriptor_list; d != NULL; d = d->next )
    {
        if ( d->connected == CON_PLAYING &&
             ( ch = ( d->original ? d->original : d->character ) ) != NULL )
        {

            if ( ch->pcdata->nextquest > 0 )
            {
                ch->pcdata->nextquest--;
                if ( ch->pcdata->nextquest == 0 )
                {
                    send_to_char ( "You may now quest again.\n\r", ch );
                    return;
                }
            }
            else if ( IS_SET ( ch->act, PLR_QUESTOR ) )
            {
                if ( --ch->pcdata->countdown <= 0 )
                {
                    printf_to_char ( ch,
                                     "You have run out of time for your quest!\n\rYou may quest again in %d minutes.\n\r",
                                     ch->pcdata->nextquest );
                    end_quest ( ch, 18 );
                }
                if ( ch->pcdata->countdown > 0 && ch->pcdata->countdown < 6 )
                {
                    send_to_char
                        ( "Better hurry, you're almost out of time for your quest!\n\r",
                          ch );
                    return;
                }
            }
        }
    }
    return;
}

void end_quest ( CHAR_DATA * ch, int time )
{
    REMOVE_BIT ( ch->act, PLR_QUESTOR );
    ch->pcdata->questgiver = 0;
    ch->pcdata->countdown = 0;
    ch->pcdata->questmob = 0;
    ch->pcdata->questobj = 0;
    ch->pcdata->questloc = 0;
    ch->pcdata->nextquest = time;
}

void do_mob_tell ( CHAR_DATA * ch, CHAR_DATA * victim, char *argument )
{
    char buf[MSL];
    sprintf ( buf, "{R%s{R tells you '{W%s{R'{x\n\r", victim->short_descr,
              argument );
    send_to_char ( buf, ch );
//    ch->reply = victim;
    return;
}

CH_CMD ( do_qpgive )
{
    CHAR_DATA *victim;
    char arg[MIL], buf[MIL];
    int amount;
    if ( !ch || IS_NPC ( ch ) )
        return;
    argument = one_argument ( argument, arg );
    if ( argument[0] == '\0' || !is_number ( arg ) )
    {
        send_to_char ( "Syntax: qpgive [amount] [person]\n\r", ch );
        return;
    }

    if ( ( amount = atoi ( arg ) ) <= 0 )
    {
        send_to_char ( "Give how many questpoints?\n\r", ch );
        return;
    }

    if ( amount > ch->pcdata->questpoints )
    {
        send_to_char ( "You don't have that many questpoints to give.\n\r",
                       ch );
        return;
    }

    if ( ( victim = get_char_room ( ch, argument ) ) == NULL )
    {
        send_to_char ( "That person is not here.\n\r", ch );
        return;
    }

    ch->pcdata->questpoints -= amount;
    victim->pcdata->questpoints += amount;
    sprintf ( buf, "%d", amount );
    act ( "$n gives you $t questpoints.", ch, buf, victim, TO_VICT );
    act ( "You give $N $t questpoints.", ch, buf, victim, TO_CHAR );
    act ( "$n gives $N $t questpoints.", ch, buf, victim, TO_ROOM );
    return;
}