/***************************************************************************
 *  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
 *  Michael Seifert, Hans Henrik Strfeldt, 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-1998 Russ Taylor                             *
 *  ROM has been brought to you by the ROM consortium                      *
 *      Russ Taylor (rtaylor@hypercube.org)                                *
 *      Gabrielle Taylor (gtaylor@hypercube.org)                           *
 *      Brian Moore (zump@rom.org)                                         *
 *  By using this code, you have agreed to follow the terms of the         *
 *  ROM license, in the file Rom24/doc/rom.license                         *
 ***************************************************************************/

#if defined(macintosh)
#include <types.h>
#include <ctime>
#else
#include <sys/types.h>
#include <sys/time.h>
#endif
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include "merc.h"
#include "recycle.h"

AREA_DATA *area_free;
EXIT_DATA *exit_free;
ROOM_INDEX_DATA *room_index_free;
SHOP_DATA *shop_free;
RESET_DATA *reset_free;
OBJ_INDEX_DATA * obj_index_free;
MOB_INDEX_DATA *mob_index_free;
AFFECT_DATA *affect_free;
EVENT *ev_free;
VARIABLE_DATA *var_free;
NOTE_DATA *note_free;
BAN_DATA *ban_free;
DESCRIPTOR_DATA *descriptor_free;
EXTRA_DESCR_DATA *extra_descr_free;
OBJ_DATA *obj_free;
CHAR_DATA *char_free;
PC_DATA *pcdata_free;
MEM_DATA *mem_data_free;
BUFFER *buf_free;
HELP_DATA *help_free;

PROG_LIST *mprog_free;
PROG_LIST *oprog_free;
PROG_LIST *rprog_free;

PROG_CODE *mpcode_free;
PROG_CODE *opcode_free;
PROG_CODE *rpcode_free;

PROG_CODE *mprog_list;
PROG_CODE *oprog_list;
PROG_CODE *rprog_list;


extern int top_reset;
extern int top_area;
extern int top_exit;
extern int top_ed;
extern int top_room;
extern int top_mprog_index;
extern int top_oprog_index;
extern int top_rprog_index;




/*Recycle events*/
EVENT *new_event(char *comments)
{
     static EVENT ev_zero;
     EVENT *ev;

    if (ev_free == NULL)
        ev = (EVENT *) alloc_perm(sizeof(*ev));
    else
    {
        ev = ev_free;
        ev_free = ev_free->next;
    }

    *ev = ev_zero;

    ev->comments = str_dup(comments);
    ev->kill_event = FALSE;
    VALIDATE(ev);
    return ev;
}

void free_event(EVENT *ev)
{
    if (!IS_VALID(ev))
        return;

    INVALIDATE(ev);

    free_string(ev->comments);
    ev->next = ev_free;
    ev_free = ev;
}

// JH 3/17/2004 2:55AM
VARIABLE_DATA *new_variable(void *attach, int type, char *v_name, char *v_string, float v_float)
{
    static VARIABLE_DATA var_zero;
    VARIABLE_DATA *var;

    if (var_free == NULL)
        var = (VARIABLE_DATA *) alloc_perm(sizeof(*var));
    else
    {
        var = var_free;
        var_free = var_free->next;
    }

    *var = var_zero;

    switch (type)
    {
        case MOB:
            var->attached.ch = (CHAR_DATA *)attach;
            break;
        case OBJ:
            var->attached.obj = (OBJ_DATA *)attach;
            break;
        case ROOM:
            var->attached.room = (ROOM_INDEX_DATA *)attach;
            break;
        case PROG:
            var->attached.prog = (PROG_CODE *)attach;
            break;
    }
    
    var->name = str_dup(v_name);
    var->var_string = str_dup(v_string);
    var->var_float = v_float;
    
    VALIDATE(var);
    return var;
}

//JH 3/17/2004 2:55AM
void free_variable(VARIABLE_DATA *var)
{
    if (!IS_VALID(var))
        return;

    INVALIDATE(var);

    free_string(var->var_string);
    free_string(var->name);
    var->next = var_free;
    var_free = var;

}

