/*
* 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-2009 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 getFullstrText(bstring str, int skip, char toSkip, bool colorEscape) {
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(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;
ctag *cp=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]);
std::pair<bstring, Player*> p;
Player* ply;
foreach(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(!strcmp(ply->name, cmnd->str[1])) {
target = ply;
break;
}
if(!strncmp(ply->name, 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->name, target->himHer());
else
player->print("%s is ignoring everyone.\n", target->name);
return(0);
}
// staff can always message AFK people
if( target->flagIsSet(P_AFK) &&
!player->checkStaff("%s is currently afk.\n", target->name))
return(0);
if(chan->type != COM_SIGN && target->isEffected("deafness") && !player->isStaff()) {
player->print("%s is deaf and cannot hear anything.\n", target->name);
return(0);
}
if( target->isIgnoring(player->name) &&
!target->checkStaff("%s is ignoring you.\n", target->name)
)
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->name);
return(0);
}
}
} else {
if( !target->languageIsKnown(LUNKNOWN+player->current_language) &&
!player->isStaff()
) {
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->getRoom(), "%M whispers something to %N.", player, target);
if(!target->isGagging(player->name)) {
target->printColor("%s%s%M %s%s, \"%s%s\".\n",
target->customColorize("*CC:TELL*"),
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->name, target->name, text.c_str());
}
// sign doesnt use reply anyway
if(chan->type != COM_SIGN) {
if(!target->isStaff() &&
( ( player->flagIsSet(P_INCOGNITO) && !player->inSameRoom(target) ) ||
( player->isInvisible() && !target->isEffected("detect-invisible") ) ||
( player->flagIsSet(P_MISTED) && !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()->name);
} else if(player->flagIsSet(P_IGNORE_ALL)) {
player->print("You are ignoring all, as such they will be unable to respond.\n");
}
} else {
cp = player->getRoom()->first_ply;
while(cp) {
if(cp->crt != player && cp->crt != target &&
!cp->crt->isEffected("blindness")) {
if(cp->crt->getRace() == DARKELF || cp->crt->isStaff())
cp->crt->print("%M signed, \"%s\" to %N.\n", player, text.c_str(), target);
else
cp->crt->print("%M signed something in dark elven to %N.\n", player, target);
}
cp = cp->next_tag;
}
}
if(player->isDm() || target->isDm())
return(0);
broadcast(watchingEaves, "^E--- %s %s to %s, \"%s%s\".", player->name,
com_text[chan->type], target->name, ooc_str, text.c_str());
player->bug("%s %s, \"%s%s\" to %s.\n", player->name,
com_text[chan->type], ooc_str, text.c_str(), target->name);
target->bug("%s %s, \"%s%s\" to %s.\n", player->name,
com_text[chan->type], ooc_str, text.c_str(), target->name);
if(chan->type != COM_SIGN)
target->setLastCommunicate(player->name);
return(0);
}
//*********************************************************************
// commTarget
//*********************************************************************
// function that does the actual printing of message for below
void commTarget(Creature* player, Player* target, int type, bool ooc, char 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->name, 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*") << "### ";
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->name, 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->name, speak.c_str(), get_language_adj(lang));
}
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, *target=0;
Player* pTarget=0;
AreaRoom* aRoom=0;
Room *new_rom=0;
int i=0;
char speak[35], lang, ooc_str[10];
ctag *cp=0;
xtag *xp=0;
if(creature->isPet())
owner = creature->following;
else
owner = creature;
player = owner->getConstPlayer();
// 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));
// GT uses their leader's pointer to find the people we're talking
// to while everything else uses the room pointer
if(chan->type == COM_GT) {
cp = creature->first_fol;
if(cp)
target = cp->crt;
if( (!creature->following && !creature->first_fol) ||
(target && target->isPlayer() && target->flagIsSet(P_DM_INVIS) && !target->flagIsSet(P_INCOGNITO))
) {
creature->print("You are not in a group.\n");
return(0);
}
target = (creature->following ? creature->following : creature);
cp = target->first_fol;
commTarget(creature, target->getPlayer(), chan->type, chan->ooc, lang, text, speak, ooc_str, false);
} else {
cp = creature->getRoom()->first_ply;
creature->unhide();
}
// GT prints to the leader above
if(chan->type != COM_GT) {
if(chan->type == COM_EMOTE) {
creature->printColor("You emote: %s.\n", text.c_str());
player->bug("%s emoted: %s.\n", creature->name, 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));
if(!chan->ooc && creature->flagIsSet(P_LANGUAGE_COLORS))
ANSI(creature->getSock(), get_lang_color(lang));
creature->printColor("%s \"%s%s\"^x.\n", intro, ooc_str, text.c_str());
player->bug("%s %s in %s, \"%s%s.\"\n", creature->name, com_text[chan->type],
get_language_adj(lang), ooc_str, text.c_str());
}
}
while(cp) {
pTarget = cp->crt->getPlayer();
cp = cp->next_tag;
if(!pTarget)
continue;
if(chan->shout)
pTarget->wake("Loud noises disturb your sleep.", true);
// GT prints to the player!
if(pTarget == creature && chan->type != COM_GT)
continue;
if(pTarget->isGagging(creature->isPet() ? creature->following->name : creature->name))
continue;
commTarget(creature, pTarget, 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.
xp = creature->getRoom()->first_ext;
while(xp) {
aRoom = 0;
new_rom = 0;
i=0;
cp=0;
// don't shout through closed doors
if(!xp->ext->flagIsSet(X_CLOSED))
Move::getRoom(0, xp->ext, &new_rom, &aRoom, true);
xp = xp->next_tag;
// the same-room checks aren't run in getRoom because
// we don't send a creature.
if(aRoom) {
if(creature->area_room && aRoom == creature->area_room)
continue;
cp = aRoom->first_ply;
} else if(new_rom) {
if(creature->parent_rom && new_rom == creature->parent_rom)
continue;
cp = new_rom->first_ply;
} else
continue;
while(cp) {
pTarget = cp->crt->getPlayer();
cp = cp->next_tag;
if(!pTarget)
continue;
pTarget->wake("Loud noises disturb your sleep.", true);
if(pTarget->isGagging(creature->name))
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) {
xp = creature->getRoom()->first_ext;
while(xp) {
// got the phrase right?
if(xp->ext->getPassPhrase() != "" && xp->ext->getPassPhrase() == text) {
// right language?
if(!xp->ext->getPassLanguage() || lang == xp->ext->getPassLanguage()) {
// even needs to be open?
if(xp->ext->flagIsSet(X_LOCKED)) {
broadcast(NULL, creature->getRoom(), "The %s opens!", xp->ext->name);
xp->ext->clearFlag(X_LOCKED);
xp->ext->clearFlag(X_CLOSED);
if(xp->ext->getOpen() != "") {
if(xp->ext->flagIsSet(X_ONOPEN_PLAYER)) {
creature->print("%s.\n", xp->ext->getOpen().c_str());
} else {
broadcast(0, creature->getRoom(), xp->ext->getOpen().c_str());
}
}
}
}
}
xp = xp->next_tag;
}
}
// DMs still broadcast to eaves on GT
if(creature->isDm() && chan->type != COM_GT)
return(0);
if(creature->isPet()) {
name = creature->following->name;
name += "'s ";
name += creature->name;
} else
name = creature->name;
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->getPlayer();
// spam check
if(pPlayer)
pPlayer->checkForSpam();
return(0);
}
//*********************************************************************
// 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;
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;
// 0 = not found, -1 = not unique
check = 0;
std::map<int, Guild*>::iterator it;
for(it = gConfig->guilds.begin(); it != gConfig->guilds.end(); it++) {
if((*it).second->name.left(i).toLower() == cmnd->str[1]) {
if(!check) {
check = 1;
guild = (*it).second;
} else
check = -1;
}
}
if(!check) {
player->print("Guild not found.\n");
return(0);
} else if(check == -1) {
player->print("Guild name was not unique.\n");
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), extra.c_str());
player->printColor(player->customColorize(chan->color + chan->displayFmt), player, text.c_str());
} else {
std::ostringstream eaves;
eaves << "--- " << extra << player->name << " ";
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
std::pair<bstring, Player*> p;
Player* ply=0;
Socket* sock=0;
foreach(p, gServer->players) {
ply = p.second;
sock = ply->getSock();
if(!sock->isConnected())
continue;
// no gagging staff!
if(player && ply->isGagging(player->name) && !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->printColor("%s%s", ply->customColorize(chan->color), extra.c_str());
ply->printColor(ply->customColorize(chan->color + chan->displayFmt), player, text.c_str());
ply->print("\n");
}
// 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());
}
}
}
// TODO: Maybe put languages back in
//oldPrint(fd, "You are using the '%s' channel!\n", chanStr.c_str());
// } else {
// for(a=0;a<Tablesize;a++) {
// if(!Ply[a].ply)
// continue;
//
// if(is_gag_ply(player->name, Ply[a].ply))
// continue;
//
// if(Ply[a].ply->flagIsSet(P_NO_BROADCASTS))
// continue;
//
// if(Ply[a].ply->isStaff() || (Ply[a].ply->isEffected("comprehend-languages") && player->current_language)) {
// if(Ply[a].ply->flagIsSet(P_LANGUAGE_COLORS) && player->current_language != LCOMMON)
// ANSI(Ply[a].ply->fd, get_lang_color(player->current_language));
//
// if(player->current_language == LCOMMON)
// oldPrint(Ply[a].ply->fd, "### %M broadcasted, \"%s\"\n", player, &cmnd->fullstr[i+1]);
// else
// oldPrint(Ply[a].ply->fd, "### %M broadcasted, \"%s\" in %s.\n",
// player, &cmnd->fullstr[i+1], get_language_adj(player->current_language));
//
//
// } else {
// if(!Ply[a].ply->languageIsKnown(LUNKNOWN+player->current_language)) {
// oldPrint(Ply[a].ply->fd, "### %M broadcasted something in %s.\n", player, get_language_adj(player->current_language));
// } else {
// if(Ply[a].ply->flagIsSet(P_LANGUAGE_COLORS) && player->current_language != LCOMMON )
// ANSI(Ply[a].ply->fd, get_lang_color(player->current_language));
// if(player->current_language == LCOMMON)
// oldPrint(Ply[a].ply->fd, "### %M broadcasted, \"%s\"\n", player, &cmnd->fullstr[i+1]);
// else
// oldPrint(Ply[a].ply->fd, "### %M broadcasted, \"%s\" in %s.\n",
// player, &cmnd->fullstr[i+1], get_language_adj(player->current_language));
//
// }
// }
//
// ANSI(Ply[a].ply->fd, getMainTextColor());
//
// }// end for
// }
//
// player->bug("%s broadcasted, \"%s\" in %s.\n",
// player->name, &cmnd->fullstr[i+1], get_language_adj(player->current_language));
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(BaseRoom *inRoom, Creature *talker) {
ctag *cp = 0;
int lang=0;
if(!talker || !inRoom)
return;
lang = talker->current_language;
if(!lang)
return;
cp = inRoom->first_ply;
while(cp) {
if(cp->crt->languageIsKnown(lang) || cp->crt->isEffected("comprehend-languages") || cp->crt->isStaff()) {
cp = cp->next_tag;
continue;
}
cp->crt->print("%M says something in %s.\n", talker, get_language_adj(lang));
cp = cp->next_tag;
}
}
//*********************************************************************
// 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( !in_group(player, target->name) &&
!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->name, 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->name);
broadcast(isWatcher, "^C*** %s is no longer globally gagged.", target->name);
broadcast(isDm, "^g*** %s turned off %s's global gag.", player->name, target->name);
target->clearFlag(P_GLOBAL_GAG);
return(0);
}
if(target->isCt()) {
target->printColor("^R%s tried to gag you!\n", player->name);
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->name, player->name);
target->setFlag(P_GLOBAL_GAG);
broadcast(isWatcher, "^C*** %s has been globally gagged.", target->name);
broadcast(isDm, "^g*** %s globally gagged %s.", player->name, target->name);
return(0);
}