/* speech.c */
#include "copyright.h"

/* Commands which involve speaking */
#include <ctype.h>
#include <string.h>

#include "config.h"
#include "externs.h"
#include "db.h"
#include "interface.h"
#include "match.h"

char *spname(thing)
    dbref thing;
{
  static char buff[BUFFER_LEN];
#ifdef FULL_INVIS
  if(!Dark(thing)) {
    strcpy(buff, db[thing].name);
  } else {
    if(Typeof(thing) != TYPE_PLAYER) {
      strcpy(buff, "Something");
    } else {
      strcpy(buff, "Someone");
    }
  }
#else
  strcpy(buff, db[thing].name);
#endif
  return (buff);
}

/* this function is a kludge for regenerating messages split by '=' */
const char *reconstruct_message(arg1, arg2)
    const char *arg1;
    const char *arg2;
{
  static char buf[BUFFER_LEN];
  if (arg2 && *arg2) {
    strcpy(buf, arg1);
    strcat(buf, " = ");
    strcat(buf, arg2);
    return buf;
  } else {
    return arg1;
  }
}

void do_say(player, arg1, arg2)
    dbref player;
    const char *arg1;
    const char *arg2;
{
  dbref loc;
  const char *message;
  char tbuf1[BUFFER_LEN];

  if ((loc = getloc(player)) == NOTHING)
    return;
  message = reconstruct_message(arg1, arg2);
  strcpy(tbuf1, pronoun_substitute(player, message, player));
  /* notify everybody */
  notify(player, tprintf("You say \"%s\"", tbuf1));
  notify_except(db[loc].contents, player,
		tprintf("%s says \"%s\"", spname(player), tbuf1));
}

void do_oemit(player, arg1, arg2)
    dbref player;
    const char *arg1;
    const char *arg2;
{
  dbref who;
  dbref loc;
  char tbuf1[BUFFER_LEN];
  void oemit_notify_except();

  init_match(player, arg1, TYPE_PLAYER);
  if ((loc = getloc(player)) == NOTHING)
    return;
  match_neighbor();
  match_me();
  switch (who = match_result()) {
    case NOTHING:
    case AMBIGUOUS:
      who = player;
    default:
      strcpy(tbuf1, pronoun_substitute(player, arg2, player));
      notify(player, tprintf("%s", tbuf1));
      oemit_notify_except(db[loc].contents, player, who, tbuf1);
  }
}

void do_whisper(player, arg1, arg2)
    dbref player;
    const char *arg1;
    const char *arg2;
{
  dbref who;
  int key;
  const char *gap;
  init_match(player, arg1, TYPE_PLAYER);
  match_neighbor();
  match_possession();
  match_container();
  match_me();
  if (Wizard(player)) {
    match_absolute();
    match_player();
  }
  switch (who = match_result()) {
    case NOTHING:
      notify(player, "Whisper to whom?");
      break;
    case AMBIGUOUS:
      notify(player, "I don't know who you mean!");
      break;
    default:
      gap = " ";
      switch (*arg2) {
      case SEMI_POSE_TOKEN:
	gap = "";
      case POSE_TOKEN:
	key = 1;
	arg2 = arg2 + 1;
	break;
      default:
	key = 2;
	break;
      }
      switch (key) {
      case 1:
	notify(player, tprintf("%s senses, \"%s%s%s\"", db[who].name,
	  db[player].name, gap, arg2));
	notify(who, tprintf("You sense: %s%s%s", db[player].name, gap, arg2));
	break;
      case 2:
        notify(player,
	     tprintf("You whisper, \"%s\" to %s.", arg2, db[who].name));
        notify(who,
	     tprintf("%s whispers, \"%s\"", db[player].name, arg2));
        break;
      }
      break;
  }
}

void do_pemit(player, arg1, arg2)
  dbref player;
  const char *arg1;
  const char *arg2;
{
  dbref who;
  char tbuf1[BUFFER_LEN];

  init_match(player, arg1, NOTYPE);
  match_neighbor();
  match_possession();
  match_container();
  match_me();
  match_here();
  match_player();
  match_absolute();
  switch (who = match_result()) {
  case NOTHING:
    notify(player, "I don't see that player here.");
    break;
  case AMBIGUOUS:
    notify(player, "I don't know who you mean!");
    break;
  default:
    if (Typeof(who) != TYPE_PLAYER && Typeof(who) != TYPE_THING) {
      notify(player, "Only players and things can hear @pemits.");
      break;
    }
    if (Haven(who) && (player != who)) {
        notify(player,tprintf("I'm sorry, but %s wishes to be left alone now.",
			      db[who].name));
        return;
    }
    strcpy(tbuf1, pronoun_substitute(player, arg2, player));
    notify(player,
      tprintf("You pemit \"%s\" to %s.", tbuf1, db[who].name));
    if (Nospoof(who)) {
      notify(who,
        tprintf("[%s->%s] %s", db[player].name, db[who].name, tbuf1));
    } else {
      notify(who,
        tprintf("%s", tbuf1));
    }
    break;
  }
}