/* stuff for recyling notes */
NOTE_DATA *new_note()
{
    NOTE_DATA *note;

    if (note_free == NULL)
	    note = (NOTE_DATA *) alloc_perm(sizeof(*note));
    else
    { 
	    note = note_free;
	    note_free = note_free->next;
    }
    VALIDATE(note);
    return note;
}

void free_note(NOTE_DATA *note)
{
    if (!IS_VALID(note))
	return;

    free_string( note->text    );
    free_string( note->subject );
    free_string( note->to_list );
    free_string( note->date    );
    free_string( note->sender  );
    INVALIDATE(note);

    note->next = note_free;
    note_free   = note;
}

/* stuff for recycling ban structures */
BAN_DATA *new_ban (void)
{
    static BAN_DATA ban_zero;
    BAN_DATA *ban;

    if (ban_free == NULL)
        ban = (BAN_DATA *) alloc_perm (sizeof (*ban));
    else
    {
        ban = ban_free;
        ban_free = ban_free->next;
    }

    *ban = ban_zero;
    VALIDATE (ban);
    ban->name = &str_empty[0];
    return ban;
}

void free_ban (BAN_DATA * ban)
{
    if (!IS_VALID (ban))
        return;

    free_string (ban->name);
    INVALIDATE (ban);

    ban->next = ban_free;
    ban_free = ban;
}

/* stuff for recycling descriptors */
DESCRIPTOR_DATA *new_descriptor (void)
{
    static DESCRIPTOR_DATA d_zero;
    DESCRIPTOR_DATA *d;

    if (descriptor_free == NULL)
        d = (DESCRIPTOR_DATA *) alloc_perm (sizeof (*d));
    else
    {
        d = descriptor_free;
        descriptor_free = descriptor_free->next;
    }

    *d = d_zero;
    VALIDATE (d);

    d->connected = CON_GET_NAME;
    d->showstr_head = NULL;
    d->showstr_point = NULL;
    d->outsize = 2000;
    d->outbuf = (char *) alloc_mem (d->outsize);

    return d;
}

void free_descriptor (DESCRIPTOR_DATA * d)
{
    if (!IS_VALID (d))
        return;

    free_string (d->host);
    free_mem (d->outbuf, d->outsize);
    INVALIDATE (d);
    d->next = descriptor_free;
    descriptor_free = d;
}

/* stuff for recycling extended descs */
EXTRA_DESCR_DATA *new_extra_descr (void)
{
    EXTRA_DESCR_DATA *ed;

    if (extra_descr_free == NULL)
        ed = (EXTRA_DESCR_DATA *) alloc_perm (sizeof (*ed));
    else
    {
        ed = extra_descr_free;
        extra_descr_free = extra_descr_free->next;
    }

    ed->keyword = &str_empty[0];
    ed->description = &str_empty[0];
    VALIDATE (ed);
    return ed;
}

void free_extra_descr (EXTRA_DESCR_DATA * ed)
{
    if (!IS_VALID (ed))
        return;

    free_string (ed->keyword);
    free_string (ed->description);
    INVALIDATE (ed);

    ed->next = extra_descr_free;
    extra_descr_free = ed;
}


/* stuff for recycling affects */

AFFECT_DATA *new_affect (void)
{
    static AFFECT_DATA af_zero;
    AFFECT_DATA *af;

    if (affect_free == NULL)
        af = (AFFECT_DATA *) alloc_perm (sizeof (*af));
    else
    {
        af = affect_free;
        affect_free = affect_free->next;
    }

    *af = af_zero;


    VALIDATE (af);
    return af;
}

void free_affect (AFFECT_DATA * af)
{
    if (!IS_VALID (af))
        return;

    INVALIDATE (af);
    af->next = affect_free;
    affect_free = af;
}

/* stuff for recycling objects */
OBJ_DATA *new_obj (void)
{
    static OBJ_DATA obj_zero;
    OBJ_DATA *obj;

    if (obj_free == NULL)
        obj = (OBJ_DATA *) alloc_perm (sizeof (*obj));
    else
    {
        obj = obj_free;
        obj_free = obj_free->next;
    }
    *obj = obj_zero;
    VALIDATE (obj);

    return obj;
}

