/
roa/
roa/lib/boards/
roa/lib/config/
roa/lib/edits/
roa/lib/help/
roa/lib/misc/
roa/lib/plrobjs/
roa/lib/quests/
roa/lib/socials/
roa/lib/www/
roa/lib/www/LEDSign/
roa/lib/www/LEDSign/fonts/
roa/lib/www/LEDSign/scripts/
roa/src/s_inc/
roa/src/sclient/
roa/src/sclient/binary/
roa/src/sclient/text/
roa/src/util/
/************************************************************************
	Realms of Aurealis 		James Rhone aka Vall of RoA

speak.c					Languages, player communication
					code.

		******** Heavily modified and expanded ********
		*** BE AWARE OF ALL RIGHTS AND RESERVATIONS ***
		******** Heavily modified and expanded ********
		        All rights reserved henceforth. 

    Please note that no guarantees are associated with any code from
Realms of Aurealis.  All code which has been released to the general
public has been done so with an 'as is' pretense.  RoA is based on both
Diku and CircleMUD and ALL licenses from both *MUST* be adhered to as well
as the RoA license.   *** Read, Learn, Understand, Improve ***
*************************************************************************/
#include "conf.h"
#include "sysdep.h"

#include "structures.h"
#include "utils.h"
#include "comm.h"
#include "interpreter.h"
#include "acmd.h"
#include "handler.h"
#include "db.h"
#include "magic.h"
#include "lists.h"
#include "global.h"
#include "boards.h"
#include "darkenelf.h"
#include "affect.h"

#define TELL_WHO(ch) ((ch)->pc_specials->tell_who)

/* extern variables */
extern char *delete_doubledollar(char *string);

/* external functions */
extern void update_last_goss(chdata *ch, char *chan, char *str);
extern void killp(char *str);
int IdListMember(IdList * member, long idnum);
int find_gskill_num(char *name);

// 6/20/98 - massive dialect change, no more offsets, seperate array -jtrhone

/* set yer default language to whatever, note its reset upon login */
ACMD(do_speak)
{
  int i, tp;

  one_argument(argument, arg);
  if (!*arg || ((tp = find_gskill_num(arg)) < 0) || tp >= MAX_GSKILLS || !GSKILL_FLAGGED(tp, G_DIALECT))
  {
    sprintf(buf, "These are the common dialects of %s:\n\r", shortmudname);
    S2C();
    for (i=0; i < MAX_GSKILLS; i++)
      if (GSKILL_FLAGGED(i, G_DIALECT))
      {
        sprintf(buf,"%%B%s%%0\n\r",gskill_names[i]);
        S2C();
      }
    sprintf(buf, "You are currently speaking in the %%B%s%%0 dialect.\n\r", gskill_names[SPEAKING(ch)]);
    S2C();
    return;
  }

  SPEAKING(ch) = tp; 
  sprintf(buf, "You are now speaking in the %%B%s%%0 dialect.\n\r", gskill_names[SPEAKING(ch)]);
  S2C();
}

/* say a particular thing in a particular language */
ACMD(do_lsay)
{
  int tp;
  char said[MAX_INPUT_LENGTH];

  half_chop(argument, arg, said);

  if (!*arg || !*said)
  {
    send_to_char("What do you wish to say?\n\r",ch);
    return;
  }

  if (!*arg || ((tp = find_gskill_num(arg)) < 0) || tp >= MAX_GSKILLS || !GSKILL_FLAGGED(tp, G_DIALECT))
  {
    send_to_char("Unknown dialect.\n\r",ch);
    return;
  }

  do_say(ch, said, 0, tp);   /* say in a particular dialect */
}

/* this scrambles a string based on characters skill in that
   particular language */
// Added check for Druid spell tongues. 06/08/98 -callahan
void scramble(chdata *reader, char *said, char *heard, int lang)
{
  char *pt = NULL;

  if (IS_NPC(reader))
  {
    strcpy(heard, said);
    return;
  }

  for (pt = said; *pt; pt++, heard++)
  {
    if (reader->gskills[lang].perc >= number(0, 75) || (*pt == ' ') ||
        (affected_by_spell(reader, SPELL_TONGUES) && (number(0, 101) <= 80)))
      *heard = *pt;
    else
      *heard = number(97, 122);  /* lower case letters */
  }
  *heard = '\0';

  // slight chance of improvement here
  if (!number(0,100) && reader->gskills[lang].perc < 95)
  {
    reader->gskills[lang].perc++;
    reader->gskills[lang].perc = MIN(reader->gskills[lang].perc, 95);
  }
}

