deltamud/deltamud/
deltamud/deltamud/bin/
deltamud/deltamud/cnf/
deltamud/deltamud/lib/
deltamud/deltamud/lib/etc/
deltamud/deltamud/lib/misc/
deltamud/deltamud/lib/plrobjs/
deltamud/deltamud/lib/text/
deltamud/deltamud/lib/text/help/
deltamud/deltamud/lib/world/
deltamud/deltamud/lib/world/trg/
/* ************************************************************************
   *   File: act.comm.c                                    Part of CircleMUD *
   *  Usage: Player-level communication commands                             *
   *                                                                         *
   *  All rights reserved.  See license.doc for complete information.        *
   *                                                                         *
   *  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 "screen.h"
#include "dg_scripts.h"
#include "clan.h"

/* extern variables */
extern struct room_data *world;
extern struct descriptor_data *descriptor_list;
extern struct char_data *character_list;
struct player_index_element *player_table;
extern int top_of_p_table;

/* extern functions */
char    *makedrunk(char *string ,struct char_data *ch);
char *get_name_by_id (long id);
long get_id_by_name (char *name);
int compare(char *string1, char *string2);

bool is_tell_ok (struct char_data *ch, struct char_data *vict);

ACMD(do_ignore) {
  struct ignore_index_element *i=NULL, *lasti=NULL;
  char *name, who[21]="\0";
  long types=0;
  int l=0, argnum=1, x=0;

  skip_spaces(&argument);

  if (!*argument) {
    send_to_char("\r\nName                 Type           Reason\r\n", ch);
    send_to_char("-------------------- -------------- ------>\r\n", ch);
    for (i=ch->ignore_list; i; i=i->next) {
      if ((name=get_name_by_id(i->id)) == NULL) {
        send_to_char("None                 None           None\r\n", ch);
        return;
      }
      sprintf(buf, "%-20s", name);
      if (IS_SET(i->type, IGNORE_PUBLIC))
        strcat(buf, " pub");
      else
        strcat(buf, "    ");
      if (IS_SET(i->type, IGNORE_PRIVATE))
        strcat(buf, " priv");
      else
        strcat(buf, "     ");
      if (IS_SET(i->type, IGNORE_EMOTE))
        strcat(buf, " emote ");
      else
        strcat(buf, "       ");
      strcat(buf, i->reason);
      strcat(buf, "\r\n");
      send_to_char(buf, ch);
    }
    if (!ch->ignore_list)
      send_to_char("None                 None           None\r\n", ch);
    return;
  }

// Who are we ignoring/unignoring?
  for (l=0; l<strlen(argument); l++) {
    if (argument[l]==' ') {
      argnum++;
      continue;
    }
    if (argnum!=1) break;
    if (strlen(who)>=20) continue; /* Don't fill up buffers */
    x=strlen(who);
    who[x]=argument[l];
    who[x+1]='\0';
  }

  if (get_id_by_name(who)==-1) {
    send_to_char("\r\nNo player with that name exists.\r\n", ch);
    return;
  }
  for (argnum=0; argnum<=top_of_p_table; argnum++) {
    if (player_table[argnum].id == get_id_by_name(who) && player_table[argnum].level >= LVL_IMMORT) {
      send_to_char("\r\nYou cannot ignore immortals.\r\n", ch);
      return;
    }
  }

  if (argument[l]!='\'') {
    send_to_char("\r\nYou must supply the ignore type(s) enclosed in ' symbols. Types: 'pub priv emote all off'\r\n", ch);
    return;
  }

  l++;

  buf[0]='\0';

// What type of ignore do we want?

  for (; l<strlen(argument); l++) {
    if (argument[l]==' ' || argument[l]=='\'') {
      if (compare(buf, "pub"))
        SET_BIT(types, IGNORE_PUBLIC);
      else if (compare(buf, "pub"))
        SET_BIT(types, IGNORE_PUBLIC);
      else if (compare(buf, "priv"))
        SET_BIT(types, IGNORE_PRIVATE);
      else if (compare(buf, "emote"))
        SET_BIT(types, IGNORE_EMOTE);
      else if (compare(buf, "all")) {
        SET_BIT(types, IGNORE_PUBLIC);
        SET_BIT(types, IGNORE_PRIVATE);
        SET_BIT(types, IGNORE_EMOTE);
      }
      else if (compare(buf, "off")) {
        for (i=ch->ignore_list; i; i=i->next) {
          if (compare(get_name_by_id(i->id), who)) {
            if (i->reason)
              free(i->reason);
            if (lasti)
              lasti->next=i->next;
            else
              ch->ignore_list=i->next;
            free(i);
            send_to_char("\r\nRemoved ", ch);
            send_to_char(who, ch);
            send_to_char(" from your ignore list.\r\n", ch);
            return;
          }
          lasti=i;
        }
        send_to_char("\r\n", ch);
        send_to_char(who, ch);
        send_to_char(" isn't on your ignore list.\r\n", ch);
        return;
      }
      else {
        send_to_char("\r\nUnknown ignore option: '", ch);
        send_to_char(buf, ch);
        send_to_char("'\r\n", ch);
        return;
      }
      buf[0]='\0';
      if (argument[l]=='\'') break;
      continue;
    }
    x=strlen(buf);
    buf[x]=argument[l];
    buf[x+1]='\0';
  }

// What is the ignore reason?

  if (argument[l]!='\'') {
    send_to_char("\r\nYou must supply the ignore type(s) enclosed in ' symbols. Types: 'pub priv emote all off'\r\n", ch);
    return;
  }

  l++;

  if (argument[l]==' ') l++;

  buf[0]='\0';

  if (!*(argument+l))
    strcpy(buf, "Ignore");
  else {
    for (; l<strlen(argument); l++) {
      x=strlen(buf);
      buf[x]=argument[l];
      buf[x+1]='\0';
    }
  }

  for (i=ch->ignore_list; i; i=i->next) {
    if (compare(get_name_by_id(i->id), who)) {
      if (i->reason)
        free(i->reason);
      if (lasti)
        lasti->next=i->next;
      else
        ch->ignore_list=i->next;
      free(i);
    }
    lasti=i;
  }

  // Delete ignore entry if it exists...

  if (!ch->ignore_list) {
    CREATE(ch->ignore_list, struct ignore_index_element, 1);
    i=ch->ignore_list;
  }
  else {
    CREATE(lasti->next, struct ignore_index_element, 1);
    i=lasti->next;
  }
  i->id=get_id_by_name(who);
  i->type=types;
  i->reason=strdup(buf);

  // Create a new ignore entry.

  sprintf(buf1, "\r\nIgnored %s on", who);
  if (IS_SET(i->type, IGNORE_PUBLIC))
    strcat(buf1, " pub");
  if (IS_SET(i->type, IGNORE_PRIVATE))
    strcat(buf1, " priv");
  if (IS_SET(i->type, IGNORE_EMOTE))
    strcat(buf1, " emote");
  sprintf(buf1+strlen(buf1), " (%s)\r\n", buf);
  send_to_char(buf1, ch);
}

