cotn/notes/
cotn/src/
/***************************************************************************
 *  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
 *  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.   *
 *                                                                         *
 *  Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael          *
 *  Chastain, Michael Quan, and Mitchell Tse.                              *
 *                                                                         *
 *  In order to use any part of this Merc Diku Mud, you must comply with   *
 *  both the original Diku license in 'license.doc' as well the Merc       *
 *  license in 'license.txt'.  In particular, you may not remove either of *
 *  these copyright notices.                                               *
 *                                                                         *
 *  Dystopia Mud improvements copyright (C) 2000, 2001 by Brian Graversen  *
 *                                                                         *
 *  Much time and thought has gone into this software and you are          *
 *  benefitting.  We hope that you share your changes too.  What goes      *
 *  around, comes around.                                                  *
 ***************************************************************************/

/***************************************************************************
 *  Dystopian Questcode copyright (C) 2001 by Brian Graversen, users must  *
 *  follow the DIKU, Merc and Godwars license as well as the license       *
 *  distributed with Dystopia                                              *
 ***************************************************************************/
 /***************************************************************************
 *                                 _/                            _/        *
 *      _/_/_/  _/_/      _/_/_/  _/    _/_/    _/    _/    _/_/_/         *
 *     _/    _/    _/  _/        _/  _/    _/  _/    _/  _/    _/          *
 *    _/    _/    _/  _/        _/  _/    _/  _/    _/  _/    _/           *
 *   _/    _/    _/    _/_/_/  _/    _/_/      _/_/_/    _/_/_/            *
 ***************************************************************************
 * Mindcloud Copyright 2001-2003 by Jeff Boschee (Zarius),                 *
 * Additional credits are in the help file CODECREDITS                     *
 * All Rights Reserved.                                                    *
 ***************************************************************************/

#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "merc.h"
#include "interp.h"

int get_rand_mob args((void));
int get_rand_hard_mob args((void));
int get_rand_item args((void));
int load_special_item args((CHAR_DATA * ch));
int get_lbound args((void));
int get_ubound args((int bound));
void give_token args((CHAR_DATA * questmaster, CHAR_DATA * ch, int value));

QUEST_DATA *quest_free;

DECLARE_QUEST_FUN(questspec_generic);
DECLARE_QUEST_FUN(questspec_newbie);
DECLARE_QUEST_FUN(questspec_special_item);
DECLARE_QUEST_FUN(questspec_rand_mob);
DECLARE_QUEST_FUN(questspec_mob_and_item);
DECLARE_QUEST_FUN(questspec_hard_mob);
DECLARE_QUEST_FUN(questspec_mass_kill);
DECLARE_QUEST_FUN(questspec_pk);

const struct quest_type quest_table[] = {
        {"questspec_generic", questspec_generic},
        {"questspec_special_item", questspec_special_item},
        {"questspec_rand_mob", questspec_rand_mob},
        {"questspec_mob_and_item", questspec_mob_and_item},
        {"questspec_hard_mob", questspec_hard_mob},
        {"questspec_mass_kill", questspec_mass_kill},
        {"questspec_pk", questspec_pk},
        {"questspec_newbie", questspec_newbie},

        /*
         * end of table 
         */
        {"", 0}
};

/*
 * Used for show_char_to_char_0()
 */
bool is_quest_target(CHAR_DATA * ch, CHAR_DATA * victim)
{
        QUEST_DATA *quest;

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

        for (quest = ch->pcdata->quests; quest; quest = quest->next)
        {
                switch (quest->type)
                {
                case QT_MOB:
                        if (victim->pIndexData->vnum == quest->vnums[0])
                                return TRUE;
                        break;
                case QT_MOB_AND_OBJ:
                        if (victim->pIndexData->vnum == quest->vnums[0])
                                return TRUE;
                        break;
                case QT_MASS_KILL:
                        if (victim->pIndexData->vnum >= quest->vnums[0] &&
                            victim->pIndexData->vnum <= quest->vnums[1])
                                return TRUE;
                        break;
                default:
                        continue;
                }
        }
        return FALSE;
}

/* 
 * This is a temp function for creating the database of quest
 * monsters, that needs to be slain. Please don't run it
 * while the mud is operationel - it takes quite a while
 * to execute.
 */
void do_createbase(CHAR_DATA * ch, char *argument)
{
        AREA_DATA *area;
        DESCRIPTOR_DATA *d;
        ROOM_INDEX_DATA *pRoom;
        MOB_INDEX_DATA *pMobIndex;
        RESET_DATA *pReset;
        FILE     *fp;
        char      arg[MAX_INPUT_LENGTH];
        char      buf[MAX_STRING_LENGTH];
        int       vnum, vnum2, iMin, iMax, col = 0;
        bool      found = FALSE;

        if ((d = ch->desc) == NULL)
        {
                send_to_char("Huh?\n\r", ch);
                return;
        }

        one_argument(argument, arg);

        /*
         * put in what ever levels you want here 
         */
        if (!str_cmp(arg, "big"))
        {
                iMin = 800;
                iMax = 2600;
        }
        else if (!str_cmp(arg, "small"))
        {
                iMin = 10;
                iMax = 400;
        }
        else
        {
                send_to_char("Big or Small moblist ??\n\r", ch);
                return;
        }

        if ((fp = fopen("../txt/questlist.txt", "w")) == NULL)
        {
                send_to_char
                        ("Unable to create questlist.txt - terminating attempt\n\r",
                         ch);
                return;
        }

        for (area = area_first; area && !found; area = area->next)
        {
                if (area == area_first)
                        write_to_descriptor(d, "\n\r", 0);
                xprintf(buf, "Processing %s....", area->name);
                write_to_descriptor(d, buf, 0);

                fprintf(fp, "/* %s */\n", area->name);
                found = FALSE;  // reset
                for (vnum = area->lvnum; vnum <= area->uvnum; vnum++)
                {
                        if ((pMobIndex = get_mob_index(vnum)) != NULL)
                        {
                                if (pMobIndex->level < iMin
                                    || pMobIndex->level > iMax)
                                        continue;

                                for (vnum2 = area->lvnum;
                                     vnum2 <= area->uvnum; vnum2++)
                                {
                                        if ((pRoom =
                                             get_room_index(vnum2)) != NULL)
                                        {
                                                for (pReset =
                                                     pRoom->reset_first;
                                                     pReset;
                                                     pReset = pReset->next)
                                                {
                                                        switch (pReset->
                                                                command)
                                                        {
                                                        default:
                                                                break;
                                                        case 'M':
                                                                if ((pMobIndex
                                                                     =
                                                                     get_mob_index
                                                                     (pReset->
                                                                      arg1))
                                                                    != NULL)
                                                                {
                                                                        if (pMobIndex->vnum == vnum)
                                                                                found = TRUE;
                                                                }
                                                        }
                                                }
                                        }
                                }
                                if (found)
                                {
                                        found = FALSE;  // reset for later use
                                        fprintf(fp, " %6d,", vnum);
                                        if (!(++col % 6))
                                                fprintf(fp, "\n");
                                }
                        }
                }
                if (col % 6)
                        fprintf(fp, "\n");
                if (area->next)
                        write_to_descriptor(d, "Ok!\n\r", 0);
                else
                        write_to_descriptor(d, "Ok!", 0);
        }
        fclose(fp);
        return;
}

