dawn/notes/
dawn/src/
dawn/src/docs/
/**************************************************************************/
// File: social.cpp - Kal's complete rewrite of the social 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 the dawn license *
 *    in licenses.txt... In particular, you may not remove this copyright  *
 *    notice.                                                              *
 **************************************************************************/
#include "include.h"
#include "socials.h"
#include "channels.h"

/**************************************************************************/
social_type *social_list=NULL;
/**************************************************************************/
char * string_replace_all( char * orig, char * old, char * newstr );
void do_mpqueue(char_data *ch, char *argument);
/**************************************************************************/
// default constructor
social_type::social_type()
{
	for(int i=0; i<SOCIAL_ATMAX; i++){
		acts[i]=str_dup("");
	}
	position_flags= (1<<(POS_RESTING )) | (1<<(POS_SITTING )) 
		 | (1<<(POS_KNEELING)) | (1<<(POS_FIGHTING)) | (1<<(POS_STANDING));
	social_flags=	SOC_IN_OOC|SOC_IN_IC;
}
/**************************************************************************/
// default destructor
social_type::~social_type()
{
	for(int i=0; i<SOCIAL_ATMAX; i++){
		free_string(acts[i]);
	}
}
/**************************************************************************/
// return true if ran correctly, i.e. the target was found
bool social_type::process_social_execution(char_data *ch, char *argument, bool global)
{
	char arg[MIL];
	MOBtrigger=true;
	argument=one_argument(argument, arg);

	char_data *target;
	ACTTO_TYPE room_world;
	if(global){
		target=get_whovis_player_world(ch, arg);
		room_world=TO_WORLD;
	}else{
		target=get_char_room(ch, arg);
		room_world=TO_ROOM;
	}

	if(IS_NULLSTR(arg)){
		if(IS_NULLSTR(acts[SOCIAL_ATNOTARGET_MSG2SELF]) 
			&& IS_NULLSTR(acts[SOCIAL_ATNOTARGET_MSG2OTHERS])){
			ch->printlnf("The %s social requires more parameters.",	name);
			ch->printlnf("Type `=Csocshow %s`x to find out more about the social.",	name);
			MOBtrigger=false;
			return false;
		}
		act(acts[SOCIAL_ATNOTARGET_MSG2SELF],	ch, NULL, NULL, TO_CHAR);
		act(acts[SOCIAL_ATNOTARGET_MSG2OTHERS], ch, NULL, NULL, TO_ROOM);
		MOBtrigger=false;
		return false;
	}

	if(target){
		// target is self
		if(target==ch){
			if(IS_NULLSTR(acts[SOCIAL_ATSELF_MSG2SELF]) 
				|| IS_NULLSTR(acts[SOCIAL_ATSELF_MSG2OTHERS])){
				ch->printlnf("The %s social can't be directed at yourself.",	name);
				ch->printlnf("Type `=Csocshow %s`x to find out more about the social.",	name);
				MOBtrigger=false;
				return false;
			}			
			act(acts[SOCIAL_ATSELF_MSG2SELF],	ch, NULL, NULL, TO_CHAR);
			act(acts[SOCIAL_ATSELF_MSG2OTHERS], ch, NULL, NULL, room_world);
			MOBtrigger=false;
			return false;
		}

		if(IS_NULLSTR(acts[SOCIAL_ATTARGET_MSG2SELF]) 
			|| IS_NULLSTR(acts[SOCIAL_ATTARGET_MSG2TARGET])
			|| IS_NULLSTR(acts[SOCIAL_ATTARGET_MSG2OTHERS]))
		{
			ch->printlnf("The %s social can't be directed at others.",	name);
			ch->printlnf("Type `=Csocshow %s`x to find out more about the social.",	name);
			MOBtrigger=false;
			return false;
		}			
		// target is another
		act(acts[SOCIAL_ATTARGET_MSG2SELF],	ch, NULL, target, TO_CHAR);
		act(acts[SOCIAL_ATTARGET_MSG2TARGET], ch, NULL, target, TO_VICT);
		act(acts[SOCIAL_ATTARGET_MSG2OTHERS], ch, NULL, target, TO_NOTVICT);
		MOBtrigger=false;

		// check for a mob response
		if(	!IS_NULLSTR(acts[SOCIAL_ATTARGET_MOBTARGETRESPONSE])
			&&	!IS_NPC(ch) 
			&&	IS_NPC(target) 
			&&	!IS_AFFECTED(target, AFF_CHARM)
			&&	!IS_SET(target->act, ACT_NOAUTOSOCIAL)
			&&	!IS_CONTROLLED(target)
			&&	IS_AWAKE(target)
			&&	can_see(target, ch)
		  )
		{
			// Conditions were right, so target happened to be a mob that executes the response 
			char buf[MSL];
			sprintf(buf,"1 %s", acts[SOCIAL_ATTARGET_MOBTARGETRESPONSE]);
			char *command=str_dup(buf);
			command=string_replace_all(command,"$N", ch->name);
			// queue the response to be done in 1 second	
			do_mpqueue(target, command);
			free_string(command);
		}
		return true;
	}

	// someone specified not found though
	ch->printlnf("You can't find any '%s' to direct the social '%s' towards.",
		arg, name);

	return false;

}
/**************************************************************************/
void social_type::execute_social(char_data *ch, char *argument, bool global)
{
	RECORD_TO_REPLAYROOM=true;
	EXECUTING_SOCIAL=true; // used for players to turn off colour in socials
	process_social_execution(ch, argument, global);
	EXECUTING_SOCIAL=false;
	RECORD_TO_REPLAYROOM=false;
}
/**************************************************************************/
// find a social, based on the character using it
social_type *find_social(char_data * ch, char *social)
{
	social_type *s;

	for(s=social_list; s; s=s->next){
		if(IS_SET(s->social_flags, SOC_IMM_ONLY) && !IS_IMMORTAL(ch)){
			continue;
		}

		if(!str_prefix(social, s->name)){
			return s;
		}
	}
	return NULL;
};
/**************************************************************************/
// return true if a social was found and ran
bool check_social(char_data *ch,char * command, char * argument, bool global)
{
	social_type *soc=find_social(ch, command);

	if(soc){
		if(!global){
			// do position checks etc
			int pos_flag= 1<<ch->position;
			if(!IS_SET(soc->position_flags, pos_flag)){
				ch->printlnf("You can't use the '%s' social in your current position.", soc->name);
				return true;
			}

			// IC / OOC room checks
			if(IS_IC(ch) && !IS_SET(soc->social_flags, SOC_IN_IC)){
				ch->printlnf("You can't use the '%s' social in an IC room.", soc->name);
				return true;
			}
			if(IS_OOC(ch) && !IS_SET(soc->social_flags, SOC_IN_OOC)){
				ch->printlnf("You can't use the '%s' social in an OOC room.", soc->name);
				return true;
			}
		}

		soc->execute_social(ch, argument, global);
		return true; // social found and ran
	}
	return false; // social not found
}
/**************************************************************************/
// assume the name field in soc is all lowercase
void social_add_sorted_to_list(social_type *soc, bool replace) 
{
	if(!social_list){
		soc->next=NULL;
		social_list=soc;
		return;
	}

	social_type *node=social_list;
	social_type *prev=NULL;

	while(node && strcmp(soc->name, node->name)>0){
		prev=node;
		node=node->next;
	}

	if(node && (strcmp(soc->name, node->name)==0)){ // can't have duplicated entries
		if(replace){
			if(prev){ // replace node
				soc->next=node->next;
				delete prev->next;
				prev->next=soc;
			}else{ // replace first in the list
				assert(node==social_list);
				soc->next=social_list->next;
				delete social_list;
				social_list=soc;
			}
		}else{
			delete soc;
		}
		return;
	}
	
	if(prev){
		soc->next=prev->next;
		prev->next=soc;
	}else{ // add to be first in the list
		assert(node==social_list);
		soc->next=social_list;
		social_list=soc;
	}
}
/**************************************************************************/
// import socials from the old socials table
void do_social_import(char_data *ch, char *)
{
	social_type *soc;

	for(int i=0; !IS_NULLSTR(social_table[i].name); i++){
		soc=new social_type;
		soc->name=str_dup(lowercase(social_table[i].name));
		soc->acts[SOCIAL_ATNOTARGET_MSG2SELF		]=safe_str_dup(social_table[i].char_no_arg);
		soc->acts[SOCIAL_ATNOTARGET_MSG2OTHERS		]=safe_str_dup(social_table[i].others_no_arg);
		soc->acts[SOCIAL_ATSELF_MSG2SELF			]=safe_str_dup(social_table[i].char_auto);
		soc->acts[SOCIAL_ATSELF_MSG2OTHERS			]=safe_str_dup(social_table[i].others_auto);
		soc->acts[SOCIAL_ATTARGET_MSG2SELF			]=safe_str_dup(social_table[i].char_found);
		soc->acts[SOCIAL_ATTARGET_MSG2TARGET		]=safe_str_dup(social_table[i].vict_found);
		soc->acts[SOCIAL_ATTARGET_MSG2OTHERS		]=safe_str_dup(social_table[i].others_found);
		
		// add to the linked list		
		social_add_sorted_to_list(soc, false);
	}
	ch->wrapln("Socials imported from old social_table[]... if there were socials under"
		"the new system with the same name, they will still remain.");
	save_socials();
}
/**************************************************************************/
// display the list of socials
void do_socials(char_data *ch, char *)
{
	int col=0;
	char buf[MSL];

    BUFFER *output;
    output = new_buf();	

	for(social_type *soc=social_list; soc; soc=soc->next){
		if(IS_SET(soc->social_flags, SOC_IMM_ONLY) && !IS_IMMORTAL(ch)){
			continue;
		}
		sprintf(buf, "%-12s", soc->name);
		add_buf(output, buf);
		if(++col%6==0){
			sprintf(buf,"\r\n");
			add_buf(output, buf);
		}
	}
	if(col%6!=0){
		sprintf(buf,"\r\n");
		add_buf(output, buf);
	}

	sprintf(buf,"%d social%s total.\r\n", col, col==1?"":"s");
	add_buf(output, buf);

    ch->sendpage(buf_string(output));
    free_buf(output);
}
/**************************************************************************/
const struct flag_type social_flags[] =
{
    {   "ooc",			SOC_IN_OOC,		true    },
    {   "in_ooc",		SOC_IN_OOC,		true    },
    {   "ic",			SOC_IN_IC,		true    },
    {   "in_ic",		SOC_IN_IC,		true    },
    {   "imm_only",		SOC_IMM_ONLY,	true    },	
    {   NULL,			0,					0       }
};
/**************************************************************************/
// GIO STUFF BELOW TO SAVE/LOAD the socials
GIO_START(social_type)
GIO_STR(name)
GIO_WFLAG(social_flags, social_flags)
GIO_WFLAG(position_flags, position_flags)
GIO_STR_ARRAY(acts,SOCIAL_ATMAX)
GIO_FINISH
/**************************************************************************/
// save the list of socials
void save_socials()
{
	logf("===save_socials(): saving socials database to %s", SOCIAL_FILE);
	GIOSAVE_LIST(social_list, social_type, SOCIAL_FILE, true);
}
/**************************************************************************/
// load the list of socials
void load_socials()
{
	logf("===load_socials(): reading in socials database from %s", SOCIAL_FILE);
	GIOLOAD_LIST(social_list, social_type, SOCIAL_FILE);

	// patch up the NULL pointers for str_dup("");
	// One day might even sort the list alphabetically, but not today :)
	social_count=0;
	for(social_type *soc=social_list; soc; soc=soc->next){
		social_count++;
		for(int i=0; i<SOCIAL_ATMAX; i++){
			if(soc->acts[i]==NULL){
				soc->acts[i]=str_dup("");
			}
		}
	}
}