void free_obj (OBJ_DATA * obj)
{
    AFFECT_DATA *paf, *paf_next;
    EXTRA_DESCR_DATA *ed, *ed_next;

    if (!IS_VALID (obj))
        return;

    for (paf = obj->affected; paf != NULL; paf = paf_next)
    {
        paf_next = paf->next;
        free_affect (paf);
    }
    obj->affected = NULL;

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

    free_string (obj->name);
    free_string (obj->description);
    free_string (obj->short_descr);
    free_string (obj->owner);
    INVALIDATE (obj);

    obj->next = obj_free;
    obj_free = obj;
}


/* stuff for recyling characters */
CHAR_DATA *new_char (void)
{
    static CHAR_DATA ch_zero;
    CHAR_DATA *ch;
    int i;

    if (char_free == NULL)
        ch = (CHAR_DATA *) alloc_perm (sizeof (*ch));
    else
    {
        ch = char_free;
        char_free = char_free->next;
    }

    *ch = ch_zero;
    VALIDATE (ch);
    ch->name = &str_empty[0];
    ch->short_descr = &str_empty[0];
    ch->long_descr = &str_empty[0];
    ch->description = &str_empty[0];
    ch->prompt = &str_empty[0];
    ch->prefix = &str_empty[0];
    ch->logon = current_time;
    ch->lines = PAGELEN;
    for (i = 0; i < 4; i++)
        ch->armor[i] = 100;
    ch->position = POS_STANDING;
    ch->hit = 85;
    ch->max_hit = 85;
    ch->move = 100;
    ch->max_move = 100;

    for (i = 0; i < MAX_MAGIC_TYPE; i++)
    {
        ch->magic_points[i] = 100;
        ch->max_magic_points[i] = 100;
    }
    for (i = 0; i < MAX_STATS; i++)
    {
        ch->perm_stat[i] = 13;
        ch->mod_stat[i] = 0;
    }

    return ch;
}


void free_char (CHAR_DATA * ch)
{
    OBJ_DATA *obj;
    OBJ_DATA *obj_next;
    AFFECT_DATA *paf;
    AFFECT_DATA *paf_next;
    MENU_DATA *menu = NULL, *menu_next = NULL;
    
    if (!IS_VALID (ch))
        return;

    if (IS_NPC (ch))
        mobile_count--;

    for (obj = ch->carrying; obj != NULL; obj = obj_next)
    {
        obj_next = obj->next_content;
        extract_obj (obj);
    }

    for (paf = ch->affected; paf != NULL; paf = paf_next)
    {
        paf_next = paf->next;
        affect_remove (ch, paf);
    }
    
    if (!IS_NPC(ch))
    {
        for (menu = ch->pcdata->menu; menu; menu = menu_next)
        {
            menu_next = menu->next;
            menu_from_char(ch, menu);
            free_menu(menu);
        }
    }
    
    free_string (ch->name);
    free_string (ch->short_descr);
    free_string (ch->long_descr);
    free_string (ch->description);
    free_string (ch->prompt);
    free_string (ch->prefix);
    free_note (ch->pnote); 
    free_pcdata (ch->pcdata);

    ch->next = char_free;
    char_free = ch;

    INVALIDATE (ch);
    return;
}

PC_DATA *new_pcdata (void)
{
    int alias;

    static PC_DATA pcdata_zero;
    PC_DATA *pcdata;

    if (pcdata_free == NULL)
        pcdata = (PC_DATA *) alloc_perm (sizeof (*pcdata));
    else
    {
        pcdata = pcdata_free;
        pcdata_free = pcdata_free->next;
    }

    *pcdata = pcdata_zero;

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

    pcdata->buffer = new_buf ();
    pcdata->menu_locked = NULL;
    
    VALIDATE (pcdata);
    return pcdata;
}


void free_pcdata (PC_DATA * pcdata)
{
    int alias;

    if (!IS_VALID (pcdata))
        return;

    free_string (pcdata->pwd);
    free_string (pcdata->bamfin);
    free_string (pcdata->bamfout);
    free_string (pcdata->title);
    free_buf (pcdata->buffer);
    
    for (alias = 0; alias < MAX_ALIAS; alias++)
    {
        free_string (pcdata->alias[alias]);
        free_string (pcdata->alias_sub[alias]);
    }
    
    INVALIDATE (pcdata);
    pcdata->next = pcdata_free;
    pcdata_free = pcdata;

    return;
}




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

