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.                                                  *
 ***************************************************************************/
 /***************************************************************************
 *                                 _/                            _/        *
 *      _/_/_/  _/_/      _/_/_/  _/    _/_/    _/    _/    _/_/_/         *
 *     _/    _/    _/  _/        _/  _/    _/  _/    _/  _/    _/          *
 *    _/    _/    _/  _/        _/  _/    _/  _/    _/  _/    _/           *
 *   _/    _/    _/    _/_/_/  _/    _/_/      _/_/_/    _/_/_/            *
 ***************************************************************************
 * 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 <unistd.h>
#include <time.h>
#include "merc.h"
#include "interp.h"


AREA_AFFECT *area_affect_free = NULL;

bool      gFound;

#define RID ROOM_INDEX_DATA

bool      examine_room
args((RID * pRoom, RID * tRoom, AREA_DATA * pArea, int steps));
void      examine_steps
args((RID * pRoom, RID * tRoom, AREA_DATA * pArea, int steps));
void dijkstra args((RID * chRoom, RID * victRoom));
RID      *heap_getMinElement args((HEAP * heap));
HEAP     *init_heap args((RID * root));

/*
 * Is astr contained within bstr ?
 *
 */
bool is_contained(const char *astr, const char *bstr)
{
        int       i, alen, blen, count;

        alen = strlen(astr);
        blen = strlen(bstr);
        if (alen > blen)
                return FALSE;
        for (i = 0; i <= (blen - alen); i++)
        {
                count = 0;
                while (count < alen
                       && UPPER(astr[count]) == UPPER(bstr[i + count]))
                        count++;
                if (count == alen)
                        return TRUE;
        }
        return FALSE;
}

/*
 * A case sensitive version
 */
bool is_contained2(const char *astr, const char *bstr)
{
        int       i, alen, blen, count;

        alen = strlen(astr);
        blen = strlen(bstr);
        if (alen > blen)
                return FALSE;
        for (i = 0; i <= (blen - alen); i++)
        {
                count = 0;
                while (count < alen && astr[count] == bstr[i + count])
                        count++;
                if (count == alen)
                        return TRUE;
        }
        return FALSE;
}

int strlen2(const char *s)
{
        int       i, b, count = 0;

        if (s[0] == '\0')
                return 0;
        b = strlen(s);
        for (i = 0; i < b; i++)
        {
                if (s[i] == '#')
                        count++;
        }
        return (b + 7 * count);
}



void win_prize(CHAR_DATA * ch)
{
        int       i, vnum;
        OBJ_DATA *obj;
        OBJ_INDEX_DATA *pIndex;

        if (IS_NPC(ch))
                return;
        i = number_range(1, 100);
        if (i < 50)
                vnum = OBJ_VNUM_PROTOPLASM;
        else if (i < 65)
                vnum = 33851;
        else if (i < 75)
                vnum = 33852;
        else if (i < 80)
                vnum = 33853;
        else if (i < 85)
                vnum = 33854;
        else if (i < 90)
                vnum = 33855;
        else if (i < 95)
                vnum = 33856;
        else
                vnum = 33857;
        if ((pIndex = get_obj_index(vnum)) == NULL)
        {
                bug("BAD PRIZE!!", 0);
                return;
        }
        obj = create_object(pIndex, 50);
        if (vnum == OBJ_VNUM_PROTOPLASM)
        {
                obj->level = 1;
                free_string(obj->short_descr);
                free_string(obj->name);
                free_string(obj->description);
                obj->short_descr = str_dup("A prize token");
                obj->description = str_dup("A token lies on the floor");
                obj->name = str_dup("prize token");
                obj->value[0] = number_range(100, 300);
                obj->item_type = ITEM_QUEST;
        }
        obj_to_char(obj, ch);
        return;
}

void do_clearstats2(CHAR_DATA * ch, char *argument)
{
        OBJ_DATA *obj;
        OBJ_DATA *obj_next;

        if (IS_NPC(ch))
                return;

        powerdown(ch);  /* remove class shit */

        for (obj = ch->carrying; obj != NULL; obj = obj_next)
        {
                obj_next = obj->next_content;
                if (obj->wear_loc != WEAR_NONE)
                {
                        obj_from_char(obj);
                        obj_to_char(obj, ch);
                }
        }

        while (ch->affected)
                affect_remove(ch, ch->affected);

        if (IS_SET(ch->affected_by, AFF_POLYMORPH))
                REMOVE_BIT(ch->affected_by, AFF_POLYMORPH);
        if (IS_SET(ch->affected_by, AFF_ETHEREAL))
                REMOVE_BIT(ch->affected_by, AFF_ETHEREAL);
        if (IS_EXTRA(ch, EXTRA_DRAGON))
                REMOVE_BIT(ch->extra, EXTRA_DRAGON);

        ch->affected_by = 0;
        ch->armor = 100;
        ch->hit = UMAX(1, ch->hit);
        ch->mana = UMAX(1, ch->mana);
        ch->move = UMAX(1, ch->move);
        ch->hitroll = 0;
        ch->damroll = 0;
        ch->saving_throw = 0;
        ch->pcdata->mod_str = 0;
        ch->pcdata->mod_int = 0;
        ch->pcdata->mod_wis = 0;
        ch->pcdata->mod_dex = 0;
        ch->pcdata->mod_con = 0;
        if (IS_SET(ch->newbits, NEW_DFORM))
                REMOVE_BIT(ch->newbits, NEW_DFORM);
        if (IS_POLYAFF(ch, POLY_ZULOFORM))
                REMOVE_BIT(ch->polyaff, POLY_ZULOFORM);
        if (IS_SET(ch->newbits, NEW_CUBEFORM))
                REMOVE_BIT(ch->newbits, NEW_CUBEFORM);
        if (IS_SET(ch->newbits2, NEW2_EAGLES))
                REMOVE_BIT(ch->newbits2, NEW2_EAGLES);
        if (IS_SET(ch->newbits2, NEW2_VVIGOR))
                REMOVE_BIT(ch->newbits2, NEW2_VVIGOR);
        if (IS_SET(ch->newbits, NEW_CLOUDBLESS))
                REMOVE_BIT(ch->newbits, NEW_CLOUDBLESS);
        if (IS_SET(ch->newbits2, NEW2_HAWKEYES))
                REMOVE_BIT(ch->newbits2, NEW2_HAWKEYES);
        save_char_obj(ch);
        send_to_char
                ("Your stats have been cleared.  Please rewear your equipment.\n\r",
                 ch);
        return;
}

/*
 *  If an item have a bad char in it's short/long/name desc, the mud
 *  will freeze when the char with that item tries to log on, so use
 *  this check on any renaming of items (glamour/reshape/etc).
 */
bool has_bad_chars(CHAR_DATA * ch, char *argument)
{
        int       i;

        if (argument[0] == '\0')
                return FALSE;
        for (i = 0; argument[i] != '\0'; i++)
        {
                if (argument[i] == '~')
                        return TRUE;
        }
        return FALSE;
}

bool is_webbed(CHAR_DATA * ch)
{
        if (IS_AFFECTED(ch, AFF_WEBBED))
        {
                send_to_char("Not while webbed.\n\r", ch);
                return TRUE;
        }
        if (IS_AFFECTED2(ch, AFF2_THORNS))
        {
                send_to_char("Not while rooted by brambles.\n\r", ch);
                return TRUE;
        }
        return FALSE;
}

void ragnarok_stop()
{
        DESCRIPTOR_DATA *d;

        ragnarok = FALSE;
        do_info(NULL,
                "#CPeace has been restored in the realms, the time of ragnarok is no more#n");
        for (d = descriptor_list; d != NULL; d = d->next)
        {
                if (d->character && d->connected == CON_PLAYING)
                {
                        d->character->fight_timer = 0;
                        d->character->pcdata->safe_counter = 5;
                        do_call(d->character, "all");
                        do_restore(d->character, "self");
                }
        }
        return;
}