ACMD(do_say)
{
   chdata *tmp;
   char *argu = argument;
   char said[MAX_INPUT_LENGTH];
   char heard[MAX_INPUT_LENGTH];
   char verb[MAX_INPUT_LENGTH];
   char letter;

   if (IN_NOWHERE(ch)) return;

   *said = '\0';

   skip_spaces(&argu);
   delete_doubledollar(argu);	// 03/18/98 -callahan

   if (strlen(argu) >= MAX_INPUT_LENGTH)
   {
     send_to_char("Argument too long.\n\r",ch);
     return;
   }

   if (!*argu)
      send_to_char("Yes, but WHAT do you want to say?\n\r", ch);
   else 
   {
      // determine verb based on punctuation  2/19/98 -jtrhone
      letter = argu[strlen(argu)-1];
      switch (letter) {
        case '!':
          strcpy(verb, "exclaim");
          break;
        case '?':
          strcpy(verb, "ask");
          break;
        default:
          strcpy(verb, "say");
          break;
      }

      if (subcmd <= 0)
	subcmd = SPEAKING(ch);

      // they may screw up talking...
      scramble(ch, argu, said, subcmd);

      // Added IdListMember() for ignore. 03/16/98 - callahan
      // added look for ppl in CHAT mode
      for (tmp = world[ch->in_room].people; tmp; tmp=tmp->next_in_room)
	if (tmp != ch && !IdListMember(tmp->gagged, GET_IDNUM(ch)) && !INCHAT(tmp))
        {
          scramble(tmp, said, heard, subcmd);
          sprintf(buf, "$n %ss in %s, '%s'", verb, gskill_names[subcmd], heard);
	  act(buf, FALSE, ch, 0, tmp, TO_VICT);
        }

      if (IS_PC(ch) && !PRF_FLAGGED(ch, PRF_NOREPEAT)) 
      {
	 sprintf(buf, "You %s in %s, '%s'\n\r", verb, gskill_names[subcmd], said);
	 S2C();
      } 
      else
	 send_to_char("Ok.\n\r", ch);
   }
}

// Added reference to IDListMember() for ignore. 03/16/98 - callahan

ACMD(do_gsay)
{
   chdata *k;
   struct follow_type *f;
   char said[MAX_INPUT_LENGTH];
   char heard[MAX_INPUT_LENGTH];
   char *argu = argument;

   if (!IS_AFFECTED(ch, AFF_GROUP)) {
      send_to_char("But you are not the member of a group!\n\r", ch);
      return;
   }

   skip_spaces(&argu);
   delete_doubledollar(argu);	// 03/18/98 -callahan

   if (!*argu)
      send_to_char("Yes, but WHAT do you want to group-say?\n\r", ch);
   else 
   {
      if (ch->master)
	 k = ch->master;
      else
	 k = ch;

     scramble(ch, argu, said, SPEAKING(ch));
     if (IS_AFFECTED(k, AFF_GROUP) && (k != ch) && !IdListMember(k->gagged, GET_IDNUM(ch)) && !INCHAT(k))
     {
       scramble(k, said, heard, SPEAKING(ch));
       sprintf(buf, "%s gsays in %s, '%%B%%3%s%%0'\n\r", GET_NAME(ch), gskill_names[SPEAKING(ch)], heard);
       send_to_char(buf, k);
     }

     for (f = k->followers; f; f = f->next)
      if (IS_AFFECTED(f->follower, AFF_GROUP) && (f->follower != ch) &&
          !IdListMember(f->follower->gagged, GET_IDNUM(ch)) && !INCHAT(f->follower))
      { 
	scramble(f->follower, said, heard, SPEAKING(ch));
        sprintf(buf, "%s gsays in %s, '%%B%%3%s%%0'\n\r", GET_NAME(ch), gskill_names[SPEAKING(ch)], heard);
	send_to_char(buf, f->follower);
      }

      if (IS_PC(ch) && !PRF_FLAGGED(ch, PRF_NOREPEAT)) 
      { 
       sprintf(buf, "You gsay in %s, '%%B%%3%s%%0'\n\r", gskill_names[SPEAKING(ch)], said);
       S2C();
      } 
      else
       send_to_char("Ok.\n\r", ch);
   }
}