long get_pc_id (void)
{
    int val;

    val = (current_time <= last_pc_id) ? last_pc_id + 1 : current_time;
    last_pc_id = val;
    return val;
}

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


/* procedures and constants needed for buffering */
MEM_DATA *new_mem_data (void)
{
    MEM_DATA *memory;

    if (mem_data_free == NULL)
        memory = (MEM_DATA *) alloc_mem (sizeof (*memory));
    else
    {
        memory = mem_data_free;
        mem_data_free = mem_data_free->next;
    }

    memory->next = NULL;
    memory->id = 0;
    memory->reaction = 0;
    memory->when = 0;
    VALIDATE (memory);

    return memory;
}

void free_mem_data (MEM_DATA * memory)
{
    if (!IS_VALID (memory))
        return;

    memory->next = mem_data_free;
    mem_data_free = memory;
    INVALIDATE (memory);
}



/* buffer sizes */
const int buf_size[MAX_BUF_LIST] = {
    16, 32, 64, 128, 256, 1024, 2048, 4096, 8192, 16384
};

/* local procedure for finding the next acceptable size */
/* -1 indicates out-of-boundary error */
int get_size (int val)
{
    int i;

    for (i = 0; i < MAX_BUF_LIST; i++)
        if (buf_size[i] >= val)
        {
            return buf_size[i];
        }

    return -1;
}

BUFFER *new_buf ()
{
    BUFFER *buffer;

    if (buf_free == NULL)
        buffer = (BUFFER *) alloc_perm (sizeof (*buffer));
    else
    {
        buffer = buf_free;
        buf_free = buf_free->next;
    }

    buffer->next = NULL;
    buffer->state = BUFFER_SAFE;
    buffer->size = get_size (BASE_BUF);

    buffer->string = (char *) alloc_mem (buffer->size);
    buffer->string[0] = '\0';
    VALIDATE (buffer);

    return buffer;
}

BUFFER *new_buf_size (int size)
{
    BUFFER *buffer;

    if (buf_free == NULL)
        buffer = (BUFFER *) alloc_perm (sizeof (*buffer));
    else
    {
        buffer = buf_free;
        buf_free = buf_free->next;
    }

    buffer->next = NULL;
    buffer->state = BUFFER_SAFE;
    buffer->size = get_size (size);
    if (buffer->size == -1)
    {
        bug ("new_buf: buffer size %d too large.", size);
        exit (1);
    }
    buffer->string = (char *) alloc_mem (buffer->size);
    buffer->string[0] = '\0';
    VALIDATE (buffer);

    return buffer;
}


void free_buf (BUFFER * buffer)
{
    if (!IS_VALID (buffer))
        return;

    free_mem (buffer->string, buffer->size);
    buffer->string = NULL;
    buffer->size = 0;
    buffer->state = BUFFER_FREED;
    INVALIDATE (buffer);

    buffer->next = buf_free;
    buf_free = buffer;
}


bool add_buf (BUFFER * buffer, const char *string)
{
    int len;
    char *oldstr;
    int oldsize;

    oldstr = buffer->string;
    oldsize = buffer->size;

    if (buffer->state == BUFFER_OVERFLOW)    /* don't waste time on bad strings! */
        return FALSE;

    len = strlen (buffer->string) + strlen (string) + 1;

    while (len >= buffer->size)
    {                            /* increase the buffer size */
        buffer->size = get_size (buffer->size + 1);
        {
            if (buffer->size == -1)
            {                    /* overflow */
                buffer->size = oldsize;
                buffer->state = BUFFER_OVERFLOW;
                bug ("buffer overflow past size %d", buffer->size);
                return FALSE;
            }
        }
    }

    if (buffer->size != oldsize)
    {
        buffer->string = (char *) alloc_mem (buffer->size);

        strcpy (buffer->string, oldstr);
        free_mem (oldstr, oldsize);
    }

    strcat (buffer->string, string);
    return TRUE;
}


void clear_buf (BUFFER * buffer)
{
    buffer->string[0] = '\0';
    buffer->state = BUFFER_SAFE;
}