int get_lbound()
{
        int       vnum, count = 0;

        static const int mob_table[] = {
                14003, 31108, 1105, 1122, 1602, 1702, 1710, 2007,
                2101, 2201, 2307, 2315, 2801, 2904, 3406, 3601, 4150,
                4700, 5000, 5006, 6303, 6507, 6601, 7200, 7801,
                8000, 8308, 8904, 9203, 9401, 11006, 7705, 93000, 80001,

                /*
                 * END 
                 */
                -1
        };

        /*
         * counting the size of the table 
         */
        for (count = 0; mob_table[count] != -1; count++);

        vnum = number_range(0, count - 1);
        return mob_table[vnum];
}

int get_ubound(int bound)
{
        int       vnum;

        switch (bound)
        {
        case 14003:
                vnum = 14011;
                break;
        case 31108:
                vnum = 31118;
                break;
        case 1105:
                vnum = 1109;
                break;
        case 1122:
                vnum = 1125;
                break;
        case 1602:
                vnum = 1605;
                break;
        case 1702:
                vnum = 1708;
                break;
        case 1710:
                vnum = 1716;
                break;
        case 2007:
                vnum = 2013;
                break;
        case 2101:
                vnum = 2108;
                break;
        case 2201:
                vnum = 2205;
                break;
        case 2307:
                vnum = 2311;
                break;
        case 2315:
                vnum = 2321;
                break;
        case 2801:
                vnum = 2808;
                break;
        case 2904:
                vnum = 2913;
                break;
        case 3406:
                vnum = 3408;
                break;
        case 3601:
                vnum = 3604;
                break;
        case 4150:
                vnum = 4154;
                break;
        case 4700:
                vnum = 4708;
                break;
        case 5000:
                vnum = 5003;
                break;
        case 5006:
                vnum = 5008;
                break;
        case 2612:
                vnum = 2616;
                break;
        case 6303:
                vnum = 6310;
                break;
        case 6507:
                vnum = 6510;
                break;
        case 6601:
                vnum = 6606;
                break;
        case 7200:
                vnum = 7202;
                break;
        case 7801:
                vnum = 7808;
                break;
        case 8000:
                vnum = 8005;
                break;
        case 8308:
                vnum = 8312;
                break;
        case 8904:
                vnum = 8908;
                break;
        case 9203:
                vnum = 9207;
                break;
        case 9401:
                vnum = 9407;
                break;
        case 11006:
                vnum = 11008;
                break;
        case 7705:
                vnum = 7709;
                break;
        case 93000:
                vnum = 93004;
                break;
        case 80001:
                vnum = 80005;
                break;
        default:
                vnum = bound;
                bug("Bad Quest Vnum : %d", bound);
                break;
        }
        return vnum;
}

/*
 * Returns the vnum of a random object that actually pops on the mud.
 * It's a bit ugly, but it works :)
 */
int get_rand_item()
{
        OBJ_INDEX_DATA *pObjIndex;
        ROOM_INDEX_DATA *pRoom;
        RESET_DATA *pReset;
        AREA_DATA *area;
        int       vnum, i;
        bool      found = FALSE;

        while (!found)
        {
                vnum = number_range(101, 90000);
                if ((pObjIndex = get_obj_index(vnum)) != NULL)
                {
                        if (!CAN_WEAR(pObjIndex, ITEM_TAKE))
                                continue;
                        if (pObjIndex->item_type == ITEM_MONEY)
                                continue;
                        if ((area = pObjIndex->area) != NULL)
                        {
                                for (i = area->lvnum; i <= area->uvnum; i++)
                                {
                                        if ((pRoom =
                                             get_room_index(i)) != NULL)
                                        {
                                                for (pReset =
                                                     pRoom->reset_first;
                                                     pReset;
                                                     pReset = pReset->next)
                                                {
                                                        switch (pReset->
                                                                command)
                                                        {
                                                        default:
                                                                break;
                                                        case 'O':
                                                                if ((pObjIndex
                                                                     =
                                                                     get_obj_index
                                                                     (pReset->
                                                                      arg1))
                                                                    != NULL)
                                                                {
                                                                        if (pObjIndex->vnum == vnum)
                                                                                found = TRUE;
                                                                }
                                                        }
                                                }
                                        }
                                }
                        }
                }
        }
        return vnum;
}