ACMD(do_tell)
{
   chdata *vict;
   int emote = FALSE;
   char chbuf[MAX_STRING_LENGTH], *tmp;
   extern char *delete_doubledollar(char *string);
    
   // Needed this... 04/02/98 -callahan
   delete_doubledollar(argument); 

   half_chop(argument, buf, buf2);

   if (*buf2 == ':')
     emote = TRUE;

   if (!*buf || !*buf2)
      send_to_char("Who do you wish to tell what??\n\r", ch);
   else if (!(vict = get_char_vis(ch, buf)))
      send_to_char("No-one by that name here..\n\r", ch);
   else if (ch == vict)
      send_to_char("You try to tell yourself something.\n\r", ch);
   else if (IS_NPC(vict) && !SAME_ROOM(ch, vict))/* Wooo here come bitchin. */
      send_to_char("No-one by that name here..\n\r", ch);
   else if (IS_PC(ch) && PRF_FLAGGED(ch, PRF_NOTELL))
      send_to_char("You can't tell other people while you have notell on.\n\r", ch);
   else if (ROOM_FLAGGED2(ch->in_room, SOUNDPROOF))
   {
     send_to_char("This area seems to absorb your words.\n\r",ch);
     return;
   }
   else if (ROOM_FLAGGED2(vict->in_room, SOUNDPROOF))
   {
     send_to_char("Your words are absorbed.\n\r",ch);
     return;
   }
   else if (IS_PC(vict) && !vict->desc) /* linkless */
      act("$E's soulless at the moment.", FALSE, ch, 0, vict, TO_CHAR);
   else if (PLR_FLAGGED(vict, PLR_WRITING))
      act("$E's writing a message right now, try again later.", FALSE, ch, 0, vict, TO_CHAR);
   else if (PLR_FLAGGED(vict, PLR_MAILING))
      act("$E's writing a message right now, try again later.", FALSE, ch, 0, vict, TO_CHAR);
   else if (PLR_FLAGGED(vict, PLR_BUILDING))
      act("$E's building, please try again later.",
          FALSE, ch, 0, vict, TO_CHAR);
   else if (PLR_FLAGGED(vict, PLR_AFK))
      act("$E's afk, please try again later.",
          FALSE, ch, 0, vict, TO_CHAR);

   // Added IdListMember() for ignore. /03/16/98 - callahan
   else if (PRF_FLAGGED(vict, PRF_NOTELL) || IdListMember(vict->gagged, GET_IDNUM(ch)))
      act("$E chooses not to hear you.", FALSE, ch, 0, vict, TO_CHAR);
   else if (IS_PC(vict) && TELL_LEV(vict) > GET_LEVEL(ch))
      act("$E chooses not to hear you.", FALSE, ch, 0, vict, TO_CHAR);
   else if (INCHAT(vict))
      act("$E is currently in chat mode.", FALSE, ch, 0, vict, TO_CHAR);
   else {
     if (IS_PC(vict))
       TELL_WHO(vict) = GET_IDNUM(ch);

     // Added emote support below. 04/02/98 -callahan
     if (emote) {
       tmp = buf2;
       tmp++;

       sprintf(buf, "%%1From afar, %s %s%%0\n\r", Name(ch), tmp);
       sprintf(chbuf, "%%1From afar, to %s: %s %s%%0\n\r", Name(vict),
               Name(ch), tmp);
     } else {
       sprintf(buf, "%%1%s tells you '%s'%%0\n\r", Name(ch), buf2);
       sprintf(chbuf, "%%1You tell %s '%s'%%0\n\r", Name(vict), buf2);
     }

     CCAP(buf);
     send_to_char(buf, vict);

     if (IS_PC(ch) && !PRF_FLAGGED(ch, PRF_NOREPEAT))
       send_to_char(chbuf, ch);
     else
       send_to_char("Ok.\n\r", ch);
   }
}

