Rot/deity/
Rot/player/
Rot/src/utils/pfiles/
Rot/src/utils/www/
/***************************************************************************
*   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 'rom.license'                             *
***************************************************************************/
/***************************************************************************
*       ROT 2.0 is copyright 1996-1999 by Russ Walsh                       *
*       By using this code, you have agreed to follow the terms of the     *
*       ROT license, in the file 'rot.license'                             *
***************************************************************************/

#if defined(macintosh)
#include <types.h>
#include <time.h>
#else
#include <sys/types.h>
#include <sys/time.h>
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "merc.h"
#include "recycle.h"

/* stuff for recyling notes */
NOTE_DATA *note_free;

NOTE_DATA *new_note()
{
    NOTE_DATA *note;

    if (note_free == NULL)
	note = 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, "recycle.c/free_note #1");
    free_string( note->subject, "recycle.c/free_note #2");
    free_string( note->to_list, "recycle.c/free_note #3");
    free_string( note->date, "recycle.c/free_note #4");
    free_string( note->sender, "recycle.c/free_note #5");
    INVALIDATE(note);

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

/* stuff for recyling mudlist */
MUD_DATA *mud_free;

MUD_DATA *new_mud()
{
    MUD_DATA *mud;

    if (mud_free == NULL)
        mud = alloc_perm(sizeof(*mud));
    else   
    {   
        mud = mud_free;
        mud_free = mud_free->next;
    }
    VALIDATE(mud);
    return mud;
}
 
void free_mud(MUD_DATA *mud)
{
    if (!IS_VALID(mud))
        return;
           
    free_string( mud->address, "recycle.c/free_mud #1");
    free_string( mud->base, "recycle.c/free_mud #2");
    free_string( mud->name, "recycle.c/free_mud #3");
    free_string( mud->www, "recycle.c/free_mud #4");
    free_string( mud->date, "recycle.c/free_mud #5");
    free_string( mud->sender, "recycle.c/free_mud #6");
    INVALIDATE(mud);
 
    mud->next = mud_free;
    mud_free   = mud;
}

    
/* stuff for recycling ban structures */
BAN_DATA *ban_free;

BAN_DATA *new_ban(void)
{
    static BAN_DATA ban_zero;
    BAN_DATA *ban;

    if (ban_free == NULL)
	ban = 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, "recycle.c/free_ban");
    INVALIDATE(ban);

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

/* stuff for recycling wizlist structures */
WIZ_DATA *wiz_free;

