dawn/notes/
dawn/src/
dawn/src/docs/
/**************************************************************************/
// recycle.cpp - memory management systems
/***************************************************************************
 * The Dawn of Time v1.69r (c)1997-2004 Michael Garratt                    *
 * >> A number of people have contributed to the Dawn codebase, with the   *
 *    majority of code written by Michael Garratt - www.dawnoftime.org     *
 * >> To use this source code, you must fully comply with all the licenses *
 *    in licenses.txt... In particular, you may not remove this copyright  *
 *    notice.                                                              *
 ***************************************************************************
 * >> Original Diku Mud copyright (c)1990, 1991 by Sebastian Hammer,       *
 *    Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, & Katja Nyboe.   *
 * >> Merc Diku Mud improvements copyright (C) 1992, 1993 by Michael       *
 *    Chastain, Michael Quan, and Mitchell Tse.                            *
 * >> ROM 2.4 is copyright 1993-1995 Russ Taylor and 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) *
 * >> Oblivion 1.2 is copyright 1996 Wes Wagner                            *
 **************************************************************************/

#include "include.h" // dawn standard includes
#include "nanny.h"
#include "track.h"
#include "channels.h"
#ifdef IMC
#include "imc.h"
#endif

/**************************************************************************/	
// note recycling
NOTE_DATA *note_free;
/**************************************************************************/	
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;
}
/**************************************************************************/	 
// 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 = (BAN_DATA *)alloc_perm(sizeof(*ban));
    }else{
		ban = ban_free;
		ban_free = ban_free->next;
    }
	
    *ban = ban_zero;
    VALIDATE(ban);
    
    ban->intended_people	= &str_empty[0];
	ban->sitemasks			= &str_empty[0];
    ban->ban_date			= current_time;
    ban->reason				= &str_empty[0];
    ban->by					= &str_empty[0];
	ban->expire_date		= 0; // never expire by default
	ban->custom_disconnect_message	=	&str_empty[0];
	ban->allowed_email_masks		=	&str_empty[0];
	ban->disallowed_email_masks		=	&str_empty[0];
	ban->disallowed_email_custom_message=	&str_empty[0];
    return ban;
}
/**************************************************************************/
void free_ban(BAN_DATA *ban)
{
    if (!IS_VALID(ban))
	return;

    free_string(ban->intended_people	);
	free_string(ban->sitemasks			);
    free_string(ban->reason				);
    free_string(ban->by					);
	free_string(ban->custom_disconnect_message	);
	free_string(ban->allowed_email_masks		);
	free_string(ban->disallowed_email_masks		);
	free_string(ban->disallowed_email_custom_message);

    INVALIDATE(ban);

    ban->next = ban_free;
    ban_free = ban;
}
/**************************************************************************/
// connection recycling  
connection_data *connection_allocate()
{
    static connection_data c_zero;
    connection_data *c;

    if(!connection_free){
		c = (connection_data *)alloc_perm(sizeof(*c));

		// set the initial default string values
		c->ident_raw_result=str_dup("");
		c->ident_username=str_dup("");
		c->mxp_version=str_dup("");
		c->mxp_supports=str_dup("");
		c->mxp_options=str_dup("");
		c->terminal_type=str_dup("");

		c->protocol=PROTOCOL_ALL;
		c->contype=CONTYPE_UNSET;
		c->local_ip=str_dup("");
		c->local_port=0;
		c->local_tcp_pair=str_dup("");
		c->remote_ip=str_dup("");
		c->remote_port=0;
		c->remote_tcp_pair=str_dup("");
		c->remote_hostname=str_dup("");
		c->web_request=NULL;
    }else{
		c = connection_free;
		connection_free = connection_free->next;
    }
	
    *c = c_zero;
    VALIDATE(c);

    c->connected_state   = CON_DETECT_CLIENT_SETTINGS;
	c->connected_state_pulse_counter=0;
    c->showstr_head    = NULL;
    c->showstr_point = NULL;
    c->outsize = 2000;
    c->outbuf  = (char *) alloc_mem( c->outsize );
	c->idle_since = current_time; // initialise idle timer to now
	c->resolved=false;
	c->changed_flag=NULL;
	c->multiple_logins=false;
	c->wrong_password_count=0;
	c->parse_colour=true;
	c->pEdit    = NULL;
	c->pString  = NULL;
	c->editor   = 0;		
	c->colour_mode = CT_AUTODETECT;

	// visual debugging default settings
	c->visual_debugging_enabled=false;
	c->visual_debug_hexoutput=true;
	c->visual_debug_flush_before_prompt=true;
	c->visual_debug_strip_prompt=true;
	c->visual_debug_column_width=25;
	return c;
}
/**************************************************************************/
void connection_deallocate(connection_data *c)
{
    if (!IS_VALID(c)){
		bugf("connection_deallocate(): called to deallocate invalid connetion.");
		return;
	}

	// reset to the defaults
	replace_string(c->ident_raw_result, "");
	replace_string(c->ident_username, "");
	replace_string(c->mxp_version, "");
	replace_string(c->mxp_supports, "");
	replace_string(c->mxp_options, "");
	replace_string(c->terminal_type, "");

	c->protocol=PROTOCOL_ALL;
	c->contype=CONTYPE_UNSET;
	replace_string(c->local_ip,"");
	c->local_port=0;
	replace_string(c->local_tcp_pair,"");
	replace_string(c->remote_ip,"");
	c->remote_port=0;
	replace_string(c->remote_tcp_pair,"");
	replace_string(c->remote_hostname,"");

	delete c->web_request;
	c->web_request=NULL;
    free_mem( c->outbuf, c->outsize );
    INVALIDATE(c);
    c->next = connection_free;
    connection_free = c;
}
/**************************************************************************/
/* 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 = (GEN_DATA *)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 = (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 *affect_free;
/**************************************************************************/
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 *obj_free;
/**************************************************************************/
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;

    obj->name		=str_dup("");
    obj->description=str_dup("");
    obj->short_descr=str_dup("");
    obj->owner		=str_dup("");
    obj->killer		=str_dup("");
	obj->lastdrop_remote_ip=str_dup("");

	obj->uid	= get_next_uid();
    VALIDATE(obj);
    return obj;
}
/**************************************************************************/
void free_obj(OBJ_DATA *obj)
{
    AFFECT_DATA *paf, *paf_next;
    EXTRA_DESCR_DATA *ed, *ec_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 = ec_next )
    {
		ec_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 );
	free_string( obj->lastdrop_remote_ip);
    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 = (char_data *)alloc_perm(sizeof(*ch));
    }else{
        ch = char_free;
        char_free = char_free->next;
    }

    *ch				= ch_zero;
	ch->uid			= get_next_uid();
    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->gprompt                 = &str_empty[0];
    ch->prompt                  = &str_empty[0];
    ch->olcprompt               = &str_empty[0];
    ch->prefix					= &str_empty[0];
	ch->remote_ip_copy			= &str_empty[0];

    ch->logon                   = current_time;
    ch->lines                   = PAGELEN;
	ch->level					=0;
	ch->trust					=0;
    for(i = 0; i < 4; i++){
        ch->armor[i]            = 100;
	}
    ch->position                = POS_STANDING;
    ch->hit                     = 20;
    ch->max_hit                 = 20;
    ch->mana                    = 100;
    ch->max_mana                = 100;
    ch->move                    = 100;
    ch->max_move                = 100;

    ch->subversion				= 2;
    ch->last_ic_room            = NULL;
    ch->mounted_on				= NULL;
    ch->ridden_by				= NULL;
    ch->no_xp                   = false;
    ch->subdued                 = false;
    ch->last_force              = -20;  // hasn't been forced
    ch->controlling             = NULL; // not switched into anyone
	ch->colour_prefix			= COLOURCODE;

	// setup the default colours
	ch->saycolour				= 'x';
	ch->motecolour				= 'S';
	
    ch->tethered=false;
    ch->bucking=false;
	
	SET_CONFIG(ch, CONFIG_SHOWMISC);
	SET_CONFIG(ch, CONFIG_AUTORECALL);
	SET_CONFIG(ch, CONFIG_AUTOLANDONREST);
	SET_BIT(ch->comm,COMM_AUTOSELF);	

	for (i = 0; i < MAX_STATS; i ++){
        ch->perm_stats[i] = 1;
        ch->modifiers[i] = 0;
    }
	
	assert(track_table!=NULL);
	ch->track_index = track_table->add_char(ch);

	ch->pload=NULL;

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

	// remove them from the track table sooner than later
	// so the table can record any info about
	// the char before it is freed.
	track_table->del_char(ch);

    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_note(ch->pnote);