void do_pose(player, arg1, arg2, space)
    dbref player;
    const char *arg1, *arg2;
    int space;
{
  dbref loc;
  const char *message;
  char tbuf1[BUFFER_LEN];

  if ((loc = getloc(player)) == NOTHING)
    return;

  message = reconstruct_message(arg1, arg2);
  strcpy(tbuf1, pronoun_substitute(player, message, player));
  /* notify everybody */
  if(!space)
    notify_except(db[loc].contents, NOTHING,
		  tprintf("%s %s", spname(player), tbuf1));
  else
    notify_except(db[loc].contents, NOTHING,
		  tprintf("%s%s", spname(player), tbuf1));
}

void do_wall(player, arg1, arg2, key)
    dbref player;
    const char *arg1;
    const char *arg2;
    int key;
{
  const char *gap;
  const char *message;
  if (!Wizard(player)) {
    notify(player, "Having delusions of grandeur today, are we?");
    return;
  }
  message = reconstruct_message(arg1, arg2);
  gap = " ";
  switch (*arg1) {
  case SAY_TOKEN:
    key = 1;
    message = message + 1;
    break;
  case SEMI_POSE_TOKEN:
    gap = "";
  case POSE_TOKEN:
    key = 2;
    message = message + 1;
    break;
  }
  switch (key) {
  case 2:
    fprintf(stderr, "WALL from %d: %s%s%s\n", player, db[player].name,
	    gap, message);
    raw_broadcast(0, "Announcement: %s%s%s", db[player].name, gap, message);
    break;
  case 3:
    fprintf(stderr, "WALL from %s(%d): %s\n", db[player].name, player,
	    message);
    raw_broadcast(0, "Announcement [%s]: %s", db[player].name, message);
    break;
  default:
    fprintf(stderr, "WALL from %s(%d): %s\n", db[player].name, player,
	    message);
    raw_broadcast(0, "Announcement: %s shouts, \"%s\"", db[player].name,
		  message);
    break;
  }
}

void do_wizwall(player, arg1, arg2, privs, key)
    dbref player;
    const char *arg1;
    const char *arg2;
    int privs;
    int key;
{
  /* privs is 0 for wizard wizwall, 1 for royalty-wizard wizwall */
  const char *gap;
  const char *message;

  if (!Wizard(player)
#ifdef ROYALTY_FLAG
&& !Royalty(player)
#endif
      ) {
    notify(player, "What makes you think someone wants to listen to you?");
    return;
  }

  if (!privs && !Wizard(player)) {
    notify(player, "Posing as a wizard could be hazardous to your health.");
    return;
  }

  message = reconstruct_message(arg1, arg2);
  gap = " ";
  switch(*arg1) {
    case SAY_TOKEN:
      key = 1;
      message = message + 1;
      break;
    case SEMI_POSE_TOKEN:
      gap = "";
    case POSE_TOKEN:
      key = 2;
      message = message + 1;
      break;
  }

  if (!privs) {
    switch(key) {
    case 2:
      raw_broadcast(WIZARD, "Broadcast: %s%s%s", db[player].name, gap,
		    message);
      break;
    case 3:
      raw_broadcast(WIZARD, "Broadcast [%s]: %s", db[player].name, message);
      break;
    default:
      raw_broadcast(WIZARD, "Broadcast: %s says, \"%s\"", db[player].name,
		    message);
    }
  }
#ifdef ROYALTY_FLAG
  else {
    switch (key) {
    case 2:
      raw_broadcast(WIZARD, "Admin: %s%s%s", db[player].name, gap, message);
      raw_broadcast(ROYALTY, "Admin: %s%s%s", db[player].name, gap, message);
      break;
    case 3:
      raw_broadcast(WIZARD, "Admin [%s]: %s", db[player].name, message);
      raw_broadcast(ROYALTY, "Admin [%s]: %s", db[player].name, message);
      break;
    default:
      raw_broadcast(WIZARD, "Admin: %s says, \"%s\"", db[player].name,
		    message);
      raw_broadcast(ROYALTY, "Admin: %s says, \"%s\"", db[player].name,
		    message); 
    }
  }
#endif
}

