/******************************************************************************
 Snippet: Alternative socials.
 Author:  Richard Woolcock (aka KaVir).
 Date:    1st March 1999.
 ******************************************************************************
 This code is copyright (C) 1999 by Richard Woolcock.  It may be used and
 distributed freely, as long as you don't remove this copyright notice.
 ******************************************************************************/

#if 0
#undef void	draw_bar	args( ( CHAR_DATA *ch ) );
#endif

#if 0
#undef void	text_bar	args( ( CHAR_DATA *ch, char *argument ) );
#endif

/******************************************************************************
 Required libraries
 ******************************************************************************/

#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include "merc.h"

/******************************************************************************
 Required enumerated types
 ******************************************************************************/

typedef enum		/************************************************/
{			/* Enumeration to determine social direction:   */
    PERFORM_NONE,	/* Social cannot be directed at anyone.		*/
    PERFORM_TO,		/* You can perform this social TO someone.	*/
    PERFORM_AT,		/* You can perform this social AT someone.	*/
    PERFORM_BEFORE,	/* You can perform this social BEFORE someone.	*/
    PERFORM_ON		/* You can perform this social ON someone.	*/
} perform_type;		/************************************************/

/******************************************************************************
 Required structure types
 ******************************************************************************/

typedef struct		/************************************************/
{			/* Structure to store details of one social:	*/
    char *social;	/* This is the name of the social.		*/
    bool to;		/* Can this social be performed TO someone?	*/
    bool at;		/* Can this social be performed AT someone?	*/
    bool before;	/* Can this social be performed BEFORE someone?	*/
    bool on;		/* Can this social be performed ON someone?	*/
    char *words[50];	/* Up to 50 adverbs.  The last MUST be NULL.	*/
} socials_type;		/************************************************/

/******************************************************************************
 The socials_table (non-stack based, no external visibility)
 ******************************************************************************/

static socials_type socials_table[] =
{
    {
	"bow", TRUE, FALSE, TRUE, FALSE, 
	{
	    "airily", "angrily", "arrogantly", "calmly", "charmingly", 
	    "coldly", "confidently", "coolly", "coyly", "curtly",
	    "deeply", "earnestly", "formally", "gallantly", "hesitantly",
	    "humbly", "mockingly", "nervously", "politely", "primly",
	    "regally", "sincerely", "solemnly", "timidly", "warily",
	    "warmly", NULL
	}
    },
    {
	"chuckle", FALSE, TRUE, FALSE, FALSE, 
	{
	    "absently", "arrogantly", "brightly", "calmly", "cheerily", 
	    "coldly", "confidently", "coolly", "cynically", "darkly",
	    "dryly", "gently", "huskily", "loudly", "merrily",
	    "mockingly", "nervously", "openly", "politely", "softly", 
	    NULL
	}
    },
    {
	"grin", FALSE, TRUE, FALSE, FALSE, 
	{
	    "broadly", "cruelly", "evilly", "icily", "merrily", 
	    "mockingly", "nervously", "openly", "savagely", "shakily", 
	    "sharply", "slyly", "smoothly", "smugly", "softly", 
	    "sourly", "warily", "wickedly", "wryly", NULL
	}
    },
    {
	"nod", FALSE, TRUE, FALSE, FALSE, 
	{
	    "absently", "aggressively", "angrilly", "arrogantly", "blankly",
	    "brightly", "calmly", "charmingly", "cheerily", "coldly",
	    "confidently", "coolly", "coyly", "curtly", "earnestly",
	    "firmly", "gloomily", "glumly", "grimly", "happily",
	    "hesitantly", "humbly", "mockingly", "nervously", "politely",
	    "regally", "sadly", "shyly", "solemnly", "warily", NULL
	}
    },
    {
	"smile", FALSE, TRUE, FALSE, FALSE, 
	{
	    "absently", "archly", "blankly", "brightly", "broadly",
	    "calmly", "charmingly", "cheerily", "coldly", "confidently",
	    "coolly", "coyly", "cynically", "demurely", "dreamily",
	    "dryly", "frostily", "happily", "hesitently", "innocently",
	    "merrily", "mockingly", "nervously", "openly", "politely",
	    "sadly", "shyly", "smoothly", "smugly", "softly",
	    "sweetly", "tenderly", "timidly", "warily", "warmly",
	    "wryly", NULL
	}
    },
    {
	NULL, FALSE, FALSE, FALSE, FALSE, { NULL }
    }
};