int isignoresend (struct char_data *ch1, struct char_data *ch2, long type) { // Is ch2 on ch1's ignore? If so send them a 'your are on ignore' msg
  struct ignore_index_element *i;
  for (i=ch1->ignore_list; i; i=i->next) {
    if (i->id==get_id_by_name(GET_NAME(ch2)) && IS_SET(i->type, type)) {
      sprintf(buf, "\r\nYou are on %s's ignore list. (%s)\r\n", GET_NAME(ch1), i->reason);
      send_to_char(buf, ch2);
      return 1;
    }
  }
  return 0;
}

int isignore (struct char_data *ch1, struct char_data *ch2, long type) { // Is ch2 on ch1's ignore?
  struct ignore_index_element *i;
  for (i=ch1->ignore_list; i; i=i->next) {
    if (i->id==get_id_by_name(GET_NAME(ch2)) && IS_SET(i->type, type)) {
      return 1;
    }
  }
  return 0;
}

ACMD(do_say)
{
  struct char_data *vict;
  int state;
  char *dead_msgs[10] = {
    "You feel a slight breeze.",
    "Something beckons at your ear.",
    "You hear a faint whisper.",
    "The hair on your skin stands on end.",
    "The room suddenly gets cold.",
    "Something taps at the back of your mind.",
    "Your heartbeat slows a little.",
    "You notice something in the corner of your eye.",
    "The shadows around you shift a little.",
    "You feel a chill run down your spine."
  };

  skip_spaces(&argument);

  if (IS_NPC(ch) && MOB_FLAGGED (ch, MOB_NOTALK)) {
    send_to_char ("You weren't designed to talk.\r\n", ch);
    return;
  }
  else
    if (!*argument) {
      send_to_char("What do you want to say?\r\n", ch);
      return;
    }
  buf[0]='\0';

  sprintf(buf2, "You ");

  if (!*argument) {
    send_to_char("What do you wish to say?\r\n", ch);
    return;
  }
  argument = makedrunk(argument, ch);
// no auto-periods
//        if (argument[strlen(argument)-1] != '.' && argument[strlen(argument)-1] != '?' 
//           && argument[strlen(argument)-1] != '!')
//                 strcat(argument, '.');

  if(argument[strlen(argument)-1]=='?')
    state = 1;
  else if(argument[strlen(argument)-1]=='!')
    state = 2;
  else
    state = 0;

  switch(state) {
    case 1:
      sprintf(buf + strlen(buf), "asks, \'%s\'", argument);
      sprintf(buf2 + strlen(buf2), "ask, \'%s\'", argument);
      break;
    case 2:
      sprintf(buf + strlen(buf), "exclaims, \'%s\'", argument);
      sprintf(buf2 + strlen(buf2), "exclaim, \'%s\'", argument);
      break;
    case 3:
      sprintf(buf + strlen(buf), "bewilders, \'%s\'", argument);
      sprintf(buf2 + strlen(buf2), "bewilders, \'%s\'", argument);
      break;
    case 0:
      sprintf(buf + strlen(buf), "says, \'%s\'", argument);
      sprintf(buf2 + strlen(buf2), "say, \'%s\'", argument);
      break;
    default:
      break;
  }

  for (vict=world[ch->in_room].people; vict; vict=vict->next_in_room) {
    if (vict == ch) {
      if (PRF_FLAGGED(ch, PRF_NOREPEAT))
	send_to_char (OK, ch);
      else
        act(buf2, FALSE, ch, 0, 0, TO_CHAR);
      continue;
    }
    if (!isignore(vict, ch, IGNORE_PUBLIC)) {
      buf1[0]='\0';
      if (PRF2_FLAGGED(ch, PRF2_INTANGIBLE) && !PRF2_FLAGGED(vict, PRF2_INTANGIBLE) && !PRF2_FLAGGED(ch, PRF2_MBUILDING) && GET_LEVEL(vict)<LVL_IMMORT) {
        strcpy(buf1, dead_msgs[number(0, 9)]);
      } else {
        strcat(buf1, PERS(ch, vict));
        strcat(buf1, " ");
        strcat(buf1, buf);
      }
      act (buf1, FALSE, vict, 0, 0, TO_CHAR);
    }
  }
  speech_mtrigger(ch, argument);
  speech_wtrigger(ch, argument);
}