void powerdown(CHAR_DATA * ch)
{
        if (IS_NPC(ch))
                return;

        if (IS_CLASS(ch, CLASS_DEMON))
        {
                if (IS_POLYAFF(ch, POLY_ZULOFORM))  /* demonform */
                {
                        REMOVE_BIT(ch->polyaff, POLY_ZULOFORM);
                        REMOVE_BIT(ch->affected_by, AFF_POLYMORPH);
                        free_string(ch->morph);
                        ch->morph = str_dup("");
                }
        }
        else if (IS_CLASS(ch, CLASS_MONK))  /* spiritpower and monkflame */
        {
                if (IS_SET(ch->newbits, NEW_MONKFLAME))
                        REMOVE_BIT(ch->newbits, NEW_MONKFLAME);
                if (IS_SET(ch->newbits, NEW_POWER))
                        REMOVE_BIT(ch->newbits, NEW_POWER);
        }
        else if (IS_CLASS(ch, CLASS_WEREWOLF))
        {
                if (IS_SET(ch->special, SPC_WOLFMAN))
                        do_unwerewolf(ch, "");
        }
        else if (IS_CLASS(ch, CLASS_DROW))
        {
                if (IS_SET(ch->newbits, NEW_DFORM)) /* spiderform */
                {
                        free_string(ch->morph);
                        ch->morph = str_dup("");
                        REMOVE_BIT(ch->newbits, NEW_DFORM);
                        REMOVE_BIT(ch->newbits, THIRD_HAND);
                        REMOVE_BIT(ch->newbits, FOURTH_HAND);
                }
        }
        else if (IS_CLASS(ch, CLASS_VAMPIRE))
        {
                if (IS_EXTRA(ch, EXTRA_DRAGON)) /* dragonform */
                {
                        REMOVE_BIT(ch->extra, EXTRA_DRAGON);
                        free_string(ch->morph);
                        ch->morph = str_dup("");
                }
                if (IS_POLYAFF(ch, POLY_ZULOFORM))  /* zuloform */
                {
                        REMOVE_BIT(ch->polyaff, POLY_ZULOFORM);
                        REMOVE_BIT(ch->affected_by, AFF_POLYMORPH);
                        free_string(ch->morph);
                        ch->morph = str_dup("");
                }
        }
        else if (IS_CLASS(ch, CLASS_GIANT))
        {
                if (IS_SET(ch->newbits, NEW_CUBEFORM))  /* dawnstrength */
                {
                        REMOVE_BIT(ch->newbits, NEW_CUBEFORM);
                        REMOVE_BIT(ch->affected_by, AFF_POLYMORPH);
                        free_string(ch->morph);
                        ch->morph = str_dup("");
                }
        }
        else if (IS_CLASS(ch, CLASS_TANARRI))
        {
                if (ch->pcdata->powers[TANARRI_FURY_ON] == 1)   /* fury */
                        ch->pcdata->powers[TANARRI_FURY_ON] = 0;
        }
        else if (IS_CLASS(ch, CLASS_DRONE)) /* nightmare aura */
        {
                if (ch->pcdata->powers[DRONE_NIGHTMARE] == 1)
                        ch->pcdata->powers[DRONE_NIGHTMARE] = 0;
        }
        else if (IS_CLASS(ch, CLASS_SHAPESHIFTER))
        {
                if (IS_SET(ch->affected_by, AFF_POLYMORPH)) /* reset form */
                {
                        ch->pcdata->powers[SHAPE_FORM] = 0;
                        REMOVE_BIT(ch->affected_by, AFF_POLYMORPH);
                        free_string(ch->morph);
                        ch->morph = str_dup("");
                }
        }
        else if (IS_CLASS(ch, CLASS_CYBORG))
        {
                if (IS_SET(ch->newbits, NEW_CUBEFORM))  /* avatar of Lloth */
                {
                        REMOVE_BIT(ch->newbits, NEW_CUBEFORM);
                        REMOVE_BIT(ch->affected_by, AFF_POLYMORPH);
                        free_string(ch->morph);
                        ch->morph = str_dup("");
                }
        }
        else if (IS_CLASS(ch, CLASS_UNDEAD_KNIGHT))
        {
                if (IS_SET(ch->pcdata->powers[AURAS], MIGHT_AURA))  /* aura of might */
                        REMOVE_BIT(ch->pcdata->powers[AURAS], MIGHT_AURA);
        }
        else if (IS_CLASS(ch, CLASS_ANGEL))
        {
                if (IS_SET(ch->newbits, NEW_CUBEFORM))  /* godly favor */
                {
                        REMOVE_BIT(ch->newbits, NEW_CUBEFORM);
                        REMOVE_BIT(ch->affected_by, AFF_POLYMORPH);
                        free_string(ch->morph);
                        ch->morph = str_dup("");
                }
        }
        else if (IS_CLASS(ch, CLASS_FAE))
        {
                if (IS_SET(ch->newbits, NEW_CUBEFORM))  /* elemental form */
                {
                        REMOVE_BIT(ch->newbits, NEW_CUBEFORM);
                        REMOVE_BIT(ch->affected_by, AFF_POLYMORPH);
                        if (IS_SET(ch->affected_by, AFF_PASS_DOOR))
                                REMOVE_BIT(ch->affected_by, AFF_PASS_DOOR);
                        free_string(ch->morph);
                        ch->morph = str_dup("");
                }
        }

        /*
         * and a little bit of everything 
         */
        REMOVE_BIT(ch->pcdata->jflags, JFLAG_DRONE_HORRID);
        return;
}

int get_ratio(CHAR_DATA * ch)
{
        long      ratio;

        if (IS_NPC(ch))
                return 0;
        if ((ch->pkill + ch->pdeath) == 0)
                ratio = 0;  // to avoid divide by zero.
        else if (ch->pkill > ch->pdeath)
                ratio = ch->pkill * 100 * ((ch->pkill * ch->pkill) -
                                           (ch->pdeath * ch->pdeath)) /
                        ((ch->pkill + ch->pdeath) * (ch->pkill + ch->pdeath));
        else if (ch->pkill > 0)
                ratio = (-100) * (ch->pdeath - ch->pkill) / ch->pkill;
        else
                ratio = (-100) * ch->pdeath;
        return (int) ratio;
}

bool multicheck(CHAR_DATA * ch)
{
        CHAR_DATA *gch;
        char      buf[MAX_STRING_LENGTH];

        if (ch->level > 6)
                return FALSE;

        for (gch = char_list; gch; gch = gch->next)
        {
                if (IS_NPC(gch))
                        continue;
                if (gch == ch)
                        continue;
                if (gch->level > 6)
                        continue;
                if (strlen(gch->lasthost) > 2)
                {
                        if (gch->desc)
                        {
                                if (!str_cmp(gch->desc->host, ch->desc->host))
                                {
                                        xprintf(buf,
                                                "%s has connected from the same IP as %s",
                                                ch->name, gch->name);
                                        log_string(LOG_SECURITY, buf);
                                        //do_info(ch, buf);
                                        return TRUE;
                                }
                        }
                        else if (!str_cmp(gch->lasthost, ch->desc->host))
                        {
                                xprintf(buf,
                                        "%s has connected from the same IP as %s",
                                        ch->name, gch->name);
                                log_string(LOG_SECURITY, buf);
                                return TRUE;
                        }
                }
        }
        return FALSE;
}



void death_info(char *str)
{
        DESCRIPTOR_DATA *d;
        char      buf[MAX_STRING_LENGTH];

        if (str[0] == '\0')
                return;

        xprintf(buf, "#0/\\/\\ #RDe#Ya#Rth #0/\\/\\#n %s\n\r", str);

        for (d = descriptor_list; d != NULL; d = d->next)
        {
                if (d->connected == CON_PLAYING && d->character != NULL)
                        send_to_char(buf, d->character);
        }
        return;
}