void do_gripe(player, arg1, arg2)
    dbref player;
    const char *arg1;
    const char *arg2;
{
  dbref loc;
  const char *message;
  loc = db[player].location;
  message = reconstruct_message(arg1, arg2);
  fprintf(stderr, "GRIPE from %s(%d) in %s(%d): %s\n",
	  db[player].name, player,
	  db[loc].name, loc,
	  message);
  fflush(stderr);

  /* try telling GOD about it */
  if (!Haven(GOD)) { 
    notify(GOD,
	   tprintf("%s gripes: \"%s\"",
		   unparse_object(GOD, player), message));
  }

  notify(player, "Your complaint has been duly noted.");
}

/* doesn't really belong here, but I couldn't figure out where else */

void do_page(player, arg1, arg2)
    dbref player;
    const char *arg1;
    const char *arg2;
{
  dbref target;
  const char *message, *gap;
  char *spoof;
  int key;
  if ((!*arg1) && (!*arg2)) {
    if (db[player].pageto == NOTHING) {
      notify(player, "You haven't paged anyone since connecting.");
    } else {
      notify(player,
             tprintf("You last paged %s.", db[db[player].pageto].name));
    }
    return;
  }
  if (Haven(player))
	  notify(player, "You are set HAVEN and cannot receive pages.");
  
  if (index(arg1, ' ') != NULL) {
    message = reconstruct_message(arg1, arg2);
    target = db[player].pageto;
  } else {
    message = arg2;
    if (!*arg1) {
      target = db[player].pageto;
    } else if ((target = lookup_player(arg1)) == NOTHING) {
      if (!*arg2) {
        target = db[player].pageto;
        message = arg1;
      } else {
        target = short_page(arg1);
      }
    }
  }
  if (target == NOTHING) {
    notify(player, "I can't find who you're trying to page.");
    return;
  } else if (target == AMBIGUOUS) {
    notify(player, "I'm not sure who you want to page!");
    return;
  } else if ((!(db[target].flags & PLAYER_CONNECT)) ||
             (Dark(target) && Haven(target))) {
    page_return(player, target, "Away", "AWAY",
      "That player is not connected.");
    return;
  } else if (Haven(target)) {
    page_return(player, target, "Haven", "HAVEN",
      "That player is not accepting any pages.");
    return;
  } else if (!eval_boolexp(db[player].owner, db[target].usekey, 
			   target, 0, USELOCK)) {
    page_return(player, target, "Haven", "HAVEN",
      "That player is not accepting your pages.");
    return;
  } if (!payfor(player, PAGE_COST)) {
    notify(player, tprintf("You don't have enough %s.", MONIES));
    return;
  }
  db[player].pageto = target;
  gap = " ";
  switch (*message) {
    case SEMI_POSE_TOKEN:
      gap = "";
    case POSE_TOKEN:
      key = 1;
      message = message + 1;
      break;
    case NULL:
      key = 2;
      break;
    default:
      key = 3;
      break;
  }

  if (Typeof(player) != TYPE_PLAYER && Nospoof(target))
    strcpy(spoof, tprintf("[#%d] ", player));
  else
    strcpy(spoof, "");

  switch (key) {
    case 1:
      notify(target, tprintf("%sFrom afar, %s%s%s", spoof,
			     db[player].name, gap, message));
      notify(player, tprintf("Long distance to %s: %s%s%s", db[target].name,
            db[player].name, gap, message));
      break;
    case 2:
      notify(target, tprintf("%sYou sense that %s is looking for you in %s",
	    spoof, db[player].name, db[db[player].location].name));
      notify(player, tprintf("You have paged %s.", db[target].name));
      break;
    case 3:
      notify(target, tprintf("%s%s pages: %s", spoof, db[player].name, 
			     message));
      notify(player, tprintf("You paged %s with '%s'.", db[target].name,
            message));
      break;
  }
  page_return(player, target, "Idle", "IDLE", NULL);
  return;
}

void esnotify(player, msg, sender)
    dbref player;
    const char *msg;
    dbref sender;
{
  if (player < 0 || player >= db_top) return;

  if (Nospoof(player)) {
    notify(player, tprintf("[%s:] %s", spname(sender), msg));
  } else {
    notify(player, tprintf("%s", msg));
  }
}
 
void notify_except(first, exception, msg)
    dbref first;
    dbref exception;
    const char *msg;
{
  if(first < 0 || first >= db_top)
    return;
  if (db[first].location != exception)
    notify(db[first].location, msg);
  DOLIST(first, first) {
    if (first != exception) {
      notify(first, msg);
    }
  }
}

void emit_notify_except(first, exception, msg)
    dbref first;
    dbref exception;
    const char *msg;
{
  if(first < 0 || first >= db_top)
    return;
  if (db[first].location != exception)
    esnotify(db[first].location, msg, exception);
  DOLIST(first, first) {
    if (first != exception) {
      esnotify(first, msg, exception);
    }
  }
}

