AlloyMUSH-1.1/conf/
AlloyMUSH-1.1/misc/
AlloyMUSH-1.1/scripts/
AlloyMUSH-1.1/vms/
/* speech.c -- Commands which involve speaking */

#ifndef	lint
static char RCSid[] = "$Id: speech.c,v 1.5 1994/10/24 15:01:48 xmen Exp $";

#endif

#include "copyright.h"
#include "autoconf.h"

#include "interface.h"
#include "match.h"
#include "flags.h"
#include "attrs.h"
#include "ansi.h"
#include "powers.h"

/* AlloyAddition: Yes, it's pointless, but SB wouldn't shut up about it! */

void
do_think(player, cause, key, message)
    dbref player, cause;
    int key;
    char *message;
{
    notify(player, message);
}

int 
sp_ok(player)
    dbref player;
{
    if (!mudconf.robot_speak) {
	if (Robot(player) && !controls(player, Location(player))) {
	    notify(player, "Sorry, robots may not speak in public.");
	    return 0;
	}
    }
    if (!could_doit(player, Location(player), A_LSPEAK)) {
    	notify(player,
    	 "What makes you think that anyone here wants to hear you?");
    	return 0;
    }
    return 1;
}

static void 
say_shout(target, prefix, flags, player, message)
    int target, flags;
    dbref player;
    char *message;
    const char *prefix;
{
    if (flags & SAY_NOTAG)
	raw_broadcast(target, "%s%s", Name(player), message);
    else
	raw_broadcast(target, "%s%s%s", prefix, Name(player), message);
}

static const char *announce_msg = "Announcement: ";
static const char *broadcast_msg = "Broadcast: ";