ACMD (do_gsay)
{
  struct char_data *k;
  struct follow_type *f;

  skip_spaces (&argument);

  if (!IS_AFFECTED (ch, AFF_GROUP))
    {
      send_to_char ("But you are not the member of a group!\r\n", ch);
      return;
    }
  if (!*argument)
    send_to_char ("Yes, but WHAT do you want to group-say?\r\n", ch);
  else
    {
      if (ch->master)
	k = ch->master;
      else
	k = ch;

      argument = makedrunk(argument, ch);
      sprintf (buf, "$n tells the group, '%s'", argument);

      if (IS_AFFECTED (k, AFF_GROUP) && (k != ch))
	act (buf, FALSE, ch, 0, k, TO_VICT | TO_SLEEP);
      for (f = k->followers; f; f = f->next)
	if (IS_AFFECTED (f->follower, AFF_GROUP) && (f->follower != ch) && !isignore(f->follower, ch, IGNORE_PRIVATE))
	  act (buf, FALSE, ch, 0, f->follower, TO_VICT | TO_SLEEP);

      if (PRF_FLAGGED (ch, PRF_NOREPEAT))
	send_to_char ("&YOkay.&n\r\n", ch);
      else
	{
	  sprintf (buf, "You tell the group, '%s'", argument);
	  act (buf, FALSE, ch, 0, 0, TO_CHAR | TO_SLEEP);
	}
    }
}