#ifdef IMC
    imc_freechardata( ch );
#endif
   	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;
	int i;

    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->karns = 3;              // default karns
    pcdata->next_karn_countdown = (pcdata->karns*700)+200; 
   
	pcdata->emote_index=-1;
	pcdata->say_index=-1;
	pcdata->last_logout_site=&str_empty[0];
	pcdata->last_logout_time=0;
    pcdata->fadein=&str_empty[0];
    pcdata->fadeout=&str_empty[0];
    pcdata->battlelag=&str_empty[0];

	// for email banning verification
	pcdata->email	=str_dup("");
	pcdata->created_from=str_dup("");
	pcdata->unlock_id=str_dup("");

	pcdata->sublevel=0;
	pcdata->sublevel_trains=0;
	pcdata->sublevel_pracs=0;
	pcdata->birthdate=0;
	pcdata->who_text=&str_empty[0];
	pcdata->title=&str_empty[0];
	pcdata->immtitle=&str_empty[0];
    pcdata->immtalk_name=&str_empty[0];
	pcdata->imm_role=&str_empty[0];
	pcdata->history=&str_empty[0];

	// players default to a security of 1 on olc
	if(GAMESETTING5(GAMESET5_DEDICATED_OLC_BUILDING_MUD)){
		pcdata->security= URANGE(0,(game_settings->default_newbie_security_on_olc_port),9);
	}else{
		pcdata->security=0;
	}

	{	// setup the replaytell buffers	
		for(i=0; i<MAX_REPLAYTELL; i++){
			pcdata->replaytell_text[i]=&str_empty[0];
		}
		pcdata->next_replaytell=0;
	}

	{	// setup the replayroom buffers
		for(i=0; i<MAX_REPLAYROOM; i++){
			pcdata->replayroom_text[i]=&str_empty[0];
		}
		pcdata->next_replayroom=0;
	}

	{	// setup the replaychannels buffers
		for(i=0; i<MAX_REPLAYCHANNELS; i++){
			pcdata->replaychannels_text[i]=&str_empty[0];
		}
		pcdata->next_replaychannels=0;
	}

	for (int index=0; index<RPS_AUDIT_SIZE; index++){
		pcdata->emotecheck[index]=str_dup("");
		pcdata->saycheck[index]=str_dup("");
	}

	pcdata->letter_workspace_text=str_dup("");

	pcdata->preference_msp=PREF_AUTOSENSE;
	pcdata->preference_mxp=PREF_AUTOSENSE;
	pcdata->preference_dawnftp=PREF_AUTOSENSE;
	pcdata->preference_colour_in_socials=PREF_AUTOSENSE; // use the mudwide default

	for(alias=0; alias<MAX_HELP_HISTORY; alias++){
		pcdata->help_history[alias]=str_dup("");
	}

	pcdata->afk_message=str_dup("");
	pcdata->channeloff=CHANNEL_FLAME;
	pcdata->autoafkafter=0;
	pcdata->hero_level_count=0;

    VALIDATE(pcdata);
    return pcdata;
}
/**************************************************************************/	
void free_pcdata(PC_DATA *pcdata)
{
    int alias;
	int index;
	int i;

    if (!IS_VALID(pcdata))
	return;
	
	for (index=0; index<RPS_AUDIT_SIZE; index++){
		free_string(pcdata->emotecheck[index]);
		free_string(pcdata->saycheck[index]);
	}

    free_string(pcdata->pwd);
    free_string(pcdata->bamfin);
    free_string(pcdata->bamfout);
    free_buf(pcdata->buffer);
    
    for (alias = 0; alias < MAX_ALIAS; alias++)
    {
        free_string(pcdata->alias[alias]);
        free_string(pcdata->alias_sub[alias]);
    }
	free_string(pcdata->last_logout_site);
    free_string(pcdata->fadein);
    free_string(pcdata->fadeout);

	// for email banning verification
	free_string(pcdata->email);
	free_string(pcdata->created_from);
	free_string(pcdata->unlock_id);
	free_string(pcdata->who_text);
	free_string(pcdata->title);
	free_string(pcdata->immtitle);

	// free the replaytell stuff
	for(i=0; i<MAX_REPLAYTELL; i++){
		free_string(pcdata->replaytell_text[i]);
	}

	// free the replayroom buffers
	for(i=0; i<MAX_REPLAYROOM; i++){
		free_string(pcdata->replayroom_text[i]);
	}

	// free the replaychannels buffers
	for(i=0; i<MAX_REPLAYCHANNELS; i++){
		free_string(pcdata->replaychannels_text[i]);
	}
	
	// free the help history stuff
	for(i=0; i<MAX_HELP_HISTORY; i++){
		free_string(pcdata->help_history[i]);
	}
	
    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 = ((int)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;

/**************************************************************************/	
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, 60000
};

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

/**************************************************************************/	
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 = str_len(buffer->string) + str_len(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;
				bugf("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 
MPROG_LIST *mprog_free;
/**************************************************************************/	
MPROG_LIST *new_mprog(void)
{
	static MPROG_LIST mp_zero;
	MPROG_LIST *mp;
	
	if (mprog_free == NULL)
		mp = (MPROG_LIST *)alloc_perm(sizeof(*mp));
	else
	{
		mp = mprog_free;
		mprog_free=mprog_free->next;
	}
	
	*mp = mp_zero;
	mp->trig_type	= 0;
	mp->prog		= NULL;
	return mp;
}
/**************************************************************************/	
void free_mprogs(MPROG_LIST *mp)
{
	if(!mp){
		return;
	}

	if(mp->next){
		free_mprogs(mp->next);
	}
	mp->next = mprog_free;
	mprog_free = mp;
}
/**************************************************************************/