void 
do_say(player, cause, key, message)
    dbref player, cause;
    int key;
    char *message;
{
    dbref loc;
    char *buf2, *bp, *s, *sp;
    int say_flags, depth, tmp;

    tmp = ((key & SAY_URGENT) == 0) ? NOWALL : 0;
    
    /* Convert prefix-coded messages into the normal type */

    say_flags = key & (SAY_NOTAG | SAY_HERE | SAY_ROOM | SAY_URGENT);
    key &= ~(SAY_NOTAG | SAY_HERE | SAY_ROOM | SAY_URGENT);

    if (key == SAY_PREFIX) {
	switch (*message++) {
	case '"':
	    key = SAY_SAY;
	    break;
	case ':':
	    if (*message == ' ') {
		message++;
		key = SAY_POSE_NOSPC;
	    } else {
		key = SAY_POSE;
	    }
	    break;
	case ';':
	    key = SAY_POSE_NOSPC;
	    break;
	case '\\':
	    key = SAY_EMIT;
	    break;
	default:
	    return;
	}
    }
    /* Make sure speaker is somewhere if speaking in a place */

    loc = where_is(player);
    switch (key) {
    case SAY_SAY:
    case SAY_POSE:
    case SAY_POSE_NOSPC:
    case SAY_EMIT:
	if (loc == NOTHING)
	    return;
	if (!sp_ok(player))
	    return;
	break;
    }
    
    switch (key) {
    case SAY_SHOUT:
    case SAY_WIZSHOUT:
    case SAY_WALLPOSE:
    case SAY_WIZPOSE:
    case SAY_WALLEMIT:
    case SAY_WIZEMIT:
        if (!Wizard(player) && !Has_power(player, POW_ANNOUNCE)) {
            notify(player, "Permission denied.");
            return;
        }
    }

    sp = s = alloc_mbuf("do_say.s");
    if (!Dark(player)) safe_mb_str(Name(player), s, &sp);
    else safe_mb_str("A disembodied voice", s, &sp);
    
    /* Send the message on its way  */

    switch (key) {
    case SAY_SAY:
	notify(player, tprintf("You say \"%s\"", message));
	notify_except(loc, player, player,
		      tprintf("%s says \"%s\"", s, message));
	break;
    case SAY_POSE:
	notify_all_from_inside(loc, player,
			       tprintf("%s %s", s, message));
	break;
    case SAY_POSE_NOSPC:
	notify_all_from_inside(loc, player,
			       tprintf("%s%s", s, message));
	break;
    case SAY_EMIT:
	if ((say_flags & SAY_HERE) || !say_flags)
	    notify_all_from_inside(loc, player, message);
	if (say_flags & SAY_ROOM) {
	    if (isRoom(loc) && (say_flags & SAY_HERE)) {
		return;
	    }
	    depth = 0;
	    while (!isRoom(loc) && (depth++ < 20)) {
		loc = Location(loc);
		if ((loc == NOTHING) || (loc == Location(loc)))
		    return;
	    }
	    if (isRoom(loc)) {
		notify_all_from_inside(loc, player, message);
	    }
	}
	break;
    case SAY_SHOUT:
	switch (*message) {
	case ':':
	    message[0] = ' ';
	    say_shout(tmp, announce_msg, say_flags, player, message);
	    break;
	case ';':
	    message++;
	    say_shout(tmp, announce_msg, say_flags, player, message);
	    break;
	case '"':
	    message++;
	default:
	    buf2 = alloc_lbuf("do_say.shout");
	    bp = buf2;
	    safe_str((char *) " announces \"", buf2, &bp);
	    safe_str(message, buf2, &bp);
	    safe_chr('"', buf2, &bp);
	    say_shout(tmp, announce_msg, say_flags, player, buf2);
	    free_lbuf(buf2);
	}
	STARTLOG(LOG_SHOUTS, "WIZ", "SHOUT")
	    log_name(player);
	buf2 = alloc_lbuf("do_say.LOG.shout");
	sprintf(buf2, " announces: '%s'", message);
	log_text(buf2);
	free_lbuf(buf2);
	ENDLOG
	    break;
    case SAY_WIZSHOUT:
	switch (*message) {
	case ':':
	    message[0] = ' ';
	    say_shout(tmp | WIZARD, broadcast_msg, say_flags, player,
		      message);
	    break;
	case ';':
	    message++;
	    say_shout(tmp | WIZARD, broadcast_msg, say_flags, player,
		      message);
	    break;
	case '"':
	    message++;
	default:
	    buf2 = alloc_lbuf("do_say.wizshout");
	    bp = buf2;
	    safe_str((char *) " says \"", buf2, &bp);
	    safe_str(message, buf2, &bp);
	    safe_chr('"', buf2, &bp);
	    say_shout(tmp | WIZARD, broadcast_msg, say_flags, player,
		      buf2);
	    free_lbuf(buf2);
	}
	STARTLOG(LOG_SHOUTS, "WIZ", "BCAST")
	    log_name(player);
	buf2 = alloc_lbuf("do_say.LOG.wizshout");
	sprintf(buf2, " broadcasts: '%s'", message);
	log_text(buf2);
	free_lbuf(buf2);
	ENDLOG
	    break;
    case SAY_WALLPOSE:
	if (say_flags & SAY_NOTAG)
	    raw_broadcast(tmp, "%s %s", Name(player), message);
	else
	    raw_broadcast(tmp, "Announcement: %s %s", Name(player),
			  message);
	STARTLOG(LOG_SHOUTS, "WIZ", "SHOUT")
	    log_name(player);
	buf2 = alloc_lbuf("do_say.LOG.wallpose");
	sprintf(buf2, " WALLposes: '%s'", message);
	log_text(buf2);
	free_lbuf(buf2);
	ENDLOG
	    break;
    case SAY_WIZPOSE:
	if (say_flags & SAY_NOTAG)
	    raw_broadcast(tmp | WIZARD, "%s %s", Name(player), message);
	else
	    raw_broadcast(tmp | WIZARD, "Broadcast: %s %s", Name(player),
			  message);
	STARTLOG(LOG_SHOUTS, "WIZ", "BCAST")
	    log_name(player);
	buf2 = alloc_lbuf("do_say.LOG.wizpose");
	sprintf(buf2, " WIZposes: '%s'", message);
	log_text(buf2);
	free_lbuf(buf2);
	ENDLOG
	    break;
    case SAY_WALLEMIT:
	if (say_flags & SAY_NOTAG)
	    raw_broadcast(tmp, "%s", message);
	else
	    raw_broadcast(tmp, "Announcement: %s", message);
	STARTLOG(LOG_SHOUTS, "WIZ", "SHOUT")
	    log_name(player);
	buf2 = alloc_lbuf("do_say.LOG.wallemit");
	sprintf(buf2, " WALLemits: '%s'", message);
	log_text(buf2);
	free_lbuf(buf2);
	ENDLOG
	    break;
    case SAY_WIZEMIT:
	if (say_flags & SAY_NOTAG)
	    raw_broadcast(tmp | WIZARD, "%s", message);
	else
	    raw_broadcast(tmp | WIZARD, "Broadcast: %s", message);
	STARTLOG(LOG_SHOUTS, "WIZ", "BCAST")
	    log_name(player);
	buf2 = alloc_lbuf("do_say.LOG.wizemit");
	sprintf(buf2, " WIZemit: '%s'", message);
	log_text(buf2);
	free_lbuf(buf2);
	ENDLOG
	    break;
    }
    free_mbuf(s);
}