/******************************************************************************
 Required local operation prototype
 ******************************************************************************/

static void display_socials	( CHAR_DATA *ch, char *social, int social_no );
#if 0
static void draw_bar		( CHAR_DATA *ch );
static void text_bar		( CHAR_DATA *ch, char *argument );
#endif

/******************************************************************************
 Required global operation (add the prototype for this to merc.h)
 ******************************************************************************/

/*
 * This is designed to replace the check_social() operation.  The parameters
 * are the same, simply change the function call from 'check_social' to 
 * 'Social_perform' (remember that C is case sensitive).
 */
bool Social_perform( CHAR_DATA *ch, char *social_word, char *argument )
{
    char buf  [MAX_STRING_LENGTH];	/* General storage string buffer */

    char arg1 [MAX_INPUT_LENGTH];	/* First argument  */
    char arg2 [MAX_INPUT_LENGTH];	/* Second argument */
    char arg3 [MAX_INPUT_LENGTH];	/* Third argument  */

    perform_type perform = PERFORM_NONE;	/* Type of social target */

    int s_index = 0;		/* Social index */
    bool found_social = FALSE;	/* Stores if the social was found or not */

    int a_index = 0;		/* Adverb index */
    bool found_adverb = FALSE;	/* Stores if the adverb was found or not */

    /* Initialise the arguments */
    argument = one_argument( argument, arg1 );
    argument = one_argument( argument, arg2 );
    argument = one_argument( argument, arg3 );

    /* Loop until the social is found or we run out of socials */
    while ( socials_table[s_index].social && !found_social )
    {
	/* Check if the current social is the one we're looking for */
	if ( !str_prefix( social_word, socials_table[s_index].social ) )
	{
	    /* We've found the social */
	    found_social = TRUE;
	}
	else
	{
	    /* Move on to the next social in the table */
	    s_index++;
	}
    }

    /* If no social was found and we've reached the end of the table */
    if ( !found_social )
    {
	/* That social does not exist */
	return FALSE; /* No output is displayed */
    }

    /* If no arguments were passed in to the operation */
    if ( arg1[0] == '\0' )
    {
	/* List the possible adverbs available for the social */
	display_socials( ch, socials_table[s_index].social, s_index );
	return TRUE; /* Output is displayed */
    }

    /* Loop until the adverb is found or we run out of adverbs */
    while ( socials_table[s_index].words[a_index] && !found_adverb )
    {
	/* Check if the current adverb is the one we're looking for */
	if ( !str_prefix( arg1, socials_table[s_index].words[a_index] ) )
	{
	    /* We've found the adverb */
	    found_adverb = TRUE;
	}
	else
	{
	    /* Move on to the next adverb in the table */
	    a_index++;
	}
    }

    /* If no adverb was found and we've reached the end of the table */
    if ( !found_adverb )
    {
	/* List the possible adverbs available for the social */
	display_socials( ch, socials_table[s_index].social, s_index );
	return TRUE; /* Output is displayed */
    }

    /* If only an adverb argument was passed in to the operation */
    if ( arg2[0] == '\0' )
    {
	/* Display the social, no target specified, then exit operation */
	sprintf( buf, "You %s %s.\n\r", socials_table[s_index].social, 
	    socials_table[s_index].words[a_index] );
	send_to_char( buf, ch );
	sprintf( buf, "$n %ss %s.", socials_table[s_index].social, 
	    socials_table[s_index].words[a_index] );
	act( buf, ch, NULL, NULL, TO_ROOM );
	return TRUE; /* Output is displayed */
    }
    else if ( !str_prefix( arg2, "to" ) && socials_table[s_index].to )
    {
	/* The social will be performed TO someone */
	perform = PERFORM_TO;
    }
    else if ( !str_prefix( arg2, "at" ) && socials_table[s_index].at )
    {
	/* The social will be performed AT someone */
	perform = PERFORM_AT;
    }
    else if ( !str_prefix( arg2, "before" ) && socials_table[s_index].before )
    {
	/* The social will be performed BEFORE someone */
	perform = PERFORM_BEFORE;
    }
    else if ( !str_prefix( arg2, "on" ) && socials_table[s_index].on )
    {
	/* The social will be performed ON someone */
	perform = PERFORM_ON;
    }
    else /* The second parameter was invalid */
    {
	/* List the valid parameters for the social */
	display_socials( ch, socials_table[s_index].social, s_index );
	return TRUE; /* Output is displayed */
    }

    /* When the social is being directed */
    if ( perform != PERFORM_NONE )
    {
	CHAR_DATA *victim;	/* Target of social.		*/
	char *perform_buf;	/* Type of social direction.	*/
	switch ( perform )	/* Initialise perform_buf.	*/
	{
	    default:             perform_buf = "";       break;
	    case PERFORM_TO:     perform_buf = "to";     break;
	    case PERFORM_AT:     perform_buf = "at";     break;
	    case PERFORM_BEFORE: perform_buf = "before"; break;
	    case PERFORM_ON:     perform_buf = "on";     break;
	}

	/* If no arguments were passed in to the operation */
	if ( arg3[0] == '\0' )
	{
	    /* No target was specified for the social */
	    sprintf( buf, "Who do you wish to %s %s %s?\n\r\n\r", 
		socials_table[s_index].social, 
		socials_table[s_index].words[a_index], perform_buf );
	    send_to_char( buf, ch );
	}
	else if ( ( victim = get_char_room( ch, arg3 ) ) == NULL )
	{
	    /* The victim does not exist */
	    send_to_char( "They aren't here.\n\r",ch);
	}
	else if ( victim == ch )
	{
	    /* Socials cannot be targetted on yourself */
	    send_to_char("Not on yourself.\n\r",ch);
	}
	else
	{
	    /* Display the directed social */
	    sprintf( buf, "You %s %s %s $M.", socials_table[s_index].social, 
		socials_table[s_index].words[a_index], perform_buf );
	    act( buf, ch, NULL, victim, TO_CHAR );
	    sprintf( buf, "$n %ss %s %s $N.", socials_table[s_index].social, 
		socials_table[s_index].words[a_index], perform_buf );
	    act( buf, ch, NULL, victim, TO_NOTVICT );
	    sprintf( buf, "$n %ss %s %s you.", socials_table[s_index].social, 
		socials_table[s_index].words[a_index], perform_buf );
	    act( buf, ch, NULL, victim, TO_VICT );
	}
	return TRUE; /* Output is displayed */
    }
    return TRUE; /* Output is displayed */
}