ACMD(do_reply)
{
   chdata *vict = NULL;
   dsdata *i;
   char *argu = argument;

   if (IS_NPC(ch)) return;

   for (i = descriptor_list; i; i = i->next) 
     if (D_CHECK(i) && IS_PC(i->character))
       if (TELL_WHO(ch) == (long) GET_IDNUM(i->character) &&
	   can_see(ch, i->character))
         vict = i->character;

   skip_spaces(&argu);
   delete_doubledollar(argu);   // 03/18/98 -callahan

   if (!*argu)
      send_to_char("Reply what??\n\r", ch);
   else if (!vict)
      send_to_char("That person is not here.\n\r", ch);
   else if (ch == vict)
      send_to_char("You try to reply to yourself.\n\r", ch);
   else if (PRF_FLAGGED(ch, PRF_NOTELL))
      send_to_char("You can't reply to other people while you have notell on.\n\r", ch);
   else if (ROOM_FLAGGED2(ch->in_room, SOUNDPROOF))
   {
     send_to_char("This area seems to absorb your words.\n\r",ch);
     return;
   }
   else if (ROOM_FLAGGED2(vict->in_room, SOUNDPROOF))
   {
     send_to_char("Your words are absorbed.\n\r",ch);
     return;
   }
   else if (IS_PC(vict) && !vict->desc) /* linkless */
      act("$E's soulless at the moment.", FALSE, ch, 0, vict, TO_CHAR);
   else if (PLR_FLAGGED(vict, PLR_WRITING))
      act("$E's writing a message right now, try again later.", FALSE, ch, 0, vict, TO_CHAR);
   else if (PLR_FLAGGED(vict, PLR_MAILING))
      act("$E's writing a message right now, try again later.", FALSE, ch, 0, vict, TO_CHAR);
   else if (PLR_FLAGGED(vict, PLR_BUILDING))
      act("$E's building, please try again later.",
          FALSE, ch, 0, vict, TO_CHAR);
   else if (PLR_FLAGGED(vict, PLR_AFK))
      act("$E's afk, please try again later.",
          FALSE, ch, 0, vict, TO_CHAR);

   // Added IdListMember() for ignore. /03/16/98 - callahan
   else if (PRF_FLAGGED(vict, PRF_NOTELL) || 
            IdListMember(vict->gagged, GET_IDNUM(ch)))
      act("$E chooses not to hear you.", FALSE, ch, 0, vict, TO_CHAR);
   else if (IS_PC(vict) && TELL_LEV(vict) > GET_LEVEL(ch))
      act("$E chooses not to hear you.", FALSE, ch, 0, vict, TO_CHAR);
   else if (INCHAT(vict))
      act("$E is currently in chat mode.", FALSE, ch, 0, vict, TO_CHAR);
   else {
      if (IS_PC(vict))
        TELL_WHO(vict) = GET_IDNUM(ch);
      
      sprintf(buf, "%%1%s tells you '%s'%%0\n\r", GET_NAME(ch), argu);
      CCAP(buf);
      send_to_char(buf, vict);

      if (!PRF_FLAGGED(ch, PRF_NOREPEAT)) 
      {
	 sprintf(buf, "%%1You tell %s '%s'%%0\n\r", GET_NAME(vict), argu);
	 S2C();
      } 
      else
	 send_to_char("Ok.\n\r", ch);
   }
}


// Combined whisper and ask, and added say-to. 05/02/98 -callahan
ACMD(do_commune)
{
  chdata *vict;
  char *action_sing, *action_plur, *action_others;
  char said[MAX_INPUT_LENGTH], heard[MAX_INPUT_LENGTH];
  BOOL ask = FALSE, exclaim = FALSE;
  
  half_chop(argument, buf, buf2);
    
  if (buf2[strlen(buf2) - 1] == '?')
    ask = TRUE;
    
  if (buf2[strlen(buf2) - 1] == '!')
    exclaim = TRUE;
  
  if (subcmd == SCMD_WHISPER) {
    action_sing = "whisper to";
    action_plur = "whispers to";
    action_others = "$n whispers something to $N.";
  } else if (subcmd == SCMD_ASK) {
    action_sing = "ask";
    action_plur = "asks";
    action_others = "$n asks $N a question.";
  } else {
    sprintf(arg, "$n %s $N, \"%s\"",
            (ask ? "asks" : (exclaim ? "exclaims to" : "says to")), buf2);
    action_sing = (ask ? "ask" : (exclaim ? "exclaim to" : "say to"));
    action_plur = (ask ? "asks" : (exclaim ? "exclaims to" : "says to"));
    action_others = arg;
  }

  if (!*buf || !*buf2) {
    sprintf(buf, "Whom do you want to %s.. and what??\r\n", action_sing);
    send_to_char(buf, ch);  
  } else if (!(vict = get_char_room_vis(ch, buf)))
    send_to_char("That person does not seem to be here.\r\n", ch);
  else if (vict == ch)
    send_to_char("You can't get your mouth close enough to your ear...\r\n", ch);
  else {
    if (INCHAT(vict)) {
      act("$N is in chat mode.", FALSE, ch, 0, vict, TO_CHAR);
      return;
    } 

    // Added check for IDListMember() for ignore. 03/17/98 -callahan 
    if (!IdListMember(vict->gagged, GET_IDNUM(ch))) {
      scramble(ch, buf2, said, SPEAKING(ch));
      scramble(vict, said, heard, SPEAKING(ch));

      sprintf(buf, "%s %s you in %s, '%s'\n\r", Name(ch), action_plur, gskill_names[SPEAKING(ch)], heard);
      CCAP(buf);

      send_to_char(buf, vict);

      if (NoRepeat(ch))
        send_to_char("Ok.\r\n", ch);
      else
        send_to_char(tprintf("You %s %s in %s, '%s'\r\n", action_sing, Name(vict), gskill_names[SPEAKING(ch)], buf2), ch);

      act(action_others, FALSE, ch, 0, vict, TO_NOTVICT);
    } else {
      send_to_char("You feel as though you are being ignored...\r\n", ch);
      act("$n attempts to whisper something to $N, but is ignored.",
          FALSE, ch, 0, vict, TO_NOTVICT);
    }
  }
}