void
perform_tell (struct char_data *ch, struct char_data *vict, char *arg)
{
  send_to_char (CCRED (vict, C_NRM), vict);
  sprintf (buf, "$n tells you, '%s'", arg);
  arg = makedrunk(arg, ch);
  act (buf, FALSE, ch, 0, vict, TO_VICT | TO_SLEEP);
  send_to_char (CCNRM (vict, C_NRM), vict);

  if (PRF_FLAGGED (ch, PRF_NOREPEAT))
    send_to_char (OK, ch);
  else
    {
      send_to_char (CCRED (ch, C_CMP), ch);
      sprintf (buf, "You tell $N, '%s'", arg);
      act (buf, FALSE, ch, 0, vict, TO_CHAR | TO_SLEEP);
      send_to_char (CCNRM (ch, C_CMP), ch);
    }

  GET_LAST_TELL (vict) = GET_IDNUM (ch);
}

bool
is_tell_ok (struct char_data *ch, struct char_data *vict)
{
  if (ch == vict)
    send_to_char ("You try to tell yourself something.\r\n", ch);
  else if (PRF_FLAGGED (ch, PRF_NOTELL))
    send_to_char ("You can't tell other people while you have notell on.\r\n", ch);
  else if (ROOM_FLAGGED (ch->in_room, ROOM_SOUNDPROOF))
    send_to_char ("The walls seem to absorb your words.\r\n", ch);
  else if (!IS_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 (PRF_FLAGGED (vict, PRF_NOTELL) || ROOM_FLAGGED (vict->in_room, ROOM_SOUNDPROOF))
    act ("$E can't hear you.", FALSE, ch, 0, vict, TO_CHAR | TO_SLEEP);
  else if (isignoresend(vict, ch, IGNORE_PRIVATE))
    return 0;
  else if (PRF_FLAGGED (vict, PRF_AFK))
    {
      act ("$E has AFK on, and may not see your message.",
	   FALSE, ch, 0, vict, TO_CHAR | TO_SLEEP);
      return 1;			/* put this here so the tell still gets to vict */
    }
  else
    return 1;

  return 0;
}

/*
 * Yes, do_tell probably could be combined with whisper and ask, but
 * called frequently, and should IMHO be kept as tight as possible.
 */
ACMD (do_tell)
{
  struct char_data *vict;

  half_chop (argument, buf, buf2);

  if (!*buf || !*buf2)
    send_to_char ("Who do you wish to tell what??\r\n", ch);
  else if (!(vict = get_char_vis (ch, buf)))
    send_to_char (NOPERSON, ch);
  else if (is_tell_ok (ch, vict))
    perform_tell (ch, vict, buf2);
}


ACMD (do_reply)
{
  struct char_data *tch = character_list;

  skip_spaces (&argument);

  if (GET_LAST_TELL (ch) == NOBODY)
    send_to_char ("You have no-one to reply to!\r\n", ch);
  else if (!*argument)
    send_to_char ("What is your reply?\r\n", ch);
  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.
       */

      while (tch != NULL && GET_IDNUM (tch) != GET_LAST_TELL (ch))
	tch = tch->next;

      if (tch == NULL)
	send_to_char ("They are no longer playing.\r\n", ch);
      else if (is_tell_ok (ch, tch)) {
        argument = makedrunk(argument, ch);
	perform_tell (ch, tch, argument);
    }
    }
}


ACMD (do_spec_comm)
{
  struct char_data *vict;
  char *action_sing, *action_plur, *action_others;

  if (subcmd == SCMD_WHISPER)
    {
      action_sing = "whisper to";
      action_plur = "whispers to";
      action_others = "$n whispers something to $N.";
    }
  else
    {
      action_sing = "ask";
      action_plur = "asks";
      action_others = "$n asks $N a question.";
    }

  half_chop (argument, buf, buf2);

  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 (NOPERSON, ch);
  else if (vict == ch)
    send_to_char ("You can't get your mouth close enough to your ear...\r\n", ch);
  else if (isignoresend(vict, ch, IGNORE_PRIVATE)) return;
  else
    {
      argument = makedrunk(argument, ch);
      sprintf(buf, "$n %s you, '%s'", action_plur, buf2);
      act (buf, FALSE, ch, 0, vict, TO_VICT);
      if (PRF_FLAGGED (ch, PRF_NOREPEAT))
	send_to_char (OK, ch);
      else
	{
	  sprintf (buf, "You %s %s, '%s'\r\n", action_sing, GET_NAME (vict), buf2);
	  act (buf, FALSE, ch, 0, 0, TO_CHAR);
	}
      act (action_others, FALSE, ch, 0, vict, TO_NOTVICT);
    }
}



