DalekenMUD/
DalekenMUD/data/
DalekenMUD/data/notes/
DalekenMUD/data/player/
DalekenMUD/data/system/poses/
DalekenMUD/doc/Homepage/images/
DalekenMUD/log/
/*___________________________________________________________________________*
   )()(			  DalekenMUD 1.12 (C) 2000			)()(
   `]['		       by Martin Thomson, Lee Brooks,			`]['
    ||		       Ken Herbert and David Jacques			 ||
    || ----------------------------------------------------------------- ||
    || Envy Diku Mud improvements copyright (C) 1994 by Michael Quan,	 ||
    || David Love, Guilherme 'Willie' Arnold, and Mitchell Tse.		 ||
    || Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael	 ||
    || Chastain, Michael Quan, and Mitchell Tse.			 ||
    || Original Diku Mud copyright (C) 1990, 1991			 ||
    || by Sebastian Hammer, Michael Seifert, Hans Henrik St{rfeldt,	 ||
    || Tom Madsen, and Katja Nyboe.					 ||
    || ----------------------------------------------------------------- ||
    || Any use of this software must follow the licenses of the		 ||
    || creators.  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.					 ||
    || ----------------------------------------------------------------- ||
    ||                              mem.c                                ||
    || Memory management/recycling code, basically a set of C++ style    ||
    || "constructors" and "destructors" for most datatypes.              ||
 *_/<>\_________________________________________________________________/<>\_*/


#include "mud.h"
#include "olc.h"
#include "event.h"
#include "db.h"

/* from event.c */
void event_remove_global	args( ( EVENT *e ) );


/*
 * Globals
 */

ALIAS_DATA		*alias_free;
AREA_DATA		*area_free;
EXTRA_DESCR_DATA	*extra_descr_free;
EXIT_DATA		*exit_free;
ROOM_INDEX_DATA		*room_index_free;
OBJ_INDEX_DATA		*obj_index_free;
SHOP_DATA		*shop_free;
MOB_INDEX_DATA		*mob_index_free;
RESET_DATA		*reset_free;
HELP_DATA		*help_free;
QUEST_DATA		*quest_free;
MPROG_VAR		*mpvar_free;
RELIGION_DATA		*religion_free;
RELIGION_SKILL		*religion_skill_free;
CLAN_DATA		*clan_free;
NOTE_DATA		*note_free;
BAN_DATA		*ban_free;
POSE_DATA		*pose_free;
PLANE_DATA		*plane_free;
MPROG_DATA		*mprog_free;
MPROG_GLOBAL		*mprog_global_free;
HIGHEST_ENTRY		*highent_free;
TEXT_BLOCK		*text_block_free;

extern HELP_DATA *help_last;
SOCIAL_DATA *social_free;
extern RELIGION_DATA *religion_last;
extern CLAN_DATA *clan_last;

/*****************************************************************************
 Name:		new_reset_data
 Purpose:	Creates and clears a reset structure.
 ****************************************************************************/