int load_special_item(CHAR_DATA * ch)
{
        OBJ_DATA *obj;
        OBJ_INDEX_DATA *pObjIndex;
        int       vnum;

        vnum = number_range(99501, 99505);
        if ((pObjIndex = get_obj_index(vnum)) == NULL)
        {
                bug("Load_special_item : %d", vnum);
                return 103; // Just to be on the safe side
        }
        obj = create_object(pObjIndex, 50);
        obj->ownerid = ch->pcdata->playerid;
        SET_BIT(obj->extra_flags, ITEM_MQUEST);
        obj->timer = 25;    // so it will eventually decay...
        obj_to_room(obj, get_rand_room());
        return vnum;
}

int get_rand_mob()
{
        int       vnum, count = 0;

        static const int questmob_table[] = {
                /*
                 * KaVir   Odds and ends 
                 */
                105, 600, 902, 903, 904, 905,
                907, 908, 912, 913, 914, 915,
                916, 917, 918, 922, 924, 926,
                1000, 1341, 1347, 1348, 1349, 1512,
                2015, 2108, 2301, 2323, 2325, 2410,
                2433, 2436, 2437, 2446, 2452, 2453,
                2454, 2456, 2458, 2460, 2462, 2463,
                2464, 2468, 2469, 2470, 2605, 2608,
                2611, 2612, 2613, 2614, 2615, 2617,
                2803, 2804, 2906, 3009, 3603, 4100,
                4101, 4707, 5008, 5010, 5100, 5111,
                5315, 6311, 6600, 6601, 6602, 6603,
                6604, 6605, 6606, 6607, 6608, 7008,
                7013, 7703, 8000, 8101, 8102, 8105,
                8120, 8123, 8600, 9208, 9233, 9322,
                11001, 11004, 11005, 11006, 11007, 11008,
                11009, 11010, 11011, 11101, 11104, 11115,
                11118, 11121, 11124, 11125, 11126, 11127,
                11133, 11136, 11137, 11138, 11139, 14004,
                14005, 14006, 14008, 14009, 14010, 14011,
                14012, 19101, 19103, 19108, 25000, 25002,
                25003, 25007,
/* Anon    DragonSpyre */
                14004, 14005, 14006, 14008,
                14009, 14010, 14011, 14012,
/* Wynfair Castle Dragonheart */
                19101, 19103,
                19108,
/* Xara    Sunyata */
                31053, 31056, 31057, 31059, 31060,
                31061, 31064, 31065, 31066, 31067, 31068,
/* Xara    Easy Evil Ones */
                11101, 11104, 11115, 11118, 11121, 11124,
                11125, 11126, 11127, 11133, 11136, 11137,
                11138, 11139,
/* Xara    Mountain of the Evil Ones */
                31100, 31101, 31102, 31103,
                31104, 31105, 31106, 31107, 31109, 31110,
                31111, 31113, 31114, 31115, 31119, 31120,
                31121, 31122, 31123, 31124, 31125, 31126,
                31127,
/* Diku    Midgaard */
                3009, 3603, 4100, 4101, 4707,
                5008, 5010, 5100, 5111, 5315, 6311,
                6600, 6601, 6602, 6603, 6604, 6605,
                6606, 6607, 6608, 7008, 7013, 7703,
                8000, 8101, 8102, 8105, 8120, 8123,
                8600, 9208, 9233, 9322, 11001, 11004,
                11005, 11006, 11007, 11008, 11009, 11010,
                11011, 11101, 11104, 11115, 11118, 11121,
                11124, 11125, 11126, 11127, 11133, 11136,
                11137, 11138, 11139, 14004, 14005, 14006,
                14008, 14009, 14010, 14011, 14012, 19101,
                19103, 19108, 25000, 25002, 25003, 25007,
/* Jaromir Atlantis */
                8101, 8102, 8105, 8120, 8123,
/* Copper  In the Air */
                1000,
/* Diku    Limbo */
/* Generic Smurf Village */
                105,
/* Copper  Plains of the North */

/* Casret  Ultima */
                2410, 2433, 2436, 2437, 2446,
                2452, 2453, 2454, 2456, 2458, 2460,
                2462, 2463, 2464, 2468, 2469, 2470,
/* Hatchet New Ofcol */
                600,
/* Anon    High Tower of Sorcery */
                1341, 1347, 1348, 1349,
/* Vougon  Gnome Village */
                1512,
/* Tyrst   Wyvern's Tower */

/* Raff    Dwarven Catacombs */
                2015,
/* Raff    Dangerous Neighborhood */
                2108,
/* Wench   Dragon Tower */
/* Chris   The Keep of Mahn-Tor */
                2301, 2323, 2325,
/* Merc    Troll Den */
                2803, 2804,
/* Nirrad  Land of the Fire Newts */
                2906,
/* Copper  Chapel Catacombs */
/* Copper  Miden'nir */
/* Alfa    Graveyard */
                3603,
/* Hatchet Mud School */

/* Alfa    Moria */
                4100, 4101,
/* Anon    Kingdom of Juargan */
                4707,
/* Anon    Great Eastern Desert */
                5008, 5010,
/* Andi    The Great Pyramid */
                2605, 2608, 2611, 2612, 2613, 2614,
                2615, 2617,
/* Anon    Drow City */
                5100,
/* Anon    Thalos */

/* Kahn    Old Thalos */
                5315,
/* Alfa    Ofcol */

/* Anon    Arachnos */
                6311,
/* Diku    Haon Dor */

/* Anon    Dwarven Kingdom */

/* Sandman Dwarven Day Care */
                6600,
                6601, 6602, 6603, 6604, 6605, 6606,
                6607, 6608,
/* Diku    Sewer */
                7008, 7013,
/* Hatchet Valley of the Elves */

/* Diku    Redferne's Residence */

/* Glop    Mega-City One  */
                8000,
/* Generic Old Marsh */

/* Furey   Machine Dreams */
                8600,
/* Alfa    Holy Grove */
/* Dylan   Dylan's Area */
/* Raff    Elemental Canyon */
                9208, 9233,
/* Doctor  Galaxy */
                9322,
/* PinkF   Mob Factory */

/* KaVir   The learning centre */
                25000, 25002, 25003,
                25007,
/* KaVir   Artifacts */
                600, 902, 903, 904, 905,
                907, 908, 912, 913, 914, 915,
                916, 917, 918, 922, 924, 926,
                1000, 1341, 1347, 1348, 1349, 1512,
                2015, 2108, 2301, 2323, 2325, 2410,
                2433, 2436, 2437, 2446, 2452, 2453,
                2454, 2456, 2458, 2460, 2462, 2463,
                2464, 2468, 2469, 2470, 2605, 2608,
                2611, 2612, 2613, 2614, 2615, 2617,
                2803, 2804, 2906, 3009, 3603, 4100,
                4101, 4707, 5008, 5010, 5100, 5111,
                5315, 6311, 6600, 6601, 6602, 6603,
                6604, 6605, 6606, 6607, 6608, 7008,
                7013, 7703, 8000, 8101, 8102, 8105,
                8120, 8123, 8600, 9208, 9233, 9322,
                11001, 11004, 11005, 11006, 11007, 11008,
                11009, 11010, 11011, 11101, 11104, 11115,
                11118, 11121, 11124, 11125, 11126, 11127,
                11133, 11136, 11137, 11138, 11139, 14004,
                14005, 14006, 14008, 14009, 14010, 14011,
                14012, 19101, 19103, 19108, 25000, 25002,
                25003, 25007,
/* Spawn   Doom */
                11001, 11004, 11005, 11006,
                11007, 11008, 11009, 11010, 11011,
/* KaVir   Vallandar's Tomb */
                30330,
/* Garth   Cannabis */
                30232, 30234, 30235, 30237, 30238, 30240,
/* Dunkirk The Arena */
/* Andersen Astral/Githyanki */
                7703,
/* Jobo     Jobo's Hell */
                30100, 30101, 30102, 30103, 30104,
                30105, 30106, 30107, 30108, 30109, 30110,
                30111,
/* Jobo     Jobo's Heaven */
                99000, 99002, 99003, 99004,
/* Jobo     Old Dystopia */
                30406,
                30409,
/* Jobo     Realm of the Dawnbringers */
                80001, 80002, 80003, 80004, 80005,
                80006,
/* Jobo     Class EQ and other Relics */

/* Antibody Dome Ship StarSword */
                93000, 93001, 93002, 93003, 93004,
                93007, 93008, 93009, 93010, 93011, 93012,
                93013, 93014, 93015, 93016, 93017, 93018,
                93029, 93030,
/* Antibody Disneyworld */
                50002, 50003, 50004, 50005,
                50006, 50007, 50008, 50011, 50012, 50013,
                50014, 50018, 50019, 50022, 50024, 50026,
                50027, 50029,

/* Willaz   Lair of the black Dragon */
                32000,
/* Nyria    Santa's Workshop */
                50201, 50204, 50205, 50206,
                50207, 50208, 50209, 50210, 50211, 50212,
                50213, 50214, 50216, 50217, 50218, 50219,
/* Jatr     Village of Kakakaru */
                77002, 77003, 77004, 77005, 77006, 77008,
                77009, 77010, 77011, 77012, 77013, 77014,
                77015, 77016,
/* THE END */
                -1
        };

        /*
         * counting the size of the table 
         */
        for (count = 0; questmob_table[count] != -1; count++);

        vnum = number_range(0, count - 1);
        return questmob_table[vnum];
}