void notify_except2(first, exc1, exc2, msg)
    dbref first;
    dbref exc1;
    dbref exc2;
    const char *msg;
{
  if(first < 0 || first >= db_top)
    return;
  if ((db[first].location != exc1) && (db[first].location != exc2))
    notify(db[first].location, msg);
  DOLIST(first, first) {
    if (first != exc1 && first != exc2) {
      notify(first, msg);
    }
  }
}

void oemit_notify_except(first, exc1, exc2, msg)
    dbref first;
    dbref exc1;
    dbref exc2;
    const char *msg;
{
  if(first < 0 || first >= db_top)
    return;
  if ((db[first].location != exc1) && (db[first].location != exc2))
    esnotify(db[first].location, msg, exc1);
  DOLIST(first, first) {
    if (first != exc1 && first != exc2) {
      esnotify(first, msg, exc1);
    }
  }
}

void do_emit(player, arg1, arg2)
    dbref player;
    const char *arg1;
    const char *arg2;
{
  dbref loc;
  const char *message;
  char tbuf1[BUFFER_LEN];

  if ((loc = getloc(player)) == NOTHING)
    return;
  message = reconstruct_message(arg1, arg2);
  strcpy(tbuf1, pronoun_substitute(player, message, player));
  /* notify everybody */
  notify(player, tprintf("%s", tbuf1));
  emit_notify_except(db[loc].contents, player, tbuf1);
}

void do_remit(player, arg1, arg2)
    dbref player;
    const char *arg1;
    const char *arg2;
{
  dbref room;
  const char *rmno;
  char tbuf1[BUFFER_LEN];

  init_match(player, arg1, NOTYPE);
  match_here();
  match_absolute();
  match_neighbor();
  match_me();
  match_player();
  match_exit();

  switch (room = match_result()) {
    case NOTHING:
    case AMBIGUOUS:
      notify(player, "I can't find that.");
      break;
    default:
      if (Typeof(room) == TYPE_EXIT) {
	notify(player, "There can't be anything in that!");
	break;
      }
      if((Typeof(room) == TYPE_PLAYER) && Haven(room)) {
	notify(player, "That person is havened.  No @remitting allowed.");
	break;
      }
      strcpy(tbuf1, pronoun_substitute(player, arg2, player));
      rmno = unparse_object(player, room);
      notify(player,
        tprintf("You remit, \"%s\" in %s", tbuf1, rmno));
      oemit_notify_except(db[room].contents, player, room, tbuf1);
  }
}

void do_lemit(player, arg1, arg2)
  dbref player;
  const char *arg1;
  const char *arg2;
{
  dbref room;
  int rec = 0;
  const char *message;
  char tbuf1[BUFFER_LEN];
  message = reconstruct_message(arg1, arg2);
  strcpy(tbuf1, pronoun_substitute(player, message, player));

  /* only players and things may use this command */
  if (Typeof(player) != TYPE_PLAYER && Typeof(player) != TYPE_THING)
    return;

  /* prevent infinite loop if player is inside himself */
  if ((room = db[player].location) == player) {
    notify(player, "Invalid container object.");
    return;
  }
  while ((Typeof(room) != TYPE_ROOM) && (rec < 15)) {
    room = db[room].location;
    rec++;
  }
  if (rec > 15) {
    notify(player, "Too many containers.");
    return;
  } else {
    notify(player, tprintf("You lemit: \"%s\"", tbuf1));
    oemit_notify_except(db[room].contents, player, room, tbuf1);
  }
}

void do_zemit(player, arg1, arg2)
     dbref player;
     const char *arg1;
     const char *arg2;
{
  const char *where;
  dbref zone;
  dbref room;
  char tbuf1[BUFFER_LEN];

  init_match(player, arg1, NOTYPE);
  match_absolute();

  switch (zone = match_result()) {
  case NOTHING:
  case AMBIGUOUS:
    notify(player, "Invalid zone.");
    return;
  default:
    if (!controls(player, zone)) {
      notify(player, "Permission denied.");
      return;
    }
    if (!payfor(player, FIND_COST)) {
      notify(player, "Sorry, you don't have enough money to do that.");
      return;
    }
    strcpy(tbuf1, pronoun_substitute(player, arg2, player));
    where = unparse_object(player, zone);
    notify(player,
	   tprintf("You zemit, \"%s\" in zone %s", tbuf1, where));
    for (room = 0; room < db_top; room++)
      if ((getzone(room) == zone) && (Typeof(room) == TYPE_ROOM))
	oemit_notify_except(db[room].contents, player, room, tbuf1);
  }
}