dawn/notes/
dawn/src/
dawn/src/docs/
/**************************************************************************/
// who.cpp - The who command and related code
/***************************************************************************
 * 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

/**************************************************************************/
// prototypes for the whoformat functions in whofmt.cpp
char *whoformat_dawn( char_data *ch, char_data *wch, bool two_column);
char *whoformat_storm( char_data *ch, char_data *wch, bool two_column);
char *whoformat_just_names( char_data *ch, char_data *wch, bool two_column);
char *whoformat_endless( char_data *ch, char_data *wch, bool two_column);
char *whoformat_wotl( char_data *ch, char_data *wch, bool two_column);

/**************************************************************************/
struct	who_format_type who_formatter [] =
{
	// name,			function ran,			use two columns when a lot of players are on
	{ "default",		NULL,					false		}, // spacer - if you select default you get the mud whoformat setting
	{ "dawn",			whoformat_dawn,			true		}, 
	{ "storm",			whoformat_storm,		false		}, 
	{ "endless",		whoformat_endless,		false		}, 
	{ "just_names",		whoformat_just_names,	false		}, 
	{ "wotl",			whoformat_wotl,			false		}, 
	{ "", NULL, false}
};
/**************************************************************************/
void who_show_formats(char_data *ch)
{
	int i;
	for(i=0; !IS_NULLSTR(who_formatter[i].name); i++){
		ch->printlnf("   %s", who_formatter[i].name);
	}
}

/**************************************************************************/
int who_format_lookup(char *argument)
{

	int i;
	// do an exact lookup on a who format name first
	for ( i= 0; !IS_NULLSTR(who_formatter[i].name); i++){
		if(!str_cmp( argument, who_formatter[i].name))
			return i;
	}

	// do an prefix lookup on a who format name
	for ( i= 0; !IS_NULLSTR(who_formatter[i].name); i++){
		if(!str_prefix( argument, who_formatter[i].name))
			return i;
	}

	return -1;
}
/**************************************************************************/
// return the format 
int who_get_format(char_data *ch)
{
	if(ch->pcdata && ch->pcdata->who_format>0){
		return ch->pcdata->who_format;
	}
	return game_settings->default_who_format_index;
}
/**************************************************************************/
const char *who_format_name(int index)
{
	return who_formatter[index].name;
}

/**************************************************************************/
// used to pick which format of the wholist you want to see
void do_whoformat( char_data *ch, char *argument )
{
    // unswitched mobs can't use the wholist
    if (IS_UNSWITCHED_MOB(ch)){
		ch->println("players only sorry");
        return;
    }

	if(IS_NULLSTR(argument)){
		ch->println("syntax: whoformat <format>");
		ch->println("Where format is one of the following:");
		who_show_formats(ch);
		ch->printlnf("Your who format is currently set to %s.", who_format_name(TRUE_CH(ch)->pcdata->who_format));

		if(IS_ADMIN(ch)){
			ch->println("adminnote: The mudwide default format can be changed in gameedit with setwhoformat.");
		}
		return;
	}

	int format=who_format_lookup(argument);
	if(format<0){
		ch->printlnf("'%s' is not an available who format.", argument);
		do_whoformat(ch, "");
		return;
	}

	if(TRUE_CH(ch)->pcdata->who_format==format){
		ch->printlnf("Your who format is already set to %s.", who_formatter[format].name);
		return;
	}

	ch->printlnf("Who format changed from %s to %s.",
		who_formatter[TRUE_CH(ch)->pcdata->who_format].name,
		who_formatter[format].name);

	TRUE_CH(ch)->pcdata->who_format=format;
}

/**************************************************************************/
void do_whois (char_data *ch, char *)
{

	ch->println("`xThe whois command has been replaced by a searchable wholist.");
	ch->printlnf( "e.g. for example if you wanted to see all names starting\r\n"
		"with K on the wholist, type `=Cwho k`x ... you can be as specific\r\n"
		"as you like, eg `=Cwho ka`x will show all names starting with ka." );
	return;
		  
}