int get_rand_hard_mob()
{
        int       vnum, count = 0;

        static const int questmob_table[] = {
                /*
                 * The Forbidden Fortress 
                 */
/* KaVir   Odds and ends */
                5105, 5106, 5107, 5108, 5109, 8103,
                8106, 8107, 8108, 8109, 8112, 8114,
                8115, 8116, 8118, 8119, 8121, 8124,
/* Anon    DragonSpyre */
/* Wynfair Castle Dragonheart */
/* Xara    Sunyata */
                31054,
/* Xara    Easy Evil Ones */

/* Xara    Mountain of the Evil Ones */

/* Diku    Midgaard */
                5105, 5106, 5107, 5108, 5109,
                8103, 8106, 8107, 8108, 8109, 8112,
                8114, 8115, 8116, 8118, 8119, 8121,
                8124,
/* Jaromir Atlantis */
                8103, 8106, 8107, 8108, 8109,
                8112, 8114, 8115, 8116, 8118, 8119,
                8121, 8124,

/* Anon    Drow City */
                5105, 5106, 5107, 5108,
                5109,



/* Jobo     Old Dystopia */
                30400, 30401, 30402, 30403, 30408,
                30500, 30501, 30502, 30503, 30506, 30508,
                30509,
/* Jobo     Realm of the Dawnbringers */

/* THE END */
                -1
        };

        /*
         * counting the size of the table 
         */
        for (count = 0; questmob_table[count] != -1; count++);

        vnum = number_range(0, count - 1);
        return questmob_table[vnum];
}