WIZ_DATA *new_wiz(void)
{
    static WIZ_DATA wiz_zero;
    WIZ_DATA *wiz;

    if (wiz_free == NULL)
	wiz = alloc_perm(sizeof(*wiz));
    else
    {
	wiz = wiz_free;
	wiz_free = wiz_free->next;
    }

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

void free_wiz(WIZ_DATA *wiz)
{
    if (!IS_VALID(wiz))
	return;

    free_string(wiz->name, "recycle.c/free_wiz");
    INVALIDATE(wiz);

    wiz->next = wiz_free;
    wiz_free = wiz;
}

/* stuff for recycling banklist structures */
BANK_DATA *bank_free;

BANK_DATA *new_bank(void)
{
    static BANK_DATA bank_zero;
    BANK_DATA *bank;

    if (bank_free == NULL)
        bank = alloc_perm(sizeof(*bank));
    else  
    {   
        bank = bank_free;
        bank_free = bank_free->next;
    }

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

void free_bank(BANK_DATA *bank)
{
    if (!IS_VALID(bank))
        return;
          
    free_string(bank->name, "recycle.c/free_bank");
    INVALIDATE(bank);
 
    bank->next = bank_free;
    bank_free = bank;
}

/* stuff for recycling clanlist structures */
CLN_DATA *cln_free;

CLN_DATA *new_cln(void)
{
    static CLN_DATA cln_zero;
    CLN_DATA *cln;

    if (cln_free == NULL)
	cln = alloc_perm(sizeof(*cln));
    else
    {
	cln = cln_free;
	cln_free = cln_free->next;
    }

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

MBR_DATA *mbr_free;

MBR_DATA *new_mbr(void)
{
    static MBR_DATA mbr_zero;
    MBR_DATA *mbr;

    if (mbr_free == NULL)
	mbr = alloc_perm(sizeof(*mbr));
    else
    {
	mbr = mbr_free;
	mbr_free = mbr_free->next;
    }

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

void free_mbr(MBR_DATA *mbr)
{
    if (!IS_VALID(mbr))
	return;

    free_string(mbr->name, "recycle.c/free_mbr");
    INVALIDATE(mbr);

    mbr->next = mbr_free;
    mbr_free = mbr;
}

/* stuff for recycling descriptors */
DESCRIPTOR_DATA *descriptor_free;

DESCRIPTOR_DATA *new_descriptor(void)
{
    static DESCRIPTOR_DATA d_zero;
    DESCRIPTOR_DATA *d;

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

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

    free_string( d->host, "recycle.c/free_descriptor");
    free_mem( d->outbuf, d->outsize, "recycle.c/free_descriptor" );
    INVALIDATE(d);
    d->next = descriptor_free;
    descriptor_free = d;
}

/* stuff for recycling gen_data */
GEN_DATA *gen_data_free;

GEN_DATA *new_gen_data(void)
{
    static GEN_DATA gen_zero;
    GEN_DATA *gen;

    if (gen_data_free == NULL)
	gen = alloc_perm(sizeof(*gen));
    else
    {
	gen = gen_data_free;
	gen_data_free = gen_data_free->next;
    }
    *gen = gen_zero;
    VALIDATE(gen);
    return gen;
}

void free_gen_data(GEN_DATA *gen)
{
    if (!IS_VALID(gen))
	return;

    INVALIDATE(gen);

    gen->next = gen_data_free;
    gen_data_free = gen;
} 

/* stuff for recycling extended descs */
EXTRA_DESCR_DATA *extra_descr_free;

EXTRA_DESCR_DATA *new_extra_descr(void)
{
    EXTRA_DESCR_DATA *ed;

    if (extra_descr_free == NULL)
	ed = 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, "recycle.c/free_extra_descr #1");
    free_string(ed->description, "recycle.c/free_extra_descr #2");
    INVALIDATE(ed);
    
    ed->next = extra_descr_free;
    extra_descr_free = ed;
}


/* stuff for recycling affects */
AFFECT_DATA *affect_free;

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

    if (affect_free == NULL)
	af = 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 *obj_free;

OBJ_DATA *new_obj(void)
{
    static OBJ_DATA obj_zero;
    OBJ_DATA *obj;

    if (obj_free == NULL)
	obj = alloc_perm(sizeof(*obj));
    else
    {
	obj = obj_free;
	obj_free = obj_free->next;
    }
    *obj = obj_zero;
    VALIDATE(obj);
    obj->inscribed = FALSE;
    obj->spell_name = "";
    obj->spell_count = 0;

    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, "recycle.c/free_obj #1");
    free_string( obj->description, "recycle.c/free_obj #2");
    free_string( obj->short_descr, "recycle.c/free_obj #3");
    free_string( obj->owner, "recycle.c/free_obj #4");
    free_string( obj->killer, "recycle.c/free_obj #5");
    if ( obj->spell_name[0] != '\0')
	free_string( obj->spell_name, "recycle.c/free_obj #6");
    INVALIDATE(obj);

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


/* stuff for recyling characters */
CHAR_DATA *char_free;

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

    if (char_free == NULL)
	ch = 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->die_descr		= &str_empty[0];
    ch->say_descr		= &str_empty[0];
    ch->logon                   = current_time;
    ch->lines                   = PAGELEN;
    ch->running			= FALSE;
    for (i = 0; i < 4; i++)
        ch->armor[i]            = 100;
    ch->position                = POS_STANDING;
    ch->hit                     = 100;
    ch->max_hit                 = 100;
    ch->mana                    = 100;
    ch->max_mana                = 100;
    ch->move                    = 100;
    ch->max_move                = 100;
    ch->color			= 0;
    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;

    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);
    }

    free_string(ch->name, "recycle.c/free_char #1");
    free_string(ch->short_descr, "recycle.c/free_char #1");
    free_string(ch->long_descr, "recycle.c/free_char #3");
    free_string(ch->description, "recycle.c/free_char #4");
    free_string(ch->prompt, "recycle.c/free_char #5");
    free_string(ch->prefix, "recycle.c/free_char #6");
    free_note(ch->pnote);
    if ( ch->die_descr[0] != '\0')
	free_string(ch->die_descr, "recycle.c/free_char #7");
    if ( ch->say_descr[0] != '\0')
	free_string(ch->say_descr, "recycle.c/free_char #8");
    free_pcdata(ch->pcdata);

    ch->next = char_free;
    char_free  = ch;

    INVALIDATE(ch);
    return;
}

PC_DATA *pcdata_free;

PC_DATA *new_pcdata(void)
{
    int alias;

    static PC_DATA pcdata_zero;
    PC_DATA *pcdata;

    if (pcdata_free == NULL)
	pcdata = 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;
    }
    for (alias = 0; alias < MAX_FORGET; alias++)
    {
	pcdata->forget[alias] = NULL;
    }
    for (alias = 0; alias < MAX_DUPES; alias++)
    {
	pcdata->dupes[alias] = NULL;
    }

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