void avatar_info(char *str)
{
        DESCRIPTOR_DATA *d;
        char      buf[MAX_STRING_LENGTH];

        if (str[0] == '\0')
                return;

        xprintf(buf, "#p-=#P[ #WAvatar #P]#p=-#n %s\n\r", str);

        for (d = descriptor_list; d != NULL; d = d->next)
        {
                if (d->connected == CON_PLAYING && d->character != NULL)
                        send_to_char(buf, d->character);
        }
        return;
}

void leave_info(char *str)
{
        DESCRIPTOR_DATA *d;
        char      buf[MAX_STRING_LENGTH];

        if (str[0] == '\0')
                return;

        xprintf(buf, "#G+#g-#G+ #0Leaves #G+#g-#G+#n %s\n\r", str);

        for (d = descriptor_list; d != NULL; d = d->next)
        {
                if (d->connected == CON_PLAYING && d->character != NULL)
                        send_to_char(buf, d->character);
        }
        return;
}

void enter_info(char *str)
{
        DESCRIPTOR_DATA *d;
        char      buf[MAX_STRING_LENGTH];

        if (str[0] == '\0')
                return;

        xprintf(buf, "#0=#w-#0= #WEnters #0=#w-#0= %s\n\r", str);

        for (d = descriptor_list; d != NULL; d = d->next)
        {
                if (d->connected == CON_PLAYING && d->character != NULL)
                        send_to_char(buf, d->character);
        }
        return;
}


void forge_affect(OBJ_DATA * obj, int value)
{
        AFFECT_DATA paf;

        paf.type = 0;
        paf.duration = -1;
        paf.location = APPLY_HITROLL;
        paf.modifier = value;
        paf.bitvector = 0;
        affect_to_obj(obj, &paf);

        paf.type = 0;
        paf.duration = -1;
        paf.location = APPLY_DAMROLL;
        paf.modifier = value;
        paf.bitvector = 0;
        affect_to_obj(obj, &paf);
}

void dump_last_command()
{
        FILE     *fp;
        char      buf[MAX_STRING_LENGTH];

        fp = fopen("../txt/crash.txt", "a");
        if (cmd_done)
                fprintf(fp,
                        "Last command typed : %s  (thread count : %d) (command executed without flaws)\n",
                        last_command, thread_count);
        else
                fprintf(fp,
                        "Last command typed : %s  (thread count : %d) (crash happended during this command)\n",
                        last_command, thread_count);
        fflush(fp);
        fclose(fp);

        /*
         * creates a note to the immortals
         */
        xprintf(buf,
                "It seems we have crashed, the last command typed was\n\r\n\r");
        strcat(buf, last_command);
        strcat(buf,
               "\n\r\n\rPlease remember that this doesn't mean that this caused the crash.\n\r\n\rRegards,\n\r\n\rThe Crash Code");
        make_note("Immortal", "Crash Code", "imm", "We Crashed", 7, buf);
}

void update_revision(CHAR_DATA * ch)
{
        if (IS_NPC(ch))
                return;
        if (ch->pcdata->revision == CURRENT_REVISION)
                return;

        /*
         * We don't end cases with break, since we want the player to be fully updated.
         */
        switch (ch->pcdata->revision)
        {
        case 1:
                ch->pcdata->damreduct = 100;
                ch->pcdata->damreductdec = 0;
                ch->pcdata->revision++;
        default:
                break;
        }
        return;
}

bool in_fortress(CHAR_DATA * ch)
{
        if (!ch->in_room)
                return FALSE;
        if (ch->in_room->vnum >= 151 && ch->in_room->vnum <= 170)
                return TRUE;
        return FALSE;
}

bool in_arena(CHAR_DATA * ch)
{
        if (!ch->in_room)
                return FALSE;
        if (ch->in_room->vnum >= 50 && ch->in_room->vnum <= 67)
                return TRUE;
        return FALSE;
}

void increase_total_output(int clenght)
{
        total_output += clenght;
}

void logout_message(CHAR_DATA * ch)
{
        static char *const he_she[] = { "XX", "he", "she" };
        static char *const him_her[] = { "XX", "him", "her" };
        static char *const his_her[] = { "XX", "his", "her" };

        DESCRIPTOR_DATA *d;
        char      buf[400]; // that should be plenty.
        const char *dmess;
        const char *i;
        char     *ptr2;
        char     *ptr;
        int       size;

        size = strlen2(ch->pcdata->logoutmessage);
        if (size > 380)
        {
                bug("Bad logoutmessage.", 0);
                return;
        }

        ptr2 = "#C<- #RLeaves #C->#n ";
        ptr = buf;
        dmess = ch->pcdata->logoutmessage;

        while ((*ptr = *ptr2) != '\0')
                ++ptr, ++ptr2;

        while (*dmess != '\0')
        {
                if (*dmess != '$')
                {
                        *ptr++ = *dmess++;
                        continue;
                }
                ++dmess;
                switch (*dmess)
                {
                default:
                        i = "";
                        break;
                case 'n':
                        i = ch->name;
                        break;
                case 'e':
                        i = he_she[URANGE(1, ch->sex, 2)];
                        break;
                case 'm':
                        i = him_her[URANGE(1, ch->sex, 2)];
                        break;
                case 's':
                        i = his_her[URANGE(1, ch->sex, 2)];
                        break;
                }
                ++dmess;
                /*
                 * copying the data into the pointer 
                 */
                while ((*ptr = *i) != '\0')
                        ++ptr, ++i;
        }
        *ptr++ = '\n';
        *ptr++ = '\r';

        for (d = descriptor_list; d; d = d->next)
        {
                if (d->lookup_status != STATUS_DONE)
                        continue;
                if (d->connected != CON_PLAYING)
                        continue;
                write_to_buffer(d, buf, ptr - buf);
        }
        return;
}

void update_mudinfo()
{
        DESCRIPTOR_DATA *d;
        int       i, pcount = 0;

        /*
         * Each week, the data is stored to a file, and
         * the variable cleared.
         */
        if (mudinfo[MUDINFO_UPDATED] > 20160)
        {
                write_mudinfo_database();
                for (i = 0; i < (MUDINFO_MAX - 2); i++)
                {
                        mudinfo[i] = 0;
                }
                log_string(LOG_GAME, "Mudinfo database updated.");
        }

        /*
         * Increase update count 
         */
        mudinfo[MUDINFO_UPDATED]++;

        /*
         * Outdate the output data 
         */

        if (total_output > mudinfo[MUDINFO_DATA_PEAK])
                mudinfo[MUDINFO_DATA_PEAK] = total_output;

        /*
         * The stored data 
         */
        if (mudinfo[MUDINFO_BYTE] > 1048576)    // 1 megabyte
        {
                mudinfo[MUDINFO_MBYTE]++;
                mudinfo[MUDINFO_BYTE] -= 1048576;
        }
        mudinfo[MUDINFO_BYTE] += total_output;

        /*
         * The temp data 
         */
        if (mudinfo[MUDINFO_BYTE_S] > 1048576)  // 1 megabyte
        {
                mudinfo[MUDINFO_MBYTE_S]++;
                mudinfo[MUDINFO_BYTE_S] -= 1048576;
        }
        mudinfo[MUDINFO_BYTE_S] += total_output;

        /*
         * We clear the counter 
         */
        total_output = 0;

        for (d = descriptor_list; d; d = d->next)
        {
                if (d->connected == CON_PLAYING
                    && d->lookup_status == STATUS_DONE)
                {
                        if (d->character)
                        {
                                if (d->character->level < 13)
                                {
                                        pcount++;
                                        if (d->out_compress)
                                                mudinfo[MUDINFO_MCCP_USERS]++;
                                        else
                                                mudinfo[MUDINFO_OTHER_USERS]++;
                                        if (IS_SET
                                            (d->character->act, PLR_SOUND))
                                                mudinfo[MUDINFO_MSP_USERS]++;
                                }
                        }
                }
        }

        if (pcount > mudinfo[MUDINFO_PEAK_USERS])
                mudinfo[MUDINFO_PEAK_USERS] = pcount;

        save_mudinfo();
}