/* ---------------------------------------------------------------------------
 * do_page: Handle the page command.
 * Page-pose code from shadow@prelude.cc.purdue.
 */

static void 
page_pose(player, target, message)
    dbref player, target;
    char *message;
{
    char *nbuf;

    nbuf = alloc_lbuf("page_pose");
    strcpy(nbuf, Name(player));

    if (Ansi(target))
    	notify_with_cause(target, player,
	    tprintf("%sFrom afar, %s%s%s", ANSI_HILITE, Name(player), message,
	    ANSI_NORMAL));
    else
    	notify_with_cause(target, player,
		      tprintf("From afar, %s%s", Name(player), message));
    notify(player,
	   tprintf("Long distance to %s: %s%s",
		   Name(target), nbuf, message));
    free_lbuf(nbuf);
}

static void 
page_return(player, target, tag, anum, dflt)
    dbref player, target;
    int anum;
    const char *tag, *dflt;
{
    dbref aowner;
    int aflags;
    char *str, *str2;
    struct tm *tp;
    time_t t;

    str = atr_pget(target, anum, &aowner, &aflags);
    if (*str) {
	str2 = exec(target, player, EV_FCHECK | EV_EVAL | EV_TOP, str,
		    (char **) NULL, 0);
	t = time(NULL);
	tp = localtime(&t);
	notify_with_cause(player, target,
			  tprintf("%s message from %s: %s",
				  tag, Name(target), str2));
	notify_with_cause(target, player,
			  tprintf("[%d:%02d] %s message sent to %s.",
			       tp->tm_hour, tp->tm_min, tag, Name(player)));
	free_lbuf(str2);
    } else if (dflt && *dflt) {
	notify_with_cause(player, target, dflt);
    }
    free_lbuf(str);
}

static int 
page_check(player, target)
    dbref player, target;
{
    if (!payfor(player, Guest(player) ? 0 : mudconf.pagecost)) {
	notify(player,
	       tprintf("You don't have enough %s.",
		       mudconf.many_coins));
    } else if (!Connected(target)) {
	page_return(player, target, "Away", A_AWAY,
		    "Sorry, that player is not connected.");
    } else if (!could_doit(player, target, A_LPAGE)) {
	if (Wizard(target) && Dark(target))
	    page_return(player, target, "Away", A_AWAY,
			"Sorry, that player is not connected.");
	else
	    page_return(player, target, "Reject", A_REJECT,
			"Sorry, that player is not accepting pages.");
    } else if (!could_doit(target, player, A_LPAGE)) {
	if (Wizard(player)) {
	    notify(player,
		   "Warning: that player can't return your page.");
	    return 1;
	} else {
	    notify(player,
		   "Sorry, that player can't return your page.");
	    return 0;
	}
    } else {
	return 1;
    }
    return 0;
}

static int silent_page_check(player, target)
     dbref player, target;
{
    if (!payfor(player, Guest(player) ? 0 : mudconf.pagecost) ||
	!Connected(target) ||
	!could_doit(player, target, A_LPAGE))
	return 0;
    else
	return 1;
}


void 
do_page(player, cause, key, tname, message)
    dbref player, cause;
    int key;
    char *tname, *message;
{
    dbref target;
    char *nbuf, *temp;

    if (!tname || !*tname)
    {
    	temp = atr_get_raw(player, A_PAGEDTO);
    	
    	if (!temp || !*temp) target = NOTHING;
    	else target = lookup_player(player, temp, 1);
    	
    	if (target == NOTHING) {
    		notify(player, "You haven't paged anybody.");
    		return;
    	}
    	if (!*message) {
    		notify(player, tprintf(
    		"You last paged %s.", Name(target)));
    		return;
    	}
    }
    else
    	target = lookup_player(player, tname, 1);
    if (target == NOTHING) {
	notify(player, "I don't recognize that name.");
    } else if (!page_check(player, target)) {
	;
    } else if (!*message) {
	nbuf = alloc_lbuf("do_page");
	strcpy(nbuf, Name(where_is(player)));
	if (Ansi(target))
		notify_with_cause(target, player,
	tprintf("%sYou sense that %s is looking for you in %s%s",
			       ANSI_HILITE, Name(player), nbuf, ANSI_NORMAL));
	else
		notify_with_cause(target, player,	
			tprintf("You sense that %s is looking for you in %s",
			Name(player), nbuf));
	notify(player,
	       tprintf("You notified %s of your location.",
		       Name(target)));
	free_lbuf(nbuf);
	page_return(player, target, "Idle", A_IDLE, NULL);
    } else {
	switch (*message) {
	case ':':
	    message[0] = ' ';
	    page_pose(player, target, message);
	    break;
	case ';':
	    message++;
	    page_pose(player, target, message);
	    break;
	case '"':
	    message++;
	default:
	    if (Ansi(target))
	    	notify_with_cause(target, player,
tprintf("%s%s pages: %s%s", ANSI_HILITE, Name(player), message, ANSI_NORMAL));
	    else
	    	notify_with_cause(target, player,
			    tprintf("%s pages: %s", Name(player), message));
	    notify(player,
		   tprintf("You paged %s with '%s'.",
			   Name(target), message));
	}
	atr_add_raw(player, A_PAGEDTO, Name(target));
	atr_add_raw(target, A_PAGEDBY, Name(player));
	page_return(player, target, "Idle", A_IDLE, NULL);
    }
}

