/* * speech.c -- Commands which involve speaking */ /* * $Id: speech.cpp,v 1.4 2000/06/08 20:30:36 sdennis Exp $ */ #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #include "mudconf.h" #include "db.h" #include "interface.h" #include "match.h" #include "flags.h" #include "powers.h" #include "attrs.h" #include "alloc.h" extern char *FDECL(next_token, (char *, char)); static int idle_timeout_val(dbref player) { // If IDLETIMEOUT attribute is not present, the value // returned will be zero. // dbref aowner; int aflags; char *ITbuffer = atr_get(player, A_IDLETMOUT, &aowner, &aflags); int idle_timeout = Tiny_atol(ITbuffer); free_lbuf(ITbuffer); return idle_timeout; } int sp_ok(dbref player) { if (Gagged(player) && (!(Wizard(player)))) { notify(player, "Sorry. Gagged players cannot speak."); return 0; } if (!mudconf.robot_speak) { if (Robot(player) && !controls(player, Location(player))) { notify(player, "Sorry robots may not speak in public."); return 0; } } if (Auditorium(Location(player))) { if (!could_doit(player, Location(player), A_LSPEECH)) { notify(player, "Sorry, you may not speak in this place."); 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: "; static const char *admin_msg = "Admin: "; void do_think(dbref player, dbref cause, int key, char *message) { char *str, *buf, *bp; buf = bp = alloc_lbuf("do_think"); str = message; TinyExec(buf, &bp, 0, player, cause, EV_FCHECK | EV_EVAL | EV_TOP, &str, (char **)NULL, 0); *bp = '\0'; notify(player, buf); free_lbuf(buf); } 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 | SAY_HTML); key &= ~(SAY_NOTAG | SAY_HERE | SAY_ROOM | SAY_HTML); 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_saypose(player, tprintf("You say \"%s\"", message)); notify_except(loc, player, player, tprintf("%s says \"%s\"", Name(player), message), MSG_SAYPOSE); break; case SAY_POSE: notify_all_from_inside_saypose(loc, player, tprintf("%s %s", Name(player), message)); break; case SAY_POSE_NOSPC: notify_all_from_inside_saypose(loc, player, tprintf("%s%s", Name(player), message)); break; case SAY_EMIT: if ((say_flags & SAY_HERE) || (say_flags & SAY_HTML) || !say_flags) { if (say_flags & SAY_HTML) { notify_all_from_inside_html(loc, player, message); } else { notify_all_from_inside(loc, player, message); } } 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_from_inside(loc, player, message); } } 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); log_text(" shouts: "); log_text(message); 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); log_text((char *)" broadcasts: '"); log_text(message); log_text((char *)"'"); ENDLOG break; case SAY_ADMINSHOUT: switch (*message) { case ':': message[0] = ' '; say_shout(WIZARD, admin_msg, say_flags, player, message); say_shout(ROYALTY, admin_msg, say_flags, player, message); break; case ';': message++; say_shout(WIZARD, admin_msg, say_flags, player, message); say_shout(ROYALTY, admin_msg, say_flags, player, message); break; case '"': message++; default: buf2 = alloc_lbuf("do_say.adminshout"); bp = buf2; safe_str((char *)" says \"", buf2, &bp); safe_str(message, buf2, &bp); safe_chr('"', buf2, &bp); *bp = '\0'; say_shout(WIZARD, admin_msg, say_flags, player, buf2); say_shout(ROYALTY, admin_msg, say_flags, player, buf2); free_lbuf(buf2); } STARTLOG(LOG_SHOUTS, "WIZ", "ASHOUT"); log_name(player); log_text(" yells: "); log_text(message); 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); log_text(" WALLposes: "); log_text(message); 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); log_text(" WIZposes: "); log_text(message); 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); log_text(" WALLemits: "); log_text(message); 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); log_text(" WIZemit: "); log_text(message); ENDLOG; break; } } /* * --------------------------------------------------------------------------- * * do_page: Handle the page command. * * Page-pose code from shadow@prelude.cc.purdue. */ static void page_return(dbref player, dbref target, const char *tag, int anum, const char *dflt) { dbref aowner; int aflags; char *str, *str2, *buf, *bp; str = atr_pget(target, anum, &aowner, &aflags); if (*str) { str2 = bp = alloc_lbuf("page_return"); buf = str; TinyExec(str2, &bp, 0, target, player, EV_FCHECK | EV_EVAL | EV_TOP | EV_NO_LOCATION, &buf, (char **)NULL, 0); *bp = '\0'; if (*str2) { CLinearTimeAbsolute ltaNow; ltaNow.GetLocal(); FIELDEDTIME ft; ltaNow.ReturnFields(&ft); notify_with_cause_ooc(player, target, tprintf("%s message from %s: %s", tag, Name(target), str2)); notify_with_cause_ooc(target, player, tprintf("[%d:%02d] %s message sent to %s.", ft.iHour, ft.iMinute, tag, Name(player))); } free_lbuf(str2); } else if (dflt && *dflt) { notify_with_cause_ooc(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 (!Connected(target)) { page_return(player, target, "Away", A_AWAY, tprintf("Sorry, %s is not connected.", Name(target))); } else if (!could_doit(player, target, A_LPAGE)) { if (Wizard(target) && Dark(target)) { page_return(player, target, "Away", A_AWAY, tprintf("Sorry, %s is not connected.", Name(target))); } else { page_return(player, target, "Reject", A_REJECT, tprintf("Sorry, %s is not accepting pages.", Name(target))); } } else if (!could_doit(target, player, A_LPAGE)) { if (Wizard(player)) { notify(player, tprintf("Warning: %s can't return your page.", Name(target))); return 1; } else { notify(player, tprintf("Sorry, %s can't return your page.", Name(target))); return 0; } } else { return 1; } return 0; } /* * Used in do_page */ static char *dbrefs_to_names(dbref player, char *list, char *namelist, int ismessage) { char *bp, *p; char oldlist[LBUF_SIZE]; StringCopy(oldlist, list); bp = namelist; TINY_STRTOK_STATE tts; Tiny_StrTokString(&tts, oldlist); Tiny_StrTokControl(&tts, " "); for (p = Tiny_StrTokParse(&tts); p; p = Tiny_StrTokParse(&tts)) { if (ismessage) { safe_str(tprintf("%s, ", Name(Tiny_atol(p))), namelist, &bp); } else { if (lookup_player(player, p, 1) != NOTHING) { safe_str(tprintf("%s, ", Name(lookup_player(player, p, 1))), namelist, &bp); } } } *(bp - 2) = '\0'; return bp; } void do_page(dbref player, dbref cause, int key, char *tname, char *message) { dbref target, aowner; char *p, *buf1, *bp, *buf2, *bp2, *mp, *str; char targetname[LBUF_SIZE]; int ispose = 0; int ismessage = 0; int count = 0; int n = 0; int aflags = 0; buf1 = alloc_lbuf("page_return_list"); bp = buf1; buf2 = alloc_lbuf("page_list"); bp2 = buf2; if ((tname[0] == ':') || (tname[0] == ';') || (message[0] == ':') || (message[0] == ';')) ispose = 1; mp = message; if (!*message) { atr_get_str(targetname, player, A_LASTPAGE, &aowner, &aflags); if (!*tname) { if (!*targetname) { notify(player, "You have not paged anyone."); } else { TINY_STRTOK_STATE tts; Tiny_StrTokString(&tts, targetname); Tiny_StrTokControl(&tts, " "); for (p = Tiny_StrTokParse(&tts); p; p = Tiny_StrTokParse(&tts)) { target = Tiny_atol(p); notify(player, tprintf("You last paged %s.", Name(target))); } } free_lbuf(buf1); free_lbuf(buf2); return; } StringCopy(message, tname); StringCopy(tname, targetname); ismessage = 1; } /* * Count the words */ for (n = 0, str = tname; str; str = (char *)next_token(str, ' '), n++) ; if (((target = lookup_player(player, tname, 1)) == NOTHING) && n > 1) { bp = dbrefs_to_names(player, tname, buf1, ismessage); TINY_STRTOK_STATE tts; Tiny_StrTokString(&tts, tname); Tiny_StrTokControl(&tts, " "); for (p = Tiny_StrTokParse(&tts); p; p = Tiny_StrTokParse(&tts)) { // If it's a memory page, grab the number from the list. // if (ismessage) { target = Tiny_atol(p); } else { target = lookup_player(player, p, 1); } message = mp; if (target == NOTHING) { notify(player, tprintf("I don't recognize \"%s\".", p)); } else if (!page_check(player, target)) { ; } else { switch (*message) { case ':': notify_with_cause_ooc(target, player, tprintf("From afar, to (%s): %s %s", buf1, Name(player), message + 1)); break; case ';': message++; notify_with_cause_ooc(target, player, tprintf("From afar, to (%s): %s%s", buf1, Name(player), message)); break; case '"': message++; default: notify_with_cause_ooc(target, player, tprintf("To (%s), %s pages: %s", buf1, Name(player), message)); } if (fetch_idle(target) >= idle_timeout_val(target)) { page_return(player, target, "Idle", A_IDLE, NULL); } safe_str(tprintf("%d ", target), buf2, &bp2); count++; } } } else { if (ismessage) target = Tiny_atol(tname); if (target == NOTHING) { notify(player, tprintf("I don't recognize \"%s\".", tname)); } else if (!page_check(player, target)) { ; } else { switch (*message) { case ':': notify_with_cause_ooc(target, player, tprintf("From afar, %s %s", Name(player), message + 1)); break; case ';': message++; notify_with_cause_ooc(target, player, tprintf("From afar, %s%s", Name(player), message)); break; case '"': message++; default: notify_with_cause_ooc(target, player, tprintf("%s pages: %s", Name(player), message)); } if (fetch_idle(target) >= idle_timeout_val(target)) { page_return(player, target, "Idle", A_IDLE, NULL); } safe_str(tprintf("%d ", target), buf2, &bp2); safe_str(tprintf("%s, ", Name(target)), buf1, &bp); count++; } *(bp - 2) = '\0'; } if (count == 0) { free_lbuf(buf1); free_lbuf(buf2); return; } *(bp2 - 1) = '\0'; atr_add(player, A_LASTPAGE, buf2, Owner(player), aflags); if (count == 1) { if (*buf1) { if (ispose != 1) { notify(player, tprintf("You paged %s with '%s'.", buf1, mp)); } else { if (mp[0] == ':') notify(player, tprintf("Long distance to %s: %s %s", buf1, Name(player), mp + 1)); else notify(player, tprintf("Long distance to %s: %s%s", buf1, Name(player), mp + 1)); } } } else { *(bp - 2) = ')'; *(bp - 1) = '\0'; if (*buf1) { if (ispose != 1) { notify(player, tprintf("You paged (%s with '%s'.", buf1, mp)); } else { if (mp[0] == ':') notify(player, tprintf("Long distance to (%s: %s %s", buf1, Name(player), mp + 1)); else notify(player, tprintf("Long distance to (%s: %s%s", buf1, Name(player), mp + 1)); } } } free_lbuf(buf1); free_lbuf(buf2); } /* * --------------------------------------------------------------------------- * * 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"); StringCopy(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_list(dbref player, char *list, const char *message) { /* * Send a message to a list of dbrefs. To avoid repeated generation * * of the NOSPOOF string, we set it up the first time we * encounter something Nospoof, and then check for it * thereafter. The list is destructively modified. */ char *p; dbref who; int ok_to_do; if (!message || !*message || !list || !*list) return; TINY_STRTOK_STATE tts; Tiny_StrTokString(&tts, list); Tiny_StrTokControl(&tts, " "); for (p = Tiny_StrTokParse(&tts); p; p = Tiny_StrTokParse(&tts)) { ok_to_do = 0; init_match(player, p, TYPE_PLAYER); match_everything(0); who = match_result(); if (!ok_to_do && (Long_Fingers(player) || nearby(player, who) || Controls(player, who))) { ok_to_do = 1; } if (!ok_to_do && (isPlayer(who)) && mudconf.pemit_players) { if (!page_check(player, who)) return; ok_to_do = 1; } switch (who) { case NOTHING: notify(player, "Emit to whom?"); break; case AMBIGUOUS: notify(player, "I don't know who you mean!"); break; default: if (!ok_to_do) { notify(player, "You cannot do that."); break; } if (Good_obj(who)) notify_with_cause(who, player, message); } } } 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, depth, pemit_flags; if (key & PEMIT_CONTENTS) { do_contents = 1; key &= ~PEMIT_CONTENTS; } else { do_contents = 0; } if (key & PEMIT_LIST) { do_pemit_list(player, recipient, message); return; } pemit_flags = key & (PEMIT_HERE | PEMIT_ROOM | PEMIT_HTML); key &= ~(PEMIT_HERE | PEMIT_ROOM | PEMIT_HTML); ok_to_do = 0; switch (key) { case PEMIT_FSAY: case PEMIT_FPOSE: case PEMIT_FPOSE_NS: case PEMIT_FEMIT: target = match_controlled(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) || Long_Fingers(player) || 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_from_inside(target, player, message); } } else { if (pemit_flags & PEMIT_HTML) { notify_with_cause_html(target, player, message); } else { notify_with_cause(target, player, message); } } break; case PEMIT_OEMIT: notify_except(Location(target), player, target, message, 0); 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); 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), 0); } 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 ((Typeof(loc) == TYPE_ROOM) && (pemit_flags & PEMIT_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_from_inside(loc, player, message); } } break; } } }