void recycle_descriptors()
{
        DESCRIPTOR_DATA *dclose;
        DESCRIPTOR_DATA *dclose_next;

        for (dclose = descriptor_list; dclose; dclose = dclose_next)
        {
                dclose_next = dclose->next;
                if (dclose->lookup_status != STATUS_CLOSED)
                        continue;

                /*
                 * First let's get it out of the descriptor list.
                 */
                if (dclose == descriptor_list)
                {
                        descriptor_list = descriptor_list->next;
                }
                else
                {
                        DESCRIPTOR_DATA *d;

                        for (d = descriptor_list; d && d->next != dclose;
                             d = d->next)
                                ;
                        if (d != NULL)
                                d->next = dclose->next;
                        else
                        {
                                bug("Recycle_descriptors: dclose not found.",
                                    0);
                                continue;
                        }
                }

                /*
                 * Clear out that memory
                 */
                free_string(dclose->host);
                free_mem(dclose->outbuf, dclose->outsize);

                /*
                 * Mccp
                 */
                if (dclose->out_compress)
                {
                        deflateEnd(dclose->out_compress);
                        free_mem(dclose->out_compress_buf, COMPRESS_BUF_SIZE);
                        free_mem(dclose->out_compress, sizeof(z_stream));
                }

                /*
                 * Bye bye mr. Descriptor.
                 */
                close(dclose->descriptor);

                /*
                 * And then we recycle
                 */
                dclose->next = descriptor_free;
                descriptor_free = dclose;
        }
}

void affect_to_area(AREA_DATA * pArea, AREA_AFFECT * paf)
{
        AREA_AFFECT *paf_new;

        if (area_affect_free == NULL)
        {
                paf_new = alloc_perm(sizeof(*paf_new));
        }
        else
        {
                paf_new = area_affect_free;
                area_affect_free = area_affect_free->next;
        }

        *paf_new = *paf;
        paf_new->next = pArea->affects;
        pArea->affects = paf_new;

        return;
}

void area_affect_remove(AREA_DATA * pArea, AREA_AFFECT * paf)
{
        if (pArea->affects == NULL)
        {
                bug("Area_affect_remove: no affect.", 0);
                return;
        }
        if (paf == pArea->affects)
        {
                pArea->affects = paf->next;
        }
        else
        {
                AREA_AFFECT *prev;

                for (prev = pArea->affects; prev; prev = prev->next)
                {
                        if (prev->next == paf)
                        {
                                prev->next = paf->next;
                                break;
                        }
                }
                if (!prev)
                {
                        bug("Area_affect_remove: cannot find paf.", 0);
                        return;
                }
        }

        paf->next = area_affect_free;
        area_affect_free = paf;

        return;
}

/*
 * A religion of 0 will result in any religion is true,
 * but a religion != 0 will only result in true if the spell
 * has that given religion.
 */
bool has_area_affect(AREA_DATA * pArea, int affect, int religion)
{
        AREA_AFFECT *paf;

        for (paf = pArea->affects; paf; paf = paf->next)
        {
                if (paf->type == affect)
                {
                        if (religion != 0 && paf->religion != religion)
                                continue;
                        else
                                return TRUE;
                }
        }
        return FALSE;
}

int get_next_playerid()
{
        top_playerid++;
        save_coreinfo();
        return top_playerid;
}


void tie_message(CHAR_DATA * ch, CHAR_DATA * victim)
{
        static char *const he_she[] = { "XX", "he", "she" };
        static char *const him_her[] = { "XX", "him", "her" };
        static char *const his_her[] = { "XX", "his", "her" };
        DESCRIPTOR_DATA *d;
        char      buf[400]; // that should be plenty.
        const char *dmess;
        const char *i;
        char     *ptr2;
        char     *ptr;
        int       size;

        size = strlen2(ch->pcdata->tiemessage);
        if (size > 380)
        {
                bug("Bad tiemessage.", 0);
                return;
        }

        ptr2 = "#C<- #RTie #C->#n ";
        ptr = buf;
        dmess = ch->pcdata->tiemessage;

        while ((*ptr = *ptr2) != '\0')
                ++ptr, ++ptr2;

        while (*dmess != '\0')
        {
                if (*dmess != '$')
                {
                        *ptr++ = *dmess++;
                        continue;
                }
                ++dmess;
                switch (*dmess)
                {
                default:
                        i = "";
                        break;
                case 'n':
                        i = ch->name;
                        break;
                case 'e':
                        i = he_she[URANGE(1, ch->sex, 2)];
                        break;
                case 'm':
                        i = him_her[URANGE(1, ch->sex, 2)];
                        break;
                case 's':
                        i = his_her[URANGE(1, ch->sex, 2)];
                        break;
                case 'N':
                        i = victim->name;
                        break;
                case 'S':
                        i = his_her[URANGE(1, victim->sex, 2)];
                        break;
                case 'M':
                        i = him_her[URANGE(1, victim->sex, 2)];
                        break;
                case 'E':
                        i = he_she[URANGE(1, victim->sex, 2)];
                        break;
                }
                ++dmess;
                /*
                 * copying the data into the pointer 
                 */
                while ((*ptr = *i) != '\0')
                        ++ptr, ++i;
        }
        *ptr++ = '\n';
        *ptr++ = '\r';

        for (d = descriptor_list; d; d = d->next)
        {
                if (d->lookup_status != STATUS_DONE)
                        continue;
                if (d->connected != CON_PLAYING)
                        continue;
                write_to_buffer(d, buf, ptr - buf);
        }
        return;
}

void login_message(CHAR_DATA * ch)
{
        static char *const he_she[] = { "XX", "he", "she" };
        static char *const him_her[] = { "XX", "him", "her" };
        static char *const his_her[] = { "XX", "his", "her" };

        DESCRIPTOR_DATA *d;
        char      buf[400]; // that should be plenty.
        const char *dmess;
        const char *i;
        char     *ptr2;
        char     *ptr;
        int       size;

        size = strlen2(ch->pcdata->loginmessage);
        if (size > 380)
        {
                bug("Bad loginmessage.", 0);
                return;
        }

        ptr2 = "#C<- #REnters #C->#n ";
        ptr = buf;
        dmess = ch->pcdata->loginmessage;

        while ((*ptr = *ptr2) != '\0')
                ++ptr, ++ptr2;

        while (*dmess != '\0')
        {
                if (*dmess != '$')
                {
                        *ptr++ = *dmess++;
                        continue;
                }
                ++dmess;
                switch (*dmess)
                {
                default:
                        i = "";
                        break;
                case 'n':
                        i = ch->name;
                        break;
                case 'e':
                        i = he_she[URANGE(1, ch->sex, 2)];
                        break;
                case 'm':
                        i = him_her[URANGE(1, ch->sex, 2)];
                        break;
                case 's':
                        i = his_her[URANGE(1, ch->sex, 2)];
                        break;
                }
                ++dmess;
                /*
                 * copying the data into the pointer 
                 */
                while ((*ptr = *i) != '\0')
                        ++ptr, ++i;
        }
        *ptr++ = '\n';
        *ptr++ = '\r';

        for (d = descriptor_list; d; d = d->next)
        {
                if (d->lookup_status != STATUS_DONE)
                        continue;
                if (d->connected != CON_PLAYING)
                        continue;
                write_to_buffer(d, buf, ptr - buf);
        }
        return;
}
void check_help_soundex(char *argument, CHAR_DATA * ch)
{
        HELP_DATA *pHelp;
        char      buf[MAX_STRING_LENGTH];
        char      tbuf[MAX_STRING_LENGTH];
        char      arg[MAX_INPUT_LENGTH];
        char      keyword[MAX_INPUT_LENGTH];
        char     *str;
        bool      found = FALSE;

        one_argument(argument, arg);

        if (arg[0] == '\0')
                return;

        xprintf(buf, "\n\r[Perhaps:");
        for (pHelp = first_help; pHelp; pHelp = pHelp->next)
        {
                if (pHelp->level > ch->level)
                        continue;

                str = pHelp->keyword;
                str = one_argument(str, keyword);
                while (keyword[0] != '\0')
                {
                        if (SoundexMatch
                            (GetSoundexKey(arg), GetSoundexKey(keyword)) > 75)
                        {
                                found = TRUE;
                                xprintf(tbuf, " %s", keyword);
                                strcat(buf, tbuf);
                        }
                        str = one_argument(str, keyword);
                }
        }
        strcat(buf, "]\n\r");
        if (found)
                send_to_char(buf, ch);
}