char *buf_string (BUFFER * buffer)
{
    return buffer->string;
}

/* stuff for recycling mobprograms */

PROG_LIST *new_mprog (void)
{
    static PROG_LIST mp_zero;
    PROG_LIST *mp;

    if (mprog_free == NULL)
        mp = ( PROG_LIST *) alloc_perm (sizeof (*mp));
    else
    {
        mp = mprog_free;
        mprog_free = mprog_free->next;
    }

    *mp = mp_zero;
    mp->vnum = 0;
    mp->trig_type = 0;
    mp->code = str_dup ("");
    VALIDATE (mp);
    return mp;
}

void free_mprog (PROG_LIST * mp)
{
    if (!IS_VALID (mp))
        return;

    INVALIDATE (mp);
    mp->next = mprog_free;
    mprog_free = mp;
}

HELP_DATA *new_help (void)
{
    HELP_DATA *help;

    if (help_free)
    {
        help = help_free;
        help_free = help_free->next;
    }
    else
        help = (HELP_DATA *) alloc_perm (sizeof (*help));

    return help;
}

void free_help (HELP_DATA * help)
{
    free_string (help->keyword);
    free_string (help->text);
    help->next = help_free;
    help_free = help;
}

PROG_LIST *new_oprog(void)
{
   static PROG_LIST op_zero;
   PROG_LIST *op;

   if (oprog_free == NULL)
       op = (PROG_LIST *) alloc_perm(sizeof(*op));
   else
   {
       op = oprog_free;
       oprog_free=oprog_free->next;
   }

   *op = op_zero;
   op->vnum             = 0;
   op->trig_type        = 0;
   op->code             = str_dup("");
   VALIDATE(op);
   return op;
}

void free_oprog(PROG_LIST *op)
{
   if (!IS_VALID(op))
      return;

   INVALIDATE(op);
   op->next = oprog_free;
   oprog_free = op;
}

PROG_LIST *new_rprog(void)
{
   static PROG_LIST rp_zero;
   PROG_LIST *rp;

   if (rprog_free == NULL)
       rp = (PROG_LIST *) alloc_perm(sizeof(*rp));
   else
   {
       rp = rprog_free;
       rprog_free=rprog_free->next;
   }

   *rp = rp_zero;
   rp->vnum             = 0;
   rp->trig_type        = 0;
   rp->code             = str_dup("");
   VALIDATE(rp);
   return rp;
}

void free_rprog(PROG_LIST *rp)
{
   if (!IS_VALID(rp))
      return;

   INVALIDATE(rp);
   rp->next = rprog_free;
   rprog_free = rp;
}

void free_extra_descr args ((EXTRA_DESCR_DATA * pExtra));
void free_affect args ((AFFECT_DATA * af));
void free_mprog args ((PROG_LIST * mp));
void free_oprog args ( ( PROG_LIST *op ) );
void free_rprog args ( ( PROG_LIST *rp ) );


RESET_DATA *new_reset_data (void)
{
    RESET_DATA *pReset;

    if (!reset_free)
    {
        pReset = (RESET_DATA *) alloc_perm (sizeof (*pReset));
        top_reset++;
    }
    else
    {
        pReset = reset_free;
        reset_free = reset_free->next;
    }

    pReset->next = NULL;
    pReset->command = 'X';
    pReset->arg1 = 0;
    pReset->arg2 = 0;
    pReset->arg3 = 0;
    pReset->arg4 = 0;

    return pReset;
}



void free_reset_data (RESET_DATA * pReset)
{
    pReset->next = reset_free;
    reset_free = pReset;
    return;
}



AREA_DATA *new_area (void)
{
    AREA_DATA *pArea;
    char buf[MAX_INPUT_LENGTH];

    if (!area_free)
    {
        pArea = (AREA_DATA *) alloc_perm (sizeof (*pArea));
        top_area++;
    }
    else
    {
        pArea = area_free;
        area_free = area_free->next;
    }

    pArea->next = NULL;
    pArea->name = str_dup ("New area");
/*    pArea->recall           =   ROOM_VNUM_TEMPLE;      ROM OLC */
    pArea->area_flags = AREA_ADDED;
    pArea->security = 1;
    pArea->builders = str_dup ("None");
    pArea->min_vnum = 0;
    pArea->max_vnum = 0;
    pArea->age = 0;
    pArea->nplayer = 0;
    pArea->empty = TRUE;        /* ROM patch */
    sprintf (buf, "area%d.are", pArea->vnum);
    pArea->file_name = str_dup (buf);
    pArea->vnum = top_area - 1;

    return pArea;
}



