/* 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); }