void do_showquest(CHAR_DATA * ch, char *argument)
{
        QUEST_DATA *quest;
        OBJ_INDEX_DATA *pObjIndex;
        MOB_INDEX_DATA *pMobIndex1;
        MOB_INDEX_DATA *pMobIndex2;
        MOB_INDEX_DATA *pMobIndex3;
        CHAR_DATA *gch;
        CHAR_DATA *ich = NULL;
        char      buf[MAX_STRING_LENGTH];
        bool      found = FALSE;
        bool      found2 = FALSE;

        if (IS_NPC(ch))
                return;
        for (quest = ch->pcdata->quests; quest; quest = quest->next)
        {
                found = TRUE;
                switch (quest->type)
                {
                default:
                        xprintf(buf,
                                "Do_showquests: %s has bad quest type %d.",
                                ch->name, quest->type);
                        bug(buf, 0);
                        break;
                case QT_MOB:
                        if ((pMobIndex1 =
                             get_mob_index(quest->vnums[0])) == NULL
                            && quest->vnums[0] != -1)
                        {
                                xprintf(buf,
                                        "Do_showquests: %s has bad quest mob %d.",
                                        ch->name, quest->vnums[0]);
                                bug(buf, 0);
                                break;
                        }
                        if ((pMobIndex2 =
                             get_mob_index(quest->giver)) == NULL)
                        {
                                xprintf(buf,
                                        "Do_showquests: %s has bad quest mob %d.",
                                        ch->name, quest->giver);
                                bug(buf, 0);
                                break;
                        }
                        xprintf(buf,
                                "You have been charged by #G%s#n to complete the following quest\n\r",
                                pMobIndex2->short_descr);
                        send_to_char(buf, ch);
                        if (quest->vnums[0] != -1)
                        {
                                xprintf(buf, " * Find and slay #R%s#n.\n\r",
                                        pMobIndex1->short_descr);
                                send_to_char(buf, ch);
                                xprintf(buf,
                                        " * You have #C%d#n hours to complete the quest.\n\r",
                                        quest->time);
                                send_to_char(buf, ch);
                        }
                        else
                        {
                                send_to_char
                                        (" * This quest has been #Ccompleted#n.\n\r",
                                         ch);
                                xprintf(buf,
                                        " * You have #C%d#n hours to return to the questgiver.\n\r",
                                        quest->time);
                                send_to_char(buf, ch);
                        }
                        break;
                case QT_PK:
                        if ((pMobIndex2 =
                             get_mob_index(quest->giver)) == NULL)
                        {
                                xprintf(buf,
                                        "Do_showquests: %s has bad quest mob %d.",
                                        ch->name, quest->giver);
                                bug(buf, 0);
                                break;
                        }
                        for (gch = char_list; gch && !found2; gch = gch->next)
                        {
                                if (IS_NPC(gch))
                                        continue;
                                if (gch->pcdata->playerid == quest->vnums[0])
                                {
                                        ich = gch;
                                        found2 = TRUE;
                                }
                        }
                        xprintf(buf,
                                "You have been charged by #G%s#n to complete the following quest\n\r",
                                pMobIndex2->short_descr);
                        send_to_char(buf, ch);
                        if (quest->vnums[0] != -1)
                        {
                                xprintf(buf, " * Hunt and slay #R%s#n.\n\r",
                                        found2 ? ich->name : "someone");
                                send_to_char(buf, ch);
                                xprintf(buf,
                                        " * You have #C%d#n hours to complete the quest.\n\r",
                                        quest->time);
                                send_to_char(buf, ch);
                        }
                        else
                        {
                                send_to_char
                                        (" * This quest has been #Ccompleted#n.\n\r",
                                         ch);
                                xprintf(buf,
                                        " * You have #C%d#n hours to return to the questgiver.\n\r",
                                        quest->time);
                                send_to_char(buf, ch);
                        }
                        break;
                case QT_OBJ:
                        if ((pObjIndex =
                             get_obj_index(quest->vnums[0])) == NULL)
                        {
                                xprintf(buf,
                                        "Do_showquests: %s has bad quest item %d.",
                                        ch->name, quest->vnums[0]);
                                bug(buf, 0);
                                break;
                        }
                        if ((pMobIndex2 =
                             get_mob_index(quest->giver)) == NULL)
                        {
                                xprintf(buf,
                                        "Do_showquests: %s has bad quest mob %d.",
                                        ch->name, quest->giver);
                                bug(buf, 0);
                                break;
                        }
                        xprintf(buf,
                                "You have been charged by #G%s#n to complete the following quest\n\r",
                                pMobIndex2->short_descr);
                        send_to_char(buf, ch);
                        xprintf(buf, " * Find and return #R%s#n.\n\r",
                                pObjIndex->short_descr);
                        send_to_char(buf, ch);
                        xprintf(buf,
                                " * You have #C%d#n hours to complete the quest.\n\r",
                                quest->time);
                        send_to_char(buf, ch);
                        break;
                case QT_MOB_AND_OBJ:
                        if ((pMobIndex1 =
                             get_mob_index(quest->vnums[0])) == NULL
                            && quest->vnums[0] != -1)
                        {
                                xprintf(buf,
                                        "Do_showquests: %s has bad quest mob %d.",
                                        ch->name, quest->vnums[0]);
                                bug(buf, 0);
                                break;
                        }
                        if ((pObjIndex =
                             get_obj_index(quest->vnums[1])) == NULL)
                        {
                                xprintf(buf,
                                        "Do_showquests: %s has bad quest item %d.",
                                        ch->name, quest->vnums[1]);
                                bug(buf, 0);
                                break;
                        }
                        if ((pMobIndex2 =
                             get_mob_index(quest->giver)) == NULL)
                        {
                                xprintf(buf,
                                        "Do_showquests: %s has bad quest mob %d.",
                                        ch->name, quest->giver);
                                bug(buf, 0);
                                break;
                        }
                        xprintf(buf,
                                "You have been charged by #G%s#n to complete the following quest\n\r",
                                pMobIndex2->short_descr);
                        send_to_char(buf, ch);
                        if (quest->vnums[0] != -1)
                        {
                                xprintf(buf, " * Find and slay #R%s#n.\n\r",
                                        pMobIndex1->short_descr);
                                send_to_char(buf, ch);
                        }
                        xprintf(buf, " * Find and return #R%s#n.\n\r",
                                pObjIndex->short_descr);
                        send_to_char(buf, ch);
                        xprintf(buf,
                                " * You have #C%d#n hours to complete the quest.\n\r",
                                quest->time);
                        send_to_char(buf, ch);
                        break;
                case QT_MASS_KILL:
                        if ((pMobIndex1 =
                             get_mob_index(quest->vnums[0])) == NULL
                            && quest->vnums[0] != -1)
                        {
                                xprintf(buf,
                                        "Do_showquests: %s has bad quest mob %d.",
                                        ch->name, quest->vnums[0]);
                                bug(buf, 0);
                                break;
                        }
                        if ((pMobIndex3 =
                             get_mob_index(quest->vnums[1])) == NULL)
                        {
                                xprintf(buf,
                                        "Do_showquests: %s has bad quest mob %d.",
                                        ch->name, quest->vnums[1]);
                                bug(buf, 0);
                                break;
                        }
                        if ((pMobIndex2 =
                             get_mob_index(quest->giver)) == NULL)
                        {
                                xprintf(buf,
                                        "Do_showquests: %s has bad quest mob %d.",
                                        ch->name, quest->giver);
                                bug(buf, 0);
                                break;
                        }
                        xprintf(buf,
                                "You have been charged by #G%s#n to complete the following quest\n\r",
                                pMobIndex2->short_descr);
                        send_to_char(buf, ch);
                        if (quest->vnums[3] >= quest->vnums[2])
                        {
                                send_to_char
                                        (" * This quest has been #Ccompleted#n.\n\r",
                                         ch);
                                xprintf(buf,
                                        " * You have #C%d#n hours to return to the questgiver.\n\r",
                                        quest->time);
                                send_to_char(buf, ch);
                        }
                        else
                        {
                                xprintf(buf,
                                        " * Find and slay #C%d#n monsters ranging from\n\r",
                                        quest->vnums[2] - quest->vnums[3]);
                                send_to_char(buf, ch);
                                xprintf(buf, "   #R%s#n to #R%s#n.\n\r",
                                        pMobIndex1->short_descr,
                                        pMobIndex3->short_descr);
                                send_to_char(buf, ch);
                                xprintf(buf,
                                        " * You have #C%d#n hours to complete the quest.\n\r",
                                        quest->time);
                                send_to_char(buf, ch);
                        }
                        break;
                }
        }
        if (!found)
                send_to_char("You are currently undertaking no quests.\n\r",
                             ch);
        return;
}

