muddy/
muddy/CVS/
muddy/area/
muddy/area/CVS/
muddy/clans/CVS/
muddy/classes/CVS/
muddy/doc/
muddy/doc/CVS/
muddy/etc/CVS/
muddy/etc/i3/
muddy/etc/i3/CVS/
muddy/imc/CVS/
muddy/lang/CVS/
muddy/licenses/CVS/
muddy/msgdb/CVS/
muddy/new/CVS/
muddy/notes/
muddy/player/
muddy/races/CVS/
muddy/religions/CVS/
muddy/src/CVS/
muddy/src/comm/CVS/
muddy/src/db/CVS/
muddy/src/intermud/
muddy/src/intermud/CVS/
muddy/src/irc/CVS/
muddy/src/olc/CVS/
/* $Id: recycle.c,v 1.666 2004/09/20 10:49:52 shrike Exp $ */

/************************************************************************************
 *    Copyright 2004 Astrum Metaphora consortium                                    *
 *                                                                                  *
 *    Licensed under the Apache License, Version 2.0 (the "License");               *
 *    you may not use this file except in compliance with the License.              *
 *    You may obtain a copy of the License at                                       *
 *                                                                                  *
 *    http://www.apache.org/licenses/LICENSE-2.0                                    *
 *                                                                                  *
 *    Unless required by applicable law or agreed to in writing, software           *
 *    distributed under the License is distributed on an "AS IS" BASIS,             *
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.      *
 *    See the License for the specific language governing permissions and           *
 *    limitations under the License.                                                *
 *                                                                                  *
 ************************************************************************************/
/************************************************************************************
 *     ANATOLIA 2.1 is copyright 1996-1997 Serdar BULUT, Ibrahim CANPUNAR           *
 *     ANATOLIA has been brought to you by ANATOLIA consortium                      *
 *       Serdar BULUT {Chronos}         bulut@rorqual.cc.metu.edu.tr                *
 *       Ibrahim Canpunar  {Asena}      canpunar@rorqual.cc.metu.edu.tr             *
 *       Murat BICER  {KIO}             mbicer@rorqual.cc.metu.edu.tr               *
 *       D.Baris ACAR {Powerman}        dbacar@rorqual.cc.metu.edu.tr               *
 *     By using this code, you have agreed to follow the terms of the               *
 *     ANATOLIA license, in the file Anatolia/anatolia.licence                      *
 ***********************************************************************************/

/************************************************************************************
 *  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.                                                        *
 *                                                                                  *
 *  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.                                                           *
 ************************************************************************************/

/************************************************************************************
*       ROM 2.4 is copyright 1993-1995 Russ Taylor                                  *
*       ROM has been brought to you by the ROM consortium                           *
*           Russ Taylor (rtaylor@pacinfo.com)                                       *
*           Gabrielle Taylor (gtaylor@pacinfo.com)                                  *
*           Brian Moore (rom@rom.efn.org)                                           *
*       By using this code, you have agreed to follow the terms of the              *
*       ROM license, in the file Rom24/doc/rom.license                              *
*************************************************************************************/

/************************************************************************************
 * Copyright (c) 1998 fjoe <fjoe@iclub.nsu.ru>                                      *
 * All rights reserved.                                                             *
 *                                                                                  *
 * Redistribution and use in source and binary forms, with or without               *
 * modification, are permitted provided that the following conditions               *
 * are met:                                                                         *
 * 1. Redistributions of source code must retain the above copyright                *
 *    notice, this list of conditions and the following disclaimer.                 *
 * 2. Redistributions in binary form must reproduce the above copyright             *
 *    notice, this list of conditions and the following disclaimer in the           *
 *    documentation and/or other materials provided with the distribution.          *
 *                                                                                  *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND           *
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE            *
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE       *
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE          *
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL       *
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS          *
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)            *
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT       *
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY        *
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF           *
 * SUCH DAMAGE.                                                                     *
 ************************************************************************************/

#include <sys/types.h>
// Welesh : compat
#if   !defined (WIN32)
#include <sys/time.h>
#include <regex.h>
#else
#include "compat\regex-win32\regex.h"
#endif

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "merc.h"
#include "db/db.h"

