/* ************************************************************************ * File: act.comm.c EmpireMUD AD 1.0 * * Usage: Player-level communication commands * * * * All rights reserved. See license.doc for complete information. * * * * Code base by Paul Clarke. EmpireMUD Project, a tbgMUD Production. * * Based upon CircleMUD 3.0, beta patch level 17, by Jeremy Elson. * * * * Copyright (C) 1993, 94 by the Trustees of the Johns Hopkins University * * CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991. * ************************************************************************ */ #include "conf.h" #include "sysdep.h" #include "structs.h" #include "utils.h" #include "comm.h" #include "interpreter.h" #include "handler.h" #include "db.h" #include "skills.h" /* externs */ extern const char *langs[]; #define MAX_RECENT_CHANNELS 20 /* Number of pub_comm uses to remember */ /* * Structure for recording channel usage * I know that this could record char_data, but if that character quits * it would be lost. invis_lev is recorded so we don't accidently * undermine invisibility. channel could be stored as a number, but * we'd probably use more memory having a constant string of channel * names, and that would be one more thing to change when adding a new * channel. For now, I think we're best off like this. -PC */ struct recent_channel_data { char *name; /* PERS() of person using channel */ int min_lev; int invis_lev; /* char's invis level, Someone */ bool mort_invis; /* mortal invis spell */ char *channel; /* name of channel */ char *message; struct recent_channel_data *next; }; struct recent_channel_data *recent_channels; /* Adds a channel usage to the recent_channels array */ void add_to_recent_channels(Creature ch, char *channel, char *message, bool normal, int level) { int count; struct recent_channel_data *chan, *rcd; /* Find the total amount and the last entry */ for (count = 1, rcd = recent_channels; rcd && rcd->next; rcd = rcd->next, count++); if (count >= MAX_RECENT_CHANNELS) { chan = recent_channels; if (chan->name) free(chan->name); if (chan->channel) free(chan->channel); if (chan->message) free(chan->message); recent_channels = recent_channels->next; free(chan); } /* rcd is now the last entry */ CREATE(chan, struct recent_channel_data, 1); chan->name = str_dup(PERS(ch, ch, normal)); chan->min_lev = level; chan->invis_lev = GET_INVIS_LEV(ch); chan->mort_invis = AFF_FLAGGED(ch, AFF_INVISIBLE); chan->channel = str_dup(channel); chan->message = str_dup(message); if (rcd) rcd->next = chan; else recent_channels = chan; chan->next = NULL; } /* Display all recent channel uses to a person */ void output_recent_channels(Creature ch) { struct recent_channel_data *rcd; for (rcd = recent_channels; rcd; rcd = rcd->next) if (GET_LEVEL(ch) >= rcd->min_lev) msg_to_char(ch, "(%s&0) %s&0: %s&0\r\n", rcd->channel, (GET_LEVEL(ch) >= rcd->invis_lev && (!rcd->mort_invis || PRF_FLAGGED(ch, PRF_HOLYLIGHT))) ? rcd->name : "Someone", rcd->message); } ACMD(do_history) { msg_to_char(ch, "Last %d channels:\r\n", MAX_RECENT_CHANNELS); output_recent_channels(ch); } ACMD(do_say) { Creature c; skip_spaces(&argument); if (!*argument) msg_to_char(ch, "Yes, but WHAT do you want to say?\r\n"); else if (subcmd != SCMD_OOCSAY && ROOM_AFF_FLAGGED(ch->in_room, ROOM_AFF_SILENT)) msg_to_char(ch, "You speak, but no words come out!\r\n"); else { if (subcmd == SCMD_OOCSAY) strcpy(buf1, " out of character,"); else sprintf(buf1, " in %s,", langs[(int) GET_SPEAKING(ch)]); //&6&bYou say, in english, &4'&0&6test&4&b'&0 sprintf(buf, "&6&b$n says,%s &4'&0&6%s&4&b'&0", buf1, argument); for (c = world[ch->in_room].people; c; c = c->next_in_room) { if (REAL_NPC(c) || ch == c) continue; if (subcmd == SCMD_OOCSAY || IS_IMMORTAL(ch) || IS_GOD(ch) || IS_IMMORTAL(c) || IS_GOD(c) || IS_NPC(ch) || IS_NPC(ch) || IS_SET(GET_LANGUAGES(c), LANGUAGE_BIT(GET_SPEAKING(ch)))) act(buf, FALSE, ch, 0, c, TO_VICT); else act("$n says something you don't understand.", FALSE, ch, 0, c, TO_VICT); } if (!REAL_NPC(ch) && PRF_FLAGGED(ch, PRF_NOREPEAT)) msg_to_char(ch, OK); else { delete_doubledollar(argument); msg_to_char(ch, "&6&bYou say,%s &4'&0&6%s&4&b'&0\r\n", buf1, argument); } } } ACMD(do_psay) { Creature k; struct follow_type *f; skip_spaces(&argument); if (!AFF_FLAGGED(ch, AFF_PARTY)) { msg_to_char(ch, "But you are not the member of a party!\r\n"); return; } if (!*argument) msg_to_char(ch, "Yes, but WHAT do you want to party-talk?\r\n"); else { if (ch->master) k = ch->master; else k = ch; sprintf(buf, "$n tells the party, '%s'", argument); if (AFF_FLAGGED(k, AFF_PARTY) && (k != ch)) act(buf, FALSE, ch, 0, k, TO_VICT | TO_SLEEP); for (f = k->followers; f; f = f->next) if (AFF_FLAGGED(f->follower, AFF_PARTY) && (f->follower != ch)) if (!PRF_FLAGGED(f->follower, PRF_RP) && !IS_IMMORTAL(f->follower)) act(buf, FALSE, ch, 0, f->follower, TO_VICT | TO_SLEEP); if (PRF_FLAGGED(ch, PRF_NOREPEAT)) msg_to_char(ch, OK); else msg_to_char(ch, "You tell the party, '%s'\r\n", argument); } } /* Send a tell to a person, sanity checks are done below */ void perform_tell(Creature ch, Creature vict, char *arg) { char **msg, msgbuf[MAX_STRING_LENGTH]; sprintf(buf, "$o tells you, '%s'&0", arg); msg_to_char(vict, "&1&b"); act(buf, FALSE, ch, 0, vict, TO_VICT | TO_SLEEP | TO_NODARK); if (!REAL_NPC(ch) && PRF_FLAGGED(ch, PRF_NOREPEAT)) msg_to_char(ch, OK); else { sprintf(buf, "&1&bYou tell $O, '%s'&0", arg); act(buf, FALSE, ch, 0, vict, TO_CHAR | TO_SLEEP | TO_NODARK); } if (IS_AFK(vict)) { act("$E is AFK and may not receive your message.", FALSE, ch, 0, vict, TO_CHAR); if (AFK_MSG(vict)) msg_to_char(ch, "Message: %s\r\n", AFK_MSG(vict)); Global_ignore_dark = TRUE; sprintf(msgbuf, "%s: %s\r\n", PERS(ch, vict, 1), arg); Global_ignore_dark = FALSE; if (AFK_MSGS(vict)) sprintf(buf, "%s%s", AFK_MSGS(vict), msgbuf); else sprintf(buf, "%s", msgbuf); msg = &(AFK_MSGS(vict)); if (*msg) free(*msg); if (!*buf) *msg = NULL; else *msg = str_dup(buf); } if (!REAL_NPC(vict) && !REAL_NPC(ch)) GET_LAST_TELL(vict) = GET_IDNUM(ch); } /* Verifies the tellability of a person */ int is_tell_ok(Creature ch, Creature vict) { if (ch == vict) msg_to_char(ch, "You try to tell yourself something.\r\n"); else if (!REAL_NPC(ch) && PRF_FLAGGED(ch, PRF_NOTELL)) msg_to_char(ch, "You can't tell other people while you have notell on.\r\n"); else if (!REAL_NPC(vict) && !vict->desc) /* linkless */ act("$E's linkless at the moment.", FALSE, ch, 0, vict, TO_CHAR | TO_SLEEP); else if (PLR_FLAGGED(vict, PLR_WRITING)) act("$E's writing a message right now; try again later.", FALSE, ch, 0, vict, TO_CHAR | TO_SLEEP); else if ((!REAL_NPC(vict) && PRF_FLAGGED(vict, PRF_NOTELL))) act("$E can't hear you.", FALSE, ch, 0, vict, TO_CHAR | TO_SLEEP); else if (!REAL_NPC(vict) && PRF_FLAGGED(vict, PRF_RP) && !IS_IMMORTAL(ch) && !IS_IMMORTAL(vict)) msg_to_char(ch, "You can't use tell with people who are role-playing.\r\n"); else return (TRUE); return (FALSE); } ACMD(do_tell) { Creature vict = NULL; if (REAL_NPC(ch)) return; half_chop(argument, buf, buf2); if (!*buf || !*buf2) msg_to_char(ch, "Who do you wish to tell what??\r\n"); else if (!(vict = get_player_vis(ch, buf, FIND_CHAR_WORLD | FIND_NO_DARK))) msg_to_char(ch, NOPERSON); else if (is_tell_ok(ch, vict)) perform_tell(ch, vict, buf2); } ACMD(do_reply) { Creature tch = character_list; if (REAL_NPC(ch)) return; skip_spaces(&argument); if (GET_LAST_TELL(ch) == NOBODY) msg_to_char(ch, "You have no-one to reply to!\r\n"); else if (!*argument) msg_to_char(ch, "What is your reply?\r\n"); else { /* * Make sure the person you're replying to is still playing by searching * for them. Note, now last tell is stored as player IDnum instead of * a pointer, which is much better because it's safer, plus will still * work if someone logs out and back in again. */ /* * XXX: A descriptor list based search would be faster although * we could not find link dead people. Not that they can * hear tells anyway. :) -gg 2/24/98 */ while (tch != NULL && (REAL_NPC(tch) || GET_IDNUM(tch) != GET_LAST_TELL(ch))) tch = tch->next; if (tch == NULL) msg_to_char(ch, "They are no longer playing.\r\n"); else if (is_tell_ok(ch, tch)) perform_tell(ch, tch, argument); } } ACMD(do_spec_comm) { Creature vict; const char *action_sing, *action_plur, *action_others; switch (subcmd) { case SCMD_WHISPER: action_sing = "whisper to"; action_plur = "whispers to"; action_others = "$n whispers something to $N."; break; case SCMD_ASK: action_sing = "ask"; action_plur = "asks"; action_others = "$n asks $N a question."; break; default: action_sing = "oops"; action_plur = "oopses"; action_others = "$n is tongue-tied trying to speak with $N."; break; } half_chop(argument, buf, buf2); if (!*buf || !*buf2) { sprintf(buf, "Whom do you want to %s.. and what??\r\n", action_sing); msg_to_char(ch, buf); } else if (ROOM_AFF_FLAGGED(ch->in_room, ROOM_AFF_SILENT)) msg_to_char(ch, "You speak, but no words come out!\r\n"); else if (!(vict = get_char_vis(ch, buf, FIND_CHAR_ROOM))) msg_to_char(ch, NOPERSON); else if (vict == ch) msg_to_char(ch, "You can't get your mouth close enough to your ear...\r\n"); else { sprintf(buf, "$n %s you, '%s'", action_plur, buf2); act(buf, FALSE, ch, 0, vict, TO_VICT); if (PRF_FLAGGED(ch, PRF_NOREPEAT)) msg_to_char(ch, OK); else msg_to_char(ch, "You %s %s, '%s'\r\n", action_sing, PERS(vict, ch, 0), buf2); act(action_others, FALSE, ch, 0, vict, TO_NOTVICT); } } ACMD(do_page) { Descr d; Creature vict; half_chop(argument, arg, buf2); if (REAL_NPC(ch)) msg_to_char(ch, "Monsters can't page.. go away.\r\n"); else if (!*arg) msg_to_char(ch, "Whom do you wish to page?\r\n"); else { sprintf(buf, "\007*$n* %s", buf2); if (!str_cmp(arg, "all")) { if (GET_LEVEL(ch) >= LVL_IMPL) { for (d = descriptor_list; d; d = d->next) if (STATE(d) == CON_PLAYING && d->character) act(buf, FALSE, ch, 0, d->character, TO_VICT); } else msg_to_char(ch, "You will never be godly enough to do that!\r\n"); return; } if ((vict = get_char_vis(ch, arg, FIND_CHAR_WORLD)) != NULL) { act(buf, FALSE, ch, 0, vict, TO_VICT); if (PRF_FLAGGED(ch, PRF_NOREPEAT)) msg_to_char(ch, OK); else act(buf, FALSE, ch, 0, vict, TO_CHAR); } else msg_to_char(ch, "There is no such person in the game!\r\n"); } } /*********************************************************************** * generalized communication func, originally by Fred C. Merkel (Torg) * * This function has been rewritten (several times) by Paul Clarke * * (Gideon) for TBG use. The basis remains the same, but the output * * and handling have been customized. -Paul, 11/19/98 * **********************************************************************/ /* Basic distance */ #define distance(x, y, a, b) ((x - a) * (x - a) + (y - b) * (y - b)) ACMD(do_pub_comm) { Descr i; char level_string[10], invis_string[10]; bool emote = 0; int level = 0, min_lev = 0; /* Array of flags which must _not_ be set in order for comm to be heard */ static int channels[] = { PRF_DEAF, PRF_NOGOSS, PRF_NOOOC, PRF_NOGODNET, PRF_NOWIZ }; /* * com_msgs: [0] Message if you can't perform the action because of mute. * [1] name of the action. * [2] message if you're not on the channel. * [3] a color string. * [4] channel type: * "0": $n shouts, '...' (limited by distance) * "1": $n shouts, '...' * "2": [SHOUT $n]: ... */ static char *com_msgs[][5] = { { "You cannot shout!!\r\n", "shout", "You aren't even on the channel!\r\n", "&3", "0" }, { "You can't gossip!\r\n", "gossip", "You aren't even on the channel!\r\n", "&3", "1" }, { "You can't use the out-of-character channel!\r\n", "OOC", "You aren't even on the channel!\r\n", "&3", "2" }, { "You can't use the god channel!\r\n", "GOD", "You aren't even on the channel!\r\n", "&1", "2" }, { "You can't use the immortal channel!\r\n", "IMMORTAL", "You aren't even on the channel!\r\n", "&6", "3" } }; /* to keep pets, etc from being ordered to shout */ if (AFF_FLAGGED(ch, AFF_CHARM) && !ch->desc) return; if (PLR_FLAGGED(ch, PLR_MUTED)) { msg_to_char(ch, com_msgs[subcmd][0]); return; } if (atoi(com_msgs[subcmd][4]) == 2 && REAL_NPC(ch)) return; if (atoi(com_msgs[subcmd][4]) == 0 && ROOM_AFF_FLAGGED(ch->in_room, ROOM_AFF_SILENT)) { msg_to_char(ch, "You try to, but no words come out!\r\n"); return; } /* make sure the char is on the channel */ if (channels[subcmd] && PRF_FLAGGED(ch, channels[subcmd])) { msg_to_char(ch, com_msgs[subcmd][2]); return; } /* skip leading spaces */ skip_spaces(&argument); /* make sure that there is something there to say! */ if (!*argument) { sprintf(buf, "Yes, %s, fine, %s we must, but WHAT???\r\n", com_msgs[subcmd][1], com_msgs[subcmd][1]); msg_to_char(ch, buf); return; } if (atoi(com_msgs[subcmd][4]) == 2 || atoi(com_msgs[subcmd][4]) == 3) { if (*argument == '*') { emote = TRUE; argument++; } if (*argument == '#') { one_argument(argument + 1, buf1); if (is_number(buf1)) { half_chop(argument+1, buf1, argument); level = atoi(buf1); if (level > GET_REAL_LEVEL(ch)) { msg_to_char(ch, "You can't speak above your own level.\r\n"); return; } } } if (!emote) if (*argument == '*') { emote = TRUE; argument++; } skip_spaces(&argument); } /* override levels */ switch (subcmd) { case SCMD_WIZNET: min_lev = LVL_START_IMM; break; case SCMD_GODNET: min_lev = LVL_GOD; break; } level = MAX(level, min_lev); if (level > min_lev) sprintf(level_string, " <%d>", level); else level_string[0] = '\0'; if (GET_INVIS_LEV(ch) > 0) sprintf(invis_string, " (i%d)", GET_INVIS_LEV(ch)); else *invis_string = '\0'; /* Add to the public message archive, as above */ sprintf(buf, "%s%s", com_msgs[subcmd][3], com_msgs[subcmd][1]); if (atoi(com_msgs[subcmd][4]) != 0 && atoi(com_msgs[subcmd][4]) != 3) add_to_recent_channels(ch, buf, argument, (atoi(com_msgs[subcmd][4]) == 2), level); switch(atoi(com_msgs[subcmd][4])) { case 0: case 1: if (PRF_FLAGGED(ch, PRF_NOREPEAT)) msg_to_char(ch, OK); else { sprintf(buf1, "%sYou %s, in %s, '%s'&0", com_msgs[subcmd][3], com_msgs[subcmd][1], langs[(int) GET_SPEAKING(ch)], argument); act(buf1, FALSE, ch, 0, 0, TO_CHAR | TO_SLEEP); } for (i = descriptor_list; i; i = i->next) { if (STATE(i) == CON_PLAYING && i != ch->desc && i->character && (!channels[subcmd] || !PRF_FLAGGED(i->character, channels[subcmd])) && !PLR_FLAGGED(i->character, PLR_WRITING)) { /* distance */ if (atoi(com_msgs[subcmd][4]) == 0 && distance(X_COORD(ch->in_room), Y_COORD(ch->in_room), X_COORD(i->character->in_room), Y_COORD(i->character->in_room)) > distance(0, 0, 50, 0)) continue; /* language: gossip-style */ if (atoi(com_msgs[subcmd][4]) == 1 && !IS_IMMORTAL(ch) && !IS_GOD(ch) && !IS_IMMORTAL(i->character) && !IS_GOD(i->character) && !IS_NPC(ch) && !IS_NPC(i->character) && !IS_SET(GET_LANGUAGES(i->character), LANGUAGE_BIT(GET_SPEAKING(ch)))) continue; if (atoi(com_msgs[subcmd][4]) == 0 && ROOM_AFF_FLAGGED(i->character->in_room, ROOM_AFF_SILENT) && GET_QUIETUS(i->character) < 1) continue; sprintf(buf, "$n %ss, in %s, '%s'&0", com_msgs[subcmd][1], langs[(int) GET_SPEAKING(ch)], argument); sprintf(buf1, "$n %ss something you don't understand.&0", com_msgs[subcmd][1]); msg_to_char(i->character, "%s", com_msgs[subcmd][3]); if (!IS_IMMORTAL(ch) && !IS_GOD(ch) && !IS_IMMORTAL(i->character) && !IS_GOD(i->character) && !IS_NPC(ch) && !IS_NPC(i->character) && !IS_SET(GET_LANGUAGES(i->character), LANGUAGE_BIT(GET_SPEAKING(ch)))) act(buf1, FALSE, ch, 0, i->character, TO_VICT | TO_SLEEP); else act(buf, FALSE, ch, 0, i->character, TO_VICT | TO_SLEEP); } } break; case 2: case 3: default: /* No invis checks here for name, this is to self */ if (PRF_FLAGGED(ch, PRF_NOREPEAT)) msg_to_char(ch, OK); else { if (emote) sprintf(buf, "&0[%s%s&0%s%s] $o %s&0", com_msgs[subcmd][3], com_msgs[subcmd][1], invis_string, level_string, argument); else sprintf(buf, "&0[%s%s&0 $o%s%s]: %s&0", com_msgs[subcmd][3], com_msgs[subcmd][1], invis_string, level_string, argument); act(buf, FALSE, ch, 0, 0, TO_CHAR | TO_SLEEP); } for (i = descriptor_list; i; i = i->next) { if (STATE(i) != CON_PLAYING || i == ch->desc || !i->character || PLR_FLAGGED(i->character, PLR_WRITING)) continue; if (channels[subcmd] && PRF_FLAGGED(i->character, channels[subcmd])) continue; if (GET_REAL_LEVEL(i->character) < level) continue; if (atoi(com_msgs[subcmd][4]) == 2 && PRF_FLAGGED(i->character, PRF_RP) && !IS_IMMORTAL(i->character)) continue; if (emote) sprintf(buf, "&0[%s%s&0%s%s] %s %s&0", com_msgs[subcmd][3], com_msgs[subcmd][1], CAN_SEE_NO_DARK(i->character, ch) ? invis_string : "", level_string, !CAN_SEE_NO_DARK(i->character, ch) ? "Someone" : "$o", argument); else sprintf(buf, "&0[%s%s&0 %s%s%s]: %s&0", com_msgs[subcmd][3], com_msgs[subcmd][1], !CAN_SEE_NO_DARK(i->character, ch) ? "Someone" : "$o", CAN_SEE_NO_DARK(i->character, ch) ? invis_string : "", level_string, argument); act(buf, FALSE, ch, 0, i->character, TO_VICT | TO_SLEEP | TO_NODARK); } break; } } /* Output text on a virtual channel */ void perform_vcsay(Creature ch, long vc, char *vc_name, char *string) { Descr d; if (ch) { sprintf(buf, "[%s %s]: %s\r\n", vc_name, PERS(ch, ch, 1), string); sprintf(buf1, "[%s Someone]: %s\r\n", vc_name, string); } else sprintf(buf1, "[%s SYSTEM]: %s\r\n", vc_name, string); for (d = descriptor_list; d; d = d->next) { if (!d->character || STATE(d) != CON_PLAYING) continue; if (GET_VC(d->character) != vc) continue; if (PRF_FLAGGED(d->character, PRF_RP) && !IS_IMMORTAL(d->character)) continue; if (ch && CAN_SEE(d->character, ch)) msg_to_char(d->character, buf); else msg_to_char(d->character, buf1); } } ACMD(do_vcsay) { skip_spaces(&argument); if (IS_NPC(ch)) msg_to_char(ch, "You're probably not really on a virtual channel..\r\n"); else if (GET_VC(ch) < 1) msg_to_char(ch, "You're not on a virtual channel.\r\n"); else if (PLR_FLAGGED(ch, PLR_MUTED)) msg_to_char(ch, "You can't talk on a virtual channel while muted.\r\n"); else if (!*argument) msg_to_char(ch, "Say what on the virtual channel?\r\n"); else perform_vcsay(ch, GET_VC(ch), GET_VC_NAME(ch), argument); } ACMD(do_vc) { int i; Descr d; Creature c; char arg1[MAX_STRING_LENGTH]; char *commands[] = { "open", "close", "invite", "join", "moderater", "rename", "kick", "who", "\n" }; two_arguments(argument, arg, arg1); if (IS_NPC(ch)) return; /* Find the command now */ for (i = 0; str_cmp(commands[i], "\n") && !is_abbrev(arg, commands[i]); i++); if (!*arg || !str_cmp(commands[i], "\n")) { msg_to_char(ch, "Available virtual channel commands:\r\n"); for (i = 0; str_cmp(commands[i], "\n"); i++) msg_to_char(ch, " %s\r\n", commands[i]); return; } if (PLR_FLAGGED(ch, PLR_MUTED)) { msg_to_char(ch, "You can't use a virtual channel while muted.\r\n"); return; } switch (i) { case 0: /* open */ if (GET_VC(ch) > 0) msg_to_char(ch, "You're already on a virtual channel!\r\n"); else if (!*arg1) msg_to_char(ch, "What would you like to name the virtual channel?\r\n"); else { GET_VC(ch) = GET_IDNUM(ch); if (GET_VC_NAME(ch)) free(GET_VC_NAME(ch)); GET_VC_NAME(ch) = str_dup(arg1); perform_vcsay(NULL, GET_VC(ch), GET_VC_NAME(ch), "Virtual channel open."); } return; case 1: /* close */ if (GET_VC(ch) < 1) msg_to_char(ch, "You're not on a virtual channel.\r\n"); else if (GET_VC(ch) != GET_IDNUM(ch)) { sprintf(buf2, "%s has left the virtual channel.", PERS(ch, ch, 1)); perform_vcsay(NULL, GET_VC(ch), GET_VC_NAME(ch), buf2); GET_VC(ch) = 0; } else { perform_vcsay(NULL, GET_VC(ch), GET_VC_NAME(ch), "Virtual channel closed."); for (d = descriptor_list; d; d = d->next) if (d->character && d->character != ch && (GET_VC(d->character) == GET_VC(ch) || GET_VC(d->character) == GET_VC(ch) * -1)) GET_VC(d->character) = 0; GET_VC(ch) = 0; } return; case 2: /* invite */ if (GET_VC(ch) < 1) msg_to_char(ch, "You're not even on a virtual channel!\r\n"); else if (GET_VC(ch) != GET_IDNUM(ch)) msg_to_char(ch, "You're not the moderator of the virtual channel!\r\n"); else if (!*arg1) msg_to_char(ch, "Invite whom to the virtual channel?\r\n"); else if (!(c = get_char_vis(ch, arg1, FIND_CHAR_WORLD))) msg_to_char(ch, NOPERSON); else if (c == ch) msg_to_char(ch, "You're already on the channel!\r\n"); else if (IS_NPC(c)) msg_to_char(ch, "You can't add NPC's to the channel!\r\n"); else if (GET_VC(c) > 0) msg_to_char(ch, "You can't invite someone who's already on a virtual channel.\r\n"); else { GET_VC(c) = -1 * GET_VC(ch); if (GET_VC_NAME(c)) free(GET_VC_NAME(c)); GET_VC_NAME(c) = str_dup(GET_VC_NAME(ch)); msg_to_char(c, "You have been invited to join virtual channel '%s'.\r\n", GET_VC_NAME(c)); msg_to_char(ch, OK); } return; case 3: /* join */ if (GET_VC(ch) > 0) msg_to_char(ch, "You're already on a virtual channel!\r\n"); else if (GET_VC(ch) == 0) msg_to_char(ch, "You haven't been invited to join any virtual channel!\r\n"); else { GET_VC(ch) = -1 * GET_VC(ch); sprintf(buf2, "%s has joined this virtual channel.", PERS(ch, ch, 1)); perform_vcsay(NULL, GET_VC(ch), GET_VC_NAME(ch), buf2); } return; case 4: /* moderator */ if (GET_VC(ch) < 1) msg_to_char(ch, "You're not even on a virtual channel!\r\n"); else if (GET_VC(ch) != GET_IDNUM(ch)) msg_to_char(ch, "You're not even the moderator of the channel!\r\n"); else if (!*arg1) msg_to_char(ch, "Make whom the moderator of the channel?\r\n"); else if (!(c = get_char_vis(ch, arg1, FIND_CHAR_WORLD))) msg_to_char(ch, NOPERSON); else if (IS_NPC(c) || GET_VC(c) != GET_VC(ch)) msg_to_char(ch, "That person isn't even on the channel!\r\n"); else if (c == ch) msg_to_char(ch, "You're already the moderator!\r\n"); else { for (d = descriptor_list; d; d = d->next) if (d->character && d->character != ch && (GET_VC(d->character) == GET_VC(ch) || GET_VC(d->character) == GET_VC(ch) * -1)) GET_VC(d->character) = (GET_VC(d->character) > 0 ? GET_IDNUM(c) : -1 * GET_IDNUM(c)); GET_VC(ch) = GET_IDNUM(c); sprintf(buf2, "%s is now the moderator of this channel.", PERS(c, c, 1)); perform_vcsay(NULL, GET_VC(ch), GET_VC_NAME(ch), buf2); } return; case 5: /* rename */ if (GET_VC(ch) < 1) msg_to_char(ch, "You're not even on a virtual channel!\r\n"); else if (GET_VC(ch) != GET_IDNUM(ch)) msg_to_char(ch, "You're not even the moderator of the channel!\r\n"); else if (!*arg1) msg_to_char(ch, "Rename the virtual channel to what?\r\n"); else { for (d = descriptor_list; d; d = d->next) if (d->character && (GET_VC(d->character) == GET_VC(ch) || GET_VC(d->character) == GET_VC(ch) * -1)) { if (GET_VC_NAME(d->character)) free(GET_VC_NAME(d->character)); GET_VC_NAME(d->character) = str_dup(arg1); } perform_vcsay(NULL, GET_VC(ch), GET_VC_NAME(ch), "The virtual channel has been renamed."); } return; case 6: /* kick */ if (GET_VC(ch) < 1) msg_to_char(ch, "You're not even on a virtual channel!\r\n"); else if (GET_VC(ch) != GET_IDNUM(ch)) msg_to_char(ch, "You're not even the moderator of the channel!\r\n"); else if (!*arg1) msg_to_char(ch, "Kick who off the channel?\r\n"); else if (!(c = get_char_vis(ch, arg1, FIND_CHAR_WORLD))) msg_to_char(ch, NOPERSON); else if (IS_NPC(c) || GET_VC(c) != GET_VC(ch)) msg_to_char(ch, "That person isn't even on the channel!\r\n"); else if (c == ch) msg_to_char(ch, "Use 'vc close' for that!\r\n"); else { msg_to_char(c, "You have been kicked off the virtual channel.\r\n"); GET_VC(c) = 0; sprintf(buf2, "%s has been kicked off the channel.", PERS(c, c, 1)); perform_vcsay(NULL, GET_VC(ch), GET_VC_NAME(ch), buf2); } return; case 7: /* who */ if (GET_VC(ch) < 1) msg_to_char(ch, "You're not even on a virtual channel!\r\n"); else { msg_to_char(ch, "People on virtual channel %s:\r\n", GET_VC_NAME(ch)); for (d = descriptor_list; d; d = d->next) if (d->character && (GET_VC(d->character) == GET_VC(ch) || GET_VC(d->character) == GET_VC(ch) * -1)) msg_to_char(ch, " %s%s\r\n", CAN_SEE(ch, d->character) ? PERS(d->character, ch, 1) : "Someone", GET_VC(d->character) < 0 ? " (invited)" : ""); } return; default: msg_to_char(ch, "Invalid virtual channel ability.\r\n"); return; } } ACMD(do_speak) { extern const char *langs[]; int i; bool c = FALSE; one_argument(argument, arg); if (IS_NPC(ch)) return; if (!*arg) { msg_to_char(ch, "You are currently speaking %s.\r\n", langs[(int) GET_SPEAKING(ch)]); msg_to_char(ch, "You know how to speak"); for (i = 0; i < NUM_LANGS; i++) if (IS_SET(GET_LANGUAGES(ch), LANGUAGE_BIT(i))) { msg_to_char(ch, "%s %s", c ? "," : "", langs[i]); c = TRUE; } msg_to_char(ch, ".\r\n"); } else if ((i = search_block(arg, langs, FALSE)) < 0) msg_to_char(ch, "Invalid language.\r\n"); else if (GET_SPEAKING(ch) == i) msg_to_char(ch, "You're already speaking that language.\r\n"); else if (!IS_SET(GET_LANGUAGES(ch), LANGUAGE_BIT(i))) msg_to_char(ch, "You don't know how to speak that language.\r\n"); else { SET_SPEAKING(ch) = i; msg_to_char(ch, "You will now speak %s.\r\n", langs[i]); } }