void quest_to_char(CHAR_DATA * ch, QUEST_DATA * quest)
{
        QUEST_DATA *quest_new;

        if (IS_NPC(ch))
        {
                bug("Quest_to_char: on npc", 0);
                return;
        }

        if (quest_free == NULL)
                quest_new = alloc_perm(sizeof(*quest_new));
        else
        {
                quest_new = quest_free;
                quest_free = quest_free->next;
        }

        *quest_new = *quest;
        quest_new->next = ch->pcdata->quests;
        ch->pcdata->quests = quest_new;

        return;
}

/*
 * Remove an affect from a char.
 */
void quest_from_char(CHAR_DATA * ch, QUEST_DATA * quest)
{
        if (IS_NPC(ch))
        {
                bug("Quest_from_char: on npc", 0);
                return;
        }
        if (ch->pcdata->quests == NULL)
        {
                bug("Quest_from_char: No quest", 0);
                return;
        }
        if (quest == ch->pcdata->quests)
                ch->pcdata->quests = quest->next;
        else
        {
                QUEST_DATA *prev;

                for (prev = ch->pcdata->quests; prev; prev = prev->next)
                {
                        if (prev->next == quest)
                        {
                                prev->next = quest->next;
                                break;
                        }
                }
                if (prev == NULL)
                {
                        bug("Quest_from_char: No quest", 0);
                        return;
                }
        }
        quest->next = quest_free;
        quest_free = quest;
        return;
}

QUEST_FUN *quest_lookup(const char *name)
{
        int       cmd;

        for (cmd = 0; *quest_table[cmd].quest_name; cmd++)
                if (!str_cmp(name, quest_table[cmd].quest_name))
                        return quest_table[cmd].quest_fun;
        return 0;
}

char     *quest_string(QUEST_FUN * fun)
{
        int       cmd;

        for (cmd = 0; *quest_table[cmd].quest_fun; cmd++)
                if (fun == quest_table[cmd].quest_fun)
                        return quest_table[cmd].quest_name;

        return 0;
}

void give_token(CHAR_DATA * questmaster, CHAR_DATA * ch, int value)
{
        OBJ_DATA *obj;
        char      buf[MAX_STRING_LENGTH];

        value *= ccenter[CCENTER_QPS_LEVEL];
        value /= 100;
        if (IS_SET(ch->pcdata->tempflag, TEMP_EDGE))
                value *= 1.1;
        if (ch->pcdata->time_tick > 49)
        {
                value *= 100 + ch->pcdata->time_tick / 10;
                value /= 100;
        }
        if (global_qp == TRUE)
                value *= 2;

        obj = create_object(get_obj_index(OBJ_VNUM_PROTOPLASM), 50);
        obj->value[0] = value;
        obj->level = value;
        obj->cost = 1000;
        obj->item_type = ITEM_QUEST;
        obj_to_char(obj, ch);
        free_string(obj->name);
        obj->name = str_dup("bone token");
        free_string(obj->short_descr);
        xprintf(buf, "a %d point bone token", value);
        obj->short_descr = str_dup(buf);
        free_string(obj->description);
        xprintf(buf, "A %d point bone token lies on the floor.", value);
        obj->description = str_dup(buf);
        act("You recieve $p from $N.", ch, obj, questmaster, TO_CHAR);
        act("$n recieves $p from $N.", ch, obj, questmaster, TO_ROOM);
        ch->pcdata->questsrun++;
        ch->pcdata->questtotal += value;
        do_autosave(ch, "");
}