void free_area (AREA_DATA * pArea)
{
    free_string (pArea->name);
    free_string (pArea->file_name);
    free_string (pArea->builders);
    free_string (pArea->credits);

    pArea->next = area_free->next;
    area_free = pArea;
    return;
}



EXIT_DATA *new_exit (void)
{
    EXIT_DATA *pExit;

    if (!exit_free)
    {
        pExit = (EXIT_DATA *) alloc_perm (sizeof (*pExit));
        top_exit++;
    }
    else
    {
        pExit = exit_free;
        exit_free = exit_free->next;
    }

    pExit->u1.to_room = NULL;    /* ROM OLC */
    pExit->next = NULL;
/*  pExit->vnum         =   0;                        ROM OLC */
    pExit->exit_info = 0;
    pExit->key = 0;
    pExit->keyword = &str_empty[0];
    pExit->description = &str_empty[0];
    pExit->rs_flags = 0;

    return pExit;
}



void free_exit (EXIT_DATA * pExit)
{
    free_string (pExit->keyword);
    free_string (pExit->description);

    pExit->next = exit_free;
    exit_free = pExit;
    return;
}


ROOM_INDEX_DATA *new_room_index (void)
{
    ROOM_INDEX_DATA *pRoom;
    int door;

    if (!room_index_free)
    {
        pRoom = (ROOM_INDEX_DATA *) alloc_perm (sizeof (*pRoom));
        top_room++;
    }
    else
    {
        pRoom = room_index_free;
        room_index_free = room_index_free->next;
    }

    pRoom->next = NULL;
    pRoom->people = NULL;
    pRoom->contents = NULL;
    pRoom->extra_descr = NULL;
    pRoom->area = NULL;

    for (door = 0; door < MAX_DIR; door++)
        pRoom->exit[door] = NULL;

    pRoom->name = &str_empty[0];
    pRoom->description = &str_empty[0];
    pRoom->owner = &str_empty[0];
    pRoom->vnum = 0;
    pRoom->room_flags = 0;
    pRoom->light = 0;
    pRoom->sector_type = 0;
    pRoom->clan = 0;
    pRoom->heal_rate = 100;
    pRoom->mregen_rate = 100;

    return pRoom;
}



void free_room_index (ROOM_INDEX_DATA * pRoom)
{
    int door;
    EXTRA_DESCR_DATA *pExtra;
    RESET_DATA *pReset;

    free_string (pRoom->name);
    free_string (pRoom->description);
    free_string (pRoom->owner);
    free_rprog( pRoom->rprogs );

    for (door = 0; door < MAX_DIR; door++)
    {
        if (pRoom->exit[door])
            free_exit (pRoom->exit[door]);
    }

    for (pExtra = pRoom->extra_descr; pExtra; pExtra = pExtra->next)
    {
        free_extra_descr (pExtra);
    }

    for (pReset = pRoom->reset_first; pReset; pReset = pReset->next)
    {
        free_reset_data (pReset);
    }

    pRoom->next = room_index_free;
    room_index_free = pRoom;
    return;
}

SHOP_DATA *new_shop (void)
{
    SHOP_DATA *pShop;
    int buy;

    if (!shop_free)
    {
        pShop = (SHOP_DATA *) alloc_perm (sizeof (*pShop));
        top_shop++;
    }
    else
    {
        pShop = shop_free;
        shop_free = shop_free->next;
    }

    pShop->next = NULL;
    pShop->keeper = 0;

    for (buy = 0; buy < MAX_TRADE; buy++)
        pShop->buy_type[buy] = 0;

    pShop->profit_buy = 100;
    pShop->profit_sell = 100;
    pShop->open_hour = 0;
    pShop->close_hour = 23;

    return pShop;
}

void free_shop (SHOP_DATA * pShop)
{
    pShop->next = shop_free;
    shop_free = pShop;
    return;
}