/***********************************************************************/
void do_count( char_data *ch, char *)
{
    int count, immhide_count, all_count, displayed_count;
    char_data *cch;

    count             = 0;
    immhide_count     = 0;
    all_count         = 0;
    displayed_count   = 0;

	for ( cch= player_list; cch; cch= cch->next_player)
    {
        all_count++;  // count the playing people 
        if ( can_see_who(ch, cch) )
        {
            count++;  // visible people for this char 
        }
        else if (IS_IMMORTAL(cch))
        { 
            immhide_count++; // hiding imm count 
        }
    }

    max_on = UMAX(all_count,max_on);

	if (true_count <= all_count)
	{
		true_count = all_count;
		maxon_time = current_time;
	}

	if (hotrebootmaxon<=all_count)
	{
		hotrebootmaxon= all_count;
		hotrebootmaxon_time = current_time;
	}

    displayed_count = all_count-immhide_count;
 
	if (max_on == displayed_count){
        ch->printlnf("`xThere %s %d character%s on - The most since the last reboot.\r\n",
            (displayed_count==1)?"is":"are",
            displayed_count,
            (displayed_count==1)?"":"s");
    }else{
        ch->printlnf("`xThere %s %d character%s on.\r\n"
                    "The most characters on since the last reboot has been %d.\r\n",
            (count==1)?"is":"are",
            count,
            (count==1)?"":"s",
            max_on);
	}

}

/***********************************************************************/
char *get_whocount(char_data *ch, int displayed_total, bool noimm4morts)
{
    int immhide_count, all_count, displayed_count;
	static char rBuf[MSL];
	char countbuf[MSL];
    char_data *cch;

    immhide_count     = 0;
    all_count         = 0;
    displayed_count   = 0;

    for ( cch = player_list; cch; cch = cch->next_player )
    {
		all_count++;  // count the playing people

		if ((noimm4morts && cch->level>=LEVEL_IMMORTAL 
			&& !IS_IMMORTAL(ch))||(!IS_SET(cch->comm, COMM_WHOVIS)
				&& IS_IMMORTAL(cch) && !can_see_who(ch, cch)))
		{ 
			immhide_count++; // hiding imm count
		}
    }

    max_on = UMAX(all_count,max_on);

	if (true_count <= all_count)
	{
		true_count = all_count;
		maxon_time = current_time;
	}

	if (hotrebootmaxon<=all_count)
	{
		hotrebootmaxon= all_count;
		hotrebootmaxon_time = current_time;
	}

    displayed_count = all_count-immhide_count;
 
    sprintf(countbuf, "%d", displayed_total);
    if (max_on == displayed_count){
        sprintf(rBuf,"`xThere %s %d character%s on - The most since the last reboot.\r\n"
                    "%d of these characters are visible to you.\r\n",
            (displayed_count==1)?"is":"are",
            displayed_count,
            (displayed_count==1)?"":"s",
            displayed_total);
	}else{
		if(displayed_count==1){
			sprintf(rBuf,"`xThere is 1 character on you can see (yourself).\r\n"
						"The most characters on since the last reboot has been %d.\r\n",
				max_on);
		}else{
			sprintf(rBuf,"`xThere are %d character%s on, of which %s %s visible to you.\r\n"
						"The most characters on since the last reboot has been %d.\r\n",
				displayed_count,
				(displayed_count==1)?"":"s",
				displayed_total==displayed_count?"all":countbuf,
				(displayed_total==1)?"is":"are",
				max_on);
		}
	}

	return (rBuf);
}

/**************************************************************************/
void show_whocount( char_data *ch, int displayed_total, bool noimm4morts)
{
	ch->printf( "%s", get_whocount( ch, displayed_total, noimm4morts) );
}