#define MAX_NOTE_LENGTH 1000      /* arbitrary */

// modified to look for board in room first 12/30/97  -jtrhone
ACMD(do_write)
{
  obdata *paper = 0, *pen = 0;
  char	*papername, *penname;

  if (board_in_room(ch->in_room) && board_interaction(ch, argument, get_command("write")))
    return;

  papername = buf1;
  penname = buf2;

  two_arguments(argument, papername, penname);

  if (!ch->desc)
    return;

  if (!*papername)  /* nothing was delivered */ {
    send_to_char("Write?  With what?  ON what?  What are you trying to do?!?\n\r", ch);
    return;
  }

  if (*penname) /* there were two arguments */ 
  {
    if (!(paper = get_obj_in_list_vis(ch, papername, ch->carrying))) {
	 sprintf(buf, "You have no %s.\n\r", papername);
	 S2C();
	 return;
    }
    if (!(pen = get_obj_in_list_vis(ch, penname, ch->carrying))) {
	 sprintf(buf, "You have no %s.\n\r", papername);
	 S2C();
	 return;
    }
  } else /* there was one arg.let's see what we can find */	 {
     if (!(paper = get_obj_in_list_vis(ch, papername, ch->carrying))) {
	 sprintf(buf, "There is no %s in your inventory.\n\r", papername);
	 S2C();
	 return;
      }
      if (paper->type_flag == ITEM_PEN)  /* oops, a pen.. */ {
	 pen = paper;
	 paper = 0;
      } else if (paper->type_flag != ITEM_NOTE) {
	 send_to_char("That thing has nothing to do with writing.\n\r", ch);
	 return;
      }

      /* one object was found. Now for the other one. */
      if (!EQ(ch, W_HOLD)) {
	 sprintf(buf, "You can't write with a %s alone.\n\r", papername);
	 S2C();
	 return;
      }
      if (!CAN_SEE_OBJ(ch, EQ(ch, W_HOLD))) {
	 send_to_char("The stuff in your hand is invisible!  Yeech!!\n\r", ch);
	 return;
      }

      if (pen)
	 paper = EQ(ch, W_HOLD);
      else
	 pen = EQ(ch, W_HOLD);
   }

   /* ok.. now let's see what kind of stuff we've found */
   if (pen->type_flag != ITEM_PEN) {
      act("$p is no good for writing with.", FALSE, ch, pen, 0, TO_CHAR);
   } else if (paper->type_flag != ITEM_NOTE) {
      act("You can't write on $p.", FALSE, ch, paper, 0, TO_CHAR);
   } else if (paper->actdesc)
      send_to_char("There's something written on it already.\n\r", ch);
   else {
      /* we can write - hooray! */
      send_to_char("Ok.. go ahead and write.. end the note with a @.\n\r", ch);
      act("$n begins to jot down a note.", TRUE, ch, 0, 0, TO_ROOM);
      ch->desc->str = &paper->actdesc;
      ch->desc->max_str = MAX_NOTE_LENGTH;
   }
}