void free_pcdata(PC_DATA *pcdata)
{
    int alias;

    if (!IS_VALID(pcdata))
	return;

    free_string(pcdata->pwd, "recycle.c/free_pcdata #1");
    free_string(pcdata->bamfin, "recycle.c/free_pcdata #2");
    free_string(pcdata->bamfout, "recycle.c/free_pcdata #3");
    free_string(pcdata->who_descr, "recycle.c/free_pcdata #4");
    free_string(pcdata->title, "recycle.c/free_pcdata #5");
    free_string(pcdata->lquest_obj, "recycle.c/free_pcdata #6");
    free_string(pcdata->lquest_mob, "recycle.c/free_pcdata #7");
    free_string(pcdata->lquest_are, "recycle.c/free_pcdata #8");
    free_buf(pcdata->buffer);

    for (alias = 0; alias < MAX_ALIAS; alias++)
    {
	free_string(pcdata->alias[alias], "recycle.c/free_pcdata #9");
	free_string(pcdata->alias_sub[alias], "recycle.c/free_pcdata #10");
    }
    for (alias = 0; alias < MAX_FORGET; alias++)
    {
	free_string(pcdata->forget[alias], "recycle.c/free_pcdata #11");
    }
    for (alias = 0; alias < MAX_DUPES; alias++)
    {
	free_string(pcdata->dupes[alias], "recycle.c/free_pcdata #12");
    }
    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;
}

MEM_DATA *mem_data_free;

/* procedures and constants needed for buffering */

BUFFER *buf_free;

MEM_DATA *new_mem_data(void)
{
    MEM_DATA *memory;
  
    if (mem_data_free == NULL)
	memory = 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,32768,65536
};

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

    if (buf_size[0] >= val)
	return buf_size[0];
    else if (buf_size[1] >= val)
	return buf_size[1];
    else if (buf_size[2] >= val)
	return buf_size[2];
    else if (buf_size[3] >= val)
	return buf_size[3];
    else if (buf_size[4] >= val)
	return buf_size[4];
    else if (buf_size[5] >= val)
	return buf_size[5];
    else if (buf_size[6] >= val)
	return buf_size[6];
    else if (buf_size[7] >= val)
	return buf_size[7];
    else if (buf_size[8] >= val)
	return buf_size[8];
    else if (buf_size[9] >= val)
	return buf_size[9];
    else if (buf_size[10] >= val)
	return buf_size[10];
    else if (buf_size[11] >= val)
	return buf_size[11];
    else
	return -1;

/*

    for (bfs = 0; bfs < MAX_BUF_LIST; bfs++)
    {
	if (buf_size[bfs] >= val)
	{
	    return buf_size[bfs];
	}
	if (bfs >= MAX_BUF_LIST)
	{
	    return -1;
	}
    }
    
*/
    return -1;
}

BUFFER *new_buf()
{
    BUFFER *buffer;

    if (buf_free == NULL) 
	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	= 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 = 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      = 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, "recycle.c/free_buf" );
    buffer->string = NULL;
    buffer->size   = 0;
    buffer->state  = BUFFER_FREED;
    INVALIDATE(buffer);

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


bool add_buf(BUFFER *buffer, 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;

    if (buf_size[0] >= len)
        buffer->size = buf_size[0];
    else if (buf_size[1] >= len)
        buffer->size = buf_size[1];
    else if (buf_size[2] >= len)
        buffer->size = buf_size[2];
    else if (buf_size[3] >= len)
        buffer->size = buf_size[3];
    else if (buf_size[4] >= len)
        buffer->size = buf_size[4];
    else if (buf_size[5] >= len)
        buffer->size = buf_size[5];
    else if (buf_size[6] >= len)
        buffer->size = buf_size[6];
    else if (buf_size[7] >= len)
        buffer->size = buf_size[7];
    else if (buf_size[8] >= len)
        buffer->size = buf_size[8];
    else if (buf_size[9] >= len)
        buffer->size = buf_size[9];
    else if (buf_size[10] >= len)
        buffer->size = buf_size[10];
    else if (buf_size[11] >= len)
        buffer->size = buf_size[11];
    else
    {
        buffer->size = -1;
	buffer->size = oldsize;
	buffer->state = BUFFER_OVERFLOW;
	bug("BUG: add_buf: buffer overflow past size %d",buffer->size);
	return FALSE;
    }

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

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

	strcpy(buffer->string,oldstr);
	free_mem(oldstr,oldsize, "recycle.c/add.buf" );
    }

    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;
}