/**************************************************************************/
// redirects who to the correct function
char *who_format_redirector(char_data *ch, char_data *wch, bool two_columns)
{
	int who_format=who_get_format(ch);

	// calculate how long a player has been idle - used for logging and displaying
	int idletime;
	if(wch->desc){
		idletime=(int)(current_time - wch->desc->idle_since)/60;
	}else{
		idletime=wch->idle;
	}

	// if a player is logged, log all idle, afk and linkdead 
	// people they see on the wholist so we can tell if 
	// they knew the person was in one of those states when 
	// starting a pkill figure
	if ( !IS_NPC(ch) && IS_SET(ch->act, PLR_LOG)){
		char logbuf[MIL];logbuf[0]='\0';
		if(IS_SET(wch->comm, COMM_AFK)){
			strcat(logbuf," [AFK]");
		}
		if(IS_LINKDEAD(wch)){
			strcat(logbuf," [LD]");
		}
		if( idletime >= 1 ){
			strcat(logbuf,FORMATF(" %dm idle", idletime));
		}
		if(!IS_NULLSTR(logbuf)){			
			append_playerlog( ch, FORMATF("wholog:%-13s %s", wch->name, logbuf));
		}
	}

	char * who_result=who_formatter[who_format].whofunc(ch, wch, two_columns);

	char idle[MIL];
    if ( idletime >= 1 ){
		if(GAMESETTING2(GAMESET2_NO_AUTOLOGOFF_FOR_IMM)){
			if(idletime>120){
				sprintf( idle, "%2d:%02d", idletime/60, idletime%60);
			}else{
				sprintf( idle, "%4dm", idletime);
			}
		}else{
			sprintf( idle, "%3dm", idletime);
		}
    }else{
		if(GAMESETTING2(GAMESET2_NO_AUTOLOGOFF_FOR_IMM)){
	        strcpy( idle, "     " );
		}else{
	        strcpy( idle, "    " );
		}
	}

	return FORMATF("%s%s", idle, who_result);
}