/******************************************************************************
 Required local operations
 ******************************************************************************/

/* This operation displays information on a specified social */
static void display_socials( CHAR_DATA *ch, char *social, int social_no )
{
    char buf [MAX_STRING_LENGTH];	/* General storage string buffer */
    int a_index = 0;			/* Adverb index			 */
    int a_length = 0;			/* Length adverb list		 */

    /* Display the SOCIAL heading */
    sprintf( buf, "%s SOCIAL", social );
    text_bar( ch, buf );
    buf[0] = '\0';

    /* Display the default syntax */
    sprintf( buf, "Syntax: %s <type>\n\r", social );
    send_to_char( buf, ch );

    /* Check if the social can be performed TO someone */
    if ( socials_table[social_no].to )
    {
	/* Display the TO syntax */
	sprintf( buf, "Syntax: %s <type> to <target>\n\r", social );
	send_to_char( buf, ch );
    }

    /* Check if the social can be performed AT someone */
    if ( socials_table[social_no].at )
    {
	/* Display the AT syntax */
	sprintf( buf, "Syntax: %s <type> at <target>\n\r", social );
	send_to_char( buf, ch );
    }

    /* Check if the social can be performed BEFORE someone */
    if ( socials_table[social_no].before )
    {
	/* Display the BEFORE syntax */
	sprintf( buf, "Syntax: %s <type> before <target>\n\r", social );
	send_to_char( buf, ch );
    }

    /* Check if the social can be performed ON someone */
    if ( socials_table[social_no].on )
    {
	/* Display the ON syntax */
	sprintf( buf, "Syntax: %s <type> on <target>\n\r", social );
	send_to_char( buf, ch );
    }

    /* Loop through the adverbs for this social */
    while ( socials_table[social_no].words[a_index] )
    {
	/* Increment the adverb list length by the current social */
	a_length += (strlen( socials_table[social_no].words[a_index] ) + 1);

	/* Check if the list is too big to fit on the current line */
	if ( a_length >= 80 )
	{
	    /* If it is too big, start a new line */
	    strcat( buf, "\n\r" );
	    a_length = strlen( socials_table[social_no].words[a_index] ) + 1;
	}

	/* Store the current adverb */
	strcat( buf, capitalize(socials_table[social_no].words[a_index]) );
	strcat( buf, " " );

	/* Move on to the next adverb in the table */
	a_index++;
    }

    /* Append a newline to the end of the list */
    strcat( buf, "\n\r" );

    /* Display the list */
    draw_bar( ch );
    send_to_char("Type may be one of the following:\n\r",ch);
    send_to_char( buf, ch );
    draw_bar( ch );

    return;
}