void do_qcomplete(CHAR_DATA * ch, char *argument)
{
        CHAR_DATA *questmaster;
        QUEST_DATA *quest;
        OBJ_DATA *obj;
        char      arg[MAX_INPUT_LENGTH];
        char      arg2[MAX_INPUT_LENGTH];
        bool      found = FALSE;

        if (IS_NPC(ch))
                return;
        argument = one_argument(argument, arg);
        one_argument(argument, arg2);
        if ((questmaster = get_char_room(ch, NULL, arg)) == NULL)
        {
                send_to_char("You cannot seem to find that questmaster.\n\r",
                             ch);
                return;
        }
        if (!IS_NPC(questmaster))
        {
                send_to_char("Players cannot give quests.\n\r", ch);
                return;
        }
        if (questmaster->quest_fun != 0)
        {
                for (quest = ch->pcdata->quests; quest && !found;
                     quest = quest->next)
                {
                        if (quest->giver != questmaster->pIndexData->vnum)
                                continue;
                        found = TRUE;

                        /*
                         * Let's check if the quest is actually completed 
                         */
                        switch (quest->type)
                        {
                        default:
                                bug("Quest_complete: Bad Quest Type", 0);
                                return;
                        case QT_MOB:
                                if (quest->vnums[0] != -1)
                                {
                                        send_to_char
                                                ("You have not completed that quest yet.\n\r",
                                                 ch);
                                        return;
                                }
                                break;
                        case QT_PK:
                                if (quest->vnums[0] != -1)
                                {
                                        send_to_char
                                                ("You have not completed that quest yet.\n\r",
                                                 ch);
                                        return;
                                }
                                break;
                        case QT_OBJ:
                                if ((obj =
                                     get_obj_carry(ch, arg2, ch)) == NULL)
                                {
                                        send_to_char
                                                ("What object do you wish to return?\n\r",
                                                 ch);
                                        return;
                                }
                                if (obj->pIndexData->vnum != quest->vnums[0])
                                {
                                        send_to_char
                                                ("That is not the object of the quest.\n\r",
                                                 ch);
                                        return;
                                }
                                extract_obj(obj);
                                break;
                        case QT_MOB_AND_OBJ:
                                if (quest->vnums[0] != -1)
                                {
                                        send_to_char
                                                ("You have not completed that quest yet.\n\r",
                                                 ch);
                                        return;
                                }
                                if ((obj =
                                     get_obj_carry(ch, arg2, ch)) == NULL)
                                {
                                        send_to_char
                                                ("What object do you wish to return?\n\r",
                                                 ch);
                                        return;
                                }
                                if (obj->pIndexData->vnum != quest->vnums[1])
                                {
                                        send_to_char
                                                ("That is not the object of the quest.\n\r",
                                                 ch);
                                        return;
                                }
                                extract_obj(obj);
                                break;
                        case QT_MASS_KILL:
                                if (quest->vnums[2] > quest->vnums[3])
                                {
                                        send_to_char
                                                ("You have not completed that quest yet.\n\r",
                                                 ch);
                                        return;
                                }
                                break;
                        }
                        (*questmaster->quest_fun) (questmaster, ch,
                                                   "complete");
                        quest_from_char(ch, quest);
                }
                if (!found)
                        send_to_char
                                ("You are not questing for this questmaster.\n\r",
                                 ch);
        }
        else
                send_to_char("Doesn't seem like that's a questmaster.\n\r",
                             ch);
        return;
}

void do_qgain(CHAR_DATA * ch, char *argument)
{
        CHAR_DATA *questmaster;
        QUEST_DATA *quest;
        char      arg[MAX_INPUT_LENGTH];

        if (IS_NPC(ch))
                return;
        one_argument(argument, arg);
        if ((questmaster = get_char_room(ch, NULL, arg)) == NULL)
        {
                send_to_char("You cannot seem to find that questmaster.\n\r",
                             ch);
                return;
        }
        if (!IS_NPC(questmaster))
        {
                send_to_char("Players cannot give quests.\n\r", ch);
                return;
        }
        if (questmaster->quest_fun != 0)
        {
                for (quest = ch->pcdata->quests; quest; quest = quest->next)
                {
                        if (quest->giver == questmaster->pIndexData->vnum)
                        {
                                send_to_char
                                        ("You have already been given a quest from this questmaster.\n\r",
                                         ch);
                                return;
                        }
                }
                /*
                 * ROCK THEM! 
                 */
                (*questmaster->quest_fun) (questmaster, ch, "gain");
        }
        else
                send_to_char("Doesn't seem like that's a questmaster.\n\r",
                             ch);
}

void questspec_generic(CHAR_DATA * questmaster, CHAR_DATA * ch,
                       char *argument)
{
        if (!str_cmp(argument, "gain"))
        {
                QUEST_DATA new_quest;

                do_say(questmaster, "Will you smurf this smurf for me?");
                new_quest.type = QT_MOB;
                new_quest.time = 20;
                new_quest.giver = questmaster->pIndexData->vnum;
                new_quest.vnums[0] = number_range(103, 109);
                quest_to_char(ch, &new_quest);
                return;
        }
        else if (!str_cmp(argument, "complete"))
        {
                int       value = 20;

                give_token(questmaster, ch, value);
                do_say(questmaster,
                       "That's the spirit, thanks for solving my quest.");
                return;
        }
}

void questspec_newbie(CHAR_DATA * questmaster, CHAR_DATA * ch, char *argument)
{
        if (!str_cmp(argument, "gain"))
        {
                QUEST_DATA new_quest;

                do_say(questmaster,
                       "There you go, type 'showquest' to see the quest.");
                new_quest.type = QT_MOB;
                new_quest.time = 20;
                new_quest.giver = questmaster->pIndexData->vnum;
                new_quest.vnums[0] = number_range(957, 960);
                quest_to_char(ch, &new_quest);
                return;
        }
        else if (!str_cmp(argument, "complete"))
        {
                int       value = 50;

                give_token(questmaster, ch, value);
                do_say(questmaster,
                       "You can spend the questpoints at the shop on floor 3.");
                return;
        }
}