/**************************************************************************/
void do_who( char_data *ch, char *argument )
{
	// You should NOT replace this function to implement your own wholist!
	// You SHOULD write your own who format function and customise the 
	// 'who header' defines shown directly after this documentation.  You 
	// can then use the gameedit flags to change how the wholist behaves. 
	// Look in whofmt.cpp for a number of example formatting functions etc.
	// The advantages of this approach is the various methods of sorting 
	// the wholist are already done for you, extra features such as idle
	// idle time are also correctly displayed.  In addition the code 
	// correctly supports in game commands such as whoinvis, whovis etc.
	// and gives the players potentially the option to pick an alternative 
	// format from a selection (assuming the whoformat command is enabled).

	// The do_who() function creates a buffer to store the entire wholist
	// then loops thru the player_list a number of times/ways to get create 
	// a list of connected players in the format as per the gamesetting flags
	// described below.

	// The player_list is looped using the variable wch, and the player who
	// requested the wholist is refered to as 'ch' within this function.
	// The line (or lines) in the wholist to display each wch, is formatted
	// according to what ch's has selected their who format function to be.
	// these functions are listed at the top of whofmt.cpp.
	// the directing to the correct who formatter is handled by the 
	// who_format_redirector() function.  The idle time of each wch is 
	// prefixed to what who_format_redirector() returns.

	// some of the gameedit flags relating to the wholist:
	//  GAMESET2_WHOLIST_SORT_BY_LEVEL - list is level sorted
	//  GAMESET2_WHOLIST_IMMS_BEFORE_MORTS - immortals are at the top of the list
	//  GAMESET2_NO_AUTOLOGOFF_FOR_IMM - this stops immortals being logged off
	//           if this is set, the idle times for imms can get very large
	//           therefore an extra space is inserted where the idle time is
	//  GAMESET2_DONT_DISPLAY_WHO_4_LOGIN - the 'autowho at login' isn't run as part
	//           of the login process (useful if your who format is crashing the mud)
	//  GAMESET4_LOGINWHO_HIDES_IMMS_FROM_MORTS - the 'autowho at login' doesn't 
	//           display immortals to mortal players
	//  GAMESET5_DEDICATED_PKILL_STYLE_MUD - when the mud is flagged in pkill 
	//           mode the pkill header is shown at the top of the wholist
	//  GAMESET3_WHO_TITLE_DISABLED - some of the custom formats support 
	//           disabling the display of who titles
	//  GAMESET4_3TIER_IMMRANKS_IN_WHO - an alternative immortal level system 
	//           where there is only 3 categories - imp, admin and immortal

#define WHOHEADER_MORTALS "`=\x81-========= `=\x96MORTALS `=\x81=========-`x\r\n"
#define WHOHEADER_IMMORTALS "`=\x82-======== `=\x83IMMORTALS `=\x82========-`x\r\n"
#define WHOHEADER_PKILL_PORT "`r-`R=`r=`R=`r=`R=`r=`R=`r=`R=`r=`R=`r= `R P K I L L   P O R T  `r=`R=`r=`R=`r=`R=`r=`R=`r=`R=`r-`x\r\n"

	BUFFER *output;
	int nMatch;
	bool noimm4morts=false;
    char_data *wch;
	char buf[MIL], fbuf[MIL];
	bool remove_holylight=false;
	bool immSeen=false;
	int mortcolcount, immcolcount, currentcol;
	bool two_columns =false;
	bool levelsort=GAMESETTING2(GAMESET2_WHOLIST_SORT_BY_LEVEL)?true:false; 
	bool imm_before_morts=GAMESETTING2(GAMESET2_WHOLIST_IMMS_BEFORE_MORTS)?true:false; 

	int lines_to_show=ch->lines;

	if (lines_to_show==0){
        lines_to_show=9091; // pick any number greater than max on
	}

	char spacer[10];
	if(GAMESETTING2(GAMESET2_NO_AUTOLOGOFF_FOR_IMM)){
	    strcpy( spacer, "     " );
	}else{
	    strcpy( spacer, "    " );
	}


	if ( is_number( argument  ) ){
		ch->println("Levels are not supported by who.");
		return;
	}

	strcpy(buf, argument);

	if(!str_cmp(buf,"-noimm4morts"))
	{
		if(GAMESETTING4(GAMESET4_LOGINWHO_HIDES_IMMS_FROM_MORTS)){
			noimm4morts=true;
		}
		buf[0]='\0';
	}

    /*
     * Now show matching chars.
     */

    nMatch = 0;
    output = new_buf();	


	if(GAMESETTING5(GAMESET5_DEDICATED_PKILL_STYLE_MUD))
	{
		char pkbuf[MSL];
		// the pkill port header
		add_buf(output,WHOHEADER_PKILL_PORT);
        sprintf(pkbuf,"   Max Pkills  : %13s (L%d) of %d\r\n",
            p9999maxpkname, p9999maxpklevel, p9999maxpk);
		add_buf(output,pkbuf);
        sprintf(pkbuf,"   Max Pdefeats: %13s (L%d) of %d\r\n",
            p9999maxpdname, p9999maxpdlevel, p9999maxpd);
		add_buf(output,pkbuf);	
        // the mortals header
		add_buf(output,spacer);
        add_buf(output,WHOHEADER_MORTALS);
	}

	if (IS_IMMORTAL(ch) && !IS_SET(ch->act, PLR_HOLYLIGHT)){
        SET_BIT(ch->act, PLR_HOLYLIGHT);
		remove_holylight=true;
	}

	// count how many lines will be displayed
	mortcolcount=immcolcount=0;
    for ( wch = player_list; wch; wch = wch->next_player )
    {
		// players in the same clan can always see each other on who
		if(!(ch->clan && is_same_clan(ch,wch))){
			if (!can_see_who(ch,wch))
				continue;
		}

		// filter on name and clan name if appropriate 
		if( wch->clan>0 && (is_same_clan(ch,wch)||IS_IMMORTAL(ch))){
			if (!is_name( buf, wch->name )
				&& !is_name( buf, wch->clan->notename())
				)// filter on name/clanname
				continue;
		}else{
			if (!is_name( buf, wch->name )) // filter on name 
				continue;
		}

		// no imms on the mortals list
		if (wch->level>=LEVEL_IMMORTAL){
			immcolcount++;
			continue;
		}
		mortcolcount++;
	}

	if (immcolcount>0){
		immcolcount++;
	}
	if (mortcolcount+immcolcount >= lines_to_show){
		two_columns=true;
	}

	// if the who formatter can't support two columns, then we drop back to one
	if(!who_formatter[who_get_format(ch)].two_column_supported){
		two_columns=false;
	}

	// use an array of pointers to sort the list by level if necessary
	char_data *first_on_who=NULL;
	if(levelsort){
		char_data *level_sorted_chars_start[ABSOLUTE_MAX_LEVEL+1];
		char_data *level_sorted_chars_end[ABSOLUTE_MAX_LEVEL+1];
		
		// start by setting the array to NULL
		memset(level_sorted_chars_start, 0, sizeof(level_sorted_chars_start));
		memset(level_sorted_chars_end, 0, sizeof(level_sorted_chars_end));
				
		// loop thru adding each one to the pointer array
		// players of equal level are inserted closer to the end 
		// as they go, so the longer on the lower on the list they appear
		int level;
	    for ( wch = player_list; wch; wch = wch->next_player )
		{
			level=URANGE(0, wch->level-1, ABSOLUTE_MAX_LEVEL);
			if(level_sorted_chars_start[level]){
				level_sorted_chars_end[level]->next_who_list=wch;
			}else{
				level_sorted_chars_start[level]=wch;
			}
			level_sorted_chars_end[level]=wch;
			wch->next_who_list=NULL;
		}

		// now loop thru linking the end pointers together
		int last_level=-1;
		for(level=MAX_LEVEL; level>=0; level--){
			if(level_sorted_chars_end[level]){
				if(last_level!=-1){
					level_sorted_chars_end[last_level]->next_who_list=
						level_sorted_chars_start[level];
				}else{
					first_on_who=level_sorted_chars_start[level];
				}
				last_level=level;
			}
		}
	}else{
		first_on_who=player_list;
	}

	currentcol=0;
	if(!imm_before_morts){
		// list all mortals
		for ( wch = first_on_who; wch; wch = levelsort?wch->next_who_list:wch->next_player )
		{
			// players in the same clan can always see each other on who
			// except imms in clans
			if(!(ch->clan>0 && is_same_clan(ch,wch))){
				if(!can_see_who(ch,wch)){
					continue;
				}
			}

			if (noimm4morts && wch->level >= LEVEL_IMMORTAL 
				&& !IS_IMMORTAL(ch)){
				continue;
			}

			// filter on name and clan name if appropriate 
			if( wch->clan>0 && (is_same_clan(ch,wch)||IS_IMMORTAL(ch))){
				if (!is_name( buf, wch->name )
					&& !is_name( buf, wch->clan->notename())
					)// filter on name/clanname
					continue;
			}else{
				if (!is_name( buf, wch->name )) // filter on name 
					continue;
			}

			// no imms on the mortals list
			if(wch->level>=LEVEL_IMMORTAL){
				if(can_see_who(ch,wch)){
					immSeen=true;
				}
				continue;
			}

			nMatch++;

			if (two_columns){
				++currentcol%=2;
				sprintf(fbuf, "%s`x %s", str_width(who_format_redirector(ch, wch, two_columns),38), 
					currentcol==0?"\r\n":"");
				add_buf(output,fbuf);
			}else{
				add_buf(output, who_format_redirector(ch, wch, false));
				add_buf(output, "\r\n");
			}
		}
	}

	// list immortals 
	if(immSeen || imm_before_morts)
	{
		// add linefeed if nessary
		if (currentcol==1){
			add_buf(output, "\r\n");
		}

		// the immortals header
		add_buf(output,spacer);
		add_buf(output,WHOHEADER_IMMORTALS);

		currentcol=0;
		for ( wch = first_on_who; wch; wch = wch = levelsort?wch->next_who_list:wch->next_player )
		{
			if (!can_see_who(ch,wch))
				continue;

			// no mortals
			if (wch->level<LEVEL_IMMORTAL)
				continue;

			if (noimm4morts && wch->level >= LEVEL_IMMORTAL 
				&& !IS_IMMORTAL(ch))
				continue;

			if (!is_name( buf, wch->name )) // filter on name 
				continue;

			nMatch++;
			if (two_columns){
				++currentcol%=2;
				sprintf(fbuf, "%s %s", str_width(who_format_redirector(ch, wch, true),38), 
					currentcol==0?"\r\n":"");
				add_buf(output,fbuf);
			}else{
				add_buf(output, who_format_redirector(ch, wch, false));
				add_buf(output, "\r\n");
			}
		}
	}

	if(imm_before_morts){
        // the mortals header
		add_buf(output,spacer);
        add_buf(output, WHOHEADER_MORTALS);
		// list all mortals
		currentcol=0;
		for ( wch = first_on_who; wch; wch = levelsort?wch->next_who_list:wch->next_player )
		{
			// players in the same clan can always see each other on who
			if(!(ch->clan>0 && is_same_clan(ch,wch))){
				if (!can_see_who(ch,wch))
					continue;
			}

			if (noimm4morts && wch->level >= LEVEL_IMMORTAL 
				&& !IS_IMMORTAL(ch))
				continue;

			// filter on name and clan name if appropriate 
			if( wch->clan>0 && (is_same_clan(ch,wch)||IS_IMMORTAL(ch))){
				if (!is_name( buf, wch->name )
					&& !is_name( buf, wch->clan->notename())
					)// filter on name/clanname
					continue;
			}else{
				if (!is_name( buf, wch->name )) // filter on name 
					continue;
			}

			// no imms on the mortals list
			if (wch->level>=LEVEL_IMMORTAL){
				immSeen=true;
				continue;
			}

			nMatch++;

			if (two_columns){
				++currentcol%=2;
				sprintf(fbuf, "%s`x %s", str_width(who_format_redirector(ch, wch, two_columns),38), 
					currentcol==0?"\r\n":"");
				add_buf(output,fbuf);
			}else{
				add_buf(output, who_format_redirector(ch, wch, false));
				add_buf(output, "\r\n");
			}
		}
	}


	if (currentcol==1){
		add_buf(output, "\r\n");
	}
		

    show_whocount(ch, nMatch, noimm4morts);

    if (IS_NEWBIE(ch)){
        add_buf(output,"see 'help who' for an explanation of the symbols.\r\n");
    }

    if (nMatch<15){
		if(number_range(1,2)==1){
			add_buf(output,"`xFor more info on maxon and other mud related stats type `=Cmudstats`x.\r\n");
		}else{
			add_buf(output,"`xYou can customise the colours of the wholist using the `=Ccolour`x command.\r\n");
		}
	}

    ch->sendpage(buf_string(output));
    free_buf(output);

	if(remove_holylight){
		REMOVE_BIT(ch->act, PLR_HOLYLIGHT);
	}

#ifdef unix    
	// lag those that spam who 
    if (!IS_NPC(ch) && !IS_IMMORTAL(ch))
    {  
        if ( (current_time - 90) < ch->pcdata->last_who)
        {
            WAIT_STATE( ch, 4 ); // 1 second lag 
        }
        if ( (current_time - 60) < ch->pcdata->last_who)
        {
            WAIT_STATE( ch, 12 ); // 3 seconds lag 
        }
        if ( (current_time - 30) < ch->pcdata->last_who)
        {
            WAIT_STATE( ch, 20 ); 
        }
        ch->pcdata->last_who = current_time;
    }
#endif
    return;
}