/*
 * New system to replace status, called fair fight, it measures the
 * difference between two players, giving them points for their
 * stances, powers, and stats. If they are within each others range,
 * the call will return TRUE, if not FALSE. Call for fair_fight when
 * you need to see if a fight is fair (ie. decapping).
 */
bool fair_fight(CHAR_DATA * ch, CHAR_DATA * victim)
{

        return TRUE;
}

void special_decap_message(CHAR_DATA * ch, CHAR_DATA * victim)
{
        static char *const he_she[] = { "XX", "he", "she" };
        static char *const him_her[] = { "XX", "him", "her" };
        static char *const his_her[] = { "XX", "his", "her" };
        DESCRIPTOR_DATA *d;
        char      buf[400]; // that should be plenty.
        const char *dmess;
        const char *i;
        char     *ptr2;
        char     *ptr;
        int       size;

        size = strlen2(ch->pcdata->decapmessage);
        if (size > 380)
        {
                bug("Bad decapmessage.", 0);
                return;
        }

        ptr2 = "#C<- #RDeath #C->#n ";
        ptr = buf;
        dmess = ch->pcdata->decapmessage;

        while ((*ptr = *ptr2) != '\0')
                ++ptr, ++ptr2;

        while (*dmess != '\0')
        {
                if (*dmess != '$')
                {
                        *ptr++ = *dmess++;
                        continue;
                }
                ++dmess;
                switch (*dmess)
                {
                default:
                        i = "";
                        break;
                case 'n':
                        i = ch->name;
                        break;
                case 'e':
                        i = he_she[URANGE(1, ch->sex, 2)];
                        break;
                case 'm':
                        i = him_her[URANGE(1, ch->sex, 2)];
                        break;
                case 's':
                        i = his_her[URANGE(1, ch->sex, 2)];
                        break;
                case 'N':
                        i = victim->name;
                        break;
                case 'S':
                        i = his_her[URANGE(1, victim->sex, 2)];
                        break;
                case 'M':
                        i = him_her[URANGE(1, victim->sex, 2)];
                        break;
                case 'E':
                        i = he_she[URANGE(1, victim->sex, 2)];
                        break;
                }
                ++dmess;
                /*
                 * copying the data into the pointer 
                 */
                while ((*ptr = *i) != '\0')
                        ++ptr, ++i;
        }
        *ptr++ = '\n';
        *ptr++ = '\r';

        for (d = descriptor_list; d; d = d->next)
        {
                if (d->lookup_status != STATUS_DONE)
                        continue;
                if (d->connected != CON_PLAYING)
                        continue;
                write_to_buffer(d, buf, ptr - buf);
        }
        return;
}






/*
 * This function have always been broken, perhaps
 * one day in the future I'll make a functionel
 * piece of code, but untill then, it's more
 * guessing the right size than anything else.
 */
char     *get_dystopia_banner(char *title, int size)
{
        int       tSize = strlen(title);
        int       patternsize, bufferspaces = 0, blockcount, i;
        static char buf[200];

        /*
         * just so we can use strcat 
         */
        buf[0] = '\0';

        /*
         * calculating the amount of patterns on each side of the title 
         */
        patternsize = (size - tSize) / 2;
        if (!(patternsize % 4))
                patternsize -= 4;
        else
                while (patternsize % 4)
                        patternsize--;
        patternsize /= 4;

        /*
         * calculating buffer spaces 
         */
        while ((tSize + bufferspaces) % 4)
                bufferspaces++;
        blockcount = bufferspaces / 2;

        if (patternsize < 1)
        {
                strcat(buf, "#0<>== #G");
                strcat(buf, title);
                strcat(buf, " #0==<>#n");
        }
        else
        {
                /*
                 * first add patterns 
                 */
                strcat(buf, "#0<>==");
                for (i = 1; i < patternsize; i++)
                        strcat(buf, "<>==");
                /*
                 * add the title 
                 */
                if (tSize)
                {
                        strcat(buf, "#G ");
                        while (bufferspaces > blockcount)
                        {
                                bufferspaces--;
                                strcat(buf, " ");
                        }
                }
                else
                        strcat(buf, "<>");
                strcat(buf, title);
                if (tSize)
                {
                        strcat(buf, "#0 ");
                        while (bufferspaces > 0)
                        {
                                bufferspaces--;
                                strcat(buf, " ");
                        }
                }
                /*
                 * add secondary patterns 
                 */
                for (i = 0; i < patternsize; i++)
                        strcat(buf, "==<>");
                strcat(buf, "#n");
        }

        return buf;
}

int calc_ratio(int a, int b)
{
        int       ratio;

        if (b == 0 && a > 0)
                ratio = 100;
        else if ((a + b) != 0)
                ratio = (100 * a) / (a + b);
        else
                ratio = 0;
        return ratio;
}

void avatar_message(CHAR_DATA * ch)
{
        static char *const he_she[] = { "XX", "he", "she" };
        static char *const him_her[] = { "XX", "him", "her" };
        static char *const his_her[] = { "XX", "his", "her" };

        DESCRIPTOR_DATA *d;
        char      buf[400]; // that should be plenty.
        const char *dmess;
        const char *i;
        char     *ptr2;
        char     *ptr;
        int       size;

        size = strlen2(ch->pcdata->avatarmessage);
        if (size > 380)
        {
                bug("Bad avatarmessage.", 0);
                return;
        }

        ptr2 = "#C<- #RAvatar #C->#n ";
        ptr = buf;
        dmess = ch->pcdata->avatarmessage;

        while ((*ptr = *ptr2) != '\0')
                ++ptr, ++ptr2;

        while (*dmess != '\0')
        {
                if (*dmess != '$')
                {
                        *ptr++ = *dmess++;
                        continue;
                }
                ++dmess;
                switch (*dmess)
                {
                default:
                        i = "";
                        break;
                case 'n':
                        i = ch->name;
                        break;
                case 'e':
                        i = he_she[URANGE(0, ch->sex, 1)];
                        break;
                case 'm':
                        i = him_her[URANGE(0, ch->sex, 1)];
                        break;
                case 's':
                        i = his_her[URANGE(0, ch->sex, 1)];
                        break;
                }
                ++dmess;
                /*
                 * copying the data into the pointer 
                 */
                while ((*ptr = *i) != '\0')
                        ++ptr, ++i;
        }
        *ptr++ = '\n';
        *ptr++ = '\r';

        for (d = descriptor_list; d; d = d->next)
        {
                if (d->lookup_status != STATUS_DONE)
                        continue;
                if (d->connected != CON_PLAYING)
                        continue;
                write_to_buffer(d, buf, ptr - buf);
        }
        return;
}
char     *strip_ansi(char *str)
{
        static char buf[MAX_STRING_LENGTH];
        char     *ptr;

        buf[0] = '\0';
        ptr = buf;

        while (*str != '\0')
        {
                if (*str != '#')
                        *ptr++ = *str++;
                else if (*(++str) != '\0')
                        str++;
        }
        *ptr = '\0';
        return buf;
}
char     *line_indent(char *text, int wBegin, int wMax)
{
        static char buf[MAX_STRING_LENGTH];
        char     *ptr;
        char     *ptr2;
        int       count = 0;
        bool      stop = FALSE;
        int       wEnd = 0;

        buf[0] = '\0';
        ptr = text;
        ptr2 = buf;

        while (!stop)
        {
                if (count == 0)
                {
                        if (*ptr == '\0')
                                wEnd = wMax - wBegin;
                        else if (strlen(ptr) < (wMax - wBegin))
                                wEnd = wMax - wBegin;
                        else
                        {
                                int       x = 0;

                                while (*(ptr + (wMax - wBegin - x)) != ' ')
                                        x++;
                                wEnd = wMax - wBegin - (x - 1);
                                if (wEnd < 1)
                                        wEnd = wMax - wBegin;
                        }
                }
                if (count == 0 && *ptr == ' ')
                        ptr++;
                else if (++count != wEnd)
                {
                        if ((*ptr2++ = *ptr++) == '\0')
                                stop = TRUE;
                }
                else if (*ptr == '\0')
                {
                        stop = TRUE;
                        *ptr2 = '\0';
                }
                else
                {
                        int       k;

                        count = 0;
                        *ptr2++ = '\n';
                        *ptr2++ = '\r';
                        for (k = 0; k < wBegin; k++)
                                *ptr2++ = ' ';
                }
        }
        return buf;
}