OBJ_INDEX_DATA *new_obj_index (void)
{
    OBJ_INDEX_DATA *pObj;
    int value;

    if (!obj_index_free)
    {
        pObj = (OBJ_INDEX_DATA *) alloc_perm (sizeof (*pObj));
        top_obj_index++;
    }
    else
    {
        pObj = obj_index_free;
        obj_index_free = obj_index_free->next;
    }

    pObj->next = NULL;
    pObj->extra_descr = NULL;
    pObj->affected = NULL;
    pObj->area = NULL;
    pObj->name = str_dup ("no name");
    pObj->short_descr = str_dup ("(no short description)");
    pObj->description = str_dup ("(no description)");
    pObj->vnum = 0;
    pObj->item_type = ITEM_TRASH;
    pObj->extra_flags = 0;
    pObj->wear_flags = 0;
    pObj->count = 0;
    pObj->weight = 0;
    pObj->cost = 0;
    pObj->material = str_dup ("unknown");    /* ROM */
    pObj->condition = 100;        /* ROM */
    for (value = 0; value < 5; value++)    /* 5 - ROM */
        pObj->value[value] = 0;

    pObj->new_format = TRUE;    /* ROM */

    return pObj;
}

void free_obj_index (OBJ_INDEX_DATA * pObj)
{
    EXTRA_DESCR_DATA *pExtra;
    AFFECT_DATA *pAf;

    free_string (pObj->name);
    free_string (pObj->short_descr);
    free_string (pObj->description);
    free_oprog( pObj->oprogs );

    for (pAf = pObj->affected; pAf; pAf = pAf->next)
    {
        free_affect (pAf);
    }

    for (pExtra = pObj->extra_descr; pExtra; pExtra = pExtra->next)
    {
        free_extra_descr (pExtra);
    }

    pObj->next = obj_index_free;
    obj_index_free = pObj;
    return;
}

MOB_INDEX_DATA *new_mob_index (void)
{
    MOB_INDEX_DATA *pMob;

    if (!mob_index_free)
    {
        pMob = (MOB_INDEX_DATA *) alloc_perm (sizeof (*pMob));
        top_mob_index++;
    }
    else
    {
        pMob = mob_index_free;
        mob_index_free = mob_index_free->next;
    }

    pMob->next = NULL;
    pMob->spec_fun = NULL;
    pMob->pShop = NULL;
    pMob->area = NULL;
    pMob->player_name = str_dup ("no name");
    pMob->short_descr = str_dup ("(no short description)");
    pMob->long_descr = str_dup ("(no long description)\n\r");
    pMob->description = &str_empty[0];
    pMob->vnum = 0;
    pMob->count = 0;
    pMob->killed = 0;
    pMob->sex = 0;
    pMob->level = 0;
    pMob->act = ACT_IS_NPC;
    STR_ZERO_STR( pMob->affected_by, AFF_FLAGS );
    pMob->alignment = 0;
    pMob->hitroll = 0;
    pMob->race = race_lookup ("kin");    /* - Hugin */
    pMob->form = 0;                /* ROM patch -- Hugin */
    pMob->parts = 0;            /* ROM patch -- Hugin */
    pMob->imm_flags = 0;        /* ROM patch -- Hugin */
    pMob->res_flags = 0;        /* ROM patch -- Hugin */
    pMob->vuln_flags = 0;        /* ROM patch -- Hugin */
    pMob->material = str_dup ("unknown");    /* -- Hugin */
    pMob->off_flags = 0;        /* ROM patch -- Hugin */
    pMob->size = SIZE_MEDIUM;    /* ROM patch -- Hugin */
    pMob->ac[AC_PIERCE] = 0;    /* ROM patch -- Hugin */
    pMob->ac[AC_BASH] = 0;        /* ROM patch -- Hugin */
    pMob->ac[AC_SLASH] = 0;        /* ROM patch -- Hugin */
    pMob->ac[AC_EXOTIC] = 0;    /* ROM patch -- Hugin */
    pMob->hit[DICE_NUMBER] = 0;    /* ROM patch -- Hugin */
    pMob->hit[DICE_TYPE] = 0;    /* ROM patch -- Hugin */
    pMob->hit[DICE_BONUS] = 0;    /* ROM patch -- Hugin */
    pMob->chi[DICE_NUMBER] = 0;    /* ROM patch -- Hugin */
    pMob->chi[DICE_TYPE] = 0;    /* ROM patch -- Hugin */
    pMob->chi[DICE_BONUS] = 0;    /* ROM patch -- Hugin */
    pMob->elemental[DICE_NUMBER] = 0;    /* ROM patch -- Hugin */
    pMob->elemental[DICE_TYPE] = 0;    /* ROM patch -- Hugin */
    pMob->elemental[DICE_BONUS] = 0;    /* ROM patch -- Hugin */
    pMob->fae[DICE_NUMBER] = 0;    /* ROM patch -- Hugin */
    pMob->fae[DICE_TYPE] = 0;    /* ROM patch -- Hugin */
    pMob->fae[DICE_BONUS] = 0;    /* ROM patch -- Hugin */
    pMob->ley[DICE_NUMBER] = 0;    /* ROM patch -- Hugin */
    pMob->ley[DICE_TYPE] = 0;    /* ROM patch -- Hugin */
    pMob->ley[DICE_BONUS] = 0;    /* ROM patch -- Hugin */

    pMob->damage[DICE_NUMBER] = 0;    /* ROM patch -- Hugin */
    pMob->damage[DICE_TYPE] = 0;    /* ROM patch -- Hugin */
    pMob->damage[DICE_NUMBER] = 0;    /* ROM patch -- Hugin */
    pMob->start_pos = POS_STANDING;    /*  -- Hugin */
    pMob->default_pos = POS_STANDING;    /*  -- Hugin */
    pMob->wealth = 0;

    pMob->new_format = TRUE;    /* ROM */

    return pMob;
}