#if 0
/* This operation draws an 80 character line */
static void draw_bar( CHAR_DATA *ch )
{
    send_to_char( "--------------------------------------------------------------------------------\n\r", ch );
}

/* This operation draws an 80 character line with a word in the centre */
static void text_bar( CHAR_DATA *ch, char *argument )
{
    static char bar_buf[MAX_INPUT_LENGTH];	/* Buffer to store text bar */
    int text_length = strlen( argument );	/* Length of the text 	    */
    int word_start;				/* Start of text word       */
    int loop;					/* Loop counter             */

    word_start = 37 - ((text_length+1) >> 1);	/* Initialise word start    */

    /* Draw a line bar before displaying the text bar */
    draw_bar( ch );

    /* If the text is too big, just display it as is */
    if ( text_length > 70 )
    {
	send_to_char(argument,ch);
	send_to_char("\n\r",ch);
	return;
    }

    /* Set the left half of the bar to spaces */
    for ( loop = 0; loop < word_start; loop++ )
    {
	bar_buf[loop] = ' ';
    }

    /* Terminate the bar string so that strcat can be used to add the word */
    bar_buf[word_start] = '\0';

    /* Add the text, surrounded by -= =- */
    strcat( bar_buf, "-= " );
    strcat( bar_buf, argument );
    strcat( bar_buf, " =-\n\r" );

    /* Loop through the text bar */
    for ( loop = 0; bar_buf[loop]; loop++ )
    {
	/* Check if the current character is a lowercase letter */
	if ( 'a' <= bar_buf[loop] && bar_buf[loop] <= 'z' )
	{
	    /* Change all lowercase letters to uppercase */
	    bar_buf[loop] = UPPER(bar_buf[loop]);
	}
    }

    /* Display the text bar */
    send_to_char( bar_buf, ch );

    /* Draw a line bar after displaying the text bar */
    draw_bar( ch );
}
#endif