RESET_DATA *new_reset_data( void )
{
    RESET_DATA *pReset;

    if( !reset_free )
    {
	pReset = 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;

    return pReset;
}


/*****************************************************************************
 Name:		free_reset_data
 Purpose:	Clears and deletes a reset structure.
 ****************************************************************************/
void free_reset_data( RESET_DATA *pReset )
{
    pReset->next = reset_free;
    reset_free = pReset;
    return;
}


/*****************************************************************************
 Name:		new_area
 Purpose:	Creates and clears a new area structure.
 ****************************************************************************/
AREA_DATA *new_area( void )
{
    AREA_DATA *pArea;
    char buf[MAX_INPUT_LENGTH];

    if( !area_free )
    {
	pArea = 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->plane = plane_lookup( "unfinished" );
    pArea->recall = ROOM_VNUM_TEMPLE;
    pArea->area_flags = AREA_ADDED;
    pArea->security = 1;
    pArea->builders = str_dup( "None" );
    pArea->lvnum = 0;
    pArea->uvnum = 0;
    pArea->age = 15;
    pArea->nplayer = 0;
    pArea->nmobile = 0;
    pArea->order = NULL;
    pArea->token_room = 0;
    pArea->vnum = top_area - 1;	/* OLC 1.1b */
    sprintf( buf, "area%d.are", pArea->vnum );
    pArea->filename = str_dup( buf );
    pArea->description = &str_empty[0];
    pArea->repop = &str_empty[0];

    return pArea;
}


/*****************************************************************************
 Name:		free_area
 Purpose:	Clears and deletes an area structure.
 ****************************************************************************/
void free_area( AREA_DATA *pArea )
{
    free_string( pArea->name );
    free_string( pArea->filename );
    free_string( pArea->builders );

    while( pArea->events )
    {
	EVENT *tmp;

	tmp = pArea->events;
	pArea->events = tmp->next_local;
	event_remove_global( tmp );
	free_event( tmp );
    }

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


/*
 * Memory note: since exits can be freed without knowing which room they
 * belong to, there should be some way for an exit to refer to the room it is
 * in.  In order to do this, I have reused the vnum variable which is
 * originally used when first creating exits.  Instead of being the vnum of
 * the room it points to it now is the vnum of the room it is from so exits
 * can refer back to where they came from without the need for more pointers.
 * The need for this back reference is not initially apparent except when you
 * have to remove an exit from some unknown room which points to your room.
 * Hence all new exits have to have this reference so they too can be freed.
 *		--Symposium
 */
EXIT_DATA *new_exit()
{
    EXIT_DATA *pExit;

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

    pExit->to_room = NULL;
    pExit->exit_info = 0;
    pExit->key = -1;
    pExit->keyword = &str_empty[0];;
    pExit->description = &str_empty[0];;
    pExit->rs_flags = 0;

    pExit->next = exit_list;
    exit_list = pExit;

    return pExit;
}


void free_exit( EXIT_DATA * pExit )
{
    EXIT_DATA *ex;
    ROOM_INDEX_DATA *room;
    int door;

    free_string( pExit->keyword );
    free_string( pExit->description );

    /* remove it from the exit list */
    if( pExit == exit_list )
    {
	exit_list = exit_list->next;
    }
    else
    {
	for( ex = exit_list; ex; ex = ex->next )
	{
	    if( ex->next == pExit )
	    {
		ex->next = pExit->next;
		break;
	    }
	}
    }

    /* remove it from it's room */
    room = get_room_index( pExit->vnum );
    if( !room )
    {
	bug( "Exit with no return adress for in_room." );
	pExit->next = exit_free;
	exit_free = pExit;
	return;
    }
    for( door = 0; door < MAX_DIR; door++ )
    {
	if( room->exit[door] == pExit )
	    room->exit[door] = NULL;
    }

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


EXTRA_DESCR_DATA *new_extra_descr( void )
{
    EXTRA_DESCR_DATA *pExtra;

    if( !extra_descr_free )
    {
	pExtra = alloc_perm( sizeof( *pExtra ) );
	top_ed++;
    }
    else
    {
	pExtra = extra_descr_free;
	extra_descr_free = extra_descr_free->next;
    }

    pExtra->keyword = &str_empty[0];
    pExtra->description = &str_empty[0];
    pExtra->next = NULL;

    return pExtra;
}


void free_extra_descr( EXTRA_DESCR_DATA * pExtra )
{
    free_string( pExtra->keyword );
    free_string( pExtra->description );

    pExtra->next = extra_descr_free;
    extra_descr_free = pExtra;
    return;
}


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

    if( !room_index_free )
    {
	pRoom = 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->vnum = 0;
    pRoom->room_flags = 0;
    pRoom->light = 0;
    pRoom->sector_type = 0;
    pRoom->mudprogs = NULL;

    return pRoom;
}


void free_room_index( ROOM_INDEX_DATA *pRoom )
{
    int i;
    EXTRA_DESCR_DATA *pExtra, *pExtra_next;
    RESET_DATA *pReset, *pReset_next;
    ROOM_INDEX_DATA *room1, *room2;
    EXIT_DATA *ex, *ex_next;

    free_string( pRoom->name );
    free_string( pRoom->description );
    free_mprog( pRoom->mudprogs );
    pRoom->mudprogs = NULL;

    /* clear exits on both sides */
    for( i = 0; i < MAX_DIR; i++ )
    {
	if( pRoom->exit[i] )
	    free_exit( pRoom->exit[i] );
    }
    for( ex = exit_list; ex; ex = ex_next )
    {
	ex_next = ex->next;
	if( ex->to_room == pRoom )
	    free_exit( ex );
    }

    /* clear extra descriptions and resets */
    for( pExtra = pRoom->extra_descr; pExtra; pExtra = pExtra_next )
    {
	pExtra_next = pExtra->next;
	free_extra_descr( pExtra );
    }
    pRoom->extra_descr = NULL;
    for( pReset = pRoom->reset_first; pReset; pReset = pReset_next )
    {
	pReset_next = pReset->next;
	free_reset_data( pReset );
    }
    pRoom->reset_first = NULL;

    /* events */
    while( pRoom->events )
    {
	EVENT *tmp;

	tmp = pRoom->events;
	pRoom->events = tmp->next_local;
	event_remove_global( tmp );
	free_event( tmp );
    }

    /* take it off the list */
    room1 = room_index_hash[pRoom->vnum % MAX_KEY_HASH];
    if( pRoom == room1 )
    {
	room_index_hash[pRoom->vnum % MAX_KEY_HASH] = room1->next;
    }
    else
    {
	for( room2 = room1; room2; room2 = room2->next )
	{
	    if( room2->next == pRoom )
	    {
		room2->next = pRoom->next;
		break;
	    }
	}
	if( !room2 )
	{
	    bug( "Trying to free a room not on the list." );
	}
    }

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


AFFECT_DATA *new_affect( void )
{
    AFFECT_DATA *pAf;

    if( !affect_free )
    {
	pAf = alloc_perm( sizeof( *pAf ) );
	top_affect++;
    }
    else
    {
	pAf = affect_free;
	affect_free = affect_free->next;
    }

    pAf->next = NULL;
    pAf->location = 0;
    pAf->modifier = 0;
    pAf->type = 0;
    pAf->level = 0;
    pAf->duration = 0;
    vzero( pAf->bitvector );

    return pAf;
}


void free_affect( AFFECT_DATA *pAf )
{
    pAf->next = affect_free;
    affect_free = pAf;
    return;
}


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

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

    pShop->next = NULL;

    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 )
{
    if( !pShop )
	return;
    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 = 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->condition = 1000;
    pObj->reset_chance = 1000;
    for( value = 0; value < 4; value++ )
	pObj->value[value] = 0;
    pObj->mudprogs = NULL;

    return pObj;
}


void free_obj_index( OBJ_INDEX_DATA * pObj )
{
    OBJ_INDEX_DATA *obj1, *obj2;
    EXTRA_DESCR_DATA *pExtra, *pExtra_next;
    AFFECT_DATA *pAf, *pAf_next;

    free_string( pObj->name );
    free_string( pObj->short_descr );
    free_string( pObj->description );
    free_mprog( pObj->mudprogs );
    pObj->mudprogs = NULL;

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

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

    obj1 = obj_index_hash[pObj->vnum % MAX_KEY_HASH];
    if( pObj == obj1 )
    {
	obj_index_hash[pObj->vnum % MAX_KEY_HASH] = obj1->next;
    }
    else
    {
	for( obj2 = obj1; obj2; obj2 = obj2->next )
	{
	    if( obj2->next == pObj )
	    {
		obj2->next = pObj->next;
		break;
	    }
	}
	if( !obj2 )
	{
	    bug( "Trying to free an object not on the list." );
	}
    }

    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 = 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 = 0;
    pMob->pShop = NULL;
    pMob->area = NULL;
    pMob->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;
    vset( pMob->act, ACT_IS_NPC );
    vzero( pMob->affected_by );
    pMob->alignment = 0;
    pMob->reset_chance = 1000;
    pMob->mudprogs = NULL;

    return pMob;
}


void free_mob_index( MOB_INDEX_DATA * pMob )
{
    MOB_INDEX_DATA *mb1, *mb2;

    free_string( pMob->name );
    free_string( pMob->short_descr );
    free_string( pMob->long_descr );
    free_string( pMob->description );
    free_mprog( pMob->mudprogs );
    pMob->mudprogs = NULL;

    free_shop( pMob->pShop );

    mb1 = mob_index_hash[pMob->vnum % MAX_KEY_HASH];
    if( pMob == mb1 )
    {
	mob_index_hash[pMob->vnum % MAX_KEY_HASH] = mb1->next;
    }
    else
    {
	for( mb2 = mb1; mb2; mb2 = mb2->next )
	{
	    if( mb2->next == pMob )
	    {
		mb2->next = pMob->next;
		break;
	    }
	}
	if( !mb2 )
	{
	    bug( "Trying to free a mob not on the list." );
	}
    }

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


MPROG_DATA *new_mprog( void )
{
    MPROG_DATA *mprg;

    if( !mprog_free )
    {
	top_mprog++;
	mprg = (MPROG_DATA *) alloc_perm( sizeof( MPROG_DATA ) );
    }
    else
    {
	mprg = mprog_free;
	mprog_free = mprg->next;
    }
    mprg->type = 0;
    mprg->arglist = str_dup( "0" );
    mprg->comlist = str_dup( "" );
    return mprg;
}


void free_mprog( MPROG_DATA *mprg )
{
    MPROG_DATA *next;
    for( ; mprg; mprg = next )
    {
	next = mprg->next;
	free_string( mprg->arglist );
	free_string( mprg->comlist );

	mprg->next = mprog_free;
	mprog_free = mprg;
    }
    return;
}


MPROG_GLOBAL *new_mprog_global( void )
{
    MPROG_GLOBAL *mprg;

    if( !mprog_global_free )
    {
	top_mprog_global++;
	mprg = (MPROG_GLOBAL *) alloc_perm( sizeof( MPROG_GLOBAL ) );
    }
    else
    {
	mprg = mprog_global_free;
	mprog_global_free = mprg->next;
    }
    mprg->vnum = 0;
    mprg->area = NULL;
    mprg->type = 0;
    mprg->allowed = 0;
    mprg->arglist = str_dup( "0" );
    mprg->comlist = str_dup( "" );
    return mprg;
}


void free_mprog_global( MPROG_GLOBAL *mprg )
{
    MPROG_GLOBAL *prev;

    if( mprg == global_progs[mprg->vnum % MPROG_GLOBAL_HASH] )
	global_progs[mprg->vnum % MPROG_GLOBAL_HASH] = mprg->next;
    else
    {
	for( prev = global_progs[mprg->vnum % MPROG_GLOBAL_HASH];
	     prev; prev = prev->next )
	    if( prev->next == mprg )
		break;
	if( !prev )
	{
	    bug( "Disconnected global prog passed to free_mprog_global." );
	    return;
	}
	prev->next = mprg->next;
    }

    free_string( mprg->arglist );
    free_string( mprg->comlist );

    mprg->next = mprog_global_free;
    mprog_global_free = mprg;
    return;
}


void add_social( SOCIAL_DATA *social )
{
    int iHash;

    for( iHash = 0; social->name[iHash]; iHash++ )
	social->name[iHash] = LOWER( social->name[iHash] );

    if( social->name[0] < 'a' || social->name[0] > 'z' )
	iHash = 0;
    else
	iHash = ( social->name[0] - 'a' ) + 1;

    if( social_table[iHash] == NULL
	|| strcmp( social->name, social_table[iHash]->name ) < 0 )
    {
	social->next = social_table[iHash];
	social_table[iHash] = social;
    }
    else
    {
	SOCIAL_DATA *prev;
	for( prev = social_table[iHash]; prev && prev->next;
	     prev = prev->next )
	{
	    if( strcmp( social->name, social_table[iHash]->name ) < 0 )
		break;
	}
	if( prev )
	{
	    social->next = prev->next;
	    prev->next = social;
	}
    }
}


SOCIAL_DATA *new_social( char *name )
{
    SOCIAL_DATA *soc;

    if( !social_free )
    {
	top_social++;
	soc = (SOCIAL_DATA *) alloc_perm( sizeof( SOCIAL_DATA ) );
    }
    else
    {
	soc = social_free;
	social_free = soc->next;
    }

    soc->name = str_dup( name );
    soc->char_no_arg = &str_empty[0];
    soc->others_no_arg = &str_empty[0];
    soc->char_found = &str_empty[0];
    soc->others_found = &str_empty[0];
    soc->vict_found = &str_empty[0];
    soc->char_auto = &str_empty[0];
    soc->others_auto = &str_empty[0];

    if( name != NULL )
    {
	add_social( soc );
    }
    else
    {
	soc->next = social_table[0];
	social_table[0] = soc;
    }
    top_social++;
    return soc;
}


void free_social( SOCIAL_DATA * soc )
{
    SOCIAL_DATA *soc2;
    int iHash;

    free_string( soc->name );
    free_string( soc->char_no_arg );
    free_string( soc->others_no_arg );
    free_string( soc->char_found );
    free_string( soc->others_found );
    free_string( soc->vict_found );
    free_string( soc->char_auto );
    free_string( soc->others_auto );

    if( soc->name[0] < 'a' || soc->name[0] > 'z' )
	iHash = 0;
    else
	iHash = ( soc->name[0] - 'a' ) + 1;

    if( soc == social_table[iHash] )
    {
	social_table[iHash] = soc->next;
    }
    else
    {
	for( soc2 = social_table[iHash]; soc2; soc2 = soc2->next )
	{
	    if( soc2->next == soc )
		break;
	}
	if( !soc2 )
	{
	    bug( "Social not on the list." );
	    soc->next = social_free;
	    social_free = soc;
	    return;
	}
	soc2->next = soc->next;
    }

    soc->next = social_free;
    social_free = soc;
}


HELP_DATA *new_help( void )
{
    HELP_DATA *pHelp;

    if( !help_free )
    {
	pHelp = (HELP_DATA *) alloc_perm( sizeof( *pHelp ) );
    }
    else
    {
	pHelp = help_free;
	help_free = pHelp->next;
    }
    pHelp->area = NULL;
    pHelp->level = 0;
    pHelp->keyword = &str_empty[0];
    pHelp->text = &str_empty[0];

    if( !help_first )
	help_first = pHelp;
    if( help_last )
	help_last->next = pHelp;

    help_last = pHelp;
    pHelp->next = NULL;
    top_help++;

    return pHelp;
}


void free_help( HELP_DATA * pHelp )
{
    HELP_DATA *hlp;

    free_string( pHelp->keyword );
    free_string( pHelp->text );

    if( pHelp == help_first )
    {
	help_first = pHelp->next;
    }
    else
    {
	for( hlp = help_first; hlp; hlp = hlp->next )
	{
	    if( hlp->next == pHelp )
		break;
	}
	if( !hlp )
	{
	    bug( "Help not on the list." );
	    pHelp->next = help_free;
	    help_free = pHelp;
	    return;
	}
	hlp->next = pHelp->next;
    }

    pHelp->next = help_free;
    help_free = pHelp;
}


QUEST_DATA *new_quest()
{
    QUEST_DATA *qq;

    if( quest_free )
    {
	qq = quest_free;
	quest_free = quest_free->next;
    }
    else
    {
	qq = alloc_perm( sizeof( *qq ) );
    }
    qq->score = 0;
    qq->time = 15;
    qq->target = NULL;
    qq->type = QUEST_NONE;

    return qq;
}


void free_quest( QUEST_DATA *qq )
{
    switch( qq->type )
    {
    case QUEST_NONE:
    case QUEST_ITEM:
    case QUEST_KILL:
    case QUEST_BODY_PART:
	break;

    case QUEST_RACE_CORPSE:
	free_mem( qq->target, sizeof( struct quest_race_corpse ) );
	break;
    case QUEST_OBJ_MATERIAL:
	free_mem( qq->target, sizeof( struct quest_obj_material ) );
	break;
    default:
	bug( "Freeing a quest with unknown quest %d.", qq->type );
	break;
    }
    qq->next = quest_free;
    quest_free = qq;
}


MPROG_VAR *new_mpvar( void )
{
    MPROG_VAR *var;
    if( !mpvar_free )
    {
	var = alloc_perm( sizeof( MPROG_VAR ) );
    }
    else
    {
	var = mpvar_free;
	mpvar_free = var->next;
    }
    var->name = str_dup( "" );
    var->value = str_dup( "" );
    return var;
}


void free_mpvar( MPROG_VAR * var )
{
    free_string( var->name );
    free_string( var->value );
    var->next = mpvar_free;
    mpvar_free = var;
    return;
}


RELIGION_DATA *new_religion_data( void )
{
    RELIGION_DATA *new_rel;
    char buf[MAX_INPUT_LENGTH];

    if( !religion_free )
    {
	new_rel = (RELIGION_DATA *)alloc_perm( sizeof( RELIGION_DATA ) );
	top_religion++;
    }
    else
    {
	new_rel = religion_free;
	religion_free = new_rel->next;
    }
    new_rel->name = str_dup( "new religion" );
    new_rel->god_name = str_dup( "GOD" );
    sprintf( buf, "relig%d.rel", top_religion );
    new_rel->token = 0;
    new_rel->sac_events = 0;
    new_rel->align_min = 0;
    new_rel->align_max = 0;
    new_rel->skills = NULL;
    if( !religion_first )
	religion_first = new_rel;
    if( religion_last )
	religion_last->next = new_rel;
    religion_last = new_rel;
    return new_rel;
}


void free_religion_data( RELIGION_DATA *rel )
{
    RELIGION_DATA *prev;
    RELIGION_SKILL *ski1, *ski2;

    free_string( rel->name );
    free_string( rel->god_name );
    for( ski1 = rel->skills; ski1; ski1 = ski2 )
    {
	ski2 = ski1->next;
	free_religion_skill( ski1 );
    }
    if( religion_first == rel )
    {
	religion_first = rel->next;
	if( religion_last == rel )
	    religion_last = NULL;
    }
    else
    {
	for( prev = religion_first; prev; prev = prev->next )
	    if( prev->next == rel )
		break;
	if( !prev )
	    bug( "free_religion_data: religion not on list." );
	else
	{
	    if( religion_last == rel )
	    {
		religion_last = prev;
	    }
	    prev->next = rel->next;
	}
    }
    rel->next = religion_free;
}


RELIGION_SKILL *new_religion_skill( )
{
    RELIGION_SKILL *ski;

    if( !religion_skill_free )
	ski = (RELIGION_SKILL *)alloc_perm( sizeof( RELIGION_SKILL ) );
    else
    {
	ski = religion_skill_free;
	religion_skill_free = ski->next;
    }
    ski->sn = -1;
    ski->level = RANK_OVERLORD;
    return ski;
}


void free_religion_skill( RELIGION_SKILL *ski )
{
    ski->next = religion_skill_free;
    religion_skill_free = ski;
}


POSE_DATA *new_pose_data()
{
    POSE_DATA *pose;

    if( !pose_free )
    {
	pose = (POSE_DATA *)alloc_perm( sizeof( POSE_DATA ) );
	top_pose++;
    }
    else
    {
	pose = pose_free;
	pose_free = pose_free->next;
    }
    pose->to_char = str_dup( "You pose." );
    pose->to_room = str_dup( "$n poses." );
    return pose;
}


void free_pose_data( POSE_DATA *pose )
{
    free_string( pose->to_char );
    free_string( pose->to_room );
    pose->next = pose_free;
    pose_free = pose;
}


CLAN_DATA *new_clan_data()
{
    CLAN_DATA *new_clan;
    char buf[MAX_INPUT_LENGTH];

    if( !clan_free )
    {
	new_clan = (CLAN_DATA *)alloc_perm( sizeof( CLAN_DATA ) );
	top_clan++;
    }
    else
    {
	new_clan = clan_free;
	clan_free = new_clan->next;
    }
    sprintf( buf, "clan%d.cln", top_clan );
    new_clan->name = str_dup( "new clan" );
    new_clan->motto = str_dup( "" );
    new_clan->description = str_dup( "" );
    new_clan->overlord = str_dup( "" );
    new_clan->chieftains = str_dup( "" );
    new_clan->enemies = str_dup( "" );
    new_clan->recall = ROOM_VNUM_TEMPLE;
    new_clan->karma = 10;

    if( !clan_first )
	clan_first = new_clan;
    if( clan_last )
	clan_last->next = new_clan;
    clan_last = new_clan;

    return new_clan;
}


void free_clan_data( CLAN_DATA *clan )
{
    CLAN_DATA *prev;

    free_string( clan->name );
    free_string( clan->motto );
    free_string( clan->description );
    free_string( clan->overlord );
    free_string( clan->chieftains );
    free_string( clan->enemies );
    if( clan == clan_first )
    {
	clan_first = clan->next;
	if( clan_last == clan )
	    clan_last = NULL;
    }
    else
    {
	for( prev = clan_first; prev; prev = prev->next )
	    if( prev->next == clan )
		break;
	if( !prev )
	    bug( "free_clan_data: clan not on list." );
	else
	{
	    prev->next = clan->next;
	    if( clan_last == clan )
		clan_last = prev;
	}
    }
    clan->next = clan_free;
    clan_free = clan;
}


/*
 * Create an instance of an alias
 */
ALIAS_DATA *new_alias( void )
{
    ALIAS_DATA *al;

    if( !alias_free )
	return alloc_perm( sizeof( ALIAS_DATA ) );

    al = alias_free;
    alias_free = alias_free->next;
    al->name = &str_empty[0];
    al->command = &str_empty[0];

    return al;
}


void free_alias( ALIAS_DATA *al )
{
    free_string( al->name );
    free_string( al->command );

    al->next = alias_free;
    alias_free = al;
    return;
}


/*
 * Create an instance of a plane.
 * Randomise time and weather.
 */
PLANE_DATA *new_plane( void )
{
    PLANE_DATA *pl;

    if( !plane_free )
	return (PLANE_DATA *)alloc_perm( sizeof( PLANE_DATA ) );

    pl = plane_free;
    plane_free = plane_free->next;
    pl->name = &str_empty[0];

    pl->next = plane_list;
    plane_list = pl;

    pl->time.hour = number_range( 0, 23 );
    pl->time.day = number_range( 0, 34 );
    pl->time.month = number_range( 0, 16 );
    pl->time.year = number_bits( 30 );

    if( pl->time.hour < 5 )
	pl->weather.sunlight = SUN_DARK;
    else if( pl->time.hour < 6 )
	pl->weather.sunlight = SUN_RISE;
    else if( pl->time.hour < 19 )
	pl->weather.sunlight = SUN_LIGHT;
    else if( pl->time.hour < 20 )
	pl->weather.sunlight = SUN_SET;
    else
	pl->weather.sunlight = SUN_DARK;

    pl->weather.change = 0;
    pl->weather.mmhg = 960;
    if( pl->time.month >= 7 && pl->time.month <= 12 )
	pl->weather.mmhg += number_range( 1, 50 );
    else
	pl->weather.mmhg += number_range( 1, 80 );

    if( pl->weather.mmhg <= 980 )
	pl->weather.sky = SKY_LIGHTNING;
    else if( pl->weather.mmhg <= 1000 )
	pl->weather.sky = SKY_RAINING;
    else if( pl->weather.mmhg <= 1020 )
	pl->weather.sky = SKY_CLOUDY;
    else
	pl->weather.sky = SKY_CLOUDLESS;


    return pl;
}


void free_plane( PLANE_DATA *pl )
{
    free_string( pl->name );

    while( pl->events )
    {
	EVENT *tmp;

	tmp = pl->events;
	pl->events = tmp->next_local;
	event_remove_global( tmp );
	free_event( tmp );
    }

    if( pl == plane_list )
    {
	plane_list = pl->next;
    }
    else
    {
	PLANE_DATA *prev;

	for( prev = plane_list; prev; prev = prev->next )
	    if( prev->next == pl )
		break;
	if( !prev )
	    bug( "free_plane: plane not on list." );
	else
	    prev->next = pl->next;
    }

    pl->next = plane_free;
    plane_free = pl;
    return;
}


HIGHEST_ENTRY *new_highent( )
{
    HIGHEST_ENTRY *ent;

    if( highent_free )
    {
	ent = highent_free;
	highent_free = ent->next;
    }
    else
	ent = alloc_perm( sizeof( HIGHEST_ENTRY ) );

    ent->name = &str_empty[0];

    return ent;
}


void free_highent( HIGHEST_ENTRY *ent )
{
    free_string( ent->name );
    ent->next = highent_free;
    highent_free = ent;
}


TEXT_BLOCK *new_text_block( int size )
{
    TEXT_BLOCK *block, *prev = NULL;

    if( text_block_free )
    {
	for( block = text_block_free; block; block = block->next )
	{
	    if( block->size >= size )
		break;
	    prev = block;
	}
	if( block )
	{
	    if( prev )
		prev->next = block->next;
	    else
		text_block_free = block->next;
	    return block;
	}
    }

    block = alloc_perm( sizeof( TEXT_BLOCK ) );

    /* Round the size up to the next 128 bytes for simplicity. */
    if( size % 128 != 0 )
    {
	size >>= 7;
	++size;
	size = size << 7;
    }
    block->str = alloc_perm( size );
    block->size = size;
    top_text_block++;
    size_text_block += size + sizeof( TEXT_BLOCK );
    return block;
}


void free_text_block( TEXT_BLOCK *block )
{
    TEXT_BLOCK *prev;

    if( text_block_free == NULL || text_block_free->size > block->size )
    {
	block->next = text_block_free;
	text_block_free = block;
    }
    else
    {
	for( prev = text_block_free; prev && prev->next; prev = prev->next )
	    if( prev->next->size > block->size )
		break;
	if( !prev )
	{
	    bug( "free_text_block: wierd stuff happening." );
	    return;
	}
	block->next = prev->next;
	prev->next = block;
    }
}