/**************************************************************************/
// Global Social Channel
bool social_global_broadcast( char_data *ch, char *command, char *argument )
{
	bool found = false;
	char arg[MIL];
	char buf[MIL];
	social_type *soc;
	char_data *victim;
	char_data *vic;
	connection_data *d;

	for (soc = social_list;soc;soc=soc->next)
	{
		if(IS_SET(soc->social_flags, SOC_IMM_ONLY) && !IS_IMMORTAL(ch) ){
			continue;
		}
		if(!str_prefix(command,soc->name)){
			found = true;
			break;
		}
	}

	if(!found){
 		return false;
	}

	one_argument( argument, arg );
	victim = NULL;

	if((victim = get_char_world( ch, arg )) != NULL){
		if(IS_NPC(victim)){
			victim = NULL;
		}
	}

	// Found the social - Display to Char
	// Send Msg to Char - No Target	
	if ( arg[0] == '\0' ){
		sprintf( buf, "`g[S] %s`x", soc->acts[SOCIAL_ATNOTARGET_MSG2SELF]);
		act_new( buf,  ch, NULL, victim, TO_CHAR,POS_SLEEPING );
	}
 	// Does the victim exist?
	else if ( victim == NULL ){
		strcpy( buf, "`g[S] They aren't here.`x" );
		act_new( buf,  ch, NULL, victim, TO_CHAR,POS_SLEEPING );
		return true;
 	// Send Msg to Char - Victim is Char
 	}else if ( victim == ch ){
 		strcpy( buf, "`g[S] " );
 		strcat( buf, soc->acts[SOCIAL_ATSELF_MSG2SELF] );
 		strcat( buf, "`x");
 		act_new( buf,  ch, NULL, victim, TO_CHAR,POS_SLEEPING );
 	// Send Msg to Char - Victim is Exists and isn't Char
 	}else{
 		strcpy( buf, "`g[S] " );
		strcat( buf, soc->acts[SOCIAL_ATTARGET_MSG2SELF] );
 		strcat( buf, "`x");
 		act_new( buf,  ch, NULL, victim, TO_CHAR,POS_SLEEPING );
 	}
 
 	// Found the social, display to everyone else
 	for ( d = connection_list; d != NULL; d = d->next )
 	{
	 	vic = d->original ? d->original : d->character;
 		if ( d->connected_state == CON_PLAYING &&
 			d->character != ch &&
			!HAS_CHANNELOFF(vic, CHANNEL_QUIET)
			&& !IS_SET(ch->comm, COMM_GLOBAL_SOCIAL_OFF)) 
		{
 			if ( arg[0] == '\0' ){
 				strcpy( buf, "`g[S] " );
 				strcat( buf,soc->acts[SOCIAL_ATNOTARGET_MSG2OTHERS]);
 				strcat( buf, "`x");
 				act_new( buf,  ch, NULL, vic, TO_VICT,POS_SLEEPING);
 			}else if (victim == NULL){
 			// Don't do anything
 			}else if ( victim == ch ){
 				strcpy( buf, "`g[S] " );
 				strcat( buf, soc->acts[SOCIAL_ATSELF_MSG2OTHERS]);
 				strcat( buf, "`x");
 				act_new( buf,  ch, vic, victim, TO_WORLD,POS_SLEEPING);
			}else if ( vic == victim ){
 				strcpy( buf, "`g[S] " );
 				strcat( buf, soc->acts[SOCIAL_ATTARGET_MSG2TARGET]);
 				strcat( buf, "`x");
 				act_new( buf,  ch, NULL, victim,TO_VICT,POS_SLEEPING );
 			}else{
 				strcpy( buf, "`g[S] " );
 				strcat( buf, soc->acts[SOCIAL_ATTARGET_MSG2OTHERS]);
 				strcat( buf, "`x");
 				act_new( buf,  ch, vic, victim, TO_WORLD,POS_SLEEPING);
 			}
	 	}
 	} // For
  	return true;
}