char     *get_exits(CHAR_DATA * ch)
{
        //extern char *const dir_name[];
        static char buf[MAX_STRING_LENGTH];
        EXIT_DATA *pexit;
        bool      found;
        int       door;

        buf[0] = '\0';

        if (!check_blind(ch))
                return "";

        xprintf(buf, "#0[#GExits#w:#C");

        found = FALSE;
        for (door = 0; door <= 5; door++)
        {
                if ((pexit = ch->in_room->exit[door]) != NULL
                    && pexit->to_room != NULL)
                {
                        found = TRUE;
                        if (IS_SET(pexit->exit_info, EX_CLOSED))
                        {
                                strcat(buf, " #0(#C");
                                strcat(buf, dir_name[door]);
                                strcat(buf, "#0)#C");
                        }
                        else
                        {
                                strcat(buf, " ");
                                strcat(buf, dir_name[door]);
                        }
                }
        }
        if (!found)
                strcat(buf, " none");
        strcat(buf, "#0]#n\n\r");

        return buf;
}
void init_vt100(DESCRIPTOR_DATA * d, char *xbuf)
{
        CHAR_DATA *ch;
        char      buf[MAX_STRING_LENGTH];
        int       i;

        if ((ch = d->character) == NULL)
        {
                bug("Init_vt100: No character", 0);
                return;
        }
        if ((i = atoi(xbuf)) < 10)
        {
                send_to_char("VT100 Failed.\n\r", ch);
                return;
        }
        ch->pcdata->vt100_size = i;
        SET_BIT(ch->pcdata->tempflag, TEMP_VT100);
        xprintf(buf, "\e[%d;1H%s%s\e[1;1H%s%s\e[1;%dr",
                i, VT_CLEAR_LINE, VT_SAVECURSOR, VT_SETWIN_CLEAR,
                VT_CLEAR_SCREEN, i - 2);
        send_to_char(buf, ch);
        send_to_char("VT100 Initialized.\n\r", ch);
        return;
}

void recycle_dummys()
{
        DUMMY_ARG *dummy;
        DUMMY_ARG *dummy_next;

        for (dummy = dummy_list; dummy; dummy = dummy_next)
        {
                dummy_next = dummy->next;
                if (dummy->status == 1)
                        continue;   // being used

                if (dummy == dummy_list)
                {
                        dummy_list = dummy_list->next;
                }
                else
                {
                        DUMMY_ARG *prev;

                        /*
                         * we find the prev dummy arg 
                         */
                        for (prev = dummy_list; prev && prev->next != dummy;
                             prev = prev->next)
                                ;
                        if (prev != NULL)
                                prev->next = dummy->next;
                        else
                        {
                                bug("Recycle_dymmys: dummy not found.", 0);
                                continue;
                        }

                        /*
                         * recycle 
                         */
                        dummy->next = dummy_free;
                        dummy_free = dummy;
                }
        }
}

HEAP     *init_heap(RID * root)
{
        AREA_DATA *pArea;
        RID      *pRoom;
        HEAP     *heap;
        int       i, size, vnum;

        if ((pArea = root->area) == NULL)
                return NULL;
        size = pArea->uvnum - pArea->lvnum;

        if (size >= MAX_KNUDE)
        {
                bug("Init_heap: Size %d exceeds MAX_KNUDE", size);
                return NULL;
        }

        heap = calloc(1, sizeof(*heap));

        /*
         * we want the root at the beginning 
         */
        heap->knude[1] = root;
        heap->knude[1]->steps = 0;
        heap->knude[1]->heap_index = 1;

        /*
         * initializing the rest of the heap 
         */
        for (i = 2, vnum = pArea->lvnum; vnum < pArea->uvnum; vnum++)
        {
                if ((pRoom = get_room_index(vnum)))
                {
                        if (pRoom == root)
                                continue;
                        heap->knude[i] = pRoom;
                        heap->knude[i]->steps = 2 * MAX_KNUDE;
                        heap->knude[i]->heap_index = i;
                        i++;
                }
        }

        heap->iVertice = i - 1;

        /*
         * setting the rest to NULL 
         */
        for (; i < MAX_KNUDE; i++)
                heap->knude[i] = NULL;

        return heap;
}

/*
 * Finds the smallest element and returns it after
 * making sure the heap is in perfect order after
 * the removal of the vertice with the smallest
 * element.
 */
RID      *heap_getMinElement(HEAP * heap)
{
        RID      *tRoom;
        RID      *pRoom;
        bool      done = FALSE;
        int       i = 1;

        /*
         * this is the element we wish to return 
         */
        pRoom = heap->knude[1];

        if (pRoom->steps == 2 * MAX_KNUDE)
                bug("Removing room with max steps : %d", pRoom->vnum);

        /*
         * We move the last vertice to the front 
         */
        heap->knude[1] = heap->knude[heap->iVertice];
        heap->knude[1]->heap_index = 1;

        /*
         * Decrease the size of the heap and remove the last entry 
         */
        heap->knude[heap->iVertice] = NULL;
        heap->iVertice--;

        /*
         * Swap places till it fits 
         */
        while (!done)
        {
                if (heap->knude[i] == NULL)
                        done = TRUE;
                else if (heap->knude[2 * i] == NULL)
                        done = TRUE;
                else if (heap->knude[2 * i + 1] == NULL)
                {
                        if (heap->knude[i]->steps > heap->knude[2 * i]->steps)
                        {
                                tRoom = heap->knude[i];
                                heap->knude[i] = heap->knude[2 * i];
                                heap->knude[i]->heap_index = i;
                                heap->knude[2 * i] = tRoom;
                                heap->knude[2 * i]->heap_index = 2 * i;
                                i = 2 * i;
                        }
                        done = TRUE;
                }
                else if (heap->knude[i]->steps <= heap->knude[2 * i]->steps &&
                         heap->knude[i]->steps <=
                         heap->knude[2 * i + 1]->steps)
                        done = TRUE;
                else if (heap->knude[2 * i]->steps <=
                         heap->knude[2 * i + 1]->steps)
                {
                        tRoom = heap->knude[i];
                        heap->knude[i] = heap->knude[2 * i];
                        heap->knude[i]->heap_index = i;
                        heap->knude[2 * i] = tRoom;
                        heap->knude[2 * i]->heap_index = 2 * i;
                        i = 2 * i;
                }
                else
                {
                        tRoom = heap->knude[i];
                        heap->knude[i] = heap->knude[2 * i + 1];
                        heap->knude[i]->heap_index = i;
                        heap->knude[2 * i + 1] = tRoom;
                        heap->knude[2 * i + 1]->heap_index = 2 * i + 1;
                        i = 2 * i + 1;
                }
        }

        /*
         * return the element 
         */
        return pRoom;
}