#define MAX_NOTE_LENGTH 1000	/* arbitrary */

ACMD (do_write)
{
  struct obj_data *paper = 0, *pen = 0;
  char *papername, *penname;

  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?!?\r\n", 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.\r\n", papername);
	  send_to_char (buf, ch);
	  return;
	}
      if (!(pen = get_obj_in_list_vis (ch, penname, ch->carrying)))
	{
	  sprintf (buf, "You have no %s.\r\n", penname);
	  send_to_char (buf, ch);
	  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.\r\n", papername);
	  send_to_char (buf, ch);
	  return;
	}
      if (GET_OBJ_TYPE (paper) == ITEM_PEN)
	{			/* oops, a pen.. */
	  pen = paper;
	  paper = 0;
	}
      else if (GET_OBJ_TYPE (paper) != ITEM_NOTE)
	{
	  send_to_char ("That thing has nothing to do with writing.\r\n", ch);
	  return;
	}
      /* One object was found.. now for the other one. */
      if (!GET_EQ (ch, WEAR_HOLD))
	{
	  sprintf (buf, "You can't write with %s %s alone.\r\n", AN (papername),
		   papername);
	  send_to_char (buf, ch);
	  return;
	}
      if (!CAN_SEE_OBJ (ch, GET_EQ (ch, WEAR_HOLD)))
	{
	  send_to_char ("The stuff in your hand is invisible!  Yeech!!\r\n", ch);
	  return;
	}
      if (pen)
	paper = GET_EQ (ch, WEAR_HOLD);
      else
	pen = GET_EQ (ch, WEAR_HOLD);
    }


  /* ok.. now let's see what kind of stuff we've found */
  if (GET_OBJ_TYPE (pen) != ITEM_PEN)
    act ("$p is no good for writing with.", FALSE, ch, pen, 0, TO_CHAR);
  else if (GET_OBJ_TYPE (paper) != ITEM_NOTE)
    act ("You can't write on $p.", FALSE, ch, paper, 0, TO_CHAR);
  else if (paper->action_description)
    send_to_char ("There's something written on it already.\r\n", ch);
  else
    {
      /* we can write - hooray! */
      /* this is the PERFECT code example of how to set up:
       * a) the text editor with a message already loaed
       * b) the abort buffer if the player aborts the message
       */
      ch->desc->backstr = NULL;
      send_to_char ("Write your note.  (/s saves /h for help)\r\n", ch);
      /* ok, here we check for a message ALREADY on the paper */
      if (paper->action_description)
	{
	  /* we str_dup the original text to the descriptors->backstr */
	  ch->desc->backstr = str_dup (paper->action_description);
	  /* send to the player what was on the paper (cause this is already */
	  /* loaded into the editor) */
	  send_to_char (paper->action_description, ch);
	}
      act ("$n begins to jot down a note.", TRUE, ch, 0, 0, TO_ROOM);
      /* assign the descriptor's->str the value of the pointer to the text */
      /* pointer so that we can reallocate as needed (hopefully that made */
      /* sense :>) */
      ch->desc->str = &paper->action_description;
      ch->desc->max_str = MAX_NOTE_LENGTH;
      ch->desc->note = paper;
      STATE(ch->desc)=CON_TEXTED;
    }
}