/**************************************************************************/
void do_globalsocial( char_data *ch, char *argument )
{
	char arg[MIL];
	char *arg2;
	connection_data *d;
	bool emote=false;

	if(IS_NULLSTR(argument))
	{
		ch->titlebar("GLOBAL SOCIAL");		
		ch->println("`=lsyntax:`x gs <normal use of a social>");
		ch->println("`=lsyntax:`x gs emote <normal use of standard emotes>");
		ch->println("`=lsyntax:`x gs ,<normal use of standard emotes>");
		ch->println("`=lsyntax:`x gs <social text>");
		ch->println("`=lsyntax:`x gs off  - turn off global socials");
		ch->println("e.g. `=Cgs smile kal`x");
		ch->titlebar("");
		return;
	}
	// social sent, turn Social on if it isn't already 
	if(HAS_CHANNELOFF(ch, CHANNEL_QUIET))
	{
		ch->println("You must turn off quiet mode first.");
		return;
	}
	if (IS_SET(ch->comm,COMM_NOCHANNELS))
	{
		ch->println("The gods have revoked your channel privilidges.");
		return;
    }

	if(ch->in_room && IS_SET(ch->in_room->room_flags,ROOM_NOCHANNELS)){
		if(IS_IMMORTAL(ch)){
			ch->println( "`Snote: mortals can't use any channels while in this room.`x" );
		}else{
			ch->println( "You can't use any channels while in this room." );
			return;
		}
	}

	if(!str_cmp(argument,"off")){
		SET_BIT(ch->comm, COMM_GLOBAL_SOCIAL_OFF);
		ch->println("Global Socials turned off.");
		return;
	}

	// left trim the string
	argument=ltrim_string(argument);

	// search for a , indicating it is an emote
	if(argument[0]==',' && !is_space(argument[1])){
		strcpy(arg, ",");
		argument++;
		arg2=argument;
	}else{
		arg2 = one_argument( argument, arg );
	}

	if(IS_SET(ch->comm, COMM_GLOBAL_SOCIAL_OFF)){
		REMOVE_BIT(ch->comm, COMM_GLOBAL_SOCIAL_OFF);
	}

    if(social_global_broadcast(ch,arg,arg2)){
		return;
	}

	if(!IS_NULLSTR(arg2) && (!str_cmp(arg, "emote") || !str_cmp(arg, ","))){
		emote=true;
		ch->printlnf( "`g[E] %s %s`x", ch->name, arg2);
	}else{
		ch->printlnf( "`gYou socialize '%s`g'`x", argument);
	}
	
	for ( d = connection_list; d; d = d->next )
	{
		char_data *victim;
		victim = d->original ? d->original : d->character;
		if (   d->connected_state == CON_PLAYING
			&& d->character != ch
			&& !HAS_CHANNELOFF(ch, CHANNEL_QUIET)
			&& !IS_SET(ch->comm, COMM_GLOBAL_SOCIAL_OFF))
		{
			if(emote){
				act_new("`g[E] $n $t`x", ch, arg2, d->character,TO_VICT,POS_SLEEPING);
			}else{
				act_new("`g$n socializes '$t`g'`x", ch, argument,d->character,TO_VICT,POS_SLEEPING);
			}
		}
	}
}
 