void dijkstra(RID * chRoom, RID * victRoom)
{
        RID      *pRoom;
        RID      *tRoom;
        RID      *xRoom;
        HEAP     *heap;
        int       door, x;
        bool      stop;

        /*
         * allocate a new heap 
         */
        heap = init_heap(chRoom);

        /*
         * find shortest amounts of steps to each room 
         */
        while (heap->iVertice)
        {
                if ((pRoom = heap_getMinElement(heap)) == NULL)
                {
                        bug("Dijstra: Getting NULL room", 0);
                        return;
                }
                if (pRoom == victRoom)
                        gFound = TRUE;

                /*
                 * update all exits 
                 */
                for (door = 0; door < 6; door++)
                {
                        if (pRoom->exit[door] == NULL)
                                continue;
                        if (pRoom->exit[door]->to_room == NULL)
                                continue;

                        /*
                         * update step count, and swap in the heap 
                         */
                        if (pRoom->exit[door]->to_room->steps >
                            pRoom->steps + 1)
                        {
                                xRoom = pRoom->exit[door]->to_room;
                                xRoom->steps = pRoom->steps + 1;
                                stop = FALSE;
                                while ((x = xRoom->heap_index) != 1 && !stop)
                                {
                                        if (heap->knude[x / 2]->steps >
                                            xRoom->steps)
                                        {
                                                tRoom = heap->knude[x / 2];
                                                heap->knude[x / 2] = xRoom;
                                                xRoom->heap_index =
                                                        xRoom->heap_index / 2;
                                                heap->knude[x] = tRoom;
                                                heap->knude[x]->heap_index =
                                                        x;
                                        }
                                        else
                                                stop = TRUE;
                                }
                        }
                }
        }

        /*
         * free the heap 
         */
        free(heap);
}

/*
 * The mobs vnum is included for bug-reports.
 */
bool will_trigger(char *say, char *trigger, int vnum)
{
        char      buf[50];
        char     *ptr;
        bool      found;

        buf[0] = '\0';
        ptr = buf;

        while (*trigger != '\0')
        {
                switch (*trigger)
                {
                default:
                        bug("Will_trigger: Bad keyword on mob %d.", vnum);
                        return FALSE;
                case '&':  // all keywords must be included
                        trigger++;
                        while (*trigger != '\0' && *trigger != '&'
                               && *trigger != '!' && *trigger != '|')
                        {
                                if (*trigger != '*')
                                        *ptr++ = *trigger;
                                else
                                {
                                        *ptr = '\0';
                                        if (!is_contained(buf, say))
                                                return FALSE;
                                        else
                                        {
                                                buf[0] = '\0';
                                                ptr = buf;
                                        }
                                }
                                trigger++;
                        }
                        break;
                case '|':  // at least one must be included
                        trigger++;
                        found = FALSE;
                        while (*trigger != '\0' && *trigger != '&'
                               && *trigger != '!' && *trigger != '|')
                        {
                                if (*trigger != '*')
                                        *ptr++ = *trigger;
                                else
                                {
                                        *ptr = '\0';
                                        if (is_contained(buf, say))
                                                found = TRUE;
                                        buf[0] = '\0';
                                        ptr = buf;
                                }
                                trigger++;
                        }
                        if (!found)
                                return FALSE;
                        break;
                case '!':  // none of these may be included
                        trigger++;
                        while (*trigger != '\0' && *trigger != '&'
                               && *trigger != '!' && *trigger != '|')
                        {
                                if (*trigger != '*')
                                        *ptr++ = *trigger;
                                else
                                {
                                        *ptr = '\0';
                                        if (is_contained(buf, say))
                                                return FALSE;
                                        else
                                        {
                                                buf[0] = '\0';
                                                ptr = buf;
                                        }
                                }
                                trigger++;
                        }
                        break;
                }
        }
        return TRUE;
}

void mob_text(CHAR_DATA * ch, char *argument)
{
        CHAR_DATA *vch;
        CHAR_DATA *vch_next;
        CHAR_DATA *victim;
        MOB_TRIGGER *mProg;
        char     *arg;
        char      buf[MAX_STRING_LENGTH];

        if (IS_NPC(ch))
                return;

        for (vch = ch->in_room->people; vch; vch = vch_next)
        {
                int       runs = 0;

                vch_next = vch->next_in_room;
                if (!IS_NPC(vch))
                        continue;

                while (runs < 2)
                {
                        if (runs == 0)
                                mProg = vch->pIndexData->triggers;
                        else
                                mProg = vch->triggers;

                        for (; mProg; mProg = mProg->next)
                        {
                                if (will_trigger
                                    (argument, mProg->keywords,
                                     vch->pIndexData->vnum))
                                {
                                        switch (mProg->type)
                                        {
                                        default:
                                                bug("Mob_text: Bad type on mob %d.", vch->pIndexData->vnum);
                                                break;
                                        case MTRIG_SAY:
                                                do_say(vch,
                                                       mProg->roomOutput);
                                                break;
                                        case MTRIG_LOCATE:
                                                if ((arg =
                                                     cut_after_locate
                                                     (argument)) == NULL)
                                                {
                                                        do_say(vch,
                                                               mProg->
                                                               chOutput);
                                                        return;
                                                }
                                                else if ((victim =
                                                          get_char_area(ch,
                                                                        arg))
                                                         == NULL)
                                                {
                                                        do_say(vch,
                                                               mProg->
                                                               chOutput);
                                                        return;
                                                }
                                                else
                                                {
                                                        if ((arg =
                                                             pathfind(ch,
                                                                      victim))
                                                            == NULL)
                                                        {
                                                                do_say(vch,
                                                                       mProg->
                                                                       chOutput);
                                                                return;
                                                        }
                                                        else
                                                        {
                                                                xprintf(buf,
                                                                        mProg->
                                                                        roomOutput,
                                                                        arg);
                                                                do_say(vch,
                                                                       buf);
                                                                return;
                                                        }
                                                }
                                                break;
                                        case MTRIG_HUNTER:
                                                if ((arg =
                                                     cut_after_tracking
                                                     (argument)) == NULL)
                                                {
                                                        do_say(vch,
                                                               mProg->
                                                               chOutput);
                                                        return;
                                                }
                                                else if ((victim =
                                                          get_char_area(ch,
                                                                        arg))
                                                         == NULL)
                                                {
                                                        do_say(vch,
                                                               mProg->
                                                               chOutput);
                                                        return;
                                                }
                                                if (IS_NPC(victim))
                                                {
                                                        do_say(vch,
                                                               mProg->
                                                               chOutput);
                                                        return;
                                                }
                                                else
                                                {
                                                        if ((arg =
                                                             pathfind(ch,
                                                                      victim))
                                                            == NULL)
                                                        {
                                                                do_say(vch,
                                                                       mProg->
                                                                       chOutput);
                                                                return;
                                                        }
                                                        else
                                                        {
                                                                free_string
                                                                        (vch->
                                                                         hunting);
                                                                vch->hunting =
                                                                        str_dup
                                                                        (arg);
                                                                vch->tracking
                                                                        =
                                                                        TRUE;
                                                                vch->hunt_pointer = 0;
                                                                vch->hunt_playerid = victim->pcdata->playerid;
                                                                do_say(vch,
                                                                       mProg->
                                                                       roomOutput);
                                                                return;
                                                        }
                                                }
                                                break;
                                        case MTRIG_SCRY:
                                                break;
                                        }
                                        return;
                                }
                        }
                        runs++;
                }
        }
}