ACMD (do_page)
{
  struct descriptor_data *d;
  struct char_data *vict;

  half_chop (argument, arg, buf2);

  if (IS_NPC (ch))
    send_to_char ("Monsters can't page.. go away.\r\n", ch);
  else if (!*arg)
    send_to_char ("Whom do you wish to page?\r\n", ch);
  else
    {
      sprintf (buf, "\007\007*%s* %s\r\n", GET_NAME (ch), buf2);
      if (!str_cmp (arg, "all"))
	{
	  if (GET_LEVEL (ch) > LVL_GOD)
	    {
	      for (d = descriptor_list; d; d = d->next)
		if (!d->connected && d->character)
		  act (buf, FALSE, ch, 0, d->character, TO_VICT);
	    }
	  else
	    send_to_char ("You will never be godly enough to do that!\r\n", ch);
	  return;
	}
      if ((vict = get_char_vis (ch, arg)) != NULL)
	{
	  act (buf, FALSE, ch, 0, vict, TO_VICT);
	  if (PRF_FLAGGED (ch, PRF_NOREPEAT))
	    send_to_char (OK, ch);
	  else
	    act (buf, FALSE, ch, 0, vict, TO_CHAR);
	  return;
	}
      else
	send_to_char ("There is no such person in the game!\r\n", ch);
    }
}


/**********************************************************************
 * generalized communication func, originally by Fred C. Merkel (Torg) *
  *********************************************************************/

ACMD (do_gen_comm)
{
  extern int level_can_shout;
  extern int holler_move_cost;
  struct descriptor_data *i;
  char color_on[24];
  byte gmote = FALSE;

  /* Array of flags which must _not_ be set in order for comm to be heard */
  static int channels[] =
  {
    0,
    PRF_DEAF,
    PRF_NOGOSS,
    PRF_NOAUCT,
    PRF_NOGRATZ,
    0,
    PRF_NOARENA,
    0
  };

  /*
   * com_msgs: [0] Message if you can't perform the action because of noshout
   *           [1] name of the action
   *           [2] message if you're not on the channel
   *           [3] a color string.
   */
  static char *com_msgs[][4] =
  {
    {"You cannot holler!!\r\n",
     "holler",
     "",
     KYEL},

    {"You cannot shout!!\r\n",
     "shout",
     "Turn off your noshout flag first!\r\n",
     KYEL},

    {"You cannot gossip!!\r\n",
     "GOSSIP",
     "You aren't even on the channel!\r\n",
     KYEL},

    {"You cannot auction!!\r\n",
     "AUCTION",
     "You aren't even on the channel!\r\n",
     KMAG},

    {"You cannot congratulate!\r\n",
     "CONGRAT",
     "You aren't even on the channel!\r\n",
     KGRN},

    {"You cannot gemote!\r\n",
     "gemote",
     "You aren't even on the channel!\r\n",
     KGRN},

    {"You cannot arena?!\r\n",
     "ARENA",
     "You aren't even on the channel!\r\n",
     KYEL}
  };

  ACMD(do_gmote);

  /* to keep pets, etc from being ordered to shout */
  if (!ch->desc && cmd == 0)
    return;

if (IS_NPC(ch) && MOB_FLAGGED (ch, MOB_NOTALK)) {
      send_to_char ("You weren't designed to talk.\r\n", ch);
       return;
 }

  if (PLR_FLAGGED (ch, PLR_NOSHOUT))
    {
      send_to_char (com_msgs[subcmd][0], ch);
      return;
    }
  if (ROOM_FLAGGED (ch->in_room, ROOM_SOUNDPROOF))
    {
      send_to_char ("The walls seem to absorb your words.\r\n", ch);
      return;
    }
  /* level_can_shout defined in config.c */
  if (GET_LEVEL (ch) < level_can_shout)
    {
      sprintf (buf1, "You must be at least level %d before you can %s.\r\n",
	       level_can_shout, com_msgs[subcmd][1]);
      send_to_char (buf1, ch);
      return;
    }
  /* make sure the char is on the channel */
  if (PRF_FLAGGED (ch, channels[subcmd]))
    {
      send_to_char (com_msgs[subcmd][2], ch);
      return;
    }
  /* skip leading spaces */
  skip_spaces (&argument);

  if(subcmd == SCMD_GMOTE || (subcmd == SCMD_GOSSIP && *argument == '@'))
    {
      subcmd = SCMD_GOSSIP;
      gmote = TRUE;  
    }

  /* make sure that there is something there to say! */
  if (!*argument)
    {
      sprintf (buf1, "Yes, %s, fine, %s we must, but WHAT???\r\n",
	       com_msgs[subcmd][1], com_msgs[subcmd][1]);
      send_to_char (buf1, ch);
      return;
    }

  if (subcmd == SCMD_HOLLER)
    {
      if (GET_MOVE (ch) < holler_move_cost)
	{
	  send_to_char ("You're too exhausted to holler.\r\n", ch);
	  return;
	}
      else
	GET_MOVE (ch) -= holler_move_cost;
    }
  if (gmote) {
    if (*argument == '@')
      do_gmote(ch, argument + 1, 0, 1);
    else
      do_gmote(ch, argument, 0, 1);
    return;
  }
  /* Adding in drunk text here */
  argument = makedrunk(argument,ch);

  /* set up the color on code */
  strcpy (color_on, com_msgs[subcmd][3]);

  /* first, set up strings to be given to the communicator */
  if (PRF_FLAGGED (ch, PRF_NOREPEAT))
    send_to_char (OK, ch);
  else
    {
      if (subcmd == SCMD_SHOUT || subcmd == SCMD_HOLLER)
	{
	  if (COLOR_LEV (ch) >= C_CMP)
	    sprintf (buf1, "%sYou %s, '%s'%s", color_on, com_msgs[subcmd][1],
		     argument, KNRM);
	  else if (subcmd == SCMD_SHOUT || subcmd == SCMD_HOLLER)
	    sprintf (buf1, "You %s, '%s'", com_msgs[subcmd][1], argument);
	  act (buf1, FALSE, ch, 0, 0, TO_CHAR | TO_SLEEP);
	} else {
	  sprintf (buf1, "&c[&Y%s&c]&n $n: %s", com_msgs[subcmd][1], argument);
	  act (buf1, FALSE, ch, 0, 0, TO_CHAR | TO_SLEEP);
	}
    }
  if (subcmd == SCMD_SHOUT || subcmd == SCMD_HOLLER)
    sprintf (buf, "$n %ss, '%s'", com_msgs[subcmd][1], argument);
  else
    sprintf (buf, "&c[&Y%s&c]&n $n: %s", com_msgs[subcmd][1], argument);
  /* now send all the strings out */
  for (i = descriptor_list; i; i = i->next)
    {
      if (!i->connected && i != ch->desc && i->character &&
	  !PRF_FLAGGED (i->character, channels[subcmd]) &&
	  !PLR_FLAGGED (i->character, PLR_WRITING) &&
	  !ROOM_FLAGGED (i->character->in_room, ROOM_SOUNDPROOF) &&
          !isignore(i->character, ch, IGNORE_PUBLIC))
	{

	  if (subcmd == SCMD_SHOUT &&
	  ((world[ch->in_room].zone != world[i->character->in_room].zone) ||
	   GET_POS (i->character) < POS_RESTING))
	    continue;

	  if (COLOR_LEV (i->character) >= C_NRM)
	    send_to_char (color_on, i->character);
	  act (buf, FALSE, ch, 0, i->character, TO_VICT | TO_SLEEP);
	  if (COLOR_LEV (i->character) >= C_NRM)
	    send_to_char (KNRM, i->character);
	}
    }
}