/* stuff for recycling extended descs */
extern int top_ed;
extern void free_contacts(CHAR_DATA *ch);
extern void nuke_slaves (CHAR_DATA *ch);

ED_DATA *ed_new(void)
{
    ED_DATA *ed;
    ed = calloc(1, sizeof(*ed));
    top_ed++;
    return ed;
}

ED_DATA *ed_new2(const ED_DATA *ed, const char* name)
{
    ED_DATA *ed2        = ed_new();
    ed2->keyword        = str_dup(ed->keyword);
    ed2->description    = mlstr_printf(ed->description, name);
    return ed2;
}

ED_DATA *ed_dup(const ED_DATA *ed)
{
    ED_DATA *ned = ed_new();
    ned->keyword        = str_dup(ed->keyword);
    ned->description    = mlstr_dup(ed->description);
    return ned;
}

void ed_free(ED_DATA *ed)
{
    if (!ed)
        return;

    free_string(ed->keyword);
    mlstr_free(ed->description);
    free(ed);
    top_ed--;
}

void ed_fread(FILE *fp, ED_DATA **edp)
{
    ED_DATA *ed = ed_new();
    ed->keyword = fread_string(fp);
    ed->description = mlstr_fread(fp);
    SLIST_ADD(ED_DATA, *edp, ed);
}

void ed_fwrite(FILE *fp, ED_DATA *ed)
{
        fprintf(fp, "E\n%s~\n", fix_string(ed->keyword));
    mlstr_fwrite(fp, NULL, ed->description);
}

AFFECT_DATA *aff_new(void)
{
    return calloc(1, sizeof(AFFECT_DATA));
}

AFFECT_DATA *aff_dup(const AFFECT_DATA *paf)
{
    AFFECT_DATA *naf = aff_new();
    naf->where  = paf->where;
    naf->type   = paf->type;
    naf->level  = paf->level;
    naf->duration   = paf->duration;
    naf->location   = paf->location;
    naf->modifier   = paf->modifier;
    naf->bitvector  = paf->bitvector;
    return naf;
}

void aff_free(AFFECT_DATA *af)
{
    free(af);
}

OBJ_DATA *free_obj_list;

OBJ_DATA *new_obj(void)
{
    OBJ_DATA *obj;

    if (free_obj_list) {
        obj = free_obj_list;
        free_obj_list = free_obj_list->next;
        memset(obj, '\0', sizeof(*obj));
    }
    else
        obj = calloc(1, sizeof(*obj));

    return obj;
}

void free_obj(OBJ_DATA *obj)
{
    AFFECT_DATA *paf, *paf_next;
    ED_DATA     *ed,  *ed_next;
    KEY_DATA    *key, *key_next;

    if (!obj)
        return;

    for (paf = obj->affected; paf; paf = paf_next)
    {
        paf_next = paf->next;
        aff_free(paf);
    }

    obj->affected = NULL;

    for (ed = obj->ed; ed != NULL; ed = ed_next )
    {
        ed_next = ed->next;
        ed_free(ed);
    }

    obj->ed = NULL;

    if (obj->keys)
    {
      // loop thru the keys and free the allocated memory
      for ( key = obj->keys; key != NULL; key = key_next)
      {
          key_next = key->next;
          free_key(key);
      }
    }

    free_string(obj->name);
    obj->name = NULL;

    mlstr_free(obj->description);
    obj->description = NULL;

    mlstr_free(obj->short_descr);
    obj->short_descr = NULL;

    free_string(obj->owner);
    obj->owner = NULL;

    free_string(obj->material);
    obj->material = NULL;

    obj->next = free_obj_list;
    free_obj_list = obj;

}

CHAR_DATA *free_char_list;