ACMD(do_emote)
{
  char *argu = argument;

  if (PLR_FLAGGED(ch, PLR_NOEMOTE))
  {
    send_to_char("%1%BYour emote ability has been removed%0.\n\r",ch);
    return;
  }

  if (!*argu)
    send_to_char("Yes.. But what?\n\r", ch);
  else
  {
      // check for possible language bypassing -jtrhone roa
      if (IS_PC(ch) && strstr(argu, "say"))
      {
        sprintf(buf, "PLRUPD: Possible language bypass with emote (%s).", GET_NAME(ch));
	mudlog(buf, BUG, LEV_IMM, FALSE);

        sprintf(buf, "PLRUPD: %s%s.", GET_NAME(ch), argu);
	mudlog(buf, BUG, LEV_IMM, FALSE);
      }

      sprintf(buf, "$n%s", argu);
      act(buf, FALSE, ch, 0, 0, TO_ROOM);
      if (PRF_FLAGGED(ch, PRF_NOREPEAT))
	 send_to_char("Ok.\n\r", ch);
      else
	 act(buf, FALSE, ch, 0, 0, TO_CHAR);
  }
}

// anytime someone is in chat mode, their typed in text will come here...
// 4/6/98 -jtrhone
ACMD(do_chatline)
{
  char *argu = argument;
  dsdata *d;

  if (IS_NPC(ch))
    return;

  skip_spaces(&argu);
  if (!*argu)
    return;

  if (*argu == '/')
  {
    argu++;
    if (!*argu || *argu == '?')
    {
      send_to_char("Chat commands:  /who, /exit, /:  (emote).\n\r",ch);
      return;
    }

    if (*argu == ':')
    {
      argu++;
      if (!*argu || *argu == '?')
      {
        send_to_char("Chat commands:  /who, /exit, /:  (emote).\n\r",ch);
        return;
      }
      sprintf(buf, "%s %s%s\n\r", IS_IMMORTAL(ch) ? "(IMM)" : "", GET_NAME(ch), argu);
      Descriptors(d)
        if (D_CHECK(d) && ( CHAR_FLAGGED(d->character, CH_CHAT) || 
            (IS_IMMORTAL(d->character) && PLR2_FLAGGED(d->character, PLR2_CHAT))))
          {
            if (!INCHAT(d->character) && IS_IMMORTAL(d->character))
              send_to_char("(Chat)", d->character);
            send_to_char(buf, d->character);
          }
    }
    else
    if (!str_cmp(argu, "who"))
    {
      int i = 0;
      strcpy(buf, "%B%6Chat:%0\n\r");
      Descriptors(d)
      {
        if (D_CHECK(d) && CHAR_FLAGGED(d->character, CH_CHAT))
        {
          sprintf(buf+strlen(buf), "%-15.15s", GET_NAME(d->character));
          if (!(++i%4)) 
            strcat(buf, "\n\r");
         }
      }
      if ((i%4))
        strcat(buf, "\n\r");
      page_string(ch->desc, buf, 1);
    }
    else
    if (!str_cmp(argu, "exit") || !str_cmp(argu, "leave"))
    {
      REMOVE_BIT(CHAR_FLAGS(ch), CH_CHAT);
      send_to_char("Chat mode off.\n\r",ch);
    }
    return;
  }
 
  // normal chat say...
  sprintf(buf, "%s%s: %s\n\r", IS_IMMORTAL(ch) ? "(IMM) " : "", GET_NAME(ch), argu);

  Descriptors(d)
    if (D_CHECK(d) && ( CHAR_FLAGGED(d->character, CH_CHAT) || 
        (IS_IMMORTAL(d->character) && PLR2_FLAGGED(d->character, PLR2_CHAT))))
    {
      if (!INCHAT(d->character) && IS_IMMORTAL(d->character))
        send_to_char("(Chat)", d->character);
      send_to_char(buf, d->character);
    }
}


/**********************************************************************
 * generalized communication func, originally by Fred C. Merkel (Torg) *
  *********************************************************************/