/**************************************************************************/
// Kal, Dec 2001 - rewrite of code from storm
void do_pose(char_data *ch, char *)
{
	int i;
	int cl;
	
	if ( IS_NPC(ch) )
	{
		if( IS_SET(ch->act,ACT_CLERIC) )
			cl = CLASS_CLERIC;
		else if( IS_SET(ch->act,ACT_MAGE) )
			cl = CLASS_MAGE;
		else if( IS_SET(ch->act,ACT_THIEF) )
			cl = CLASS_THIEF;
		else
			cl = CLASS_WARRIOR; // NPCs pose as warriors if no other act flags are set
	} else {
		cl= ch->clss;
	}

	int p=number_range(0, UMIN(ch->level, MAX_LEVEL));
	for(i=p; i>=0; i--){
		if(!IS_NULLSTR(class_table[cl].pose_self[i])
			&& !IS_NULLSTR(class_table[cl].pose_others[i]))
		{
			act( class_table[cl].pose_self[i], ch, NULL, NULL, TO_CHAR );
			act( class_table[cl].pose_others[i], ch, NULL, NULL, TO_ROOM );
			return;
		}
	}
	ch->printlnf("Sorry, there are no poses configured for the %s class.", 
		class_table[cl].name);
}
/**************************************************************************/
/**************************************************************************/