/**************************************************************************/
void do_whotext( char_data *ch, char *argument )
{
	if(IS_NULLSTR(argument)){
		ch->println("Sets the *** text for maxlevel+1 in the wholist.");
		return;
	}

	if(c_str_len(argument )!=3){
		ch->println("The argument must have a visible width of 3!");
		return;
	}
	
	if(ch->pcdata){
		ch->printlnf( "whotext changed from '%s' to '%s'",
			ch->pcdata->who_text, argument);
		free_string(ch->pcdata->who_text);
		ch->pcdata->who_text=str_dup(argument);
	}else{
		ch->println("Players only sorry!");
	}

}
/**************************************************************************/
void do_title(char_data *ch, char *argument)
{
	// unswitched mobs can't be seen on the who
	if(IS_UNSWITCHED_MOB(ch)){
		ch->println( "Players or switched players only." );
		return;
	}

	if(IS_NULLSTR(argument)){
		ch->println("syntax: Title <text to appear to the right of your name on the wholist>.");
		ch->println("syntax: title -  (to clear your title)");
		return;
	}

	if(c_str_len(argument)>45){
		ch->printlnf("Your title can be a maximum of 45 visible characters long, that is %d.",
			c_str_len(argument));
		return;
	}

	if(c_str_len(argument)<0){
		ch->println("You can't put newline colour codes in your title sorry.");
		return;
	}

	if(!str_cmp(argument,"-")){
		ch->println("Your title has been cleared.");
		replace_string(TRUE_CH(ch)->pcdata->title,"");
		return;
	}

	if(IS_NULLSTR(TRUE_CH(ch)->pcdata->title)){
		ch->printlnf("Your who title has been set to '%s'", argument);
	}else{
		ch->printlnf("Your who title has changed from '%s' to '%s'", 
			TRUE_CH(ch)->pcdata->title,
			argument);
	}
	replace_string(TRUE_CH(ch)->pcdata->title, argument);
}
/**************************************************************************/
void do_immtitle(char_data *ch, char *argument)
{
	// unswitched mobs can't be seen on the who
	if(IS_UNSWITCHED_MOB(ch)){
		ch->println( "Players or switched players only." );
		return;
	}

	if(IS_NULLSTR(argument)){
		ch->println("Syntax: immtitle <text to appear in place of the race on the wholist>.");
		ch->println("Syntax: 'immtitle default' to set back to your racial title.");
		return;
	}

	if(!str_cmp(argument,"default")){
		if(IS_NULLSTR(TRUE_CH(ch)->pcdata->immtitle)){
			ch->println("Your who immtitle is already the default");
		}else{
			ch->printlnf("Your who immtitle has been set back to the default, it was previously '%s'", 
				TRUE_CH(ch)->pcdata->immtitle);
			replace_string(TRUE_CH(ch)->pcdata->immtitle, "");
		}
		return;
	}

	if(c_str_len(argument)!=5){
		ch->println("Your immtitle must work out to be exactly 5 visible characters long (you can use colour codes).");
		return;
	}

	if(IS_NULLSTR(TRUE_CH(ch)->pcdata->immtitle)){
		ch->printlnf("Your who immtitle has been set to '%s'", argument);
	}else{
		ch->printlnf("Your who immtitle has changed from '%s' to '%s'", 
			TRUE_CH(ch)->pcdata->immtitle,
			argument);
	}
	replace_string(TRUE_CH(ch)->pcdata->immtitle, argument);
}
/**************************************************************************/
/**************************************************************************/