// first, removed global channels... then added them 12 hours later
// via a config option useglobals checked on bootup in interpreter 4/11/98 -jtrhone
ACMD(do_gen_com)
{
   char	name[MAX_INPUT_LENGTH];
   char said[MAX_INPUT_LENGTH];
   char heard[MAX_INPUT_LENGTH];
   dsdata *i;
   BOOL real = TRUE;
   char *argu = argument;

   char *channel_names[][2]={
     { "bellow", "bellows"},
     { "yell", "yells"},
     { "(newbie)", "(newbie)"},
     { "pray", "prays"},
     { "(ooc)", "(ooc)"},
     { "ask", "asks"},
     { "answer", "answers"}
   };

   int channel_prfs[] = {
     PRF_DEAF,
     PRF_DEAF,
     PRF_DEAF,
     PRF_DEAF,
     PRF_NOOOC,
     PRF_NOQA,
     PRF_NOQA
   };

   if (strlen(argu) > MAX_INPUT_LENGTH)
	return;

   // Disallow NPC followers from using channels. 08/10/98 -callahan
   if (IS_NPC(ch) && Master(ch))
     return;

   // it they are muted...
   if (IS_PC(ch) && PLR_FLAGGED(ch, PLR_MUTE)) {
      send_to_char("You have been muted.\n\r",ch);
      return;
   }

   switch (subcmd) {
     case SCMD_OOC:
       if (PRF_FLAGGED(ch, PRF_NOOOC))
       {
         send_to_char("You are ignoring OOC (type 'noooc' to toggle).\n\r",ch);
         return;
       }
       break;

     case SCMD_QUESTION:
     case SCMD_ANSWER:
       if (PRF_FLAGGED(ch, PRF_NOQA))
       {
         send_to_char("You are ignoring QA channels (type 'noqa' to toggle).\n\r",ch);
         return;
       }
       break;

     default:
       if (PRF_FLAGGED(ch, PRF_DEAF))
       {
         send_to_char("You are ignoring natural channels (type 'deaf' to toggle).\n\r",ch);
         return;
       }
       break;
   }

   if (subcmd == SCMD_NEWBIE && !IS_IMMORTAL(ch) && GET_LEVEL(ch) > 10)
   {
     send_to_char("You are too high a level to use that channel.\n\r",ch);
     return;
   }

   if (subcmd == SCMD_PRAYER && !IS_IMMORTAL(ch) && 
       (GET_POS(ch) != POS_RESTING || !ROOM_FLAGGED(ch->in_room, PEACEFUL)))
   {
     send_to_char("You must be resting in a peaceful area before you can pray.\n\r",ch);
     return;
   }

   if (GET_LEVEL(ch) < level_can_shout && subcmd != SCMD_NEWBIE) {
      sprintf(buf1, "You must be at least level %d before you can %s.\n\r",
          level_can_shout, channel_names[subcmd][0]);
      send_to_char(buf1, ch);
      return;
   }

   if (subcmd != SCMD_PRAYER && ROOM_FLAGGED2(ch->in_room, SOUNDPROOF))
   {
     send_to_char("This area seems to absorb your words.\n\r",ch);
     return;
   }

   skip_spaces(&argu);
   delete_doubledollar(argu);   // 03/18/98 -callahan

   if (!(*argu)) 
   {
      sprintf(buf1, "What do you wish to %s?\n\r", channel_names[subcmd][0]);
      send_to_char(buf1, ch);
      return;
   }

   if (subcmd == SCMD_BELLOW && !IS_IMMORTAL(ch) && CHAR_FLAGGED(ch, CH_BELLOW))
   {
     send_to_char("You must wait until dawn before you can do such.\n\r",ch);
     return;
   }

   if ((subcmd == SCMD_YELL || subcmd == SCMD_BELLOW) && !IS_IMMORTAL(ch)) 
   {
      if (GET_MOVE(ch) < holler_move_cost) 
      {
	 send_to_char("You're too exhausted to do so.\n\r", ch);
	 return;
      } 
      else
	 GET_MOVE(ch) -= holler_move_cost;
   }

   if (subcmd == SCMD_BELLOW && !IS_IMMORTAL(ch))
     SET_BIT(CHAR_FLAGS(ch), CH_BELLOW);

   // funkit, just throw everything on the page...
   update_last_goss(ch, channel_names[subcmd][1], argu);

   switch(subcmd) {
     case SCMD_NEWBIE:
     case SCMD_OOC:
     case SCMD_QUESTION:
     case SCMD_ANSWER:
       real = FALSE;
       break;
 
     default:
       real = TRUE;
       break;
   }
     
   if (!real)
     strcpy(said, argu);
   else
     scramble(ch, argu, said, SPEAKING(ch));

   if (IS_PC(ch) && PRF_FLAGGED(ch, PRF_NOREPEAT))
      send_to_char("Ok.\n\r", ch);
   else 
   {
     if (!real)
      sprintf(buf1, "You %s, '%s'\n\r", channel_names[subcmd][0], said);
     else
      sprintf(buf1, "You %s in %s, '%s'\n\r", channel_names[subcmd][0], gskill_names[SPEAKING(ch)], said);
     send_to_char(buf1, ch);
   }

   strcpy(name, GET_NAME(ch));
   *name = UPPER(*name);
   if (!real)
   {
     sprintf(buf1, "%s %s, '%s'\n\r", name, channel_names[subcmd][1], said);
     sprintf(buf2, "Someone %s, '%s'\n\r", channel_names[subcmd][1], said);
   }

   // Added IDListMember() check for ignore. 03/17/98 - callahan
   for (i = descriptor_list; i; i = i->next) 
   {
      if (D_CHECK(i) && i != ch->desc &&
          (IS_NPC(i->character) || !PRF_FLAGGED(i->character, channel_prfs[subcmd])) && 
          !ROOM_FLAGGED2(i->character->in_room, SOUNDPROOF) && SEND_OK(i->character) &&
          !IdListMember(i->character->gagged, GET_IDNUM(ch)) && !INCHAT(i->character))
      {
	 if (subcmd == SCMD_YELL && 
	     ((world[ch->in_room].zone != world[i->character->in_room].zone) || 
	     GET_POS(i->character) < POS_RESTING))
	    continue;

         if (subcmd == SCMD_NEWBIE && !IS_IMMORTAL(i->character) && GET_LEVEL(i->character) > 10)
	    continue;

         // only immortals can see pray, UNLESS an immortal uses it, then everybody can
         if (subcmd == SCMD_PRAYER && !IS_IMMORTAL(i->character) && !IS_IMMORTAL(ch))
	    continue;

	 if (can_see(i->character, ch)) 
	 { 
	   if (real)
	   {
	     scramble(i->character, said, heard, SPEAKING(ch));
             sprintf(buf1, "%s %s in %s, '%s'\n\r", name, channel_names[subcmd][1], gskill_names[SPEAKING(ch)], heard);
 	   }
	   send_to_char(buf1, i->character);
	 } 
	 else 
	 { 
	   if (real)
	   {
             scramble(i->character, said, heard, SPEAKING(ch));
             sprintf(buf2, "Someone %s in %s, '%s'\n\r", channel_names[subcmd][1], gskill_names[SPEAKING(ch)], heard);
	   }
	   send_to_char(buf2, i->character);
	 }
      }
   }
}

