/* * communication.cpp * Functions used for communication on the mud * ____ _ * | _ \ ___ __ _| |_ __ ___ ___ * | |_) / _ \/ _` | | '_ ` _ \/ __| * | _ < __/ (_| | | | | | | \__ \ * |_| \_\___|\__,_|_|_| |_| |_|___/ * * Permission to use, modify and distribute is granted via the * Creative Commons - Attribution - Non Commercial - Share Alike 3.0 License * http://creativecommons.org/licenses/by-nc-sa/3.0/ * * Copyright (C) 2007-2012 Jason Mitchell, Randi Mitchell * Contributions by Tim Callahan, Jonathan Hseu * Based on Mordor (C) Brooke Paul, Brett J. Vickers, John P. Freeman * */ #include "mud.h" #include "commands.h" #include "communication.h" #include "move.h" #include "clans.h" #include "guilds.h" //********************************************************************* // confusionChar //********************************************************************* char confusionChar() { int n; switch(mrand(0,10)) { case 0: // random upper case return(mrand(65, 90)); case 1: case 2: // random character n = mrand(0,57); // weight all the characters in the different ranges evenly if(n <= 31) { // mrand(91, 121); 31 chars return(n + 91); } else if(n <= 38) { // mrand(58, 64); 7 chars return(n - 31 + 58); } else if(n <= 54) { // mrand(32, 47); 16 chars return(n - 31 - 7 + 32); } else { // mrand(123, 125); 3 chars return(n - 31 - 7 - 16 + 123); } case 3: // random number return(mrand(48, 57)); break; default: break; } // random lower case return(mrand(97, 122)); } //********************************************************************* // confusionText //********************************************************************* // make the player say gibberish instead of actual words bstring confusionText(Creature* speaker, bstring text) { if( (!speaker->isEffected("confusion") && !speaker->isEffected("drunkenness")) || speaker->isStaff() ) return(text); bool scramble = mrand(0,1); for(int i=0; i<text.getLength(); i++) { if(text.getAt(i) == ' ') { scramble = !mrand(0,3); // sometimes scramble spaces, too if(!mrand(0,8)) text.setAt(i, confusionChar()); } else { if(scramble || !mrand(0,8)) text.setAt(i, confusionChar()); } } return(text); } //********************************************************************* // getFullstrText //********************************************************************* // general function that gets a cmnd->fullstr and returns the portion // of the text that will get sent to other player(s) // skip = 1 when we only have 1 command to skip // Ex: say hello all // skip = 2 when we have 2 commands to skip // Ex: tell bob hello there bstring getFullstrTextTrun(bstring str, int skip, char toSkip, bool colorEscape) { return(getFullstrText(str, skip, toSkip, colorEscape, true)); } bstring getFullstrText(bstring str, int skip, char toSkip, bool colorEscape, bool truncate) { int i=0, n = str.length() - 1; // first of all, trim both directions while(i <= n && str.at(i) == toSkip) i++; while(n >= 0 && str.at(n) == toSkip) n--; while(skip > 0) { // skip a set of spaces for(; i < (int)str.length()-1; i++) if(str.at(i) == toSkip && str.at(i+1) != toSkip) break; i++; skip--; } // these numbers can't overlap if(i > n) str = ""; else { str = str.substr(0, n+1); str = str.substr(i); if(truncate) { // skip a set of spaces for(i=0; i < (int)str.length()-1; i++) { if(str.at(i) == toSkip && str.at(i+1) != toSkip) { i--; break; } } i++; // these numbers can't overlap str = str.substr(0, i); } } if(colorEscape) str = escapeColor(str); return(str); } //********************************************************************* // communicateWith //********************************************************************* // This is the base function for communication with a target player. // The commands tell, whisper, reply, and sign are all routed through here. int communicateWith(Player* player, cmd* cmnd) { bstring text = ""; Player *target=0; int i=0, found=0; char ooc_str[10]; // reuse text text = cmnd->myCommand->getName(); // get us a channel to use! commPtr chan = NULL; while(commList[i].name != NULL) { if(!strcmp(text.c_str(), commList[i].name)) { chan = &commList[i]; break; } i++; } if(!chan) { player->print("Unknown channel.\n"); return(0); } strcpy(ooc_str, (chan->ooc ? "[ooc]: " : "")); // extra checks for reply and sign if(chan->type == COM_REPLY) { strcpy(cmnd->str[1], player->getLastCommunicate().c_str()); if(!strlen(cmnd->str[1])) { player->print("You have nobody to reply to right now.\n"); return(0); } } else if(chan->type == COM_SIGN) { if(player->getRace() != DARKELF && !player->isStaff()) { player->print("Only dark elves may communicate by signing.\n"); return(0); } } // the basic communication checks all commands must obey player->clearFlag(P_AFK); if(!player->ableToDoCommand()) return(0); if(cmnd->num < chan->skip) { player->print("%s to whom?\n", com_text_u[chan->type]); return(0); } if(!player->flagIsSet(P_SECURITY_CHECK_OK)) { player->print("You may not do that yet.\n"); return(0); } // silence! if(chan->type != COM_SIGN) { if(player->flagIsSet(P_DM_SILENCED)) { player->printColor("^CYou are unable to move your fingers.\n"); return(0); } if(!player->canSpeak()) { player->printColor("^yYou cannot speak.\n"); return(0); } } else { if(player->flagIsSet(P_DM_SILENCED)) { player->printColor("^yYou are unable to move your lips.\n"); return(0); } } // run the player table cmnd->str[1][0] = up(cmnd->str[1][0]); Player* ply; for(std::pair<bstring, Player*> p : gServer->players) { ply = p.second; if(!ply->isConnected()) continue; // these two need vicinity if(chan->type == COM_SIGN || chan->type == COM_WHISPER) if(!player->inSameRoom(ply)) continue; if(!player->canSee(ply)) continue; if(ply->getName() == cmnd->str[1]) { target = ply; break; } if(!strncmp(ply->getCName(), cmnd->str[1], strlen(cmnd->str[1]))) { target = ply; found++; } } if(found > 1) { player->print("More than one person with that name.\n"); return(0); } if(!target || !player->canSee(target)) { player->print("%s to whom?\n", com_text_u[chan->type]); return(0); } // higher level communication checks if(player == target && !player->flagIsSet(P_CAN_FLASH_SELF) && !player->isStaff()) { player->print("Talking to yourself is a sign of insanity.\n"); return(0); } if(player->getClass() == BUILDER && !target->isStaff()) { player->print("You may only communicate with staff!\n"); return(0); } // polite ignore message for watchers if(!player->isCt() && target->flagIsSet(P_NO_TELLS)) { if(target->isPublicWatcher()) player->print("%s is busy at the moment. Please mudmail %s.\n", target->getCName(), target->himHer()); else player->print("%s is ignoring everyone.\n", target->getCName()); return(0); } // staff can always message AFK people if( target->flagIsSet(P_AFK) && !player->checkStaff("%s is currently afk.\n", target->getCName())) return(0); if(chan->type != COM_SIGN && target->isEffected("deafness") && !player->isStaff()) { player->print("%s is deaf and cannot hear anything.\n", target->getCName()); return(0); } if( target->isIgnoring(player->getName()) && !target->checkStaff("%s is ignoring you.\n", target->getCName()) ) return(0); if(chan->type == COM_SIGN || chan->type == COM_WHISPER) player->unhide(); if(chan->type == COM_SIGN) { if(!target->isStaff()) { if(target->getRace() != DARKELF && target->getClass() < BUILDER) { player->print("%s doesn't understand dark elven sign language.\n", target->upHeShe()); return(0); } if(target->isEffected("blindness")) { player->print("%M is blind! %s can't see what you're signing.\n", target, target->upHeShe()); return(0); } if(player->isInvisible() && !target->isEffected("detect-invisible")) { player->print("You are invisible! %s cannot see what you are signing.\n", target->getCName()); return(0); } } } else { if( !target->languageIsKnown(LUNKNOWN+player->current_language) && !player->isStaff() && !target->isEffected("comprehend-languages") ) { player->print("%s doesn't speak your current language.\n", target->upHeShe()); return(0); } } // spam check if(player->checkForSpam()) return(0); // reuse text text = getFullstrText(cmnd->fullstr, chan->skip, ' ', true); if(text == "") { player->print("%s what?\n", com_text_u[chan->type]); return(0); } text = confusionText(player, text); player->printColor("^cYou %s \"%s%s\" to %N.\n", com_text[chan->type], ooc_str, text.c_str(), target); if(chan->type == COM_WHISPER) broadcast(player->getSock(), target->getSock(), player->getParent(), "%M whispers something to %N.", player, target); if(!target->isGagging(player->getName())) { target->printColor("%s%s%M %s%s, \"%s%s\".\n", target->customColorize("*CC:TELL*").c_str(), chan->type == COM_WHISPER || chan->type == COM_SIGN ? "" : "### ", player, chan->type == COM_WHISPER || chan->type == COM_SIGN ? com_text[chan->type] : "just flashed", chan->type == COM_WHISPER || chan->type == COM_SIGN ? " to you" : "", ooc_str, text.c_str()); } else { if(!player->isDm() && !target->isDm()) broadcast(watchingEaves, "^E--- %s TRIED sending to %s, \"%s\".", player->getCName(), target->getCName(), text.c_str()); } // sign doesnt use reply anyway if(chan->type != COM_SIGN) { if(!target->isStaff() && ( ( player->isEffected("incognito") && !player->inSameRoom(target) ) || ( player->isInvisible() && !target->isEffected("detect-invisible") ) || ( player->isEffected("mist") && !target->isEffected("true-sight") ) || player->flagIsSet(P_DM_INVIS) || target->flagIsSet(P_UNCONSCIOUS) || target->isBraindead() || target->flagIsSet(P_LINKDEAD) ) ) { player->print("%s will be unable to reply.", target->upHeShe()); if(target->flagIsSet(P_LINKDEAD)) player->print(" %s is linkdead.", target->upHeShe()); player->print("\n"); if(player->flagIsSet(P_ALIASING)) player->print("Sent from: %s.\n", player->getAlias()->getCName()); } else if(player->flagIsSet(P_IGNORE_ALL)) { player->print("You are ignoring all, as such they will be unable to respond.\n"); } } else { for(Player* ply : player->getRoomParent()->players) { if( ply != player && ply != target && !ply->isEffected("blindness")) { if(ply->getRace() == DARKELF || ply->isStaff()) ply->print("%M signed, \"%s\" to %N.\n", player, text.c_str(), target); else ply->print("%M signed something in dark elven to %N.\n", player, target); } } } if(player->isDm() || target->isDm()) return(0); broadcast(watchingEaves, "^E--- %s %s to %s, \"%s%s\".", player->getCName(), com_text[chan->type], target->getCName(), ooc_str, text.c_str()); player->bug("%s %s, \"%s%s\" to %s.\n", player->getCName(), com_text[chan->type], ooc_str, text.c_str(), target->getCName()); target->bug("%s %s, \"%s%s\" to %s.\n", player->getCName(), com_text[chan->type], ooc_str, text.c_str(), target->getCName()); if(chan->type != COM_SIGN) target->setLastCommunicate(player->getName()); return(0); } //********************************************************************* // commTarget //********************************************************************* // function that does the actual printing of message for below void commTarget(Creature* player, Player* target, int type, bool ooc, int lang, bstring text, bstring speak, char *ooc_str, bool anon) { std::ostringstream out; if(!target || target->flagIsSet(P_UNCONSCIOUS)) return; if(target->isEffected("deafness") && !player->isStaff()) return; if(type != COM_GT) speak += "s"; if(type == COM_EMOTE) { out << player->getCrtStr(target, CAP) << " " << text << "\n"; target->bug("%s emoted: %s.\n", player->getCName(), text.c_str()); } else if( ooc || target->languageIsKnown(LUNKNOWN+lang) || target->isStaff() || target->isEffected("comprehend-languages")) { if(type == COM_GT) out << target->customColorize("*CC:GROUP*").c_str() << "### "; if(ooc || lang == LCOMMON) { if(anon) out << "Someone"; else out << player->getCrtStr(target, CAP); out << " " << speak; } else { if(anon) out << "Someone"; else out << player->getCrtStr(target, CAP); out << " " << speak << " in " << get_language_adj(lang); } out << ", \""; // if(!ooc && target->flagIsSet(P_LANGUAGE_COLORS)) // ANSI(fd, get_lang_color(lang)); out << ooc_str << text; out << "\".\n"; target->bug("%s %s in %s, \"%s%s.\"\n", player->getCName(), com_text[type], get_language_adj(lang), ooc_str, text.c_str()); } else { if(anon) out << "Someone"; else out << player->getCrtStr(target, CAP); out << " " << speak << " something in " << get_language_adj(lang) << ".\n"; target->bug("%s %s something in %s.\n", player->getCName(), speak.c_str(), get_language_adj(lang)); } *target << ColorOn << out.str() << ColorOff; // target->printColor("%s", out.str().c_str()); } //********************************************************************* // communicate //********************************************************************* // This function allows the player to say something to all the other // people in the room (or nearby rooms). int pCommunicate(Player* player, cmd* cmnd) { return(communicate(player, cmnd)); } int communicate(Creature* creature, cmd* cmnd) { const Player* player=0; bstring text = "", name = ""; Creature *owner=0; Player* pTarget=0; BaseRoom* room=0; int i=0, lang; char speak[35], ooc_str[10]; if(creature->isPet()) owner = creature->getMaster(); else owner = creature; player = owner->getAsConstPlayer(); // reuse text text = cmnd->myCommand->getName(); // get us a channel to use! sayPtr chan = NULL; while(sayList[i].name != NULL) { if(!strcmp(text.c_str(), sayList[i].name)) { chan = &sayList[i]; break; } i++; } if(!chan) { creature->print("Unknown channel.\n"); return(0); } strcpy(ooc_str, (chan->ooc ? "[ooc]: " : "")); owner->clearFlag(P_AFK); if(!creature->ableToDoCommand()) return(0); if(!creature->canSpeak() || (owner && owner != creature && !owner->canSpeak())) { creature->printColor("^yYour lips move but no sound comes forth.\n"); return(0); } // reuse text text = getFullstrText(cmnd->fullstr, 1, ' ', true); if(text == "") { creature->print("%s what?\n", com_text_u[chan->type]); return(0); } text = confusionText(owner, text); lang = owner->current_language; if(chan->ooc) strcpy(speak, "say"); else if(chan->type == COM_RECITE) strcpy(speak, "recite"); else if(chan->type == COM_GT) strcpy(speak, "group mentioned"); else if(chan->type == COM_YELL) { strcpy(speak, "yell"); text += "!"; } else strcpy(speak, get_language_verb(lang)); if(chan->type == COM_GT) { // Group Tell is being handled slightly differently as it now uses a std::list instead of ctags // Adapt the other communication methods to use this once they've been moved to a std::list as well Group* group = creature->getGroup(); if(group) { for(Creature* crt : group->members) { pTarget = crt->getAsPlayer(); if(!pTarget) continue; // GT prints to the player! if(pTarget == creature && chan->type != COM_GT) continue; if(pTarget->isGagging(creature->isPet() ? creature->getMaster()->getCName() : creature->getCName())) continue; if(pTarget->getGroupStatus() < GROUP_MEMBER) continue; commTarget(creature, pTarget, chan->type, chan->ooc, lang, text, speak, ooc_str, false); } } else { creature->print("You are not in a group.\n"); return(0); } } else { creature->unhide(); if(chan->type == COM_EMOTE) { creature->printColor("You emote: %s.\n", text.c_str()); player->bug("%s emoted: %s.\n", creature->getCName(), text.c_str()); } else { char intro[2046]; if(chan->ooc || lang == LCOMMON) sprintf(intro, "You %s,", speak); else sprintf(intro, "You %s in %s,", speak, get_language_adj(lang)); creature->printColor("%s%s \"%s%s\".\n^x", ((!chan->ooc && creature->flagIsSet(P_LANGUAGE_COLORS)) ? get_lang_color(lang) : ""), intro, ooc_str, text.c_str()); player->bug("%s %s in %s, \"%s%s.\"\n", creature->getCName(), com_text[chan->type], get_language_adj(lang), ooc_str, text.c_str()); } for(Player* ply : creature->getRoomParent()->players) { if(chan->shout) ply->wake("Loud noises disturb your sleep.", true); // GT prints to the player! if(ply == creature && chan->type != COM_GT) continue; if(ply->isGagging(creature->isPet() ? creature->getMaster()->getName() : creature->getName())) continue; commTarget(creature, ply, chan->type, chan->ooc, lang, text, speak, ooc_str, false); } if(chan->shout) { // Because of multiple exits leading to the same room, we will keep // track of who has heard us shout std::list<Socket*> listeners; std::list<Socket*>::iterator it; bool heard = false; // This allows a player to yell something that will be heard // not only in their room, but also in all rooms adjacent to them. In // the adjacent rooms, however, people will not know who yelled. for(Exit* exit : creature->getRoomParent()->exits) { room = 0; i=0; PlayerSet::iterator pIt, pEnd; // don't shout through closed doors if(!exit->flagIsSet(X_CLOSED)) Move::getRoom(0, exit, &room, true); // the same-room checks aren't run in getRoom because // we don't send a creature. if(room) { if(creature->getParent() && room == creature->getParent()) continue; pIt = room->players.begin(); pEnd = room->players.end(); } else continue; while(pIt != pEnd) { pTarget = (*pIt++); if(!pTarget) continue; pTarget->wake("Loud noises disturb your sleep.", true); if(pTarget->isGagging(creature->getName())) continue; // have they already heard us yell? heard = false; for(it = listeners.begin() ; it != listeners.end() ; it++) { if((*it) == pTarget->getSock()) { heard = true; break; } } if(!heard) { listeners.push_back(pTarget->getSock()); commTarget(creature, pTarget, chan->type, chan->ooc, lang, text, speak, ooc_str, true); } } } listeners.clear(); } if(chan->passphrase) { for(Exit* exit : creature->getRoomParent()->exits) { // got the phrase right? if(exit->getPassPhrase() != "" && exit->getPassPhrase() == text) { // right language? if(!exit->getPassLanguage() || lang == exit->getPassLanguage()) { // even needs to be open? if(exit->flagIsSet(X_LOCKED)) { broadcast(NULL, creature->getRoomParent(), "The %s opens!", exit->getCName()); exit->clearFlag(X_LOCKED); exit->clearFlag(X_CLOSED); if(exit->getOpen() != "") { if(exit->flagIsSet(X_ONOPEN_PLAYER)) { creature->print("%s.\n", exit->getOpen().c_str()); } else { broadcast(0, creature->getRoomParent(), exit->getOpen().c_str()); } } } } } } } } // DMs still broadcast to eaves on GT if(creature->isDm() && chan->type != COM_GT) return(0); if(creature->isPet()) { name = creature->getMaster()->getName() + "'s " + creature->getName(); } else name = creature->getName(); if(chan->type == COM_EMOTE) broadcast(watchingSuperEaves, "^E--- %s %s.", name.c_str(), text.c_str()); else broadcast(watchingSuperEaves, "^E--- %s %s, \"%s%s\" in %s.", name.c_str(), com_text[chan->type], ooc_str, text.c_str(), get_language_adj(lang)); Player* pPlayer = creature->getAsPlayer(); // spam check if(pPlayer) pPlayer->checkForSpam(); return(0); } bstring mxpTag(bstring str) { return( bstring(MXP_BEG) + str + bstring(MXP_END)); } //********************************************************************* // channel //********************************************************************** // This function is used as a base for all global communication channels int channel(Player* player, cmd* cmnd) { bstring text = "", chanStr = "", extra = ""; int i=0, check=0, skip=1; const Guild* guild=0; player->clearFlag(P_AFK); chanStr = cmnd->myCommand->getName(); i = strlen(cmnd->str[1]); // these require special attention - we most provide an // override for the check below if(chanStr == "dmcls" || chanStr == "dmclass") { chanStr = "classsend"; skip = 2; for(check=1; check<CLASS_COUNT-1; check++) if(!strncasecmp(get_class_string(check), cmnd->str[1], i)) break; // these checks are overkill, but it never hurts to be safe: // this will force them to use their own class if(check == DUNGEONMASTER && !player->isDm()) check = 0; if(check == CARETAKER && !player->isCt()) check = 0; } else if(chanStr == "dmrace") { chanStr = "racesend"; skip = 2; for(check=1; check<gConfig->raceCount()-1; check++) if(!strncasecmp(gConfig->getRace(check)->getName().c_str(), cmnd->str[1], i)) break; } else if(chanStr == "dmclan") { chanStr = "clansend"; skip = 2; std::map<int, Clan*>::iterator it; Clan *clan=0; for(it = gConfig->clans.begin() ; it != gConfig->clans.end() ; it++) { clan = (*it).second; if(!strncasecmp(cmnd->str[1], clan->getName().c_str(), i)) { check = clan->getId(); break; } } } if(chanStr == "dmguild") { skip = 2; guild = gConfig->getGuild(player, cmnd->str[1]); if(!guild) return(0); } text = getFullstrText(cmnd->fullstr, skip); if(text == "") { player->print("Send what?\n"); return(0); } text = confusionText(player, text); // this isnt a channel in the list if(chanStr == "dmguild") { doGuildSend(guild, player, text); return(0); } // get us a channel to use! channelPtr chan = NULL; i = 0; while(channelList[i].channelName != NULL) { if( !strcmp(chanStr.c_str(), channelList[i].channelName) && (!channelList[i].canSee || channelList[i].canSee(player)) ) { chan = &channelList[i]; break; } i++; } if(!chan) return(cmdNoExist(player, cmnd)); // get us that extra text we'll be attaching to the front of the message if(chan->type == COM_CLASS) { if(!check) check = player->getClass(); extra = "("; extra += get_class_string(check); if(player->getDeity() && gConfig->classes[get_class_string(check)]->needsDeity()) { extra += ":"; extra += gConfig->getDeity(player->getDeity())->getName(); } extra += ") "; } else if(chan->type == COM_RACE) { if(!check) check = player->getDisplayRace(); extra = "("; extra += gConfig->getRace(check)->getName().c_str(); extra += ") "; } else if(chan->type == COM_CLAN) { if(!player->getClan() && !player->getDeity() && !check) { player->print("You do not belong to a clan or religion.\n"); return(0); } extra = "("; if(!check) { if(player->getDeity()) { check = player->getDeityClan(); extra += gConfig->getDeity(player->getDeity())->getName(); } else { check = player->getClan(); extra += gConfig->getClan(player->getClan())->getName(); } } else extra += gConfig->getClan(check)->getName(); extra += ") "; } // it is up to the canUse function to print out the error message if(chan->canUse && !chan->canUse(player)) //oldPrint(fd, "You are not authorized to use that channel.\n"); return(0); if(chan->maxLevel != -1 && player->getLevel() > chan->maxLevel && !player->isWatcher()) { player->print("You are too high of a level to use that channel.\n"); return(0); } if(chan->minLevel != -1 && player->getLevel() < chan->minLevel && !player->isWatcher()) { player->print("You must be level %d to use the %s channel.\n", chan->minLevel, chan->channelName); return(0); } if(player->flagIsSet(P_GLOBAL_GAG) && !player->isStaff()) { // global gag - don't let them know they're gagged! if(extra != "") player->printColor("%s%s", player->customColorize(chan->color).c_str(), extra.c_str()); player->printColor(player->customColorize(chan->color + chan->displayFmt).c_str(), player, text.c_str()); } else { std::ostringstream eaves; eaves << "--- " << extra << player->getName() << " "; if(chan->type == COM_CLASS) eaves << "class"; else if(chan->type == COM_RACE) eaves << "race"; else if(chan->type == COM_CLAN) eaves << "clan"; eaves << " sent, \"" << text << "\".\n"; bstring etxt = eaves.str(); etxt = escapeColor(etxt); text = escapeColor(text); // more complicated checks go here Player* ply=0; Socket* sock=0; for(std::pair<bstring, Player*> p : gServer->players) { ply = p.second; sock = ply->getSock(); if(!sock->isConnected()) continue; // no gagging staff! if(player && ply->isGagging(player->getName()) && !player->isCt()) continue; // deaf people can always hear staff and themselves if(ply->isEffected("deafness") && !player->isStaff() && ply != player) continue; // must satisfy all the basic canHear rules to hear this channel if( ( (!chan->canHear || chan->canHear(sock)) && (!chan->flag || ply->flagIsSet(chan->flag)) && (!chan->not_flag || !ply->flagIsSet(chan->not_flag)) ) && ( // they must also satisfy any special conditions here (chan->type != COM_CLASS || ply->getClass() == check) && (chan->type != COM_RACE || ply->getDisplayRace() == check) && (chan->type != COM_CLAN || (ply->getDeity() ? ply->getDeityClan() : ply->getClan()) == check) ) ) { if(extra != "") *ply << ColorOn << ply->customColorize(chan->color) << extra << ColorOff; bstring toPrint = chan->displayFmt; bstring icName = player->getCrtStr(ply, ply->displayFlags() | CAP); bstring oocName = player->getName(); bstring prompt = ""; if(ply->getSock()->getTermType().toUpper().find("MUDLET") != bstring::npos) prompt = " PROMPT"; if(ply->canSee(player)) { icName = mxpTag(bstring("player name='") + player->getName() + "'" + prompt ) + icName + mxpTag("/player"); oocName = mxpTag(bstring("player name='") + player->getName() + "'" + prompt) + oocName + mxpTag("/player"); } toPrint.Replace("*IC-NAME*", icName.c_str()); toPrint.Replace("*OOC-NAME*", oocName.c_str()); //std::cout << "ToPrint: " << toPrint << std::endl; if(ply->isStaff() || (player->current_language && ply->isEffected("comprehend-languages")) || ply->languageIsKnown(player->current_language)) { // Listern speaks this language toPrint.Replace("*TEXT*", text.c_str()); } else { // Listern doesn't speak this language toPrint.Replace("*TEXT*", "<something incomprehensible>"); } if(player->current_language != LCOMMON) toPrint += bstring(" in ") + get_language_adj(player->current_language) + "."; *ply << ColorOn << ply->customColorize(chan->color) << toPrint << "\n" << ColorOff; } // even if they fail the check, it might still show up on eaves if( chan->eaves && watchingEaves(sock) && !(chan->type == COM_CLASS && check == DUNGEONMASTER) ) { ply->printColor("^E%s", etxt.c_str()); } } } return(0); } //********************************************************************* // cmdSpeak //********************************************************************* int cmdSpeak(Player* player, cmd* cmnd) { int lang=0; if(!player->ableToDoCommand()) return(0); if(cmnd->num < 2 ) { player->print("Speak what?\n"); return(0); } lowercize(cmnd->str[1],0); switch (cmnd->str[1][0]) { case 'a': switch (cmnd->str[1][1]) { case 'b': lang = LABYSSAL; break; case 'l': lang = 0; break; case 'r': lang = LARCANIC; break; default: player->print("You do not know that language.\n"); return(0); break; } break; case 'b': lang = LBARBARIAN; break; case 'c': switch (cmnd->str[1][1]) { case 'a': lang = LINFERNAL; break; case 'e': lang = LCELESTIAL; break; case 'o': lang = LCOMMON; break; default: player->print("You do not know that language.\n"); return(0); break; } break; case 'd': switch (cmnd->str[1][1]) { case 'a': lang = LDARKELVEN; break; case 'r': lang = LDRUIDIC; break; case 'w': lang = LDWARVEN; break; default: player->print("You do not know that language.\n"); return(0); break; } break; case 'e': lang = LELVEN; break; case 'g': switch (cmnd->str[1][1]) { case 'i': lang = LGIANTKIN; break; case 'n': lang = LGNOMISH; break; case 'o': lang = LGOBLINOID; break; default: player->print("You do not know that language.\n"); return(0); break; } break; case 'h': switch (cmnd->str[1][1]) { case 'u': lang = LCOMMON; break; default: switch (cmnd->str[1][4]) { case 'e': player->print("Half elves have no language of their own.\n"); player->print("They speak the elven or common tongues.\n"); return(0); break; case 'o': player->print("Half orcs have no language of their own.\n"); player->print("They speak the orcish or common tongues.\n"); return(0); break; case 'l': lang = LHALFLING; break; case 'g': lang = LGIANTKIN; break; default: player->print("You do not know that language.\n"); return(0); break; } break; } break; case 'i': lang = LINFERNAL; break; case 'k': switch (cmnd->str[1][1]) { case 'a': lang = LKATARAN; break; case 'o': lang = LKOBOLD; break; default: player->print("You do not know that language.\n"); return(0); break; } break; case 'm': lang = LMINOTAUR; break; case 'o': switch (cmnd->str[1][1]) { case 'g': lang = LOGRISH; break; case 'r': lang = LORCISH; break; default: player->print("You do not know that language.\n"); return(0); break; } break; case 's': switch (cmnd->str[1][1]) { case 'e': lang = LCELESTIAL; break; default: player->print("You do not know that language.\n"); return(0); break; } break; case 't': switch (cmnd->str[1][1]) { case 'i': lang = LTIEFLING; break; case 'r': lang = LTROLL; break; case 'h': lang = LTHIEFCANT; break; default: player->print("You do not know that language.\n"); return(0); break; } break; case 'w': lang = LWOLFEN; break; default: player->print("You do not know that language.\n"); return(0); break; } if(lang == player->current_language) { player->print("You're already speaking %s!\n", get_language_adj(lang)); return(0); } if(!player->isEffected("tongues") && !player->languageIsKnown(LUNKNOWN+lang) && !player->isStaff()) { player->print("You do not know how to speak %s.\n", get_language_adj(lang)); return(0); } else { player->print("You will now speak in %s.\n", get_language_adj(lang)); player->current_language = lang; } return(0); } //********************************************************************* // cmdLanguages //********************************************************************* int cmdLanguages(Player* player, cmd* cmnd) { char str[2048]; // char lang[LANGUAGE_COUNT][32]; int i, j=0; player->print("Currently speaking: %s.\n", get_language_adj(player->current_language)); player->print("Languages known:"); strcpy(str," "); for(i = 0; i < LANGUAGE_COUNT ; i++) { if(player->languageIsKnown(LUNKNOWN + i)) { j++; strcat(str, get_language_adj(i)); strcat(str, ", "); } } if(!j) strcat(str, "None."); else { str[strlen(str) - 2] = '.'; str[strlen(str) - 1] = 0; } player->print("%s\n", str); if(player->isEffected("tongues")) player->printColor("^yYou have the ability to speak any language.\n"); if(player->isEffected("comprehend-languages")) player->printColor("^yYou have the ability to comprehend any language.\n"); return(0); } //********************************************************************* // printForeignTongueMsg //********************************************************************* void printForeignTongueMsg(const BaseRoom *inRoom, Creature *talker) { int lang=0; if(!talker || !inRoom) return; lang = talker->current_language; if(!lang) return; for(Player* ply : inRoom->players) { if(ply->languageIsKnown(lang) || ply->isEffected("comprehend-languages") || ply->isStaff()) { continue; } ply->print("%M says something in %s.\n", talker, get_language_adj(lang)); } } //********************************************************************* // sayTo //********************************************************************* void Monster::sayTo(const Player* player, const bstring& message) { short language = player->current_language; broadcast_rom_LangWc(language, player->getSock(), player->currentLocation, "%M says to %N, \"%s\"^x", this, player, message.c_str()); printForeignTongueMsg(player->getConstRoomParent(), this); player->printColor("%s%M says to you, \"%s\"\n^x",get_lang_color(language), this, message.c_str()); } //********************************************************************* // canCommunicate //********************************************************************* bool canCommunicate(Player* player) { if(player->getClass() == BUILDER) { player->print("You are not allowed to broadcast.\n"); return(false); } // Non staff checks on global communication if(!player->isStaff()) { if(!player->ableToDoCommand()) return(false); if(player->flagIsSet(P_CANT_BROADCAST)) { player->print("Due to abuse, you no longer have that privilage.\n"); return(false); } if(player->inJail()) { player->print("People in jail do not have that privilage.\n"); return(false); } if(player->flagIsSet(P_OUTLAW)) { player->print("You're an outlaw, you don't have that privilage.\n"); return(false); } if(!player->canSpeak()) { player->printColor("^yYour voice is too weak to do that.\n"); return(false); } // spam check if(player->checkForSpam()) return(false); } return(true); } //********************************************************************* // bstring list functions //********************************************************************* int listWrapper(Player* player, cmd* cmnd, const char* gerund, const char* noun, bstring (Player::*show)(void) const, bool (Player::*is)(bstring name) const, void (Player::*del)(bstring name), void (Player::*add)(bstring name), void (Player::*clear)(void)) { Player *target=0; bool online=true; player->clearFlag(P_AFK); if(!player->ableToDoCommand()) return(0); if(cmnd->num == 1) { player->print("You are %s: %s\n", gerund, (player->*show)().c_str()); return(0); } cmnd->str[1][0] = up(cmnd->str[1][0]); if((player->*is)(cmnd->str[1])) { (player->*del)(cmnd->str[1]); player->print("%s removed from your %s list.\n", cmnd->str[1], noun); return(0); } if(cmnd->num == 2) { if(!strcmp(cmnd->str[1], "clear")) { (player->*clear)(); player->print("Cleared.\n"); return(0); } } target = gServer->findPlayer(cmnd->str[1]); if(!target) { loadPlayer(cmnd->str[1], &target); online = false; } if(!target || player == target) { player->print("That player does not exist.\n"); } else if(target->isStaff() && target->getClass() > player->getClass()) { player->print("You cannot %s that player.\n", noun); if(!online) free_crt(target); } else { if(!strcmp(noun, "watch")) { if( !player->inSameGroup(target) && !player->isCt() && !(player->isWatcher() && target->getLevel() <= 4) ) { player->print("%M is not a member of your group.\n", target); if(!online) free_crt(target); return(0); } } (player->*add)(cmnd->str[1]); player->print("%s added to your %s list.\n", target->getCName(), noun); if(!online) free_crt(target); } return(0); } int cmdIgnore(Player* player, cmd* cmnd) { return(listWrapper(player, cmnd, "ignoring", "ignore", &Player::showIgnoring, &Player::isIgnoring, &Player::delIgnoring, &Player::addIgnoring, &Player::clearIgnoring )); } int cmdGag(Player* player, cmd* cmnd) { return(listWrapper(player, cmnd, "gaging", "gag", &Player::showGagging, &Player::isGagging, &Player::delGagging, &Player::addGagging, &Player::clearGagging )); } int cmdRefuse(Player* player, cmd* cmnd) { return(listWrapper(player, cmnd, "refusing", "refuse", &Player::showRefusing, &Player::isRefusing, &Player::delRefusing, &Player::addRefusing, &Player::clearRefusing )); } int cmdWatch(Player* player, cmd* cmnd) { return(listWrapper(player, cmnd, "watching", "watch", &Player::showWatching, &Player::isWatching, &Player::delWatching, &Player::addWatching, &Player::clearWatching )); } //********************************************************************* // dmGag //********************************************************************* int dmGag(Player* player, cmd* cmnd) { Player *target; if(!player->isStaff() && !player->isWatcher()) return(cmdNoExist(player, cmnd)); if(!player->isWatcher()) return(cmdNoAuth(player)); if(cmnd->num < 2) { player->print("\nGlobally gag whom?\n"); return(PROMPT); } lowercize(cmnd->str[1], 1); target = gServer->findPlayer(cmnd->str[1]); if(!target) { player->print("%s is not on.\n", cmnd->str[1]); return(0); } if(target->flagIsSet(P_GLOBAL_GAG)) { player->print("%s is no longer globally gagged.\n", target->getCName()); broadcast(isWatcher, "^C*** %s is no longer globally gagged.", target->getCName()); broadcast(isDm, "^g*** %s turned off %s's global gag.", player->getCName(), target->getCName()); target->clearFlag(P_GLOBAL_GAG); return(0); } if(target->isCt()) { target->printColor("^R%s tried to gag you!\n", player->getCName()); player->print("You can't globally gag a DM or CT.\n"); return(0); } logn("log.gag", "%s was globally gagged by %s.\n", target->getCName(), player->getCName()); target->setFlag(P_GLOBAL_GAG); broadcast(isWatcher, "^C*** %s has been globally gagged.", target->getCName()); broadcast(isDm, "^g*** %s globally gagged %s.", player->getCName(), target->getCName()); return(0); }