/* do_reply: reply to a page
 * by Alloy [3-25-95]
 */

void 
do_reply(player, cause, key, message)
    dbref player, cause;
    int key;
    char *message;
{
    dbref target;
    char *nbuf, *temp;

    temp = atr_get_raw(player, A_PAGEDBY);

    if (!temp || !*temp) target = NOTHING;
    else target = lookup_player(player, temp, 1);
    
    if (target == NOTHING) {
    	notify(player, "Nobody has paged you.  You're unpopular.");
    	return;
    }
    if (!*message) {
        notify(player, tprintf("You were last paged by %s.", Name(target)));
    } else if (target == NOTHING) {
	notify(player, "I don't recognize that name.");
    } else if (!page_check(player, target)) {
	;
    } else if (!*message) {
	notify(player, tprintf("You were last paged by %s.", Name(target)));
    } else {
	switch (*message) {
	case ':':
	    message[0] = ' ';
	    page_pose(player, target, message);
	    break;
	case ';':
	    message++;
	    page_pose(player, target, message);
	    break;
	case '"':
	    message++;
	default:
	    if (Ansi(target))
	    	notify_with_cause(target, player,
tprintf("%s%s pages: %s%s", ANSI_HILITE, Name(player), message, ANSI_NORMAL));
	    else
	    	notify_with_cause(target, player,
			    tprintf("%s pages: %s", Name(player), message));
	    notify(player,
		   tprintf("You paged %s with '%s'.",
			   Name(target), message));
	}
	atr_add_raw(target, A_PAGEDBY, Name(player));
	page_return(player, target, "Idle", A_IDLE, NULL);
    }
}

/* ---------------------------------------------------------------------------
 * do_pemit: Messages to specific players, or to all but specific players.
 */

static void 
whisper_pose(player, target, message)
    dbref player, target;
    char *message;
{
    char *buff;

    buff = alloc_lbuf("do_pemit.whisper.pose");
    strcpy(buff, Name(player));
    notify(player,
	   tprintf("%s senses \"%s%s\"", Name(target), buff, message));
    notify_with_cause(target, player,
		      tprintf("You sense %s%s", buff, message));
    free_lbuf(buff);
}

static void 
pemit_list(player, cause, list, message, do_contents)
    dbref player, cause;
    char *list, *message;
    int do_contents;
{
    dbref target;
    char *tp;

    /* If we have a blank list or message, just return */
    if (!message || !*message || !list || !*list)
	return;

    /* Chop up the list, word by word. Only try a match for a dbref.
     * Enforce locality constraints. Fail silently if the pemit to the
     * object is not allowed for some reason. The locality constraints
     * have to be checked in this particular order, due to some checks
     * taking priority over others.
     */

    for (tp = (char *) strtok(list, " "); tp != NULL;
	 tp = (char *) strtok(NULL, " ")) {
	init_match(player, tp, NOTYPE);
	match_absolute();
	target = match_result();
	if (!Affects(player, target) && !nearby(player, target)) {
	    if (isPlayer(target) && mudconf.pemit_players) {
		if (!silent_page_check(player, target))
		    continue;
	    } else if (!mudconf.pemit_any)
		continue;
	}
	if (do_contents && Has_contents(target))
	    notify_all_from_inside(target, player, message);
	else
	    notify_with_cause(target, player, message);
    }
}