void trigger_remove(CHAR_DATA * ch, MOB_TRIGGER * mProg)
{
        if (ch->triggers == NULL)
        {
                bug("Trigger_remove: no trigger.", 0);
                return;
        }
        if (mProg == ch->triggers)
        {
                ch->triggers = ch->triggers->next;
        }
        else
        {
                MOB_TRIGGER *prev;

                for (prev = ch->triggers; prev; prev = prev->next)
                {
                        if (prev->next == mProg)
                        {
                                prev->next = mProg->next;
                                break;
                        }
                }
                if (!prev)
                {
                        bug("Trigger_remove: cannot find mProg.", 0);
                        return;
                }
        }
        mProg->next = trigger_free;
        trigger_free = mProg;

        return;
}

void update_aggressive_flags(CHAR_DATA * ch, CHAR_DATA * victim)
{
        int       iDef, iAggr;

        /*
         * first we check if we even care 
         */
        if (IS_NPC(ch) || IS_NPC(victim))
                return;
        if (ch->level > 6)
                return;
        if (victim->pcdata->aggress_towards == ch->pcdata->playerid)
                return;
        if (ch->pcdata->aggress_from == victim->pcdata->playerid)
                return;
        if (!str_cmp(victim->name, ch->pcdata->retaliation))
                return;
        if (in_arena(ch) || in_fortress(ch))
                return;
        if (IS_SET(ch->pcdata->tempflag, TEMP_AGGRESSIVE))
                return;
        if (ch->class == victim->class
            && ch->generation >= victim->generation)
                return;
        if (ragnarok)
                return;

        iDef = victim->race;
        iAggr = ch->race;

        /*
         * If the player aggresses someone other than
         * * the person who attacked them, they don't deserve
         * * the gang protection, since they are asking for it.
         */
        ch->pcdata->aggress_from = 0;

        /*
         * This will take care of bully players 
         * if (iDef < iAggr + 5)
         * {
         * victim->pcdata->aggress_from = ch->pcdata->playerid;
         * ch->pcdata->bully_points += 50;
         * if (ch->pcdata->bully_points > 400)
         * {
         * SET_BIT(ch->pcdata->jflags, JFLAG_BULLY);
         * ch->pcdata->bully_counter += 240;  // roughly 2 hours
         * ch->pcdata->bully_points = 0;
         * send_to_char("#PTake that, bully!#n\n\r", ch);
         * }
         * }
         */
        /*
         * this will take care of really small players attacking large players 
         */
        if (iAggr < iDef + 5)
                ch->pcdata->aggress_towards = victim->pcdata->playerid;

        /*
         * aggro counter up a little, untill I can fix it 
         */
        ch->pcdata->agg_counter = UMAX(2, ch->pcdata->agg_counter);
        victim->pcdata->agg_counter = UMAX(2, victim->pcdata->agg_counter);
}

void strip_aggression(CHAR_DATA * ch)
{
        if (IS_NPC(ch))
                return;

        ch->pcdata->agg_counter = 0;
        ch->pcdata->aggress_towards = 0;
        ch->pcdata->aggress_from = 0;
}

char     *pathfind(CHAR_DATA * ch, CHAR_DATA * victim)
{
        int const exit_names[] = { 'n', 'e', 's', 'w', 'u', 'd' };
        RID      *pRoom;
        AREA_DATA *pArea;
        static char path[MAX_STRING_LENGTH];    // should be plenty.
        int       iPath = 0, vnum, door;
        bool      found;

        if (!ch->in_room || !victim->in_room)
                return NULL;
        if (ch->in_room == victim->in_room)
                return NULL;
        if ((pArea = ch->in_room->area) != victim->in_room->area)
                return NULL;

        /*
         * initialize all rooms in the area 
         */
        for (vnum = pArea->lvnum; vnum < pArea->uvnum; vnum++)
        {
                if ((pRoom = get_room_index(vnum)))
                {
                        pRoom->visited = FALSE;
                        pRoom->steps = 999;
                        for (door = 0; door < 6; door++)
                        {
                                if (pRoom->exit[door] == NULL)
                                        continue;
                                pRoom->exit[door]->color = FALSE;
                        }
                }
        }

        /*
         * initialize variables 
         */
        pRoom = ch->in_room;
        gFound = FALSE;

        /*
         * In the first run, we only count steps, no coloring is done 
         */
        examine_steps(pRoom, victim->in_room, pArea, 0);

        /*
         * If the target room was never found, we return NULL 
         */
        if (!gFound)
                return NULL;

        /*
         * in the second run, we color the shortest path using the step counts 
         */
        if (!examine_room(pRoom, victim->in_room, pArea, 0))
                return NULL;

        /*
         * then we follow the trace 
         */
        while (pRoom != victim->in_room)
        {
                found = FALSE;
                for (door = 0; door < 6 && !found; door++)
                {
                        if (pRoom->exit[door] == NULL)
                                continue;
                        if (pRoom->exit[door]->to_room == NULL)
                                continue;
                        if (!pRoom->exit[door]->color)
                                continue;

                        pRoom->exit[door]->color = FALSE;
                        found = TRUE;
                        path[iPath] = exit_names[door];
                        iPath++;
                        pRoom = pRoom->exit[door]->to_room;
                }
                if (!found)
                {
                        bug("Pathfind: Fatal Error in %d.", pRoom->vnum);
                        return NULL;
                }
        }

        path[iPath] = '\0';
        return path;
}

bool examine_room(ROOM_INDEX_DATA * pRoom, ROOM_INDEX_DATA * tRoom,
                  AREA_DATA * pArea, int steps)
{
        int       door;

        /*
         * been here before, out of the area or can we get here faster 
         */
        if (pRoom->area != pArea)
                return FALSE;
        if (pRoom->visited)
                return FALSE;
        if (pRoom->steps < steps)
                return FALSE;

        /*
         * Have we found the room we are searching for 
         */
        if (pRoom == tRoom)
                return TRUE;

        /*
         * mark the room so we know we have been here 
         */
        pRoom->visited = TRUE;

        /*
         * Depth first traversel of all exits 
         */
        for (door = 0; door < 6; door++)
        {
                if (pRoom->exit[door] == NULL)
                        continue;
                if (pRoom->exit[door]->to_room == NULL)
                        continue;

                /*
                 * assume we are walking the right way 
                 */
                pRoom->exit[door]->color = TRUE;

                /*
                 * recursive return 
                 */
                if (examine_room
                    (pRoom->exit[door]->to_room, tRoom, pArea, steps + 1))
                        return TRUE;

                /*
                 * it seems we did not walk the right way 
                 */
                pRoom->exit[door]->color = FALSE;
        }
        return FALSE;
}

void examine_steps(ROOM_INDEX_DATA * pRoom, ROOM_INDEX_DATA * tRoom,
                   AREA_DATA * pArea, int steps)
{
        int       door;

        /*
         * Have we found the room we are searching for 
         */
        if (pRoom == tRoom)
        {
                if (pRoom->steps > steps)
                        pRoom->steps = steps;
                gFound = TRUE;
                return;
        }

        /*
         * been here before, or out of the area 
         */
        if (pRoom->area != pArea)
                return;
        if (pRoom->steps != 999)
        {
                if (pRoom->steps > steps)
                        pRoom->steps = steps;
                return;
        }

        /*
         * update the rooms step count
         */
        pRoom->steps = steps;

        /*
         * Depth first traversel of all exits 
         */
        for (door = 0; door < 6; door++)
        {
                if (pRoom->exit[door] == NULL)
                        continue;
                if (pRoom->exit[door]->to_room == NULL)
                        continue;

                examine_steps(pRoom->exit[door]->to_room, tRoom, pArea,
                              steps + 1);
        }

        return;
}