drm/player/
/***************************************************************************
 *  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			   *
***************************************************************************/

/*************************************************************************** 
*       ROT 1.4 is copyright 1996-1997 by Russ Walsh                       * 
*       By using this code, you have agreed to follow the terms of the     * 
*       ROT license, in the file doc/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 );
    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 *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 );
    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 );
    INVALIDATE ( wiz );

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

/* 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 );
    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 );

    d->connected = CON_GET_NAME;
    d->showstr_head = NULL;
    d->showstr_point = NULL;
    d->outsize = 2000;
    d->ansi = TRUE;
    d->outbuf = 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 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 );
    free_string ( ed->description );
    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 );

    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 );
    free_string ( obj->killer );
    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->material = &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 = 100;
    ch->max_hit = 100;
    ch->mana = 100;
    ch->max_mana = 100;
    ch->move = 100;
    ch->max_move = 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;

    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 );
    free_string ( ch->short_descr );
    free_string ( ch->long_descr );
    free_string ( ch->description );
    free_string ( ch->prompt );
    free_string ( ch->prefix );
    free_string ( ch->die_descr );
    free_string ( ch->say_descr );
    free_string ( ch->material );
    if ( ch->pcdata != NULL )
        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 );
    free_string ( pcdata->bamfin );
    free_string ( pcdata->bamfout );
    free_string ( pcdata->who_descr );
    free_string ( pcdata->title );
    free_string ( pcdata->spouse );
    free_string ( pcdata->socket );
    free_buf ( pcdata->buffer );

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

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 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 = 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 );
        quit ( 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 );
    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;

    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 = 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 */
MPROG_LIST *mprog_free;

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

    if ( mprog_free == NULL )
        mp = 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_empty[0];
    mp->trig_phrase = &str_empty[0];
    VALIDATE ( mp );
    return mp;
}

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

    free_string ( mp->code );
    free_string ( mp->trig_phrase );
    INVALIDATE ( mp );
    mp->next = mprog_free;
    mprog_free = mp;
}

/* Stuff for recycling imm/auction shit */
AUCTION_DATA *auction_free;
AUCTION_DATA *new_auction ( void )
{
    static AUCTION_DATA auc_zero;
    AUCTION_DATA *auction;

    if ( auction_free == NULL )
        auction = alloc_perm ( sizeof ( *auction ) );
    else
    {
        auction = auction_free;
        auction_free = auction_free->next;
    }

    *auction = auc_zero;
    VALIDATE ( auction );
    return auction;
}

void free_auction ( AUCTION_DATA * auction )
{
    if ( !IS_VALID ( auction ) )
        return;

    auction->current_bid = 0;
    auction->gold_held = 0;
    auction->high_bidder = NULL;
    auction->item = NULL;
    auction->min_bid = 0;
    auction->owner = NULL;
    auction->status = 0;
    INVALIDATE ( auction );

    auction->next = auction_free;
    auction_free = auction;
}