/*****************************************************************************
* DikuMUD (C) 1990, 1991 by: *
* Sebastian Hammer, Michael Seifert, Hans Henrik Staefeldt, Tom Madsen, *
* and Katja Nyboe. *
*---------------------------------------------------------------------------*
* MERC 2.1 (C) 1992, 1993 by: *
* Michael Chastain, Michael Quan, and Mitchell Tse. *
*---------------------------------------------------------------------------*
* SMAUG 1.4 (C) 1994, 1995, 1996, 1998 by: Derek Snider. *
* Team: Thoric, Altrag, Blodkai, Narn, Haus, Scryn, Rennard, Swordbearer, *
* gorog, Grishnakh, Nivek, Tricops, and Fireblade. *
*---------------------------------------------------------------------------*
* SMAUG 1.7 FUSS by: Samson and others of the SMAUG community. *
* Their contributions are greatly appreciated. *
*---------------------------------------------------------------------------*
* LoP (C) 2006, 2007, 2008 by: the LoP team. *
*****************************************************************************/
#include <stdio.h>
#include <string.h>
#include "h/mud.h"
int top_social;
SOCIALTYPE *find_social( const char *command )
{
SOCIALTYPE *social;
int hash;
hash = LOWER( command[0] ) % 126;
for( social = social_index[hash]; social; social = social->next )
if( !str_prefix( command, social->name ) )
return social;
return NULL;
}
SOCIALTYPE *find_exact_social( char *command )
{
SOCIALTYPE *social;
int hash;
hash = LOWER( command[0] ) % 126;
for( social = social_index[hash]; social; social = social->next )
if( !str_cmp( command, social->name ) )
return social;
return NULL;
}
bool check_social( CHAR_DATA *ch, const char *command, char *argument )
{
char arg[MIL];
CHAR_DATA *victim = NULL;
SOCIALTYPE *social;
bool gsocial = false;
bool pmobtrigger = MOBtrigger;
if( !( social = find_social( command ) ) )
return false;
if( !is_npc( ch ) && xIS_SET( ch->act, PLR_NO_EMOTE ) )
{
send_to_char( "You're anti-social!\r\n", ch );
return true;
}
switch( ch->position )
{
case POS_DEAD:
send_to_char( "Lie still; you're DEAD.\r\n", ch );
return true;
case POS_INCAP:
case POS_MORTAL:
send_to_char( "You're hurt far too bad for that.\r\n", ch );
return true;
case POS_STUNNED:
send_to_char( "You're too stunned to do that.\r\n", ch );
return true;
case POS_SLEEPING:
/*
* I just know this is the path to a 12" 'if' statement. :(
* But two players asked for it already! -- Furey
*/
if( !str_cmp( social->name, "snore" ) )
break;
send_to_char( "In your dreams, or what?\r\n", ch );
return true;
}
one_argument( argument, arg );
victim = NULL;
if( arg != NULL && arg[0] != '\0' )
{
if( !( victim = get_char_room( ch, arg ) ) )
{
if( ( victim = get_char_world( ch, arg ) ) )
gsocial = true;
}
}
if( gsocial )
MOBtrigger = false;
if( victim && ch && is_ignoring( victim, ch ) )
{
set_char_color( AT_IGNORE, ch );
if( is_immortal( ch ) )
ch_printf( ch, "%s is trying to ignore you.\r\n", victim->name );
else
ch_printf( ch, "%s is ignoring you.\r\n", victim->name );
}
if( arg == NULL || arg[0] == '\0' )
{
act_printf( AT_SOCIAL, ch, NULL, victim, TO_ROOM, "%s%s", gsocial ? "[From afar] " : "", social->others_no_arg );
act_printf( AT_SOCIAL, ch, NULL, victim, TO_CHAR, "%s%s", gsocial ? "[From afar] " : "", social->char_no_arg );
}
else if( !victim )
send_to_char( "They aren't here.\r\n", ch );
else if( victim == ch )
{
act_printf( AT_SOCIAL, ch, NULL, victim, gsocial ? TO_OTHERS : TO_ROOM, "%s%s", gsocial ? "[From afar] " : "", social->others_auto );
act_printf( AT_SOCIAL, ch, NULL, victim, TO_CHAR, "%s%s", gsocial ? "[From afar] " : "", social->char_auto );
}
else
{
act_printf( AT_SOCIAL, ch, NULL, victim, gsocial ? TO_OTHERS : TO_NOTVICT, "%s%s", gsocial ? "[From afar] " : "", social->others_found );
act_printf( AT_SOCIAL, ch, NULL, victim, TO_CHAR, "%s%s", gsocial ? "[From afar] " : "", social->char_found );
act_printf( AT_SOCIAL, ch, NULL, victim, TO_VICT, "%s%s", gsocial ? "[From afar] " : "", social->vict_found );
/*
* Make mobs do random socials back
* Also removed being drawn into a fight for socials
*/
if( !is_npc( ch ) && is_npc( victim ) && !IS_AFFECTED( victim, AFF_CHARM ) && is_awake( victim )
&& !HAS_PROG( victim->pIndexData, ACT_PROG ) )
{
bool found = false;
SOCIALTYPE *resocial, *resocial_next;
int hash;
/* Preform a random social */
for( hash = 0; hash < 126; hash++ )
{
for( resocial = social_index[hash]; resocial; resocial = resocial_next )
{
resocial_next = resocial->next;
/* Continue as long as percent is not equal to 50 */
if( number_percent( ) != 50 )
continue;
/* If it doesn't have some of the data continue */
if( !resocial->others_found || !resocial->char_found || !resocial->vict_found )
continue;
/* Send the social data */
act_printf( AT_SOCIAL, victim, NULL, ch, gsocial ? TO_OTHERS : TO_NOTVICT, "%s%s", gsocial ? "[From afar] " : "", resocial->others_found );
act_printf( AT_SOCIAL, victim, NULL, ch, TO_CHAR, "%s%s", gsocial ? "[From afar] " : "", resocial->char_found );
act_printf( AT_SOCIAL, victim, NULL, ch, TO_VICT, "%s%s", gsocial ? "[From afar] " : "", resocial->vict_found );
found = true;
break;
}
/* If one was found and used break */
if( found )
break;
}
/* If found is false then do the same social back */
if( !found )
{
if( social->others_found )
act_printf( AT_SOCIAL, victim, NULL, ch, gsocial ? TO_OTHERS : TO_NOTVICT, "%s%s", gsocial ? "[From afar] " : "", social->others_found );
if( social->char_found )
act_printf( AT_SOCIAL, victim, NULL, ch, TO_CHAR, "%s%s", gsocial ? "[From afar] " : "", social->char_found );
if( social->vict_found )
act_printf( AT_SOCIAL, victim, NULL, ch, TO_VICT, "%s%s", gsocial ? "[From afar] " : "", social->vict_found );
}
}
}
if( gsocial )
MOBtrigger = pmobtrigger;
return true;
}
SOCIALTYPE *new_social( void )
{
SOCIALTYPE *social = NULL;
CREATE( social, SOCIALTYPE, 1 );
if( !social )
{
bug( "%s: social is NULL after CREATE.", __FUNCTION__ );
return NULL;
}
social->name = NULL;
social->char_no_arg = NULL;
social->char_found = NULL;
social->char_auto = NULL;
social->others_no_arg = NULL;
social->others_found = NULL;
social->others_auto = NULL;
social->vict_found = NULL;
return social;
}
void fread_social( FILE *fp )
{
const char *word;
bool fMatch;
SOCIALTYPE *social;
social = new_social( );
for( ;; )
{
word = feof( fp ) ? "End" : fread_word( fp );
fMatch = false;
switch( UPPER( word[0] ) )
{
case '*':
fMatch = true;
fread_to_eol( fp );
break;
case 'C':
KEY( "CharNoArg", social->char_no_arg, fread_string( fp ) );
KEY( "CharFound", social->char_found, fread_string( fp ) );
KEY( "CharAuto", social->char_auto, fread_string( fp ) );
break;
case 'E':
if( !str_cmp( word, "End" ) )
{
if( !social->name )
{
bug( "%s: Name not found", __FUNCTION__ );
free_social( social );
return;
}
if( !social->char_no_arg )
{
bug( "%s: CharNoArg not found", __FUNCTION__ );
free_social( social );
return;
}
add_social( social );
return;
}
break;
case 'N':
KEY( "Name", social->name, fread_string( fp ) );
break;
case 'O':
KEY( "OthersNoArg", social->others_no_arg, fread_string( fp ) );
KEY( "OthersFound", social->others_found, fread_string( fp ) );
KEY( "OthersAuto", social->others_auto, fread_string( fp ) );
break;
case 'V':
KEY( "VictFound", social->vict_found, fread_string( fp ) );
break;
}
if( !fMatch )
{
bug( "%s: no match: %s", __FUNCTION__, word );
fread_to_eol( fp );
}
}
free_social( social );
}
void load_socials( void )
{
FILE *fp;
top_social = 0;
if( !( fp = fopen( SOCIAL_FILE, "r" ) ) )
return;
for( ;; )
{
char letter;
char *word;
letter = fread_letter( fp );
if( letter == '*' )
{
fread_to_eol( fp );
continue;
}
if( letter != '#' )
{
bug( "%s: # not found, (%c) found instead.", __FUNCTION__, letter );
break;
}
word = fread_word( fp );
if( !str_cmp( word, "SOCIAL" ) )
{
fread_social( fp );
continue;
}
else if( !str_cmp( word, "END" ) )
break;
else
{
bug( "%s: bad section (%s).", __FUNCTION__, word );
continue;
}
}
fclose( fp );
fp = NULL;
}
void save_socials( bool autosave )
{
FILE *fp;
SOCIALTYPE *social;
int x;
bool found = false;
if( autosave && !sysdata.autosavesocials )
return;
if( !( fp = fopen( SOCIAL_FILE, "w" ) ) )
{
bug( "%s: Can't open %s for writting", __FUNCTION__, SOCIAL_FILE );
perror( SOCIAL_FILE );
return;
}
for( x = 0; x < 126; x++ )
{
for( social = social_index[x]; social; social = social->next )
{
if( !social->name || social->name[0] == '\0' )
{
bug( "%s: blank social in hash bucket %d", __FUNCTION__, x );
continue;
}
if( !social->char_no_arg || social->char_no_arg[0] == '\0' )
{
bug( "%s: social with NULL char_no_arg in hash bucket %d", __FUNCTION__, x );
continue;
}
found = true;
fprintf( fp, "#SOCIAL\n" );
fprintf( fp, "Name %s~\n", social->name );
if( social->char_no_arg )
fprintf( fp, "CharNoArg %s~\n", social->char_no_arg );
if( social->others_no_arg )
fprintf( fp, "OthersNoArg %s~\n", social->others_no_arg );
if( social->char_found )
fprintf( fp, "CharFound %s~\n", social->char_found );
if( social->others_found )
fprintf( fp, "OthersFound %s~\n", social->others_found );
if( social->vict_found )
fprintf( fp, "VictFound %s~\n", social->vict_found );
if( social->char_auto )
fprintf( fp, "CharAuto %s~\n", social->char_auto );
if( social->others_auto )
fprintf( fp, "OthersAuto %s~\n", social->others_auto );
fprintf( fp, "End\n\n" );
}
}
fprintf( fp, "#END\n" );
fclose( fp );
fp = NULL;
if( !found )
remove_file( SOCIAL_FILE );
}
void free_social( SOCIALTYPE *social )
{
if( !social )
return;
STRFREE( social->name );
STRFREE( social->char_no_arg );
STRFREE( social->others_no_arg );
STRFREE( social->char_found );
STRFREE( social->others_found );
STRFREE( social->vict_found );
STRFREE( social->char_auto );
STRFREE( social->others_auto );
DISPOSE( social );
top_social--;
}
void free_socials( void )
{
SOCIALTYPE *social, *social_next;
int hash;
for( hash = 0; hash < 126; hash++ )
{
for( social = social_index[hash]; social; social = social_next )
{
social_next = social->next;
free_social( social );
}
}
}
void unlink_social( SOCIALTYPE *social )
{
SOCIALTYPE *tmp, *tmp_next;
int hash;
if( !social )
{
bug( "%s: NULL social", __FUNCTION__ );
return;
}
hash = LOWER( social->name[0] ) % 126;
if( social == ( tmp = social_index[hash] ) )
{
social_index[hash] = tmp->next;
return;
}
for( ; tmp; tmp = tmp_next )
{
tmp_next = tmp->next;
if( social == tmp_next )
{
tmp->next = tmp_next->next;
return;
}
}
}
void add_social( SOCIALTYPE *social )
{
int hash, x;
SOCIALTYPE *tmp, *prev;
if( !social )
{
bug( "%s: NULL social", __FUNCTION__ );
return;
}
if( !social->name )
{
bug( "%s: NULL social->name", __FUNCTION__ );
return;
}
if( !social->char_no_arg )
{
bug( "%s: NULL social->char_no_arg", __FUNCTION__ );
return;
}
for( x = 0; social->name[x] != '\0'; x++ )
social->name[x] = LOWER( social->name[x] );
hash = LOWER( social->name[0] ) % 126;
top_social++;
if( !( prev = tmp = social_index[hash] ) )
{
social->next = social_index[hash];
social_index[hash] = social;
return;
}
for( ; tmp; tmp = tmp->next )
{
if( ( x = strcmp( social->name, tmp->name ) ) == 0 )
{
bug( "%s: trying to add duplicate name to bucket %d", __FUNCTION__, hash );
free_social( social );
return;
}
else if( x < 0 )
{
if( tmp == social_index[hash] )
{
social->next = social_index[hash];
social_index[hash] = social;
return;
}
prev->next = social;
social->next = tmp;
return;
}
prev = tmp;
}
prev->next = social;
social->next = NULL;
}
CMDF( do_sedit )
{
SOCIALTYPE *social;
char arg1[MIL], arg2[MIL];
set_char_color( AT_SOCIAL, ch );
argument = one_argument( argument, arg1 );
argument = one_argument( argument, arg2 );
if( arg1 == NULL || arg1[0] == '\0' )
{
if( get_trust( ch ) >= PERM_HEAD )
send_to_char( "Usage: sedit <save>\r\n", ch );
send_to_char( "Usage: sedit <social> [field]\r\n", ch );
send_to_char( "Fields:\r\n ", ch );
if( get_trust( ch ) >= PERM_HEAD )
send_to_char( "name delete ", ch );
send_to_char( "create cnoarg onoarg cfound ofound vfound cauto oauto\r\n", ch );
send_to_char( " raise lower list\r\n", ch );
return;
}
if( get_trust( ch ) >= PERM_HEAD && !str_cmp( arg1, "save" ) )
{
save_socials( false );
send_to_char( "Saved.\r\n", ch );
return;
}
if( !str_cmp( arg2, "create" ) )
{
if( ( social = find_exact_social( arg1 ) ) )
{
send_to_char( "That social already exists!\r\n", ch );
return;
}
if( !( social = new_social( ) ) )
return;
social->name = STRALLOC( arg1 );
snprintf( arg2, sizeof( arg2 ), "You %s.", arg1 );
social->char_no_arg = STRALLOC( arg2 );
add_social( social );
save_socials( true );
send_to_char( "Social added.\r\n", ch );
return;
}
if( !( social = find_social( arg1 ) ) )
{
send_to_char( "Social not found.\r\n", ch );
return;
}
if( arg2 == NULL || arg2[0] == '\0' || !str_cmp( arg2, "show" ) )
{
ch_printf( ch, "Social: %s\r\n", social->name ? social->name : "(Not Set)" );
ch_printf( ch, "CNoArg: %s\r\n", social->char_no_arg ? social->char_no_arg : "(Not Set)" );
ch_printf( ch, "ONoArg: %s\r\n", social->others_no_arg ? social->others_no_arg : "(Not Set)" );
ch_printf( ch, "CFound: %s\r\n", social->char_found ? social->char_found : "(Not Set)" );
ch_printf( ch, "OFound: %s\r\n", social->others_found ? social->others_found : "(Not Set)" );
ch_printf( ch, "VFound: %s\r\n", social->vict_found ? social->vict_found : "(Not Set)" );
ch_printf( ch, "CAuto : %s\r\n", social->char_auto ? social->char_auto : "(Not Set)" );
ch_printf( ch, "OAuto : %s\r\n", social->others_auto ? social->others_auto : "(Not Set)" );
return;
}
if( get_trust( ch ) >= PERM_HEAD && !str_cmp( arg2, "delete" ) )
{
unlink_social( social );
free_social( social );
save_socials( true );
send_to_char( "Deleted.\r\n", ch );
return;
}
if( !str_cmp( arg2, "cnoarg" ) )
{
if( !argument || argument[0] == '\0' || !str_cmp( argument, "clear" ) )
{
send_to_char( "You can't clear this field. It must have a message.\r\n", ch );
return;
}
STRSET( social->char_no_arg, argument );
save_socials( true );
send_to_char( "Cnoarg set.\r\n", ch );
return;
}
if( !str_cmp( arg2, "onoarg" ) )
{
STRSET( social->others_no_arg, argument );
save_socials( true );
send_to_char( "Onoarg set.\r\n", ch );
return;
}
if( !str_cmp( arg2, "cfound" ) )
{
STRSET( social->char_found, argument );
save_socials( true );
send_to_char( "Cfound set.\r\n", ch );
return;
}
if( !str_cmp( arg2, "ofound" ) )
{
STRSET( social->others_found, argument );
save_socials( true );
send_to_char( "Ofound set.\r\n", ch );
return;
}
if( !str_cmp( arg2, "vfound" ) )
{
STRSET( social->vict_found, argument );
save_socials( true );
send_to_char( "Vfound set.\r\n", ch );
return;
}
if( !str_cmp( arg2, "cauto" ) )
{
STRSET( social->char_auto, argument );
save_socials( true );
send_to_char( "Cauto set.\r\n", ch );
return;
}
if( !str_cmp( arg2, "oauto" ) )
{
STRSET( social->others_auto, argument );
save_socials( true );
send_to_char( "Oauto set.\r\n", ch );
return;
}
if( !str_cmp( arg2, "raise" ) )
{
SOCIALTYPE *tmp, *tmp_next;
int hash = social->name[0] % 126;
if( ( tmp = social_index[hash] ) == social )
{
send_to_char( "That social is already at the top.\r\n", ch );
return;
}
if( tmp->next == social )
{
social_index[hash] = social;
tmp_next = tmp->next;
tmp->next = social->next;
social->next = tmp;
save_socials( true );
ch_printf( ch, "Moved %s above %s.\r\n", social->name, social->next->name );
return;
}
for( ; tmp; tmp = tmp->next )
{
tmp_next = tmp->next;
if( tmp_next->next == social )
{
tmp->next = social;
tmp_next->next = social->next;
social->next = tmp_next;
save_socials( true );
ch_printf( ch, "Moved %s above %s.\r\n", social->name, tmp_next->name );
return;
}
}
send_to_char( "ERROR -- Not Found!\r\n", ch );
return;
}
if( !str_cmp( arg2, "lower" ) )
{
SOCIALTYPE *tmp, *tmp_next;
int hash = social->name[0] % 126;
if( !social->next )
{
send_to_char( "That social is already at the bottom.\r\n", ch );
return;
}
tmp = social_index[hash];
if( tmp == social )
{
tmp_next = tmp->next;
social_index[hash] = social->next;
social->next = tmp_next->next;
tmp_next->next = social;
save_socials( true );
ch_printf( ch, "Moved %s below %s.\r\n", social->name, tmp_next->name );
return;
}
for( ; tmp; tmp = tmp->next )
{
if( tmp->next == social )
{
tmp_next = social->next;
tmp->next = tmp_next;
social->next = tmp_next->next;
tmp_next->next = social;
save_socials( true );
ch_printf( ch, "Moved %s below %s.\r\n", social->name, tmp_next->name );
return;
}
}
send_to_char( "ERROR -- Not Found!\r\n", ch );
return;
}
if( !str_cmp( arg2, "list" ) )
{
SOCIALTYPE *tmp;
int hash = social->name[0] % 126;
int col = 0;
pager_printf( ch, "Priority placement for [%s]:\r\n", social->name );
for( tmp = social_index[hash]; tmp; tmp = tmp->next )
{
pager_printf( ch, " %s%-12s", tmp == social ? "&[green]" : "&[plain]", tmp->name );
if( ++col == 6 )
{
send_to_pager( "\r\n", ch );
col = 0;
}
}
if( col != 0 )
send_to_pager( "\r\n", ch );
return;
}
if( get_trust( ch ) >= PERM_HEAD && !str_cmp( arg2, "name" ) )
{
bool relocate;
SOCIALTYPE *checksocial;
one_argument( argument, arg1 );
if( arg1[0] == '\0' )
{
send_to_char( "Can't clear name field!\r\n", ch );
return;
}
if( ( checksocial = find_exact_social( arg1 ) ) )
{
ch_printf( ch, "There is already a social named %s.\r\n", arg1 );
return;
}
if( arg1[0] != social->name[0] )
{
unlink_social( social );
relocate = true;
}
else
relocate = false;
STRSET( social->name, arg1 );
if( relocate )
add_social( social );
save_socials( true );
send_to_char( "Done.\r\n", ch );
return;
}
do_sedit( ch, (char *)"" );
}
CMDF( do_socials )
{
int iHash, col = 0, cnt = 0;
SOCIALTYPE *social;
char arg[MIL];
argument = one_argument( argument, arg );
set_pager_color( AT_PLAIN, ch );
for( iHash = 0; iHash < 126; iHash++ )
{
for( social = social_index[iHash]; social; social = social->next )
{
if( !social || !social->name )
continue;
if( arg != NULL && arg[0] != '\0' && str_prefix( arg, social->name ) )
continue;
cnt++;
pager_printf( ch, "%-12s", social->name );
if( ++col == 6 )
{
send_to_pager( "\r\n", ch );
col = 0;
}
}
}
if( col != 0 )
send_to_pager( "\r\n", ch );
if( cnt == 0 )
{
if( arg != NULL && arg[0] != '\0' )
pager_printf( ch, "&WNo social found under &C%s&W.&D\r\n", arg );
else
send_to_pager( "&WNo socials found at all.&D\r\n", ch );
}
else
{
if( arg != NULL && arg[0] != '\0' )
pager_printf( ch, "&C%d &Wsocials found under &C%s&W.&D\r\n", cnt, arg );
else
pager_printf( ch, "&C%d &Wsocials found in all.&D\r\n", cnt );
}
}