ACMD(do_qsay)
{
   char *argu = argument;
   dsdata *i;

   do_gen_com(ch, argu, 0, SCMD_YELL);

////////////////////////////////////////
   if (IS_PC(ch) && !PRF_FLAGGED(ch, PRF_QUEST)) {
      send_to_char("You are not on the quest channel.\n\r", ch);
      return;
   }

   if (ROOM_FLAGGED2(ch->in_room, SOUNDPROOF))
   {
     send_to_char("This area seems to absorb your words.\n\r",ch);
     return;
   }

   skip_spaces(&argu);
   delete_doubledollar(argu);   // 03/18/98 -callahan

   if (!(*argu))
      send_to_char("What do you wish to qsay?\n\r", ch);
   else {
      if (IS_PC(ch) && PRF_FLAGGED(ch, PRF_NOREPEAT))
	 send_to_char("Ok.\n\r", ch);
      else {
	 sprintf(buf1, "You quest-say, '%s'\n\r", argu);
	 send_to_char(buf1, ch);
      }

      sprintf(buf1, "$n quest-says, '%s'", argu);
      for (i = descriptor_list; i; i = i->next)

         // Added IDListMember() for ignore. 03/17/98 -callahan
	 if (D_CHECK(i) && i != ch->desc &&
	     PRF_FLAGGED(i->character, PRF_QUEST) && 
	     !ROOM_FLAGGED2(i->character->in_room, SOUNDPROOF) &&
	     SEND_OK(i->character) &&
             !IdListMember(i->character->gagged, GET_IDNUM(ch)) && !INCHAT(i->character))
	    act(buf1, 0, ch, 0, i->character, TO_VICT);
   }
}