CHAR_DATA *new_char (void)
{
    CHAR_DATA *ch;
    int i;

    if (free_char_list) {
        ch = free_char_list;
        free_char_list = free_char_list->next;
        memset(ch, '\0', sizeof(*ch));
    }
    else
        ch = calloc(1, sizeof(*ch));

    ch->remembered_rooms.nsize = sizeof(memento_t);
    ch->remembered_rooms.nstep = 4;
    ch->remembered_objects.nsize = sizeof(memento_t);
    ch->remembered_objects.nstep = 4;
    ch->remembered_mobs.nsize = sizeof(memento_t);
    ch->remembered_mobs.nstep = 4;
    ch->remembered_people.nsize = sizeof(memento_t);
    ch->remembered_people.nstep = 4;

    RESET_FIGHT_TIME(ch);
    ch->last_death_time = -1;
    ch->prefix      = str_empty;
    ch->lines       = PAGELEN;
    ch->logon       = current_time;
    ch->hit         = 20;
    ch->max_hit     = 20;
    ch->mana        = 100;
    ch->max_mana        = 100;
    ch->move        = 100;
    ch->max_move        = 100;
    ch->psp     = 10;
    ch->position        = POS_STANDING;
    for (i = 0; i < 4; i++)
        ch->armor[i]    = 100;
    for (i = 0; i < MAX_STATS; i++)
        ch->perm_stat[i] = 13;
    for (i = 0; i < MAX_DAM; i++)
        ch->resists[i] = 0;
    ch->immunes = 0;
    free_contacts(ch);
    ch->doppel = ch;
    return ch;
}

extern int mobile_count;

void free_char(CHAR_DATA *ch)
{
    OBJ_DATA *obj;
    OBJ_DATA *obj_next;
    AFFECT_DATA *paf;
    AFFECT_DATA *paf_next;

    if (!ch)
        return;

    if (IS_NPC(ch))
        mobile_count--;

    for (obj = ch->carrying; obj; obj = obj_next) {
        obj_next = obj->next_content;
        extract_obj_nocount(obj);
    }

    for (paf = ch->affected; paf; paf = paf_next) {
        paf_next = paf->next;
        affect_remove(ch,paf);
    }
    ch->affected = NULL;

    nuke_slaves (ch);

    free_string(ch->name);
    ch->name = NULL;

    mlstr_free(ch->short_descr);
    ch->short_descr = NULL;

    mlstr_free(ch->long_descr);
    ch->long_descr = NULL;

    mlstr_free(ch->description);
    ch->description = NULL;

    mlstr_free(ch->listen_data);
    ch->listen_data = NULL;

    free_string(ch->prompt);
    ch->prompt = NULL;

    free_string(ch->prefix);
    ch->prefix = NULL;

    free_string(ch->material);
    ch->material = NULL;

    free_string(ch->in_mind);
    ch->in_mind = NULL;

#ifdef IMC
    imc_freechardata(ch);
#endif
#ifdef I3
    free_i3chardata(ch);
#endif

    free_pcdata(ch->pcdata);
    ch->pcdata = NULL;

    free_contacts(ch);
    ch->doppel = NULL;

    varr_free(&ch->remembered_rooms);
    varr_free(&ch->remembered_objects);
    varr_free(&ch->remembered_mobs);
    varr_free(&ch->remembered_people);

    ch->next = free_char_list;
    free_char_list = ch;

    if (ch->in_room != NULL)
    {
        // fuck this, it wouldn't help
        //bug("BINGO! free_char: ch->in_room != NULL (%d)", ch->in_room->vnum);
    }
}

CHAR_EXPLORED_DATA * new_char_explored_data(void)
{
    CHAR_EXPLORED_DATA *explored_data;

    explored_data = calloc(1, sizeof(*explored_data));
    explored_data->name = str_empty;

    return explored_data;
}

void free_char_explored_data(CHAR_EXPLORED_DATA *explored_data)
{
    CHAR_EXPLORED_DATA *curr_area;
    CHAR_EXPLORED_DATA *next_area;

    if (!explored_data)
        return;

    for (curr_area = explored_data; curr_area;)
    {
        next_area = curr_area->next;
        free_string(curr_area->name);
        free(curr_area);
        curr_area = next_area;
    }
}

