/**************************************************************************** * [S]imulated [M]edieval [A]dventure multi[U]ser [G]ame | \\._.// * * -----------------------------------------------------------| (0...0) * * SMAUG 1.4 (C) 1994, 1995, 1996, 1998 by Derek Snider | ).:.( * * -----------------------------------------------------------| {o o} * * SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus, | / ' ' \ * * Scryn, Rennard, Swordbearer, Gorog, Grishnakh, Nivek, |~'~.VxvxV.~'~* * Tricops and Fireblade | * * ------------------------------------------------------------------------ * * Merc 2.1 Diku Mud improvments copyright (C) 1992, 1993 by Michael * * Chastain, Michael Quan, and Mitchell Tse. * * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, * * Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. * * ------------------------------------------------------------------------ * * Player communication module * ****************************************************************************/ #include <sys/types.h> #include <ctype.h> #include <stdio.h> #include <string.h> #include <time.h> #include "mud.h" #ifndef WIN32 /* #include <regex.h> */ #include "rx.h" #endif /* * Externals */ void send_obj_page_to_char(CHAR_DATA * ch, OBJ_INDEX_DATA * idx, char page); void send_room_page_to_char(CHAR_DATA * ch, ROOM_INDEX_DATA * idx, char page); void send_page_to_char(CHAR_DATA * ch, MOB_INDEX_DATA * idx, char page); void send_control_page_to_char(CHAR_DATA * ch, char page); char *act_string(const char *format, CHAR_DATA *to, CHAR_DATA *ch, const void *arg1, const void *arg2, int flags); /* From interp.c */ bool check_social(CHAR_DATA *ch, char *command, char *argument); /* from clan.c */ CLAN_DATA *get_clan(CHAR_DATA *ch, char *argument); CLAN_MEMBER *get_member(char *name, CLAN_DATA *clan); /* from act_wiz.c */ int get_permit_flag(char *flag); /* * Local functions. */ char * scramble args( ( const char *argument, int modifier ) ); char * drunk_speech args( ( const char *argument, CHAR_DATA *ch ) ); void drop_artifacts(CHAR_DATA *ch, OBJ_DATA *obj); /* Scion */ CHANNEL_MEMBER *get_chatter(CHAR_DATA *ch, CHANNEL_DATA *chan) { CHANNEL_MEMBER *chm; for (chm = chan->first_member;chm;chm=chm->next) { if (chm->ch == ch) return chm; } return NULL; } bool remove_from_chan(CHAR_DATA *ch, CHANNEL_DATA *chan) { CHANNEL_MEMBER *chm; if ((chm = get_chatter(ch, chan)) == NULL) return FALSE; UNLINK(chm, chan->first_member, chan->last_member, next, prev); DISPOSE(chm); return TRUE; } bool room_is_silent( CHAR_DATA *ch ) { ROOM_INDEX_DATA *room = ch->in_room; if ( IS_SET( room->room_flags, ROOM_SILENCE ) ) return TRUE; return FALSE; } void update_hiscores(CHAR_DATA *ch) { adjust_hiscore("hours", ch, ((ch->played + (current_time - ch->logon)) / 3600)); if (IS_SET(ch->pcdata->flags, PCFLAG_ANONYMOUS)) return; if (IS_SET(ch->pcdata->flags, PCFLAG_CHEAT)) return; adjust_hiscore("mkill", ch, ch->pcdata->mkills); adjust_hiscore("mdeath", ch, ch->pcdata->mdeaths); adjust_hiscore("fire", ch, ch->curr_talent[TAL_FIRE] + (ch->pcdata->inborn == TAL_FIRE)); adjust_hiscore("wind", ch, ch->curr_talent[TAL_WIND] + (ch->pcdata->inborn == TAL_WIND)); adjust_hiscore("earth", ch, ch->curr_talent[TAL_EARTH] + (ch->pcdata->inborn == TAL_EARTH)); adjust_hiscore("water", ch, ch->curr_talent[TAL_WATER] + (ch->pcdata->inborn == TAL_WATER)); adjust_hiscore("frost", ch, ch->curr_talent[TAL_FROST] + (ch->pcdata->inborn == TAL_FROST)); adjust_hiscore("lightning", ch, ch->curr_talent[TAL_LIGHTNING] + (ch->pcdata->inborn == TAL_LIGHTNING)); adjust_hiscore("dream", ch, ch->curr_talent[TAL_DREAM] + (ch->pcdata->inborn == TAL_DREAM)); adjust_hiscore("speech", ch, ch->curr_talent[TAL_SPEECH] + (ch->pcdata->inborn == TAL_SPEECH)); adjust_hiscore("healing", ch, ch->curr_talent[TAL_HEALING] + (ch->pcdata->inborn == TAL_HEALING)); adjust_hiscore("death", ch, ch->curr_talent[TAL_DEATH] + (ch->pcdata->inborn == TAL_DEATH)); adjust_hiscore("change", ch, ch->curr_talent[TAL_CHANGE] + (ch->pcdata->inborn == TAL_CHANGE)); adjust_hiscore("time", ch, ch->curr_talent[TAL_TIME] + (ch->pcdata->inborn == TAL_TIME)); adjust_hiscore("motion", ch, ch->curr_talent[TAL_MOTION] + (ch->pcdata->inborn == TAL_MOTION)); adjust_hiscore("mind", ch, ch->curr_talent[TAL_MIND] + (ch->pcdata->inborn == TAL_MIND)); adjust_hiscore("illusion", ch, ch->curr_talent[TAL_ILLUSION] + (ch->pcdata->inborn == TAL_ILLUSION)); adjust_hiscore("seeking", ch, ch->curr_talent[TAL_SEEKING] + (ch->pcdata->inborn == TAL_SEEKING)); adjust_hiscore("security", ch, ch->curr_talent[TAL_SECURITY] + (ch->pcdata->inborn == TAL_SECURITY)); adjust_hiscore("catalysm", ch, ch->curr_talent[TAL_CATALYSM] + (ch->pcdata->inborn == TAL_SECURITY)); adjust_hiscore("void", ch, ch->curr_talent[TAL_VOID] + (ch->pcdata->inborn == TAL_VOID)); } /* Text scrambler -- Altrag */ char *scramble( const char *argument, int modifier ) { static char arg[MAX_INPUT_LENGTH]; sh_int position; sh_int conversion = 0; modifier %= number_range( 80, 300 ); /* Bitvectors get way too large #s */ for ( position = 0; position < MAX_INPUT_LENGTH; position++ ) { if ( argument[position] == '\0' ) { arg[position] = '\0'; return arg; } else if ( argument[position] >= 'A' && argument[position] <= 'Z' ) { conversion = -conversion + position - modifier + argument[position] - 'A'; conversion = number_range( conversion - 5, conversion + 5 ); while ( conversion > 25 ) conversion -= 26; while ( conversion < 0 ) conversion += 26; arg[position] = conversion + 'A'; } else if ( argument[position] >= 'a' && argument[position] <= 'z' ) { conversion = -conversion + position - modifier + argument[position] - 'a'; conversion = number_range( conversion - 5, conversion + 5 ); while ( conversion > 25 ) conversion -= 26; while ( conversion < 0 ) conversion += 26; arg[position] = conversion + 'a'; } else if ( argument[position] >= '0' && argument[position] <= '9' ) { conversion = -conversion + position - modifier + argument[position] - '0'; conversion = number_range( conversion - 2, conversion + 2 ); while ( conversion > 9 ) conversion -= 10; while ( conversion < 0 ) conversion += 10; arg[position] = conversion + '0'; } else arg[position] = argument[position]; } arg[position] = '\0'; return arg; } char *drunk_speech( const char *argument, CHAR_DATA *ch ) { const char *arg = argument; static char buf[MAX_INPUT_LENGTH*2]; char buf1[MAX_INPUT_LENGTH*2]; sh_int drunk; char *txt; char *txt1; if ( IS_NPC( ch ) || !ch->pcdata ) return (char *) argument; drunk = ch->pcdata->condition[COND_DRUNK] / 3; if (drunk <= 0 && !IS_AFFECTED(ch, AFF_COLDBLOOD) && !IS_AFFECTED(ch, AFF_FELINE)) return (char *) argument; buf[0] = '\0'; buf1[0] = '\0'; if ( !argument ) { bug( "Drunk_speech: NULL argument", 0 ); return ""; } /* if ( *arg == '\0' ) return (char *) argument; */ txt = buf; txt1 = buf1; while ( *arg != '\0' ) { /* make lizzies hiss their s's -keo */ if ( IS_AFFECTED(ch, AFF_COLDBLOOD) ) { if ( toupper(*arg) == 'S' ) { sh_int hissn = number_range( 0, 3 ); sh_int currhiss = 0; while ( currhiss < hissn ) *txt++ = *arg, currhiss++; } } /* and kitties slur their r's -keo */ if ( IS_AFFECTED(ch, AFF_FELINE) ) { if ( toupper(*arg) == 'R' ) { sh_int slurn = number_range( 0, 3 ); sh_int currslur = 0; while ( currslur < slurn ) *txt++ = *arg, currslur++; } } if ( toupper(*arg) == 'T' ) { if ( number_percent() < ( drunk * 2 ) ) /* add 'h' after an 'T' */ { *txt++ = *arg; *txt++ = 'h'; } else *txt++ = *arg; } else if ( toupper(*arg) == 'X' ) { if ( number_percent() < ( drunk * 2 / 2 ) ) { *txt++ = 'c', *txt++ = 's', *txt++ = 'h'; } else *txt++ = *arg; } else if ( number_percent() < ( drunk * 2 / 5 ) ) /* slurred letters */ { sh_int slurn = number_range( 1, 2 ); sh_int currslur = 0; while ( currslur < slurn ) *txt++ = *arg, currslur++; } else *txt++ = *arg; arg++; }; *txt = '\0'; txt = buf; while ( *txt != '\0' ) /* Let's mess with the string's caps */ { if ( number_percent() < ( 2 * drunk / 2.5 ) ) { if ( isupper(*txt) ) *txt1 = tolower( *txt ); else if ( islower(*txt) ) *txt1 = toupper( *txt ); else *txt1 = *txt; } else *txt1 = *txt; txt1++, txt++; }; *txt1 = '\0'; txt1 = buf1; txt = buf; while ( *txt1 != '\0' ) /* Let's make them stutter */ { if ( *txt1 == ' ' ) /* If there's a space, then there's gotta be a */ { /* along there somewhere soon */ while ( *txt1 == ' ' ) /* Don't stutter on spaces */ *txt++ = *txt1++; if ( ( number_percent() < ( 2 * drunk / 4 ) ) && *txt1 != '\0' ) { sh_int offset = number_range( 0, 2 ); sh_int pos = 0; while ( *txt1 != '\0' && pos < offset ) *txt++ = *txt1++, pos++; if ( *txt1 == ' ' ) /* Make sure not to stutter a space after */ { /* the initial offset into the word */ *txt++ = *txt1++; continue; } pos = 0; offset = number_range( 2, 4 ); while ( *txt1 != '\0' && pos < offset ) { *txt++ = *txt1; pos++; if ( *txt1 == ' ' || pos == offset ) /* Make sure we don't stick */ { /* A hyphen right before a space */ txt1--; break; } *txt++ = '-'; } if ( *txt1 != '\0' ) txt1++; } } else *txt++ = *txt1++; } *txt = '\0'; return buf; } void to_channel( const char *argument, const char *verb, sh_int permit ) { char buf[MAX_STRING_LENGTH]; DESCRIPTOR_DATA *d; if ( !first_descriptor || argument[0] == '\0' ) return; sprintf(buf, "%s: %s\r\n", verb, argument ); for ( d = first_descriptor; d; d = d->next ) { CHAR_DATA *och; CHAR_DATA *vch; och = d->original ? d->original : d->character; vch = d->character; if ( !och || !vch ) continue; if ( !IS_SET(vch->pcdata->permissions, permit)) continue; if ( d->connected == CON_PLAYING ) { set_char_color( AT_LOG, vch ); send_to_char_color( buf, vch ); } } return; } void do_say( CHAR_DATA *ch, char *argument ) { char arg[MAX_INPUT_LENGTH]; char buf[MAX_STRING_LENGTH]; EXT_BV actflags; if (IS_SILENT(ch)) { send_to_char("No sound comes out.\n\r", ch); return; } MOBtrigger = TRUE; if ( argument[0] == '\0' ) { send_to_char( "Say what?\n\r", ch ); return; } if (argument[0] == '@' ) argument = one_argument(argument+1, arg); else arg[0] = '\0'; actflags = ch->act; if ( IS_NPC(ch) ) xREMOVE_BIT( ch->act, ACT_SECRETIVE ); MOBtrigger = FALSE; if (arg[0] != '\0') act( AT_SAY, "$n says $t, '$T'", ch, arg,drunk_speech(argument, ch), TO_ROOM ); else act(AT_SAY, "$n says, '$T'", ch, NULL, drunk_speech(argument, ch), TO_ROOM); ch->act = actflags; MOBtrigger = FALSE; if (arg[0] != '\0') act( AT_SAY, "You say $t, '$T'", ch, arg, drunk_speech( argument, ch ), TO_CHAR ); else act(AT_SAY, "You say, '$T'", ch, NULL, drunk_speech(argument, ch), TO_CHAR); if ( IS_SET( ch->in_room->room_flags, ROOM_LOGSPEECH ) ) { sprintf( buf, "%s: %s", IS_NPC( ch ) ? ch->short_descr : ch->name, argument ); append_to_file( LOG_FILE, buf ); } /* Yakkov's amplify request - shogar */ if ( ch->in_room && IS_SET( ch->in_room->room_flags, ROOM_AMPLIFY ) ) { ROOM_INDEX_DATA *was_in_room; EXIT_DATA *pexit; sprintf(buf,"You hear '%s'",argument); actflags = ch->act; xREMOVE_BIT(ch->act, ACT_SECRETIVE); was_in_room = ch->in_room; for ( pexit = was_in_room->first_exit; pexit; pexit = pexit->next ) { if ( pexit->to_room && pexit->to_room != was_in_room ) { ch->in_room = pexit->to_room; MOBtrigger = FALSE; act( AT_CYAN, buf, ch, NULL, NULL, TO_ROOM ); } } ch->act = actflags; ch->in_room = was_in_room; } /* if your hiding you give yourself away -keo */ if (IS_AFFECTED(ch, AFF_HIDE) && !IS_NPC(ch)) xREMOVE_BIT(ch->pcdata->perm_aff, AFF_HIDE); /* can't sing while talking -keo */ if (ch->singing) do_sing(ch, "none"); if (MOBtrigger==TRUE) { mprog_speech_trigger( argument, ch ); if ( char_died(ch) ) return; oprog_speech_trigger( argument, ch ); if ( char_died(ch) ) return; rprog_speech_trigger( argument, ch ); return; } } /* out of character says, added by popular request -keo */ void do_ooc_say( CHAR_DATA *ch, char *argument ) { char buf[MAX_STRING_LENGTH]; if ( argument[0] == '\0' ) { send_to_char( "Say what?\n\r", ch ); return; } /* Yes, it shows your real name. This is intentional */ MOBtrigger = FALSE; ch_printf(ch, "&z&CYou say out of character '%s'\n\r", argument); sprintf(buf, "&z&C%s says out of character '$t'", ch->name); act(AT_SAY, buf, ch, argument, NULL, TO_ROOM); } void do_whisper( CHAR_DATA *ch, char *argument ) { char arg[MAX_INPUT_LENGTH]; char buf[MAX_INPUT_LENGTH]; CHAR_DATA *victim; int position; MOBtrigger = TRUE; argument = one_argument( argument, arg ); if ( arg[0] == '\0' || argument[0] == '\0' ) { send_to_char( "Whisper to whom what?\n\r", ch ); return; } if ( (victim = get_char_room( ch, arg ) ) == NULL ) { send_to_char( "They aren't here.\n\r", ch ); return; } if ( ch == victim ) { send_to_char( "You have a nice little chat with yourself.\n\r", ch ); return; } if ( !IS_NPC( victim ) && ( victim->switched ) && !IS_AFFECTED(victim->switched, AFF_POSSESS) ) { send_to_char( "That player is switched.\n\r", ch ); return; } else if ( !IS_NPC( victim ) && ( !victim->desc ) ) { send_to_char( "That player is link-dead.\n\r", ch ); return; } if ( !IS_NPC(victim) && xIS_SET(victim->act, PLR_AFK) ) { send_to_char( "That player is away.\n\r", ch ); return; } if ( !IS_NPC(victim) && xIS_SET(victim->act, PLR_SILENCE) ) send_to_char( "That player is silenced. They will receive your message but can not respond.\n\r", ch ); if ( victim->desc /* make sure desc exists first -Thoric */ && victim->desc->connected == CON_EDITING ) { act( AT_PLAIN, "$E is currently in a writing buffer. Please try again in a few minutes.", ch, 0, victim, TO_CHAR ); return; } act( AT_WHISPER, "You whisper to $N '$t'", ch, argument, victim, TO_CHAR ); position = victim->position; victim->position = POS_STANDING; MOBtrigger=FALSE; act( AT_WHISPER, "$n whispers to you '$t'", ch, argument, victim, TO_VICT ); act( AT_WHISPER, "$n whispers something to $N.", ch, argument, victim, TO_NOTVICT ); victim->position = position; if ( IS_SET( ch->in_room->room_flags, ROOM_LOGSPEECH ) ) { sprintf( buf, "%s: %s (whisper to) %s.", IS_NPC( ch ) ? ch->short_descr : ch->name, argument, IS_NPC( victim ) ? victim->short_descr : victim->name ); append_to_file( LOG_FILE, buf ); } if (MOBtrigger==TRUE) mprog_speech_trigger( argument, ch ); return; } /* beep snippet installed by Scion 3/30/99 */ void do_beep(CHAR_DATA *ch, char *argument) { char arg[MAX_INPUT_LENGTH]; CHAR_DATA *victim; argument = one_argument(argument, arg); if (!*arg || !(victim = get_char_world(ch, arg))) { send_to_char( "Beep who?\n\r", ch ); return; } /* NPC check added by Samson 2-15-98 */ if ( IS_NPC( victim )) { send_to_char( "Beep who?\n\r", ch ); return; } /* PCFLAG_NOBEEP check added by Samson 2-15-98 */ if ( IS_SET(victim->pcdata->flags, PCFLAG_NOBEEP) ) { ch_printf( ch, "%s is not accepting beeps at this time.\n\r", victim->name ); return; } if (argument[0]!='\0') { ch_printf(victim, "&W^z%s beeps: %s^x&w\r\n", ch->name, argument); if (victim != ch) ch_printf(ch, "&WYou beep %s: %s\r\n", victim->name, argument); } else { ch_printf(victim, "&W^z%s beeps you from '%s'^x&w\a\n\r", ch->name, ch->in_room->name); if (victim != ch) ch_printf(ch, "&WYou beep %s.&w\n\r", victim->name); } return; } /* an attempt to reduce redundancy -keo */ void tell(CHAR_DATA *ch, CHAR_DATA *victim, char *argument) { CHAR_DATA *switched_victim = NULL; int position; char buf[MAX_STRING_LENGTH]; if (!victim) { send_to_char("Tell who what?\n\r", ch); return; } if (!IS_NPC(ch) && xIS_SET(ch->act, PLR_NO_TELL) ) { huh(ch); return; } if ( ch == victim ) { send_to_char( "You have a nice little chat with yourself.\n\r", ch); return; } else if ( !IS_NPC( victim ) && ( victim->switched ) && IS_AFFECTED(victim->switched, AFF_POSSESS) ) switched_victim = victim->switched; else if ( !IS_NPC( victim ) && ( !victim->desc ) ) { send_to_char( "That player is link-dead.\n\r", ch ); return; } if ( !IS_NPC(victim) && xIS_SET(victim->act, PLR_AFK) ) { send_to_char( "That player is away and may not have received your tell.\n\r", ch); } if ( !IS_NPC(victim) && xIS_SET(victim->act, PLR_SILENCE) ) send_to_char( "That player is silenced. They will receive your message but cannot respond.\n\r", ch); if ( ( !IS_AWAKE(victim) ) || (!IS_NPC(victim)&&IS_SET(victim->in_room->room_flags, ROOM_SILENCE) ) ) { act( AT_PLAIN, "$E can't hear you.", ch, 0, victim, TO_CHAR ); return; } if ( victim->desc /* make sure desc exists first -Thoric */ && victim->desc->connected == CON_EDITING) { act( AT_PLAIN, "$E is currently in a writing buffer. Try sending a beep if urgent.\n\r", ch, 0, victim, TO_CHAR); return; } if(switched_victim) victim = switched_victim; act( AT_TELL, "You tell $N '$t'", ch, argument, victim, TO_CHAR ); position = victim->position; victim->position = POS_STANDING; ch_printf(victim, "&R%s tells you '%s'\n\r", ch->name, argument); victim->position = position; victim->reply = ch; ch->retell = victim; if ( IS_SET( ch->in_room->room_flags, ROOM_LOGSPEECH ) ) { sprintf( buf, "%s: %s (tell to) %s.", IS_NPC( ch ) ? ch->short_descr : ch->name, argument, IS_NPC( victim ) ? victim->short_descr : victim->name ); append_to_file( LOG_FILE, buf ); } } void do_tell(CHAR_DATA *ch, char *argument) { char arg[MAX_INPUT_LENGTH]; CHAR_DATA *victim; MOBtrigger=TRUE; argument = one_argument( argument, arg ); if ( arg[0] == '\0' || argument[0] == '\0' ) { send_to_char( "Tell whom what?\n\r", ch ); return; } if ( ( victim = get_char_world( ch, arg ) ) == NULL || ( IS_NPC(victim) && victim->in_room != ch->in_room ) ) { send_to_char( "They aren't here.\n\r", ch ); return; } tell(ch, victim, argument); if (MOBtrigger==TRUE) mprog_speech_trigger( argument, ch ); return; } void do_reply( CHAR_DATA *ch, char *argument ) { tell(ch, ch->reply, argument); } void do_retell(CHAR_DATA *ch, char *argument) { tell(ch, ch->retell, argument); } void do_emote( CHAR_DATA *ch, char *argument ) { char buf[MAX_STRING_LENGTH]; char nbuf[MAX_STRING_LENGTH]; char *plast; CHAR_DATA *vch; EXT_BV actflags; int i,b; bool fHasName=FALSE; if ( !IS_NPC(ch) && xIS_SET(ch->act, PLR_NO_EMOTE) ) { send_to_char( "You can't show your emotions.\n\r", ch ); return; } if ( argument[0] == '\0' ) { send_to_char( "Emote what?\n\r", ch ); return; } actflags = ch->act; if ( IS_NPC(ch) ) xREMOVE_BIT( ch->act, ACT_SECRETIVE ); for ( plast = argument; *plast != '\0'; plast++ ) ; strcpy( buf, argument ); if (!IS_NPC(ch)) { b=strlen(buf); nbuf[0]='\0'; for (i=0; i<b; i++) { if (buf[i]=='$' && buf[i+1]=='n') { fHasName=TRUE; } nbuf[i] = buf[i]; nbuf[i+1]='\0'; } } if (fHasName == FALSE) { strcpy(nbuf, "$n"); strcat(nbuf, " "); strcat(nbuf, buf); } if ( isalpha(plast[-1]) ) strcat( buf, "." ); for ( vch = ch->in_room->first_person; vch; vch = vch->next_in_room ) { char *sbuf = nbuf; MOBtrigger = FALSE; act( AT_SOCIAL, sbuf, ch, NULL, vch, (vch == ch ? TO_CHAR : TO_VICT) ); } ch->act = actflags; if ( IS_SET( ch->in_room->room_flags, ROOM_LOGSPEECH ) ) { sprintf( buf, "%s %s (emote)", IS_NPC( ch ) ? ch->short_descr : ch->name, argument ); append_to_file( LOG_FILE, buf ); } return; } void do_bug( CHAR_DATA *ch, char *argument ) { char buf[MAX_STRING_LENGTH]; struct tm *t = localtime(¤t_time); set_char_color( AT_PLAIN, ch ); if ( argument[0] == '\0' ) { send_to_char( "\n\rUsage: 'bug <message>' (your location is automatically recorded)\n\r", ch ); return; } sprintf( buf, "(%-2.2d/%-2.2d): %s", t->tm_mon+1, t->tm_mday, argument ); append_file( ch, PBUG_FILE, buf ); send_to_char( "Thanks, your bug notice has been recorded.\n\r", ch ); return; } void do_idea( CHAR_DATA *ch, char *argument ) { char buf[MAX_STRING_LENGTH]; struct tm *t = localtime(¤t_time); set_char_color( AT_PLAIN, ch ); if ( argument[0] == '\0' ) { send_to_char( "\n\rUsage: 'idea <message>'\n\r", ch ); return; } sprintf( buf, "(%-2.2d/%-2.2d): %s", t->tm_mon+1, t->tm_mday, argument ); append_file( ch, IDEA_FILE, buf ); send_to_char( "Thanks, your idea has been recorded.\n\r", ch ); return; } void do_roleplay( CHAR_DATA *ch, char *argument ) { char buf[MAX_STRING_LENGTH]; struct tm *t = localtime(¤t_time); set_char_color( AT_PLAIN, ch ); if ( argument[0] == '\0' ) { send_to_char( "\n\rUsage: 'roleplay <message>'\n\r", ch ); if ( IS_SET(ch->pcdata->permissions, PERMIT_TALENT) || IS_SET(ch->pcdata->permissions, PERMIT_SECURITY) ) send_to_char( "Usage: 'roleplay list' or 'roleplay clear now'\n\r", ch ); return; } if ( !str_cmp( argument, "clear now" ) && (IS_SET(ch->pcdata->permissions, PERMIT_TALENT) || IS_SET(ch->pcdata->permissions, PERMIT_SECURITY)) ) { FILE *fp = fopen( RP_FILE, "w" ); if ( fp ) fclose( fp ); send_to_char( "RP file cleared.\n\r", ch); return; } if ( !str_cmp( argument, "list" ) && (IS_SET(ch->pcdata->permissions, PERMIT_TALENT) || IS_SET(ch->pcdata->permissions, PERMIT_SECURITY)) ) { send_to_char( "\n\r VNUM \n\r.......\n\r", ch ); show_file( ch, RP_FILE ); } else { sprintf( buf, "(%-2.2d/%-2.2d): %s", t->tm_mon+1, t->tm_mday, argument ); append_file( ch, RP_FILE, buf ); send_to_char( "Thanks, your roleplaying has been recorded.\n\r", ch ); return; } } void do_typo( CHAR_DATA *ch, char *argument ) { set_char_color( AT_PLAIN, ch ); if ( argument[0] == '\0' ) { send_to_char( "\n\rUsage: 'typo <message>' (your location is automatically recorded)\n\r", ch ); if ( IS_SET(ch->pcdata->permissions, PERMIT_HELP)) send_to_char("Usage: 'typo clean now'\n\r", ch); return; } if ( !str_cmp( argument, "clear now" ) && IS_SET(ch->pcdata->permissions, PERMIT_HELP) ) { FILE *fp = fopen( TYPO_FILE, "w" ); if ( fp ) fclose( fp ); send_to_char( "Typo file cleared.\n\r", ch); return; } if ( !str_cmp( argument, "list" ) ) { send_to_char( "\n\r VNUM \n\r.......\n\r", ch ); show_file( ch, TYPO_FILE ); } else { append_file( ch, TYPO_FILE, argument ); send_to_char( "Thanks, your typo notice has been recorded.\n\r", ch ); } return; } void do_rent( CHAR_DATA *ch, char *argument ) { set_char_color( AT_WHITE, ch ); send_to_char( "There is no rent here. Just save and quit.\n\r", ch ); return; } void do_qui( CHAR_DATA *ch, char *argument ) { set_char_color( AT_RED, ch ); send_to_char( "If you want to QUIT, you have to spell it out.\n\r", ch ); return; } void do_quit( CHAR_DATA *ch, char *argument ) { int x, y; OBJ_DATA *obj; if ( IS_NPC(ch) ) { huh(ch); return; } if ( IS_FIGHTING(ch) ) { set_char_color( AT_RED, ch ); send_to_char( "No way! You are fighting.\n\r", ch ); return; } if ( ch->position < POS_STUNNED ) { set_char_color( AT_BLOOD, ch ); send_to_char( "You're not DEAD yet.\n\r", ch ); return; } if (IS_SET(ch->in_room->room_flags, ROOM_NO_QUIT) && IS_SET(ch->pcdata->permissions, PERMIT_BUILD)) { send_to_char("You cannot quit in this room.\n\r", ch); return; } if ( get_timer(ch, TIMER_RECENTFIGHT)) { set_char_color( AT_RED, ch ); send_to_char( "Your adrenaline is pumping too hard to quit now!\n\r", ch ); return; } /* make sure they aren't mounted -keo */ if (IS_AFFECTED(ch, AFF_MOUNTED)) throw_rider(ch); if (ch->mount) throw_rider(ch->mount); if (IS_SET(ch->in_room->area->flags, AFLAG_NOQUIT) && !ch->pcdata->permissions) { char_from_room(ch); char_to_room(ch, get_room_index(ROOM_VNUM_NEXUS)); } /* Get 'em dismounted until we finish mount saving -- Blodkai, 4/97 */ if ( ch->position == POS_MOUNTED ) do_dismount( ch, "" ); update_hiscores(ch); do_channels(ch, "quiet"); quitting_char = ch; save_char_obj( ch ); if ( sysdata.save_pets && ch->pcdata->pet ) { act( AT_BYE, "$N follows $S master into the Void.", ch, NULL, ch->pcdata->pet, TO_ROOM ); extract_char( ch->pcdata->pet, TRUE ); } saving_char = NULL; set_char_color( AT_WHITE, ch ); ch_printf( ch, "Your surroundings begin to fade as a mystical swirling vortex of colors\r\nenvelops your body... Please come back and visit %s again.\n\r\n\r", sysdata.mud_name ); act( AT_SAY, "A soothing voice says, 'May your magic never falter, $n...'", ch, NULL, NULL, TO_CHAR ); act( AT_BYE, "$n enters the Void and is gone.", ch, NULL, NULL, TO_CANSEE ); set_char_color( AT_GREY, ch); sprintf( log_buf, "%s has quit in %s (%d).", ch->name, ch->in_room->name, ch->in_room->vnum ); while ( (obj = ch->last_carrying) != NULL ) extract_obj(obj); /* * After extract_char the ch is no longer valid! */ extract_char( ch, TRUE ); for ( x = 0; x < MAX_WEAR; x++ ) for ( y = 0; y < MAX_LAYERS; y++ ) save_equipment[x][y] = NULL; log_string_plus( log_buf, LOG_COMM, 0 ); return; } /* Made this a function so it could work recursively on containers. Make them drop artifact items. Can't leave the game with those! -- Scion */ void drop_artifacts(CHAR_DATA *ch, OBJ_DATA *obj) { /* Expecting a ch->last_carrying or an obj->last_content ( We go BACKWARDS through the lists!) */ if (!obj) return; while (obj) { if (obj->last_content) drop_artifacts(ch, obj->last_content); if (IS_OBJ_STAT(obj, ITEM_ARTIFACT)) { OBJ_DATA *tobj; tobj=obj; obj=obj->prev_content; if (tobj->in_obj) obj_from_obj(tobj); if (tobj->carried_by) obj_from_char(tobj); obj_to_room(tobj, ch->in_room); act(AT_MAGIC, "$p falls to the ground, drawn by the magic of these lands!", ch, tobj, NULL, TO_CHAR); act(AT_MAGIC, "$p falls from $n's hands, drawn by the magic of these lands!", ch, tobj, NULL, TO_CANSEE); } else obj = obj->prev_content; } } void send_rip_screen( CHAR_DATA *ch ) { FILE *rpfile; int num=0; char BUFF[MAX_STRING_LENGTH*2]; if ((rpfile = fopen(RIPSCREEN_FILE,"r")) !=NULL) { while ((BUFF[num]=fgetc(rpfile)) != EOF) num++; fclose(rpfile); BUFF[num] = 0; write_to_buffer(ch->desc,BUFF,num); } } void do_ansi( CHAR_DATA *ch, char *argument ) { char arg[MAX_INPUT_LENGTH]; one_argument( argument, arg ); if ( arg[0] == '\0' ) { send_to_char( "ANSI ON or OFF?\n\r", ch ); return; } if ( (strcmp(arg,"on")==0) || (strcmp(arg,"ON") == 0) ) { xSET_BIT(ch->act,PLR_ANSI); set_char_color( AT_WHITE + AT_BLINK, ch); send_to_char( "ANSI ON!!!\n\r", ch); return; } if ( (strcmp(arg,"off")==0) || (strcmp(arg,"OFF") == 0) ) { xREMOVE_BIT(ch->act,PLR_ANSI); send_to_char( "Okay... ANSI support is now off\n\r", ch ); return; } } void do_save( CHAR_DATA *ch, char *argument ) { if ( IS_NPC(ch) ) return; WAIT_STATE( ch, 2 ); /* For big muds with save-happy players, like RoD */ update_aris(ch); /* update char affects and RIS */ save_char_obj( ch ); saving_char = NULL; send_to_char( "Saved...\n\r", ch ); update_hiscores(ch); return; } /* * Something from original DikuMUD that Merc yanked out. * Used to prevent following loops, which can cause problems if people * follow in a loop through an exit leading back into the same room * (Which exists in many maze areas) -Thoric */ bool circle_follow( CHAR_DATA *ch, CHAR_DATA *victim ) { CHAR_DATA *tmp; for ( tmp = victim; tmp; tmp = tmp->master ) if ( tmp == ch ) return TRUE; return FALSE; } void do_dismiss( CHAR_DATA *ch, char *argument ) { CHAR_DATA *victim; check_social(ch, "dismiss", argument); if ( ( victim = get_char_room( ch, argument ) ) == NULL ) return; if ( ( IS_AFFECTED( victim, AFF_CHARM ) ) && ( victim->master == ch ) ) { stop_follower( victim ); if (IS_NPC(victim)) { stop_hating( victim ); stop_hunting( victim ); stop_fearing( victim ); } } } void do_follow( CHAR_DATA *ch, char *argument ) { char arg[MAX_INPUT_LENGTH]; CHAR_DATA *victim; one_argument( argument, arg ); if ( arg[0] == '\0' ) { send_to_char( "Follow whom?\n\r", ch ); return; } if ( ( victim = get_char_room( ch, arg ) ) == NULL ) { send_to_char( "They aren't here.\n\r", ch ); return; } if ( IS_AFFECTED(ch, AFF_CHARM) && ch->master ) { act( AT_PLAIN, "But you'd rather follow $N!", ch, NULL, ch->master, TO_CHAR ); return; } if ( victim == ch ) { if ( !ch->master ) { send_to_char( "You already follow yourself.\n\r", ch ); return; } stop_follower( ch ); return; } if ( circle_follow( ch, victim ) ) { stop_follower( victim ); return; } if ( ch->master ) stop_follower( ch ); add_follower( ch, victim ); return; } void add_follower( CHAR_DATA *ch, CHAR_DATA *master ) { if ( ch->master ) { bug( "Add_follower: non-null master.", 0 ); return; } ch->master = master; ch->leader = NULL; /* Support for saving pets --Shaddai */ if ( IS_NPC(ch) && xIS_SET(ch->act, ACT_PET) && !IS_NPC(master) ) master->pcdata->pet = ch; if ( can_see( master, ch ) ) act( AT_ACTION, "$n now follows you.", ch, NULL, master, TO_VICT ); act( AT_ACTION, "You now follow $N.", ch, NULL, master, TO_CHAR ); return; } void stop_follower( CHAR_DATA *ch ) { if ( !ch->master ) { bug( "Stop_follower: null master.", 0 ); return; } if ( IS_NPC(ch) && !IS_NPC(ch->master) && ch->master->pcdata->pet == ch ) ch->master->pcdata->pet = NULL; if ( IS_AFFECTED(ch, AFF_CHARM) ) { xREMOVE_BIT( ch->affected_by, AFF_CHARM ); affect_strip( ch, gsn_charm_person ); } if ( can_see( ch->master, ch ) ) if (!(!IS_NPC(ch->master))) act( AT_ACTION, "$n stops following you.", ch, NULL, ch->master, TO_VICT ); act( AT_ACTION, "You stop following $N.", ch, NULL, ch->master, TO_CHAR ); ch->master = NULL; ch->leader = NULL; return; } void die_follower( CHAR_DATA *ch ) { CHAR_DATA *fch; if ( ch->master ) stop_follower( ch ); ch->leader = NULL; ch->last_hit = NULL; for ( fch = first_char; fch; fch = fch->next ) { if ( fch->master == ch ) stop_follower( fch ); if ( fch->leader == ch ) fch->leader = fch; if ( fch->last_hit == ch) fch->last_hit = NULL; if ( !IS_NPC(fch)) { if (fch->pcdata->mindlink == ch) fch->pcdata->mindlink = NULL; if (fch->pcdata->consenting == ch) fch->pcdata->consenting = NULL; if (fch->pcdata->magiclink == ch) fch->pcdata->magiclink = NULL; } } return; } void do_order( CHAR_DATA *ch, char *argument ) { char arg[MAX_INPUT_LENGTH]; char argbuf[MAX_INPUT_LENGTH]; CHAR_DATA *victim; strcpy( argbuf, argument ); argument = one_argument( argument, arg ); if ( arg[0] == '\0' || argument[0] == '\0' ) { send_to_char( "Order whom to do what?\n\r", ch ); return; } if ( IS_AFFECTED( ch, AFF_CHARM ) ) { send_to_char( "You feel like taking, not giving, orders.\n\r", ch ); return; } if ( ( victim = get_char_room( ch, arg ) ) == NULL ) { send_to_char( "They aren't here.\n\r", ch ); return; } if ( victim == ch ) { send_to_char( "Aye aye, right away!\n\r", ch ); return; } if ( !IS_AFFECTED(victim, AFF_CHARM) || victim->master != ch ) { /* Attempt to command */ if (ch->curr_talent[TAL_SPEECH] + ch->curr_talent[TAL_MIND] >= 120) { use_magic(ch, TAL_SPEECH, 130); if (number_range(1, TALENT(ch, TAL_SPEECH) + TALENT(ch, TAL_MIND) + get_curr_wil(ch)) < get_curr_wil(victim)) { act(AT_MAGIC, "$N shrugs off your suggestion.", ch, NULL, victim, TO_CHAR); act(AT_MAGIC, "You shrug off $n's suggestion that you '$t'.", ch, argument, victim, TO_VICT); return; } } else { send_to_char( "Do it yourself!\n\r", ch ); return; } } /* end if charmed */ if (IS_NPC(victim) && xIS_SET(victim->act, ACT_PACIFIST)) { act(AT_MAGIC, "$N shrugs off your suggestion.", ch, NULL, victim, TO_CHAR); return; } if (IS_AFFECTED(victim, AFF_BERSERK)) { send_to_char("Your orders fail to get through their rage.\n\r", ch); return; } act( AT_ACTION, "$n orders you to '$t'.", ch, argument, victim, TO_VICT ); interpret( victim, argument, TRUE ); sprintf( log_buf, "%s: order %s.", ch->name, argbuf ); log_string_plus( log_buf, LOG_NORMAL, 0 ); send_to_char( "Ok.\n\r", ch ); WAIT_STATE( ch, PULSE_VIOLENCE ); return; } /* char *itoa(int foo) { static char bar[256]; sprintf(bar,"%d",foo); return(bar); } */ /* Overhauled 2/97 -- Blodkai Keelhauled 1/00 -- Scion */ void do_group( CHAR_DATA *ch, char *argument ) { char arg[MAX_INPUT_LENGTH]; CHAR_DATA *victim; one_argument( argument, arg ); if ( arg[0] == '\0' ) { CHAR_DATA *gch; CHAR_DATA *leader; leader = ch->leader ? ch->leader : ch; set_char_color( AT_DGREEN, ch ); ch_printf( ch, "\n\rFollowing %-12.12s [hitpnts] [ magic ] [mst] [mvs] [race]\n\r", PERS(leader, ch)); for ( gch = first_char; gch; gch = gch->next ) { if ( is_same_group( gch, ch ) ) { set_char_color( AT_DGREEN, ch ); if (IS_AFFECTED(gch, AFF_POSSESS) || (!IS_NPC(gch) && IS_SET( gch->pcdata->flags, PCFLAG_ANONYMOUS))) {/*reveal no information*/ ch_printf( ch, "&g[&G%-3d -- %3.3s&g] &G%-12s&g %59s &G%-12s&g\n\r", 0, IS_NPC(gch) ? "Mob" : "Xxx", capitalize( PERS(gch, ch) ), ((gch->protected_by && gch->protected_by->in_room == gch->in_room) ? gch->protected_by->name : "") ); } else { set_char_color( AT_GREEN, ch ); ch_printf( ch, "%-12.12s ", capitalize( PERS(gch, ch) ) ); if ( gch->hit < gch->max_hit/4 ) set_char_color( AT_DANGER, ch ); else if ( gch->hit < gch->max_hit/2.5 ) set_char_color( AT_YELLOW, ch ); else set_char_color( AT_GREY, ch ); ch_printf( ch, "%5d", gch->hit ); set_char_color( AT_GREY, ch ); ch_printf( ch, "/%-5d ", gch->max_hit ); set_char_color( AT_LBLUE, ch ); ch_printf( ch, "%5d/%-5d ", gch->mana, gch->max_mana ); if ( gch->mental_state < -25 || gch->mental_state > 25 ) set_char_color( AT_YELLOW, ch ); else set_char_color( AT_GREEN, ch ); ch_printf( ch, "%3.3s ", gch->mental_state > 75 ? "+++" : gch->mental_state > 50 ? "=++" : gch->mental_state > 25 ? "==+" : gch->mental_state > -25 ? "===" : gch->mental_state > -50 ? "-==" : gch->mental_state > -75 ? "--=" : "---" ); set_char_color( AT_DGREEN, ch ); ch_printf( ch, "%5d ", gch->move ); ch_printf( ch, " %-10s", gch->species ? gch->species : npc_race[gch->race]); set_char_color( AT_GREEN, ch ); if ( gch->protected_by && gch->protected_by->in_room == gch->in_room ) ch_printf( ch, "%-12s ", gch->protected_by->name ); send_to_char( "\n\r", ch); } } } return; } if ( !strcmp( arg, "disband" )) { CHAR_DATA *gch; int count = 0; if ( ch->leader || ch->master ) { send_to_char( "You cannot disband a group if you're following someone.\n\r", ch ); return; } for ( gch = first_char; gch; gch = gch->next ) { if ( is_same_group( ch, gch ) && ( ch != gch ) ) { gch->leader = NULL; gch->master = NULL; count++; send_to_char( "Your group is disbanded.\n\r", gch ); } } if ( count == 0 ) send_to_char( "You have no group members to disband.\n\r", ch ); else send_to_char( "You disband your group.\n\r", ch ); return; } if ( !strcmp( arg, "all" ) ) { CHAR_DATA *rch; int count = 0; for ( rch = ch->in_room->first_person; rch; rch = rch->next_in_room ) { if ( ch != rch && !IS_NPC( rch ) && can_see( ch, rch ) && rch->master == ch && !ch->master && !ch->leader && !is_same_group( rch, ch ) && IS_PKILL( ch ) == IS_PKILL( rch ) ) { rch->leader = ch; count++; } } if ( count == 0 ) send_to_char( "You have no eligible group members.\n\r", ch ); else { act( AT_ACTION, "$n groups $s followers.", ch, NULL, NULL, TO_ROOM ); send_to_char( "You group your followers.\n\r", ch ); } return; } if ( ( victim = get_char_room( ch, arg ) ) == NULL ) { send_to_char( "They aren't here.\n\r", ch ); return; } if ( ch->master || ( ch->leader && ch->leader != ch ) ) { send_to_char( "But you are following someone else!\n\r", ch ); return; } if ( victim->master != ch && ch != victim ) { act( AT_PLAIN, "$N isn't following you.", ch, NULL, victim, TO_CHAR ); return; } if ( victim == ch ) { act( AT_PLAIN, "You can't group yourself.", ch, NULL, victim, TO_CHAR ); return; } if ( is_same_group( victim, ch ) && ch != victim ) { victim->leader = NULL; act( AT_ACTION, "$n removes $N from $s group.", ch, NULL, victim, TO_NOTVICT ); act( AT_ACTION, "$n removes you from $s group.", ch, NULL, victim, TO_VICT ); act( AT_ACTION, "You remove $N from your group.", ch, NULL, victim, TO_CHAR ); return; } victim->leader = ch; act( AT_ACTION, "$N joins $n's group.", ch, NULL, victim, TO_NOTVICT); act( AT_ACTION, "You join $n's group.", ch, NULL, victim, TO_VICT ); act( AT_ACTION, "$N joins your group.", ch, NULL, victim, TO_CHAR ); return; } /* * 'Split' originally by Gnort, God of Chaos. */ void do_split( CHAR_DATA *ch, char *argument ) { char buf[MAX_STRING_LENGTH]; char arg[MAX_INPUT_LENGTH]; CHAR_DATA *gch; int members; int amount; int share; int extra; one_argument( argument, arg ); if ( arg[0] == '\0' ) { send_to_char( "Split how much?\n\r", ch ); return; } amount = atoi( arg ); if ( amount < 0 ) { send_to_char( "Your group wouldn't like that.\n\r", ch ); return; } if ( amount == 0 ) { send_to_char( "You hand out zero coins, but no one notices.\n\r", ch ); return; } if ( ch->gold < amount ) { send_to_char( "You don't have that much gold.\n\r", ch ); return; } members = 0; for ( gch = ch->in_room->first_person; gch; gch = gch->next_in_room ) { if ( is_same_group( gch, ch ) ) members++; } if ( xIS_SET(ch->act, PLR_AUTOGOLD) && members < 2 ) return; if ( members < 2 ) { send_to_char( "Just keep it all.\n\r", ch ); return; } share = amount / members; extra = amount % members; if ( share == 0 ) { send_to_char( "Don't even bother, cheapskate.\n\r", ch ); return; } ch->gold -= amount; ch->gold += share + extra; set_char_color( AT_GOLD, ch ); ch_printf( ch, "You split %d gold coins. Your share is %d gold coins.\n\r", amount, share + extra ); sprintf( buf, "$n splits %d gold coins. Your share is %d gold coins.", amount, share ); for ( gch = ch->in_room->first_person; gch; gch = gch->next_in_room ) { if ( gch != ch && is_same_group( gch, ch ) ) { act( AT_GOLD, buf, ch, NULL, gch, TO_VICT ); gch->gold += share; } } return; } void do_gtell( CHAR_DATA *ch, char *argument ) { CHAR_DATA *gch; if ( argument[0] == '\0' ) { send_to_char( "Tell your group what?\n\r", ch ); return; } if ( xIS_SET(ch->act, PLR_NO_TELL) ) { send_to_char( "Your message didn't get through!\n\r", ch ); return; } /* * Note use of send_to_char, so gtell works on sleepers. */ for ( gch = first_char; gch; gch = gch->next ) { if ( is_same_group( gch, ch ) ) { set_char_color( AT_GTELL, gch ); ch_printf( gch, "%s tells the group '%s'.\n\r", ch->name, argument ); } } return; } /* * It is very important that this be an equivalence relation: * (1) A ~ A * (2) if A ~ B then B ~ A * (3) if A ~ B and B ~ C, then A ~ C */ bool is_same_group( CHAR_DATA *ach, CHAR_DATA *bch ) { if ( ach->leader ) ach = ach->leader; if ( bch->leader ) bch = bch->leader; return ach == bch; } /* Command to leave a message on the floor using the trail code -- Scion *cackle* */ void do_graffiti(CHAR_DATA *ch, char *argument) { TRAIL_DATA *trail; for (trail=ch->in_room->first_trail; trail; trail=trail->next) { if (!strcmp(ch->name, trail->name)) break; } if (!trail) { send_to_char("There does not appear to be any space for graffiti here.\r\n", ch); return; } if (strlen(argument) < 2) { send_to_char("What do you want to write here?\r\n", ch); return; } if (strlen(argument) > 80) { send_to_char("There is not enough space to write that, unfortunately.\r\n", ch); return; } if (trail->graffiti) STRFREE(trail->graffiti); trail->graffiti = STRALLOC(argument); act(AT_PLAIN, "You write a message for all to see.", ch, NULL, NULL, TO_CHAR); act(AT_PLAIN, "$n writes a message for all to see.", ch, NULL, NULL, TO_ROOM); } /* New Channel Code by Keolah - Feb 9, 2002 * * In an attempt to make channels more versitile and player-controllable, * this code will allow the creation and use of an unlimited number of * user-controlled channels. The channel's owner will have full control * over who can use it, and allow private and public channels, as well as * kicking and banning people from specific channels. */ CHANNEL_DATA *find_chan(char *name) { CHANNEL_DATA *chan; for (chan = first_channel; chan; chan = chan->next) if (!str_cmp(chan->name, name)) return chan; return NULL; } void add_to_chan(CHAR_DATA *ch, CHANNEL_DATA *chan) { CHANNEL_MEMBER *chm; CREATE(chm, CHANNEL_MEMBER, 1); chm->ch = ch; LINK(chm, chan->first_member, chan->last_member, next, prev); } /* Channel editor -- Keolah */ void do_channels( CHAR_DATA *ch, char *argument ) { CHAR_DATA *victim; char arg1[MAX_INPUT_LENGTH]; char arg2[MAX_INPUT_LENGTH]; char buf[MAX_STRING_LENGTH]; CHANNEL_DATA *chan; CHANNEL_DATA *new_chan; CHANNEL_MEMBER *chm; if (IS_NPC(ch) || xIS_SET(ch->act, PLR_NO_CHANNEL)) { ch_printf(ch, "You can't use channels!\n\r"); return; } smash_tilde(argument); argument = one_argument(argument, arg1); argument = one_argument(argument, arg2); if (arg1[0] == '\0') { send_to_char("&wSyntax: chan create <chan>\r\n",ch); send_to_char(" chan delete <chan>\r\n",ch); send_to_char(" chan list\r\n",ch); send_to_char(" chan show <chan>\r\n", ch); send_to_char(" chan flags <chan> <value>\r\n", ch); send_to_char(" chan join|leave <chan>\n\r", ch); send_to_char(" chan invite|kick <chan> <person>\n\r", ch); send_to_char(" chan save\r\n",ch); send_to_char(" chan rejoin|quiet\n\r", ch); send_to_char(" chan clan|permit <chan> <restriction>\n\r", ch); send_to_char(" chan tag|div <chan> <string>\n\r", ch); send_to_char(" chan access|ban <chan> <name>\n\r", ch); send_to_char(" chan transfer <chan> <person>\n\r", ch); return; } if (!strcmp(arg1, "list")) { if (!first_channel) { send_to_char("No channels have been defined.\r\n",ch); return; } send_to_char("&gCurrently defined channels:\r\n",ch); for (chan=first_channel;chan;chan=chan->next) { if ((chm = get_chatter(ch, chan)) != NULL) ch_printf(ch, "&G%s (&gowned by &G%s)\r\n", chan->name, chan->owner); else ch_printf(ch, "&Y%s &G(&gowned by &G%s)\n\r", chan->name, chan->owner); } return; } if (!strcmp(arg1, "show")) { if (!(chan=find_chan(arg2))) { send_to_char("There is no channel with that name.\r\n", ch); return; } ch_printf(ch, "&gChannel &G%s:\r\n", chan->name); ch_printf(ch, "&gInfo: &G%s\n\r", chan->info); ch_printf(ch, "&gOwned by &G%s\n\r", chan->owner); ch_printf(ch, "&gTag: %s &gDivider: %s\n\r", chan->tag, chan->div); ch_printf(ch, "&gClan: %s &gPermission: &G%d\n\r", chan->clan, chan->permit); ch_printf(ch, "&gAccess list: %s\n\r", chan->access); ch_printf(ch, "&gBan list: %s\n\r", chan->ban); ch_printf(ch, "&gCurrent chatters:&G\n\r"); for (chm = chan->first_member;chm;chm = chm->next) ch_printf(ch, " %s\n\r", chm->ch->name); return; } if (!strcmp(arg1, "create")) { if (!arg2 || arg2[0] == '\0') { send_to_char("What do you want to call your new channel?\n\r", ch); return; } CREATE(new_chan, CHANNEL_DATA, 1); if (!first_channel) { first_channel=new_chan; last_channel=new_chan; } else { last_channel->next=new_chan; new_chan->prev=last_channel; last_channel=new_chan; } chan=new_chan; STRFREE(chan->name); chan->name = STRALLOC(arg2); STRFREE(chan->owner); chan->owner = STRALLOC(ch->name); STRFREE(chan->tag); sprintf(buf, "&G<&g%s&G>", chan->name); chan->tag = STRALLOC(buf); STRFREE(chan->div); chan->div = STRALLOC("&g:"); STRFREE(chan->access); chan->access = STRALLOC(""); STRFREE(chan->ban); chan->ban = STRALLOC(""); ch_printf(ch, "Channel %s created.\r\n",chan->name); add_to_chan(ch, chan); return; } if (!strcmp(arg1, "delete")) { if (!(chan=find_chan(arg2))) { send_to_char("There is no channel with that name.\r\n", ch); return; } if (str_cmp(ch->name, chan->owner) && !IS_SET(ch->pcdata->permissions, PERMIT_CHANNEL)) { send_to_char("You aren't the owner of that channel.\n\r", ch); return; } send_to_char("You delete the channel.\r\n", ch); UNLINK(chan, first_channel, last_channel, next, prev); STRFREE(chan->name); for (chm=chan->first_member;chm;chm=chm->next) { if (chm->prev) DISPOSE(chm->prev); } DISPOSE(chan->last_member); DISPOSE(chan); return; } if (!strcmp(arg1, "join")) { CLAN_DATA *clan; if (!(chan=find_chan(arg2))) { send_to_char("There is no channel with that name.\r\n", ch); return; } if ((chm=get_chatter(ch, chan)) != NULL) { send_to_char("You are already on that channel!\n\r", ch); return; } if (!is_name(ch->name, chan->access)) { if (is_name(ch->name, chan->ban)) { send_to_char("You are banned from that channel.\n\r", ch); return; } if (chan->clan && (clan = get_clan(ch, chan->clan)) != NULL) { if ((get_member(ch->name, clan)) == NULL) { ch_printf(ch, "You must be a member of the clan %s to join that channel.\n\r", chan->clan); return; } } if (chan->permit && !IS_SET(ch->pcdata->permissions, chan->permit)) { send_to_char("You don't have the required permission to join that channel.\n\r", ch); return; } } add_to_chan(ch, chan); for(chm=chan->first_member;chm;chm=chm->next) { ch_printf(chm->ch, "%s %s has joined the channel.\n\r", chan->tag, ch->name); } return; } if (!strcmp(arg1, "leave")) { if (!(chan=find_chan(arg2))) { send_to_char("There is no channel with that name.\r\n", ch); return; } if ((chm=get_chatter(ch, chan)) == NULL) { send_to_char("You aren't even on that channel!\n\r", ch); return; } for(chm=chan->first_member;chm;chm=chm->next) { ch_printf(chm->ch, "%s %s has left the channel.\n\r", chan->tag, ch->name); } remove_from_chan(ch, chan); return; } if (!strcmp(arg1, "kick")) { if (!(chan=find_chan(arg2))) { send_to_char("There is no channel with that name.\r\n", ch); return; } if ((chm=get_chatter(ch, chan)) == NULL) { send_to_char("You aren't even on that channel!\n\r", ch); return; } if (str_cmp(ch->name, chan->owner) && !IS_SET(ch->pcdata->permissions, PERMIT_CHANNEL)) { send_to_char("You aren't the owner of that channel.\n\r", ch); return; } victim = get_char_world(ch, argument); if (!victim) { send_to_char("You can't find anyone like that.\n\r", ch); return; } if ((chm = get_chatter(victim, chan)) == NULL) { send_to_char("They aren't on that channel!\n\r", ch); return; } for(chm=chan->first_member;chm;chm=chm->next) { ch_printf(chm->ch, "%s %s has been kicked by %s!\n\r", chan->tag, victim->name, ch->name); } remove_from_chan(victim, chan); return; } if (!strcmp(arg1, "invite")) { if (!(chan=find_chan(arg2))) { send_to_char("There is no channel with that name.\r\n", ch); return; } if ((chm=get_chatter(ch, chan)) == NULL) { send_to_char("You aren't even on that channel!\n\r", ch); return; } if (str_cmp(ch->name, chan->owner) && !IS_SET(ch->pcdata->permissions, PERMIT_CHANNEL)) { send_to_char("You aren't the owner of that channel.\n\r", ch); return; } victim = get_char_world(ch, argument); if (!victim) { send_to_char("You can't find anyone like that.\n\r", ch); return; } if ((chm = get_chatter(victim, chan)) != NULL) { send_to_char("They are already on that channel!\n\r", ch); return; } add_to_chan(victim, chan); for(chm=chan->first_member;chm;chm=chm->next) { ch_printf(chm->ch, "%s %s has been invited to the channel by %s.\n\r", chan->tag, victim->name, ch->name); } return; } if (!strcmp(arg1, "transfer")) { if (!(chan=find_chan(arg2))) { send_to_char("There is no channel with that name.\r\n", ch); return; } if (str_cmp(ch->name, chan->owner) && !IS_SET(ch->pcdata->permissions, PERMIT_CHANNEL)) { send_to_char("You aren't the owner of that channel.\n\r", ch); return; } victim = get_char_world(ch, argument); if (!victim) { send_to_char("You can't find anyone like that.\n\r", ch); return; } STRFREE(chan->owner); chan->owner = STRALLOC(victim->name); for(chm=chan->first_member;chm;chm=chm->next) { ch_printf(chm->ch, "%s %s has transfered ownership of the channel to %s.\n\r", chan->tag, ch->name, victim->name); } return; } if (!strcmp(arg1, "clan")) { CLAN_DATA *clan; if (!(chan=find_chan(arg2))) { send_to_char("There is no channel with that name.\r\n", ch); return; } if (str_cmp(ch->name, chan->owner) && !IS_SET(ch->pcdata->permissions, PERMIT_CHANNEL)) { send_to_char("You aren't the owner of that channel.\n\r", ch); return; } if ((clan = get_clan(ch, argument)) == NULL) { send_to_char("There is no such clan.\n\r", ch); return; } STRFREE(chan->clan); chan->clan = STRALLOC(argument); ch_printf(ch, "You restrict the channel %s to members of %s.\n\r", chan->name, clan->title); return; } if (!strcmp(arg1, "permit")) { int i; if (!(chan=find_chan(arg2))) { send_to_char("There is no channel with that name.\r\n", ch); return; } if (str_cmp(ch->name, chan->owner) && !IS_SET(ch->pcdata->permissions, PERMIT_CHANNEL)) { send_to_char("You aren't the owner of that channel.\n\r", ch); return; } i = get_permit_flag(argument); if ( i < 0 || i > MAX_BITS ) { send_to_char("Unknown flag.\r\n", ch); return; } chan->permit = 1 << i; ch_printf(ch, "You restrict the %s channel to those with %s permission.\n\r", chan->name, argument); return; } if (!strcmp(arg1, "tag")) { if (!(chan=find_chan(arg2))) { send_to_char("There is no channel with that name.\r\n", ch); return; } if (str_cmp(ch->name, chan->owner) && !IS_SET(ch->pcdata->permissions, PERMIT_CHANNEL)) { send_to_char("You aren't the owner of that channel.\n\r", ch); return; } STRFREE(chan->tag); chan->tag = STRALLOC(argument); ch_printf(ch, "You set the tag of the %s channel to '%s'.\n\r", chan->name, chan->tag); return; } if (!strcmp(arg1, "div")) { if (!(chan=find_chan(arg2))) { send_to_char("There is no channel with that name.\r\n", ch); return; } if (str_cmp(ch->name, chan->owner) && !IS_SET(ch->pcdata->permissions, PERMIT_CHANNEL)) { send_to_char("You aren't the owner of that channel.\n\r", ch); return; } STRFREE(chan->div); chan->div = STRALLOC(argument); ch_printf(ch, "You set the divider of the %s channel to '%s'.\n\r", chan->name, chan->div); return; } if (!strcmp(arg1, "info")) { if (!(chan=find_chan(arg2))) { send_to_char("There is no channel with that name.\r\n", ch); return; } if (str_cmp(ch->name, chan->owner) && !IS_SET(ch->pcdata->permissions, PERMIT_CHANNEL)) { send_to_char("You aren't the owner of that channel.\n\r", ch); return; } STRFREE(chan->info); chan->info = STRALLOC(argument); ch_printf(ch, "You set the info of the %s channel to '%s'.\n\r", chan->name, chan->info); return; } if (!strcmp(arg1, "access")) { if (!(chan=find_chan(arg2))) { send_to_char("There is no channel with that name.\r\n", ch); return; } if (str_cmp(ch->name, chan->owner) && !IS_SET(ch->pcdata->permissions, PERMIT_CHANNEL)) { send_to_char("You aren't the owner of that channel.\n\r", ch); return; } if (!strcmp(argument, "clear")) { STRFREE(chan->access); chan->access = STRALLOC(""); send_to_char("You clear the channel access list.\n\r", ch); return; } if (is_name(argument, chan->access)) { ch_printf(ch, "%s already has access to %s.\n\r", capitalize(argument), chan->name); return; } sprintf(buf, "%s %s", chan->access, argument); STRFREE(chan->access); chan->access = STRALLOC(buf); ch_printf(ch, "You allow %s access to the %s channel.\n\r", capitalize(argument), chan->name); return; } if (!strcmp(arg1, "ban")) { if (!(chan=find_chan(arg2))) { send_to_char("There is no channel with that name.\r\n", ch); return; } if (str_cmp(ch->name, chan->owner) && !IS_SET(ch->pcdata->permissions, PERMIT_CHANNEL)) { send_to_char("You aren't the owner of that channel.\n\r", ch); return; } if (!strcmp(argument, "clear")) { STRFREE(chan->ban); chan->ban = STRALLOC(""); send_to_char("You clear the channel ban list.\n\r", ch); return; } if (is_name(argument, chan->ban)) { ch_printf(ch, "%s is already banned from %s.\n\r", capitalize(argument), chan->name); return; } sprintf(buf, "%s %s", chan->ban, argument); STRFREE(chan->ban); chan->ban = STRALLOC(buf); ch_printf(ch, "You ban %s from the %s channel.\n\r", capitalize(argument), chan->name); return; } if (!strcmp(arg1, "rejoin")) { argument = ch->pcdata->channels; while (argument && argument[0] != '\0') { argument = one_argument(argument, arg2); sprintf(buf, "join %s", arg2); do_channels(ch, buf); } return; } if (!strcmp(arg1, "quiet")) { STRFREE(ch->pcdata->channels); ch->pcdata->channels = STRALLOC(""); for (chan = first_channel;chan;chan = chan->next) { if (get_chatter(ch, chan)) { sprintf(buf, "%s %s", ch->pcdata->channels, chan->name); STRFREE(ch->pcdata->channels); ch->pcdata->channels = STRALLOC(buf); sprintf(buf, "leave %s", chan->name); do_channels(ch, buf); } } return; } if (!strcmp(arg1, "save")) { FILE *fp; if ((fp=fopen(CHANNEL_FILE, "w")) == NULL) { bug("Cannot open channel file!",0); return; } for (chan=first_channel; chan; chan=chan->next) { fprintf(fp, "\n#CHANNEL\n"); fprintf(fp, "Name %s~\n", chan->name); fprintf(fp, "Owner %s~\n", chan->owner); fprintf(fp, "Tag %s~\n", chan->tag); fprintf(fp, "Div %s~\n", chan->div); fprintf(fp, "Flags %d\n", chan->flags); fprintf(fp, "Clan %s~\n", chan->clan); fprintf(fp, "Permit %d\n", chan->permit); fprintf(fp, "Access %s~\n", chan->access); fprintf(fp, "Ban %s~\n", chan->ban); fprintf(fp, "Info %s~\n", chan->info); } fprintf(fp, "#END\n"); fclose(fp); STRFREE(ch->pcdata->channels); ch->pcdata->channels = STRALLOC(""); for (chan = first_channel;chan;chan = chan->next) { if (get_chatter(ch, chan)) { sprintf(buf, "%s %s", ch->pcdata->channels, chan->name); STRFREE(ch->pcdata->channels); ch->pcdata->channels = STRALLOC(buf); } } send_to_char("channels saved.\r\n",ch); return; } send_to_char("Unknown option.\r\n",ch); } void do_chat(CHAR_DATA *ch, char *argument) { CHANNEL_DATA *chan; CHANNEL_MEMBER *chm; SOCIALTYPE *social; CHAR_DATA *victim; char arg1[MAX_INPUT_LENGTH]; char buf[MAX_STRING_LENGTH]; if (IS_NPC(ch) || xIS_SET(ch->act, PLR_NO_CHANNEL)) { ch_printf(ch, "You can't use channels!\n\r"); return; } argument = one_argument(argument, arg1); if ((chan=find_chan(arg1)) == NULL) { send_to_char("There is no channel with that name.\r\n", ch); return; } if (!argument || argument[0] == '\0') { send_to_char("Say what where?\n\r", ch); return; } if ((chm = get_chatter(ch, chan)) == NULL) { send_to_char("You aren't even on that channel!\n\r", ch); return; } /* Channel emotes */ if (argument[0] == ',') { for (chm=chan->first_member;chm;chm=chm->next) { ch_printf(chm->ch, "%s %s %s\n\r", chan->tag, ch->name, argument+1); } /* Channel socials */ } else if (argument[0] == '@') { argument = one_argument(argument, arg1); argument = one_argument(argument, buf); victim = NULL; if ((social=find_social(arg1+1)) == NULL) { ch_printf(ch, "Can't find %s social.\n\r", arg1+1); return; } if (buf) victim = get_char_world(ch, buf); if (victim && victim != ch) for (chm=chan->first_member;chm;chm=chm->next) { if (chm->ch == victim) ch_printf(chm->ch, "%s %s.\n\r", chan->tag, act_string(social->vict_found, chm->ch, ch, argument[0] != '\0' ? argument : social->adj, victim, STRING_NONE)); else if (chm->ch == ch) ch_printf(chm->ch, "%s %s.\n\r", chan->tag, act_string(social->char_found, chm->ch, ch, argument[0] != '\0' ? argument : social->adj, victim, STRING_NONE)); else ch_printf(chm->ch, "%s %s.\n\r", chan->tag, act_string(social->others_found, chm->ch, ch, argument[0] != '\0' ? argument : social->adj, victim, STRING_NONE)); } else if (victim && victim == ch) for (chm=chan->first_member;chm;chm=chm->next) { if (chm->ch == victim) ch_printf(chm->ch, "%s %s.\n\r", chan->tag, act_string(social->char_auto, chm->ch, ch, argument[0] != '\0' ? argument : social->adj, victim, STRING_NONE)); else ch_printf(chm->ch, "%s %s.\n\r", chan->tag, act_string(social->others_auto, chm->ch, ch, argument[0] != '\0' ? argument : social->adj, victim, STRING_NONE)); } else for (chm=chan->first_member;chm;chm=chm->next) { if (chm->ch == victim) ch_printf(chm->ch, "%s %s.\n\r", chan->tag, act_string(social->char_no_arg, chm->ch, ch, buf[0] != '\0' ? buf : social->adj, victim, STRING_NONE)); else ch_printf(chm->ch, "%s %s.\n\r", chan->tag, act_string(social->others_no_arg, chm->ch, ch, buf[0] != '\0' ? buf : social->adj, victim, STRING_NONE)); } /* Normal chatter */ } else { for (chm=chan->first_member;chm;chm=chm->next) { ch_printf(chm->ch, "%s %s %s %s\n\r", chan->tag, ch->name, chan->div, argument); } } } bool check_channel(CHAR_DATA *ch, char *command, char *argument) { char buf[MAX_STRING_LENGTH]; CHANNEL_DATA *chan; if ((chan=find_chan(command)) != NULL && (get_chatter(ch, chan) != NULL)) { sprintf(buf, "%s %s", command, argument); do_chat(ch, buf); return TRUE; } return FALSE; }