ACMD (do_qcomm)
{
  struct descriptor_data *i;

  if (!PRF2_FLAGGED (ch, PRF2_QCHAN))
    {
      send_to_char ("You aren't even part of the quest channel!\r\n", ch);
      return;
    }
  skip_spaces (&argument);

  if (!*argument)
    {
      sprintf (buf, "%s?  Yes, fine, %s we must, but WHAT??\r\n", CMD_NAME,
	       CMD_NAME);
      CAP (buf);
      send_to_char (buf, ch);
    }
  else
    {
      argument = makedrunk(argument, ch);
      if (PRF_FLAGGED (ch, PRF_NOREPEAT))
	send_to_char (OK, ch);
      else
	{
	  if (subcmd == SCMD_QSAY)
	    sprintf (buf, "You quest-say, '%s'", argument);
	  else
	    strcpy (buf, argument);
	  act (buf, FALSE, ch, 0, argument, TO_CHAR);
	}

      if (subcmd == SCMD_QSAY)
	sprintf (buf, "$n quest-says, '%s'", argument);
      else
	strcpy (buf, argument);

      for (i = descriptor_list; i; i = i->next)
	if (!i->connected && i != ch->desc &&
	    PRF2_FLAGGED (i->character, PRF2_QCHAN) && !isignore(i->character, ch, IGNORE_PUBLIC))
	  act (buf, 0, ch, 0, i->character, TO_VICT | TO_SLEEP);
    }
}