PC_DATA * new_pcdata(void)
{
    PC_DATA * pcdata;
    int       i;   

    pcdata = calloc(1, sizeof(*pcdata));
    pcdata->buffer = buf_new(-1);
    pcdata->learned.nsize = sizeof(pcskill_t);
    pcdata->learned.nstep = 8;
    pcdata->pwd = str_empty;
    pcdata->bamfin = str_empty;
    pcdata->bamfout = str_empty;
    pcdata->title = str_empty;
    pcdata->pretitle = str_empty;
    pcdata->twitlist = str_empty;
    pcdata->linked_list = str_empty;
    pcdata->granted = str_empty;
    pcdata->host = str_empty;
    pcdata->last_login = str_empty;
    pcdata->marryed = str_empty;
    pcdata->proposal = str_empty;
    pcdata->prog_vars = str_empty;
    pcdata->last_divorce    =   -1;
    pcdata->last_marry = -1;
    
    for (i = 0; i < 6; ++i)
        pcdata->rusnames[i] = NULL;

    return pcdata;
}

void free_pcdata(PC_DATA *pcdata)
{
    int alias;

    if (!pcdata)
        return;

    varr_free(&pcdata->learned);
    free_string(pcdata->pwd);
    free_string(pcdata->bamfin);
    free_string(pcdata->bamfout);
    free_string(pcdata->title);
    free_string(pcdata->pretitle);
    free_string(pcdata->twitlist);
    free_string(pcdata->linked_list);
    free_string(pcdata->granted);
    free_string(pcdata->host);
    free_string(pcdata->last_login);
    free_string(pcdata->marryed);
    free_string(pcdata->proposal);
    free_string(pcdata->prog_vars);
    buf_free(pcdata->buffer);

    /* in this function ALL of the explored areas are being released */
    free_char_explored_data(pcdata->explored_areas);

    for (alias = 0; alias < MAX_ALIAS; alias++) {
        free_string(pcdata->alias[alias]);
        free_string(pcdata->alias_sub[alias]);
    }
    free(pcdata);
}

/* stuff for setting ids */
long    last_pc_id;
long    last_mob_id;
long    last_obj_id;

long get_pc_id(void)
{
    return last_pc_id = (current_time <= last_pc_id) ?
                last_pc_id + 1 : current_time;
}

long get_mob_id(void)
{
    last_mob_id++;
    return last_mob_id;
}

long get_obj_id(void)
{
    last_obj_id++;
    return last_obj_id;
}

MPTRIG *mptrig_new(int type, const char *phrase, int vnum)
{
    const char *p;
    MPTRIG *mptrig;

    mptrig = calloc(1, sizeof(*mptrig));
    mptrig->type    = type;
    mptrig->vnum    = vnum;
    mptrig->phrase  = str_dup(phrase);

    for (p = mptrig->phrase; *p; p++)
        if (ISUPPER(*p)) {
            SET_BIT(mptrig->flags, TRIG_CASEDEP);
            break;
        }

    if ((type == TRIG_ACT || type == TRIG_SPEECH) && phrase[0] == '*') {
        int errcode;
        int cflags = REG_EXTENDED | REG_NOSUB;

        SET_BIT(mptrig->flags, TRIG_REGEXP);
        if (!IS_SET(mptrig->flags, TRIG_CASEDEP))
            cflags |= REG_ICASE;

        mptrig->extra = malloc(sizeof(regex_t));
        errcode = regcomp(mptrig->extra, phrase+1, cflags);
        if (errcode) {
            char buf[MAX_STRING_LENGTH];

            regerror(errcode, mptrig->extra, buf, sizeof(buf));
            log_printf("bad MOB trigger for vnum %d (phrase '%s'): %s",
                   vnum, phrase, buf);
        }
    }

    return mptrig;
}

void mptrig_add(MOB_INDEX_DATA *mob, MPTRIG *mptrig)
{
    SET_BIT(mob->mptrig_types, mptrig->type);
    SLIST_ADD(MPTRIG, mob->mptrig_list, mptrig);
}

void mptrig_fix(MOB_INDEX_DATA *mob)
{
    MPTRIG *mptrig;

    for (mptrig = mob->mptrig_list; mptrig; mptrig = mptrig->next)
        SET_BIT(mob->mptrig_types, mptrig->type);
}

void mptrig_free(MPTRIG *mp)
{
    if (!mp)
        return;

    if (IS_SET(mp->flags, TRIG_REGEXP)) {
        regfree(mp->extra);
        free(mp->extra);
    }

    free_string(mp->phrase);
    free(mp);
}