void 
do_pemit(player, cause, key, recipient, message)
    dbref player, cause;
    int key;
    char *recipient, *message;
{
    dbref target, loc;
    char *buf2, *bp;
    int do_contents, ok_to_do, depth, pemit_flags;

    if (key & PEMIT_CONTENTS) {
	do_contents = 1;
	key &= ~PEMIT_CONTENTS;
    } else {
	do_contents = 0;
    }
    if (key & PEMIT_LIST) {
	pemit_list(player, cause, recipient, message, do_contents);
	return;
    }
    pemit_flags = key & (PEMIT_HERE | PEMIT_ROOM);
    key &= ~(PEMIT_HERE | PEMIT_ROOM);
    ok_to_do = 0;

    switch (key) {
    case PEMIT_FSAY:
    case PEMIT_FPOSE:
    case PEMIT_FPOSE_NS:
    case PEMIT_FEMIT:
	target = match_affected(player, recipient);
	if (target == NOTHING)
	    return;
	ok_to_do = 1;
	break;
    default:
	init_match(player, recipient, TYPE_PLAYER);
	match_everything(0);
	target = match_result();
    }

    switch (target) {
    case NOTHING:
	switch (key) {
	case PEMIT_WHISPER:
	    notify(player, "Whisper to whom?");
	    break;
	case PEMIT_PEMIT:
	    notify(player, "Emit to whom?");
	    break;
	case PEMIT_OEMIT:
	    notify(player, "Emit except to whom?");
	    break;
	default:
	    notify(player, "Sorry.");
	}
	break;
    case AMBIGUOUS:
	notify(player, "I don't know who you mean!");
	break;
    default:
	/* Enforce locality constraints */

	if (!ok_to_do &&
	    (nearby(player, target) || Controls(player, target))) {
	    ok_to_do = 1;
	}
	if (!ok_to_do && (key == PEMIT_PEMIT) &&
	    (isPlayer(target)) && mudconf.pemit_players) {
	    if (!silent_page_check(player, target))
		return;
	    ok_to_do = 1;
	}
	if (!ok_to_do &&
	    (!mudconf.pemit_any || (key != PEMIT_PEMIT))) {
	    notify(player, "You are too far away to do that.");
	    return;
	}
	if (do_contents && !Controls(player, target) &&
	    !mudconf.pemit_any) {
	    notify(player, "Permission denied.");
	    return;
	}
	loc = where_is(target);

	switch (key) {
	case PEMIT_PEMIT:
	    if (do_contents) {
		if (Has_contents(target)) {
		    notify_all_from_inside(target, player,
					   message);
		}
	    } else {
		notify_with_cause(target, player,
				  message);
	    }
	    break;
	case PEMIT_OEMIT:
	    if (loc != NOTHING)
		notify_except(loc, player, target, message);
	    break;
	case PEMIT_WHISPER:
	    switch (*message) {
	    case ':':
		message[0] = ' ';
		whisper_pose(player, target, message);
		break;
	    case ';':
		message++;
		whisper_pose(player, target, message);
		break;
	    case '"':
		message++;
	    default:
		notify(player,
		       tprintf("You whisper \"%s\" to %s.",
			       message, Name(target)));
		notify_with_cause(target, player,
				  tprintf("%s whispers \"%s\"",
					  Name(player), message));
	    }
	    if ((!mudconf.quiet_whisper) && !Wizard(player)) {
		loc = where_is(player);
		if (loc != NOTHING) {
		    buf2 = alloc_lbuf("do_pemit.whisper.buzz");
		    bp = buf2;
		    safe_str(Name(player), buf2, &bp);
		    safe_str((char *) " whispers something to ",
			     buf2, &bp);
		    safe_str(Name(target), buf2, &bp);
		    notify_except2(loc, player, player,
				   target, buf2);
		    free_lbuf(buf2);
		}
	    }
	    break;
	case PEMIT_FSAY:
	    notify(target, tprintf("You say \"%s\"", message));
	    if (loc != NOTHING) {
		notify_except(loc, player, target,
			      tprintf("%s says \"%s\"", Name(target),
				      message));
	    }
	    break;
	case PEMIT_FPOSE:
	    notify_all_from_inside(loc, player,
				   tprintf("%s %s", Name(target), message));
	    break;
	case PEMIT_FPOSE_NS:
	    notify_all_from_inside(loc, player,
				   tprintf("%s%s", Name(target), message));
	    break;
	case PEMIT_FEMIT:
	    if ((pemit_flags & PEMIT_HERE) || !pemit_flags)
		notify_all_from_inside(loc, player, message);
	    if (pemit_flags & PEMIT_ROOM) {
		if (isRoom(loc) && (pemit_flags & PEMIT_HERE)) {
		    return;
		}
		depth = 0;
		while (!isRoom(loc) && (depth++ < 20)) {
		    loc = Location(loc);
		    if ((loc == NOTHING) || (loc == Location(loc)))
			return;
		}
		if (isRoom(loc)) {
		    notify_all_from_inside(loc, player, message);
		}
	    }
	    break;
	}
    }
}