void questspec_rand_mob(CHAR_DATA * questmaster, CHAR_DATA * ch,
                        char *argument)
{
        if (!str_cmp(argument, "gain"))
        {
                QUEST_DATA new_quest;

                do_say(questmaster,
                       "I charge you to find and kill this monster!");
                new_quest.type = QT_MOB;
                new_quest.time = 15;
                new_quest.giver = questmaster->pIndexData->vnum;
                new_quest.vnums[0] = get_rand_mob();
                quest_to_char(ch, &new_quest);
                return;
        }
        else if (!str_cmp(argument, "complete"))
        {
                int       value = 100;

                give_token(questmaster, ch, value);
                do_say(questmaster,
                       "Thanks for solving my quest, come back again if you want.");
                return;
        }
}

void questspec_hard_mob(CHAR_DATA * questmaster, CHAR_DATA * ch,
                        char *argument)
{
        if (!str_cmp(argument, "gain"))
        {
                QUEST_DATA new_quest;

                do_say(questmaster,
                       "I charge you to find and kill this horrible monster!");
                new_quest.type = QT_MOB;
                new_quest.time = 25;
                new_quest.giver = questmaster->pIndexData->vnum;
                new_quest.vnums[0] = get_rand_hard_mob();
                quest_to_char(ch, &new_quest);
                return;
        }
        else if (!str_cmp(argument, "complete"))
        {
                int       value = 200;

                give_token(questmaster, ch, value);
                do_say(questmaster,
                       "Thanks for solving my quest, come back again if you want.");
                return;
        }
}

void questspec_special_item(CHAR_DATA * questmaster, CHAR_DATA * ch,
                            char *argument)
{
        if (!str_cmp(argument, "gain"))
        {
                QUEST_DATA new_quest;

                do_say(questmaster,
                       "I charge you to retrive this ancient artifact of mine!");
                new_quest.type = QT_OBJ;
                new_quest.time = 25;
                new_quest.giver = questmaster->pIndexData->vnum;
                new_quest.vnums[0] = load_special_item(ch);
                quest_to_char(ch, &new_quest);
                return;
        }
        else if (!str_cmp(argument, "complete"))
        {
                int       value = 250;

                give_token(questmaster, ch, value);
                do_say(questmaster,
                       "Thanks for solving my quest, come back again if you want.");
                return;
        }
}

void questspec_mob_and_item(CHAR_DATA * questmaster, CHAR_DATA * ch,
                            char *argument)
{
        if (!str_cmp(argument, "gain"))
        {
                QUEST_DATA new_quest;

                do_say(questmaster,
                       "Please slay this monster and retrive this item for me!");
                new_quest.type = QT_MOB_AND_OBJ;
                new_quest.time = 25;
                new_quest.giver = questmaster->pIndexData->vnum;
                new_quest.vnums[0] = get_rand_mob();
                new_quest.vnums[1] = get_rand_item();
                quest_to_char(ch, &new_quest);
                return;
        }
        else if (!str_cmp(argument, "complete"))
        {
                int       value = 550;

                give_token(questmaster, ch, value);
                do_say(questmaster,
                       "Thanks for solving my quest, come back again if you want.");
                return;
        }
}

void questspec_mass_kill(CHAR_DATA * questmaster, CHAR_DATA * ch,
                         char *argument)
{
        if (!str_cmp(argument, "gain"))
        {
                QUEST_DATA new_quest;
                int       bound;

                bound = get_lbound();

                do_say(questmaster, "Please slay these monsters.");
                new_quest.type = QT_MASS_KILL;
                new_quest.time = 30;
                new_quest.giver = questmaster->pIndexData->vnum;
                new_quest.vnums[0] = bound;
                new_quest.vnums[1] = get_ubound(bound);
                new_quest.vnums[2] = number_range(8, 16);   // amount needed to be killed
                new_quest.vnums[3] = 0; // counter
                quest_to_char(ch, &new_quest);
                return;
        }
        else if (!str_cmp(argument, "complete"))
        {
                int       value = 175;

                give_token(questmaster, ch, value);
                do_say(questmaster,
                       "Thanks for solving my quest, come back again if you want.");
                return;
        }
}

void questspec_pk(CHAR_DATA * questmaster, CHAR_DATA * ch, char *argument)
{
        if (!str_cmp(argument, "gain"))
        {
                QUEST_DATA new_quest;
                DESCRIPTOR_DATA *d;
                CHAR_DATA *gch = NULL;
                bool      found = FALSE;

                for (d = descriptor_list; d && !found; d = d->next)
                {
                        if (d->connected == CON_PLAYING
                            && d->lookup_status == STATUS_DONE)
                        {
                                if ((gch = d->character) == NULL)
                                        continue;
                                if (ch == gch)
                                        continue;
                                found = TRUE;
                        }
                }
                if (!found)
                {
                        do_say(questmaster,
                               "Sorry, I have no quest for you at this time.");
                        return;
                }

                do_say(questmaster,
                       "I charge you to find and destroy this player!");
                new_quest.type = QT_PK;
                new_quest.time = 8;
                new_quest.giver = questmaster->pIndexData->vnum;
                new_quest.vnums[0] = gch->pcdata->playerid;
                quest_to_char(ch, &new_quest);
                return;
        }
        else if (!str_cmp(argument, "complete"))
        {
                int       value = 400;

                give_token(questmaster, ch, value);
                do_say(questmaster,
                       "Thanks for solving my quest, come back again if you want.");
                interpret(questmaster, "clap");
                return;
        }
}