void free_mob_index (MOB_INDEX_DATA * pMob)
{
    free_string (pMob->player_name);
    free_string (pMob->short_descr);
    free_string (pMob->long_descr);
    free_string (pMob->description);
    free_mprog (pMob->mprogs);

    free_shop (pMob->pShop);

    pMob->next = mob_index_free;
    mob_index_free = pMob;
    return;
}

PROG_CODE *new_mpcode (void)
{
    PROG_CODE *NewCode;

    if (!mpcode_free)
    {
        NewCode = (PROG_CODE *) alloc_perm (sizeof (*NewCode));
        top_mprog_index++;
    }
    else
    {
        NewCode = mpcode_free;
        mpcode_free = mpcode_free->next;
    }

    NewCode->vnum = 0;
    NewCode->code = str_dup ("");
    NewCode->next = NULL;

    return NewCode;
}

void free_mpcode (PROG_CODE * pMcode)
{
    free_string (pMcode->code);
    pMcode->next = mpcode_free;
    mpcode_free = pMcode;
    return;
}

PROG_CODE *new_opcode(void)
{
     PROG_CODE *NewCode;

     if (!rpcode_free)
     {
         NewCode = (PROG_CODE *) alloc_perm(sizeof(*NewCode) );
         top_oprog_index++;
     }
     else
     {
         NewCode     = opcode_free;
         opcode_free = opcode_free->next;
     }

     NewCode->vnum    = 0;
     NewCode->code    = str_dup("");
     NewCode->next    = NULL;

     return NewCode;
}

PROG_CODE *new_rpcode(void)
{
     PROG_CODE *NewCode;

     if (!rpcode_free)
     {
         NewCode = (PROG_CODE *) alloc_perm(sizeof(*NewCode) );
         top_rprog_index++;
     }
     else
     {
         NewCode     = rpcode_free;
         rpcode_free = rpcode_free->next;
     }

     NewCode->vnum    = 0;
     NewCode->code    = str_dup("");
     NewCode->next    = NULL;

     return NewCode;
}

void free_opcode(PROG_CODE *pOcode)
{
    free_string(pOcode->code);
    pOcode->next = opcode_free;
    opcode_free  = pOcode;
    return;
}

void free_rpcode(PROG_CODE *pRcode)
{
    free_string(pRcode->code);
    pRcode->next = rpcode_free;
    rpcode_free  = pRcode;
    return;
}