/* speech.c */
#include "copyright.h"
/* Commands which involve speaking */
#ifdef WANT_ANSI
#ifdef __STDC__
#include <stddef.h>
#endif /* __STDC__ */
#endif /* WANT_ANSI */
#include <ctype.h>
#include "mudconf.h"
#include "config.h"
#include "db.h"
#include "interface.h"
#include "match.h"
#include "externs.h"
#include "flags.h"
int sp_ok(dbref player)
{
if(!mudconf.robot_speak) {
if (Robot(player) && !controls(player, Location(player))) {
notify(player, "Sorry robots may not speak in public");
return 0;
}
}
return 1;
}
static void say_shout (int target, const char *prefix, int flags,
dbref player, char *message)
{
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 (dbref player, dbref cause, int key, char *message)
{
dbref loc;
char *buf2, *bp;
int say_flags, depth;
/* Convert prefix-coded messages into the normal type */
say_flags = key & (SAY_NOTAG|SAY_HERE|SAY_ROOM);
key &= ~(SAY_NOTAG|SAY_HERE|SAY_ROOM);
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;
}
/* 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\"", Name(player), message), 1);
break;
case SAY_POSE:
notify_all(loc, player, tprintf("%s %s", Name(player), message), 1);
break;
case SAY_POSE_NOSPC:
notify_all(loc, player, tprintf("%s%s", Name(player), message), 1);
break;
case SAY_EMIT:
if ((say_flags & SAY_HERE) || !say_flags) {
notify_all(loc, player, message, 1);
} else if (say_flags & SAY_ROOM) {
if ((Typeof(loc) == TYPE_ROOM) &&
(say_flags & SAY_HERE)) {
return;
}
depth = 0;
while((Typeof(loc) != TYPE_ROOM) && (depth++ < 20)) {
loc = Location(loc);
if ((loc == NOTHING) || (loc == Location(loc)))
return;
}
if (Typeof(loc) == TYPE_ROOM) {
notify_all(loc, player, message, 1);
}
}
break;
case SAY_SHOUT:
switch (*message) {
case ':':
message[0] = ' ';
say_shout(0, announce_msg, say_flags, player, message);
break;
case ';':
message++;
say_shout(0, announce_msg, say_flags, player, message);
break;
case '"':
message++;
default:
buf2 = alloc_lbuf("do_say.shout");
bp = buf2;
safe_str((char *)" shouts \"", buf2, &bp);
safe_str(message, buf2, &bp);
safe_chr('"', buf2, &bp);
*bp = '\0';
say_shout(0, 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, " shouts: '%s'", message);
log_text(buf2);
free_lbuf(buf2);
ENDLOG
break;
case SAY_WIZSHOUT:
switch (*message) {
case ':':
message[0] = ' ';
say_shout(WIZARD, broadcast_msg, say_flags, player,
message);
break;
case ';':
message++;
say_shout(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);
*bp = '\0';
say_shout(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(0, "%s %s", Name(player), message);
else
raw_broadcast(0, "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(WIZARD, "%s %s", Name(player), message);
else
raw_broadcast(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(0, "%s", message);
else
raw_broadcast(0, "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(WIZARD, "%s", message);
else
raw_broadcast(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;
case SAY_GRIPE:
STARTLOG(LOG_ALWAYS,"INF","GRIPE")
log_name_and_loc(player);
buf2=alloc_lbuf("do_say.LOG.gripe");
sprintf(buf2," gripes: '%s'", message);
log_text(buf2);
if (!Haven(GOD)) {
sprintf(buf2, "%s gripes: '%s'",
Name(player), message);
notify_with_cause(GOD, player, buf2);
}
free_lbuf(buf2);
if (!Quiet(player))
notify(player, "Your complaint has been noted.");
ENDLOG
break;
case SAY_NOTE:
STARTLOG(LOG_ALWAYS,"INF","NOTE")
log_name(player);
buf2=alloc_lbuf("do_say.LOG.note");
sprintf(buf2," notes: '%s'", message);
log_text(buf2);
if (!Haven(GOD)) {
sprintf(buf2, "%s notes: '%s'",
Name(player), message);
notify_with_cause(GOD, player, buf2);
}
free_lbuf(buf2);
if (!Quiet(player)) notify(player, "Noted.");
ENDLOG
break;
}
}
/* ---------------------------------------------------------------------------
* do_page: Handle the page command.
* Page-pose code from shadow@prelude.cc.purdue.
*/
static void page_pose (dbref player, dbref target, char *message)
{
char *nbuf;
nbuf = alloc_lbuf("page_pose");
strcpy(nbuf, Name(player));
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 (dbref player, dbref target, const char *tag,
int anum, const char *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, target, EV_FCHECK, 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 (dbref player, dbref target)
{
if (!payfor(player, Guest(player) ? 0 : mudconf.pagecost)) {
notify(player,
tprintf("You don't have enough %s.",
mudconf.many_coins));
} else if (!(Flags(target) & PLAYER_CONNECT)) {
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 {
return 1;
}
return 0;
}
void do_page(dbref player, dbref cause, int key, char *tname, char *message)
{
dbref target;
char *nbuf;
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)));
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:
notify_with_cause(target, player,
tprintf("%s pages: %s", Name(player), message));
notify(player,
tprintf("You paged %s with '%s'.",
Name(target), message));
}
page_return(player, target, "Idle", A_IDLE, NULL);
}
}
/* ---------------------------------------------------------------------------
* do_pemit: Messages to specific players, or to all but specific players.
*/
void whisper_pose (dbref player, dbref 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);
}
void do_pemit (dbref player, dbref cause, int key, char *recipient,
char *message)
{
dbref target, loc;
char *buf2, *bp;
int do_contents, ok_to_do;
if (key & PEMIT_CONTENTS) {
do_contents = 1;
key &= ~PEMIT_CONTENTS;
} else {
do_contents = 0;
}
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();
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) &&
(Typeof(target) == TYPE_PLAYER) && mudconf.pemit_players) {
if (!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(target, player, message, 1);
}
} else {
notify_with_cause(target, player, message);
}
break;
case PEMIT_OEMIT:
if (loc != NOTHING)
notify_except(loc, player, target, message, 1);
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);
*bp = '\0';
notify_except2(loc, player, player,
target, buf2, 1);
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), 1);
}
break;
case PEMIT_FPOSE:
if (loc != NOTHING)
notify_all(loc, player,
tprintf("%s %s", Name(target), message), 1);
else
notify(target,
tprintf("%s %s", Name(target), message));
break;
case PEMIT_FPOSE_NS:
if (loc != NOTHING)
notify_all(loc, player,
tprintf("%s%s", Name(target), message), 1);
else
notify(target,
tprintf("%s%s", Name(target), message));
break;
case PEMIT_FEMIT:
if (loc != NOTHING)
notify_all(loc, player, message, 1);
else
notify(target, message);
break;
}
}
}
static void notify_forward(dbref object, dbref player, const char *msg)
{
dbref exit, target, aowner;
int aflags;
char *buf, *cp;
char *dp1, *dp2;
if (Audible(object) && check_filter(object, player, A_FILTER, msg)) {
cp = buf = alloc_lbuf("notify_forward");
safe_str((char *)"From ", buf, &cp);
safe_str(Name(object), buf, &cp);
safe_str((char *)",", buf, &cp);
*cp = '\0';
cp = add_prefix(object, player, A_PREFIX, msg, buf);
free_lbuf(buf);
dp1 = buf = atr_get(object, A_FORWARDLIST, &aowner, &aflags);
if (*buf) do {
dp2 = parse_to(&dp1, ' ', 0);
if (*dp2 == '#') {
target = atoi(dp2+1);
if (Good_obj(target) && (target != object))
notify_except(target, player, object,
cp, 0);
}
} while (dp1 != NULL);
free_lbuf(buf);
if (Good_obj(Location(object)))
notify_except(Location(object), player, object, cp, 0);
free_lbuf(cp);
}
DOLIST(exit, Exits(object)) {
if (Audible(exit) &&
((target = Location(exit)) != object) &&
check_filter(exit, player, A_FILTER, msg)) {
cp = add_prefix(exit, player, A_PREFIX, msg,
"From a distance,");
notify_all(target, player, cp, 0);
free_lbuf(cp);
}
}
}
void notify_all(dbref loc, dbref player,
const char *msg, const int forward)
{
dbref first;
notify_puppet(loc, player, msg);
DOLIST(first, Contents(loc)) {
notify_puppet(first, player, msg);
}
if (forward)
notify_forward(loc, player, msg);
}
void notify_except(dbref loc, dbref player,
dbref exception, const char *msg, const int forward)
{
dbref first;
if (loc != exception)
notify_puppet(loc, player, msg);
DOLIST(first, Contents(loc)) {
if (first != exception) {
notify_puppet(first, player, msg);
}
}
if (forward)
notify_forward(loc, player, msg);
}
void notify_except2(dbref loc, dbref player,
dbref exc1, dbref exc2, const char *msg, const int forward)
{
dbref first;
if ((loc != exc1) && (loc != exc2))
notify_puppet(loc, player, msg);
DOLIST(first, Contents(loc)) {
if (first != exc1 && first != exc2) {
notify_puppet(first, player, msg);
}
}
if (forward)
notify_forward(loc, player, msg);
}
int check_filter(dbref object, dbref player, int filter, const char *msg)
{
int aflags;
dbref aowner;
char *buf, *nbuf, *cp, *dp;
buf = atr_pget(object, filter, &aowner, &aflags);
if (!*buf) {
free_lbuf(buf);
return(1);
}
dp = nbuf = exec(object, player, 0, buf, (char **)NULL, 0);
free_lbuf(buf);
do {
cp = parse_to(&dp, ',', EV_STRIP);
if (quick_wild(cp, (char *)msg)) {
free_lbuf(nbuf);
return(0);
}
} while (dp != NULL);
free_lbuf(nbuf);
return(1);
}
char *add_prefix(dbref object, dbref player, int prefix,
const char *msg, const char *dflt)
{
int aflags;
dbref aowner;
char *buf, *nbuf, *cp;
buf = atr_pget(object, prefix, &aowner, &aflags);
if (!*buf) {
cp = buf;
safe_str((char *)dflt, buf, &cp);
} else {
nbuf = exec(object, player, 0, buf, (char **)NULL, 0);
free_lbuf(buf);
buf = nbuf;
cp = &buf[strlen(buf)];
}
if (cp != buf)
safe_str((char *)" ", buf, &cp);
safe_str((char *)msg, buf, &cp);
*cp = '\0';
return(buf);
}