/*--------------------------  OBJ Sections -----------------*/
void optrig_add(OBJ_INDEX_DATA *obj, MPTRIG *optrig)
{
    SET_BIT(obj->oprog_flags, optrig->type);
    SLIST_ADD(MPTRIG, obj->oprogs, optrig);
}


MPTRIG *optrig_new(int type, const char *phrase, int vnum)
{
    const char *p;
    MPTRIG *optrig;

    optrig = calloc(1, sizeof(*optrig));
    optrig->type    = type;
    optrig->vnum    = vnum;
    optrig->phrase  = str_dup(phrase);

    for (p = optrig->phrase; *p; p++)
        if (ISUPPER(*p))
        {
            SET_BIT(optrig->flags, TRIG_CASEDEP);
            break;
        }

    if ((type == TRIG_ACT || type == TRIG_SPEECH) && phrase[0] == '*')
    {
        int errcode;
        int cflags = REG_EXTENDED | REG_NOSUB;

        SET_BIT(optrig->flags, TRIG_REGEXP);
        if (!IS_SET(optrig->flags, TRIG_CASEDEP))
            cflags |= REG_ICASE;

        optrig->extra = malloc(sizeof(regex_t));
        errcode = regcomp(optrig->extra, phrase+1, cflags);
        if (errcode)
        {
            char buf[MAX_STRING_LENGTH];

            regerror(errcode, optrig->extra, buf, sizeof(buf));
            log_printf("bad OBJ trigger for vnum %d (phrase '%s'): %s", vnum, phrase, buf);
        }
    }

    return optrig;
}

void optrig_fix(OBJ_INDEX_DATA *obj)
{
    MPTRIG *optrig;

    for (optrig = obj->oprogs; optrig; optrig = optrig->next)
        SET_BIT(obj->oprog_flags, optrig->type);
}

void optrig_free(MPTRIG *op)
{
    if (!op)
        return;

    if (IS_SET(op->flags, TRIG_REGEXP))
    {
        regfree(op->extra);
        free(op->extra);
    }

    free_string(op->phrase);
    free(op);
}

/*--------------------------  OBJ Sections -----------------*/

void rptrig_add(ROOM_INDEX_DATA *room, MPTRIG *rptrig)
{
    SET_BIT(room->rprog_flags, rptrig->type);
    SLIST_ADD(MPTRIG, room->rprogs, rptrig);
}


MPTRIG *rptrig_new(int type, const char *phrase, int vnum)
{
    const char *p;
    MPTRIG *rptrig;

    rptrig = calloc(1, sizeof(*rptrig));
    rptrig->type    = type;
    rptrig->vnum    = vnum;
    rptrig->phrase  = str_dup(phrase);

    for (p = rptrig->phrase; *p; p++)
        if (ISUPPER(*p))
        {
            SET_BIT(rptrig->flags, TRIG_CASEDEP);
            break;
        }

    if ((type == TRIG_ACT || type == TRIG_SPEECH) && phrase[0] == '*')
    {
        int errcode;
        int cflags = REG_EXTENDED | REG_NOSUB;

        SET_BIT(rptrig->flags, TRIG_REGEXP);
        if (!IS_SET(rptrig->flags, TRIG_CASEDEP))
            cflags |= REG_ICASE;

        rptrig->extra = malloc(sizeof(regex_t));
        errcode = regcomp(rptrig->extra, phrase+1, cflags);
        if (errcode)
        {
            char buf[MAX_STRING_LENGTH];

            regerror(errcode, rptrig->extra, buf, sizeof(buf));
            log_printf("bad ROOM trigger for vnum %d (phrase '%s'): %s", vnum, phrase, buf);
        }
    }

    return rptrig;
}


void rptrig_fix(ROOM_INDEX_DATA *room)
{
    MPTRIG *rptrig;

    for (rptrig = room->rprogs; rptrig; rptrig = rptrig->next)
        SET_BIT(room->rprog_flags, rptrig->type);
}

void rptrig_free(MPTRIG *rp)
{
    if (!rp)
        return;

    if (IS_SET(rp->flags, TRIG_REGEXP))
    {
        regfree(rp->extra);
        free(rp->extra);
    }

    free_string(rp->phrase);
    free(rp);
}