/****************************************************************************
* [S]imulated [M]edieval [A]dventure multi[U]ser [G]ame | *
* -----------------------------------------------------------| \\._.// *
* SmaugWiz (C) 1998 by Russ Pillsbury (Windows NT version) | (0...0) *
* -----------------------------------------------------------| ).:.( *
* SMAUG (C) 1994, 1995, 1996 by Derek Snider | {o o} *
* -----------------------------------------------------------| / ' ' \ *
* SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus, |~'~.VxvxV.~'~*
* Scryn, Swordbearer, Rennard, Tricops, and Gorog. | *
* ------------------------------------------------------------------------ *
* Merc 2.1 Diku Mud improvments copyright (C) 1992, 1993 by Michael *
* Chastain, Michael Quan, and Mitchell Tse. *
* Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, *
* Michael Seifert, Hans Henrik Staerfeldt, Tom Madsen, and Katja Nyboe. *
****************************************************************************/
#include "stdafx.h"
#include "smaug.h"
#include "SysData.h"
#include "language.h"
#include "skill.h"
#include "mobiles.h"
#include "objects.h"
#include "rooms.h"
#include "deity.h"
#include "auction.h"
#include "objectmenu.h"
#include "roommenu.h"
#include "mobmenu.h"
#include "sysmenu.h"
#include "playermenu.h"
#include "races.h"
#include "class.h"
#include "SmaugWizDoc.h"
#include "SmaugFiles.h"
#include "descriptor.h"
#include "character.h"
#include <ctype.h>
// Externals
void send_obj_page_to_char (CCharacter * ch, CObjIndexData * idx, char page);
void send_room_page_to_char (CCharacter * ch, CRoomIndexData * idx, char page);
void send_page_to_char (CCharacter * ch, CMobIndexData * idx, char page);
void send_control_page_to_char (CCharacter * ch, char page);
// Local functions.
void talk_channel (CCharacter *ch, char *argument,
int channel, const char *verb);
char *scramble (const char *argument, int modifier);
char *drunk_speech (const char *argument, CCharacter *ch);
int countlangs (const CBitVector& languages);
/* Text scrambler -- Altrag */
char *scramble (const char *argument, int modifier)
{
static char arg[MAX_INPUT_LENGTH];
short position;
short conversion = 0;
modifier %= number_range (80, 300); /* Bitvectors get way too large #s */
for (position = 0; position < MAX_INPUT_LENGTH; position++)
{
if (argument[position] == '\0')
{
arg[position] = '\0';
return arg;
}
else if (argument[position] >= 'A' && argument[position] <= 'Z')
{
conversion = -conversion + position - modifier + argument[position] - 'A';
conversion = number_range (conversion - 5, conversion + 5);
while (conversion > 25)
conversion -= 26;
while (conversion < 0)
conversion += 26;
arg[position] = conversion + 'A';
}
else if (argument[position] >= 'a' && argument[position] <= 'z')
{
conversion = -conversion + position - modifier + argument[position] - 'a';
conversion = number_range (conversion - 5, conversion + 5);
while (conversion > 25)
conversion -= 26;
while (conversion < 0)
conversion += 26;
arg[position] = conversion + 'a';
}
else if (argument[position] >= '0' && argument[position] <= '9')
{
conversion = -conversion + position - modifier + argument[position] - '0';
conversion = number_range (conversion - 2, conversion + 2);
while (conversion > 9)
conversion -= 10;
while (conversion < 0)
conversion += 10;
arg[position] = conversion + '0';
}
else
arg[position] = argument[position];
}
arg[position] = '\0';
return arg;
}
/* I'll rewrite this later if its still needed.. -- Altrag */
char *translate (CCharacter *ch, CCharacter *victim, const char *argument)
{
return "";
}
char *drunk_speech (const char *argument, CCharacter *ch)
{
const char *arg = argument;
static char buf[MAX_INPUT_LENGTH*2];
char buf1[MAX_INPUT_LENGTH*2];
short drunk;
char *txt;
char *txt1;
if (ch->IsNpc () || !ch->GetPcData ()) return (char *) argument;
drunk = ch->GetPcData ()->condition[COND_DRUNK];
if (drunk <= 0)
return (char *) argument;
buf[0] = '\0';
buf1[0] = '\0';
if (!argument)
{
bug ("Drunk_speech: NULL argument", 0);
return "";
}
/*
if (*arg == '\0')
return (char *) argument;
*/
txt = buf;
txt1 = buf1;
while (*arg != '\0')
{
if (toupper (*arg) == 'S')
{
if (number_percent () < (drunk * 2)) /* add 'h' after an 's' */
{
*txt++ = *arg;
*txt++ = 'h';
}
else
*txt++ = *arg;
}
else if (toupper (*arg) == 'X')
{
if (number_percent () < (drunk * 2 / 2))
{
*txt++ = 'c', *txt++ = 's', *txt++ = 'h';
}
else
*txt++ = *arg;
}
else if (number_percent () < (drunk * 2 / 5)) /* slurred letters */
{
short slurn = number_range (1, 2);
short currslur = 0;
while (currslur < slurn)
*txt++ = *arg, currslur++;
}
else
*txt++ = *arg;
arg++;
};
*txt = '\0';
txt = buf;
while (*txt != '\0') /* Let's mess with the string's caps */
{
if (number_percent () < (2 * drunk / 2.5))
{
if (isupper (*txt))
*txt1 = tolower (*txt);
else
if (islower (*txt))
*txt1 = toupper (*txt);
else
*txt1 = *txt;
}
else
*txt1 = *txt;
txt1++, txt++;
};
*txt1 = '\0';
txt1 = buf1;
txt = buf;
while (*txt1 != '\0') /* Let's make them stutter */
{
if (*txt1 == ' ') /* If there's a space, then there's gotta be a */
{ /* along there somewhere soon */
while (*txt1 == ' ') /* Don't stutter on spaces */
*txt++ = *txt1++;
if ((number_percent () < (2 * drunk / 4)) && *txt1 != '\0')
{
short offset = number_range (0, 2);
short pos = 0;
while (*txt1 != '\0' && pos < offset)
*txt++ = *txt1++, pos++;
if (*txt1 == ' ') /* Make sure not to stutter a space after */
{ /* the initial offset into the word */
*txt++ = *txt1++;
continue;
}
pos = 0;
offset = number_range (2, 4);
while (*txt1 != '\0' && pos < offset)
{
*txt++ = *txt1;
pos++;
if (*txt1 == ' ' || pos == offset) /* Make sure we don't stick */
{ /* A hyphen right before a space */
txt1--;
break;
}
*txt++ = '-';
}
if (*txt1 != '\0')
txt1++;
}
}
else
*txt++ = *txt1++;
}
*txt = '\0';
return buf;
}
// Generic channel function.
void talk_channel (CCharacter *ch, char *argument, int channel, const char *verb)
{
char buf [MAX_STRING_LENGTH];
char buf2 [MAX_STRING_LENGTH];
int position;
if (ch->IsNpc () && channel == CHANNEL_CLAN) {
ch->SendText ("Mobs can't be in clans.\n\r");
return;
}
if (ch->IsNpc () && channel == CHANNEL_ORDER) {
ch->SendText ("Mobs can't be in orders.\n\r");
return;
}
if (ch->IsNpc () && channel == CHANNEL_COUNCIL) {
ch->SendText ("Mobs can't be in councils.\n\r");
return;
}
if (ch->IsNpc () && channel == CHANNEL_GUILD) {
ch->SendText ("Mobs can't be in guilds.\n\r");
return;
}
if (! ch->IsPkiller () && channel == CHANNEL_WARTALK) {
if (ch->IsMortal ()) {
ch->SendText ("Peacefuls have no need to use wartalk.\n\r");
return;
}
}
if (ch->GetInRoom ()->IsSilent ()) {
ch->SendText ("You can't do that here.\n\r");
return;
}
if (ch->IsNpc () && ch->IsCharmed ()) {
if (ch->GetMaster ())
ch->GetMaster ()->SendText ("I don't think so...\n\r");
return;
}
if (argument [0] == '\0') {
sprintf (buf, "%s what?\n\r", verb);
buf [0] = UPPER (buf [0]);
ch->SendText (buf);
return;
}
if (! ch->IsNpc () && ch->IsAction (PLR_SILENCE)) {
ch->SendTextf ("You can't %s.\n\r", verb);
return;
}
REMOVE_BIT (ch->deaf, channel);
switch (channel) {
default:
set_char_color (AT_GOSSIP, ch);
ch->SendTextf ("You %s '%s'\n\r", verb, argument);
sprintf (buf, "$n %ss '$t'", verb);
break;
case CHANNEL_RACETALK:
set_char_color (AT_RACETALK, ch);
ch->SendTextf ("You %s '%s'\n\r", verb, argument);
sprintf (buf, "$n %ss '$t'", verb);
break;
case CHANNEL_WARTALK:
set_char_color (AT_WARTALK, ch);
ch->SendTextf ("You %s '%s'\n\r", verb, argument);
sprintf (buf, "$n %ss '$t'", verb);
break;
case CHANNEL_IMMTALK:
case CHANNEL_AVTALK:
sprintf (buf, "$n%c $t", channel == CHANNEL_IMMTALK ? '>' : ':');
position = ch->GetPosition ();
ch->SetPosition (POS_STANDING);
act (AT_IMMORT, buf, ch, argument, NULL, TO_CHAR);
ch->SetPosition (position);
break;
}
if (ch->GetInRoom ()->IsLogSpeech ()) {
sprintf (buf2, "%s: %s (%s)",
ch->IsNpc () ? ch->GetShortDescr () : ch->GetName (),
argument, verb);
append_to_file (FileTable.GetName (SM_LOG_FILE), buf2);
}
POSITION pos = DList.GetHeadPosition ();
while (pos) {
CDescriptor &Ds = *DList.GetNext (pos);
if (Ds.IsDisconnecting ())
continue;
CCharacter *och = Ds.m_pOriginal ? Ds.m_pOriginal : Ds.m_pCharacter;
CCharacter *vch = Ds.m_pCharacter;
if (Ds.m_Connected == CON_PLAYING && vch != ch
&& !IS_SET (och->deaf, channel)) {
char *sbuf = argument;
if (channel != CHANNEL_NEWBIE && !och->IsAuthed ())
continue;
if (channel == CHANNEL_IMMTALK && och->IsMortal ())
continue;
if (channel == CHANNEL_WARTALK && !och->IsAuthed ())
continue;
if (channel == CHANNEL_AVTALK && ! och->IsHero ())
continue;
if (channel == CHANNEL_HIGHGOD
&& och->GetTrustLevel () < SysData.MuseLevel)
continue;
if (channel == CHANNEL_HIGH &&
och->GetTrustLevel () < SysData.ThinkLevel)
continue;
/* Fix by Narn to let newbie council members see the newbie channel. */
if (channel == CHANNEL_NEWBIE &&
(och->IsMortal () && och->IsAuthed ()
&& ! (och->GetPcData ()->council &&
!str_cmp (och->GetPcData ()->council->GetName (),
"Newbie Council"))))
continue;
if (vch->GetInRoom ()->IsSilent ())
continue;
if (channel == CHANNEL_YELL
&& vch->GetInRoom ()->GetArea () != ch->GetInRoom ()->GetArea ())
continue;
if (channel == CHANNEL_CLAN || channel == CHANNEL_ORDER
|| channel == CHANNEL_GUILD) {
if (vch->IsNpc ())
continue;
if (vch->GetPcData ()->GetClan () != ch->GetPcData ()->GetClan ())
continue;
}
if (channel == CHANNEL_COUNCIL) {
if (vch->IsNpc ())
continue;
if (vch->GetPcData ()->council != ch->GetPcData ()->council)
continue;
}
if (channel == CHANNEL_RACETALK)
if (vch->GetRace () != ch->GetRace ())
continue;
CString WizStr;
if (ch->IsWizInvis () && can_see (vch, ch)
&& vch->IsImmortal ()) {
WizStr.Format ("(%d) ", (! ch->IsNpc ()) ?
ch->GetPcData ()->wizinvis : ch->GetMobInvisLevel ());
}
CString OutStr = WizStr + buf;
position = vch->GetPosition ();
if (channel != CHANNEL_SHOUT && channel != CHANNEL_YELL)
vch->SetPosition (POS_STANDING);
if (! knows_language (vch, ch->GetSpeaking (), ch) &&
! ch->IsNpc ())
sbuf = scramble (argument, ch->GetSpeaking ());
MOBtrigger = FALSE;
if (channel == CHANNEL_IMMTALK || channel == CHANNEL_AVTALK)
act (AT_IMMORT, OutStr, ch, sbuf, vch, TO_VICT);
else if (channel == CHANNEL_WARTALK)
act (AT_WARTALK, OutStr, ch, sbuf, vch, TO_VICT);
else if (channel == CHANNEL_RACETALK)
act (AT_RACETALK, OutStr, ch, sbuf, vch, TO_VICT);
else
act (AT_GOSSIP, buf, ch, sbuf, vch, TO_VICT);
vch->SetPosition (position);
}
}
}
void to_channel (const char *argument, int channel, const char *verb, short level)
{
char buf [MAX_STRING_LENGTH];
if (argument [0] == '\0' || DList.IsEmpty ())
return;
sprintf (buf, "%s: %s\r\n", verb, argument);
POSITION pos = DList.GetHeadPosition ();
while (pos) {
CDescriptor &Ds = *DList.GetNext (pos);
if (Ds.IsDisconnecting ())
continue;
CCharacter *och = Ds.m_pOriginal ? Ds.m_pOriginal : Ds.m_pCharacter;
CCharacter *vch = Ds.m_pCharacter;
if (!och || !vch)
continue;
if (vch->IsMortal ()
|| (vch->GetTrustLevel () < SysData.BuildLevel
&& channel == CHANNEL_BUILD)
|| (vch->GetTrustLevel () < SysData.LogLevel
&& (channel == CHANNEL_LOG
|| channel == CHANNEL_HIGH || channel == CHANNEL_COMM)))
continue;
if (Ds.m_Connected == CON_PLAYING
&& !IS_SET (och->deaf, channel)
&& vch->GetTrustLevel () >= level) {
set_char_color (AT_LOG, vch);
vch->SendText (buf);
}
}
}
void do_chat (CCharacter *ch, char *argument)
{
if (!ch->IsAuthed ())
{
ch->SendText ("Huh?\n\r");
return;
}
talk_channel (ch, argument, CHANNEL_CHAT, "chat");
return;
}
void do_clantalk (CCharacter *ch, char *argument)
{
if (!ch->IsAuthed ())
{
ch->SendText ("Huh?\n\r");
return;
}
if (ch->IsNpc () || !ch->GetPcData ()->GetClan ()
|| ch->GetPcData ()->GetClan ()->GetType () == CLAN_ORDER
|| ch->GetPcData ()->GetClan ()->GetType () == CLAN_GUILD)
{
ch->SendText ("Huh?\n\r");
return;
}
talk_channel (ch, argument, CHANNEL_CLAN, "clantalk");
return;
}
void do_newbiechat (CCharacter *ch, char *argument)
{
if (ch->IsNpc ()
|| (ch->IsAuthed () && ch->IsMortal ()
&& ! (ch->GetPcData ()->council &&
!str_cmp (ch->GetPcData ()->council->GetName (), "Newbie Council"))))
{
ch->SendText ("Huh?\n\r");
return;
}
talk_channel (ch, argument, CHANNEL_NEWBIE, "newbiechat");
return;
}
void do_ot (CCharacter *ch, char *argument)
{
do_ordertalk (ch, argument);
}
void do_ordertalk (CCharacter *ch, char *argument)
{
if (!ch->IsAuthed ())
{
ch->SendText ("Huh?\n\r");
return;
}
if (ch->IsNpc () || !ch->GetPcData ()->GetClan ()
|| ch->GetPcData ()->GetClan ()->GetType () != CLAN_ORDER)
{
ch->SendText ("Huh?\n\r");
return;
}
talk_channel (ch, argument, CHANNEL_ORDER, "ordertalk");
return;
}
void do_counciltalk (CCharacter *ch, char *argument)
{
if (!ch->IsAuthed ())
{
ch->SendText ("Huh?\n\r");
return;
}
if (ch->IsNpc () || !ch->GetPcData ()->council)
{
ch->SendText ("Huh?\n\r");
return;
}
talk_channel (ch, argument, CHANNEL_COUNCIL, "counciltalk");
return;
}
void do_guildtalk (CCharacter *ch, char *argument)
{
if (! ch->IsAuthed ()) {
ch->SendText ("Huh?\n\r");
return;
}
if (ch->IsNpc () || !ch->GetPcData ()->GetClan ()
|| ch->GetPcData ()->GetClan ()->GetType () != CLAN_GUILD) {
ch->SendText ("Huh?\n\r");
return;
}
talk_channel (ch, argument, CHANNEL_GUILD, "guildtalk");
}
void do_music (CCharacter *ch, char *argument)
{
if (!ch->IsAuthed ())
{
ch->SendText ("Huh?\n\r");
return;
}
talk_channel (ch, argument, CHANNEL_MUSIC, "music");
return;
}
void do_quest (CCharacter *ch, char *argument)
{
if (!ch->IsAuthed ())
{
ch->SendText ("Huh?\n\r");
return;
}
talk_channel (ch, argument, CHANNEL_QUEST, "quest");
return;
}
void do_ask (CCharacter *ch, char *argument)
{
if (!ch->IsAuthed ())
{
ch->SendText ("Huh?\n\r");
return;
}
talk_channel (ch, argument, CHANNEL_ASK, "ask");
return;
}
void do_answer (CCharacter *ch, char *argument)
{
if (!ch->IsAuthed ())
{
ch->SendText ("Huh?\n\r");
return;
}
talk_channel (ch, argument, CHANNEL_ASK, "answer");
return;
}
void do_shout (CCharacter *ch, char *argument)
{
if (! ch->IsAuthed ()) {
ch->SendText ("Huh?\n\r");
return;
}
talk_channel (ch, drunk_speech (argument, ch), CHANNEL_SHOUT, "shout");
WAIT_STATE (ch, 12);
}
void do_yell (CCharacter *ch, char *argument)
{
if (!ch->IsAuthed ())
{
ch->SendText ("Huh?\n\r");
return;
}
talk_channel (ch, drunk_speech (argument, ch), CHANNEL_YELL, "yell");
return;
}
void do_immtalk (CCharacter *ch, char *argument)
{
if (!ch->IsAuthed ())
{
ch->SendText ("Huh?\n\r");
return;
}
talk_channel (ch, argument, CHANNEL_IMMTALK, "immtalk");
return;
}
void do_muse (CCharacter *ch, char *argument)
{
if (!ch->IsAuthed ())
{
ch->SendText ("Huh?\n\r");
return;
}
talk_channel (ch, argument, CHANNEL_HIGHGOD, "muse");
return;
}
void do_think (CCharacter *ch, char *argument)
{
if (!ch->IsAuthed ())
{
ch->SendText ("Huh?\n\r");
return;
}
talk_channel (ch, argument, CHANNEL_HIGH, "think");
return;
}
void do_avtalk (CCharacter *ch, char *argument)
{
if (!ch->IsAuthed ())
{
ch->SendText ("Huh?\n\r");
return;
}
talk_channel (ch, drunk_speech (argument, ch), CHANNEL_AVTALK, "avtalk");
return;
}
void do_say (CCharacter *ch, char *argument)
{
char buf [MAX_STRING_LENGTH];
if (argument [0] == '\0') {
ch->SendText ("Say what?\n\r");
return;
}
if (ch->GetInRoom ()->IsSilent ()) {
ch->SendText ("You can't do that here.\n\r");
return;
}
CActFlags actflags = ch->GetActFlags (); // save act flags
if (ch->IsNpc ())
ch->ClrActBit (ACT_SECRETIVE);
CCharacter *vch = ch->GetInRoom ()->first_person;
for (; vch; vch = vch->GetNextInRoom ()) {
char *sbuf = argument;
if (vch == ch)
continue;
// Check to see if character is ignoring speaker
if (vch->IsIgnoring (ch)) {
// continue unless speaker is an immortal
if (ch->IsMortal ()
|| vch->GetTrustLevel () > ch->GetTrustLevel ())
continue;
else {
set_char_color (AT_IGNORE, vch);
vch->SendTextf (
"You attempt to ignore %s, but are unable to do so.\n\r",
ch->GetName ());
}
}
if (! knows_language (vch, ch->GetSpeaking (), ch) &&
(! ch->IsNpc () || ! ch->IsSpeaking (LANG_ALL)))
sbuf = scramble (argument, ch->GetSpeaking ());
sbuf = drunk_speech (sbuf, ch);
MOBtrigger = FALSE;
act (AT_SAY, "$n says '$t'", ch, sbuf, vch, TO_VICT);
}
// MOBtrigger = FALSE;
// act (AT_SAY, "$n says '$T'", ch, NULL, argument, TO_ROOM);
ch->SetActFlags (actflags); // restore act flags
MOBtrigger = FALSE;
act (AT_SAY, "You say '$T'", ch, NULL, drunk_speech (argument, ch), TO_CHAR);
if (ch->GetInRoom ()->IsLogSpeech ()) {
sprintf (buf, "%s: %s",
ch->IsNpc () ? ch->GetShortDescr () : ch->GetName (), argument);
append_to_file (FileTable.GetName (SM_LOG_FILE), buf);
}
mprog_speech_trigger (argument, ch);
if (char_died (ch))
return;
oprog_speech_trigger (argument, ch);
if (char_died (ch))
return;
rprog_speech_trigger (argument, ch);
}
void do_tell (CCharacter* ch, char* argument)
{
char arg [MAX_INPUT_LENGTH];
char buf [MAX_INPUT_LENGTH];
CCharacter *victim;
int position;
CCharacter *switched_victim = NULL;
REMOVE_BIT (ch->deaf, CHANNEL_TELLS);
if (ch->GetInRoom ()->IsSilent ()) {
ch->SendText ("You can't do that here.\n\r");
return;
}
if (! ch->IsNpc () && (ch->IsSilent ()) || ch->IsNoTell ()) {
ch->SendText ("You can't do that.\n\r");
return;
}
argument = one_argument (argument, arg);
if (arg [0] == '\0' || argument [0] == '\0') {
ch->SendText ("Tell whom what?\n\r");
return;
}
if ((victim = get_char_world (ch, arg)) == NULL
|| (victim->IsNpc () && victim->GetInRoom () != ch->GetInRoom ())
|| (ch->IsAuthed () && !victim->IsAuthed () && ch->IsMortal ())) {
ch->SendText ("They aren't here.\n\r");
return;
}
if (ch == victim) {
ch->SendText ("You have a nice little chat with yourself.\n\r");
return;
}
if (! ch->IsAuthed () && ! victim->IsAuthed () && victim->IsMortal ()) {
ch->SendText ("They can't hear you because you are not authorized.\n\r");
return;
}
if (! victim->IsNpc () && (victim->switched)
&& (ch->GetTrustLevel () > LEVEL_AVATAR)
&& ! victim->switched->IsPolymorphed ()
&& ! victim->switched->IsPossessed ()) {
ch->SendText ("That player is switched.\n\r");
return;
}
else if (!victim->IsNpc () && (victim->switched)
&& (victim->switched->IsPolymorphed ()
|| victim->switched->IsPossessed ()))
switched_victim = victim->switched;
else if (! victim->IsNpc () && (! victim->GetDesc ())) {
ch->SendText ("That player is link-dead.\n\r");
return;
}
if (! victim->IsNpc () && victim->IsAfk ()) {
ch->SendText ("That player is afk.\n\r");
return;
}
if (IS_SET (victim->deaf, CHANNEL_TELLS)
&& (ch->IsMortal ()
|| (ch->GetTrustLevel () < victim->GetTrustLevel ()))) {
act (AT_PLAIN, "$E has $S tells turned off.", ch, NULL, victim,
TO_CHAR);
return;
}
if (! victim->IsNpc () && victim->IsSilent ()) {
ch->SendText ("That player is silenced. They will receive your "
"message but cannot respond.\n\r");
}
if ((ch->IsMortal () && ! victim->IsAwake ())
|| (! victim->IsNpc () && victim->GetInRoom ()->IsSilent ())) {
act (AT_PLAIN, "$E can't hear you.", ch, 0, victim, TO_CHAR);
return;
}
if (victim->GetDesc () // make sure desc exists first -Thoric
&& victim->GetDesc ()->m_Connected == CON_EDITING
&& ch->GetTrustLevel () < LEVEL_GOD) {
act (AT_PLAIN, "$E is currently in a writing buffer. Please try "
"again in a few minutes.", ch, 0, victim, TO_CHAR);
return;
}
// Check to see if target of tell is ignoring the sender
if (victim->IsIgnoring (ch)) {
// If the sender is an imm then they cannot be ignored
if (ch->IsMortal ()
|| victim->GetTrustLevel () > ch->GetTrustLevel ()) {
set_char_color (AT_IGNORE, ch);
ch->SendTextf ("%s is ignoring you.\n\r", victim->GetName ());
return;
} else {
set_char_color (AT_IGNORE, victim);
victim->SendTextf (
"You attempt to ignore %s, but are unable to do so.\n\r",
ch->GetName ());
}
}
if (switched_victim)
victim = switched_victim;
act (AT_TELL, "You tell $N '$t'", ch, argument, victim, TO_CHAR);
position = victim->GetPosition ();
victim->SetPosition (POS_STANDING);
if (knows_language (victim, ch->GetSpeaking (), ch))
act (AT_TELL, "$n tells you '$t'", ch, argument, victim, TO_VICT);
else
act (AT_TELL, "$n tells you '$t'", ch,
scramble (argument, ch->GetSpeaking ()), victim, TO_VICT);
victim->SetPosition (position);
victim->SetReplier (ch);
if (ch->GetInRoom ()->IsLogSpeech ()) {
sprintf (buf, "%s: %s (tell to) %s.",
ch->IsNpc () ? ch->GetShortDescr () : ch->GetName (), argument,
victim->IsNpc () ? victim->GetShortDescr () : victim->GetName ());
append_to_file (FileTable.GetName (SM_LOG_FILE), buf);
}
mprog_speech_trigger (argument, ch);
}
void do_reply (CCharacter *ch, char *argument)
{
char buf [MAX_STRING_LENGTH];
CCharacter *victim;
int position;
REMOVE_BIT (ch->deaf, CHANNEL_TELLS);
if (ch->GetInRoom ()->IsSilent ()) {
ch->SendText ("You can't do that here.\n\r");
return;
}
if (! ch->IsNpc () && ch->IsSilent ()) {
ch->SendText ("Your message didn't get through.\n\r");
return;
}
if ((victim = ch->GetReplier ()) == NULL) {
ch->SendText ("They aren't here.\n\r");
return;
}
if (! victim->IsNpc () && victim->switched
&& can_see (ch, victim) && (ch->GetTrustLevel () > LEVEL_AVATAR)) {
ch->SendText ("That player is switched.\n\r");
return;
}
else if (! victim->IsNpc () && (! victim->GetDesc ())) {
ch->SendText ("That player is link-dead.\n\r");
return;
}
if (! victim->IsNpc () && victim->IsAfk ()) {
ch->SendText ("That player is afk.\n\r");
return;
}
if (IS_SET (victim->deaf, CHANNEL_TELLS)
&& (ch->IsMortal ()
|| ch->GetTrustLevel () < victim->GetTrustLevel ())) {
act (AT_PLAIN, "$E has $S tells turned off.", ch, NULL, victim,
TO_CHAR);
return;
}
if ((ch->IsMortal () && ! victim->IsAwake ())
|| (!victim->IsNpc () && victim->GetInRoom ()->IsSilent ())) {
act (AT_PLAIN, "$E can't hear you.", ch, 0, victim, TO_CHAR);
return;
}
if (victim->GetDesc () // make sure desc exists first -Thoric
&& victim->GetDesc ()->m_Connected == CON_EDITING
&& ch->GetTrustLevel () < LEVEL_GOD) {
act (AT_PLAIN, "$E is currently in a writing buffer. Please try "
"again in a few minutes.", ch, 0, victim, TO_CHAR);
return;
}
// Check to see if target of tell is ignoring the sender
if (victim->IsIgnoring (ch)) {
// If the sender is an imm then they cannot be ignored
if (ch->IsMortal ()
|| victim->GetTrustLevel () > ch->GetTrustLevel ()) {
set_char_color (AT_IGNORE, ch);
ch->SendTextf ("%s is ignoring you.\n\r", victim->GetName ());
return;
} else {
set_char_color (AT_IGNORE, victim);
victim->SendTextf (
"You attempt to ignore %s, but are unable to do so.\n\r",
ch->GetName ());
}
}
act (AT_TELL, "You tell $N '$t'", ch, argument, victim, TO_CHAR);
position = victim->GetPosition ();
victim->SetPosition (POS_STANDING);
if (knows_language (victim, ch->GetSpeaking (), ch))
act (AT_TELL, "$n tells you '$t'", ch, argument, victim, TO_VICT);
else
act (AT_TELL, "$n tells you '$t'", ch,
scramble (argument, ch->GetSpeaking ()), victim, TO_VICT);
victim->SetPosition (position);
victim->SetReplier (ch);
if (ch->GetInRoom ()->IsLogSpeech ()) {
sprintf (buf, "%s: %s (reply to) %s.",
ch->IsNpc () ? ch->GetShortDescr () : ch->GetName (), argument,
victim->IsNpc () ? victim->GetShortDescr () : victim->GetName ());
append_to_file (FileTable.GetName (SM_LOG_FILE), buf);
}
}
void do_emote (CCharacter *ch, char *argument)
{
char buf [MAX_STRING_LENGTH];
char *plast;
if (! ch->IsNpc () && ch->IsNoEmote ()) {
ch->SendText ("You can't show your emotions.\n\r");
return;
}
if (argument [0] == '\0') {
ch->SendText ("Emote what?\n\r");
return;
}
CActFlags actflags = ch->GetActFlags (); // save act flags
if (ch->IsNpc ())
ch->ClrActBit (ACT_SECRETIVE);
for (plast = argument; *plast != '\0'; plast++)
;
strcpy (buf, argument);
if (isalpha (plast [-1]))
strcat (buf, ".");
CCharacter *vch = ch->GetInRoom ()->first_person;
for (; vch; vch = vch->GetNextInRoom ()) {
char *sbuf = buf;
// Check to see if character is ignoring emoter
if (vch->IsIgnoring (ch)) {
// continue unless emoter is an immortal
if (ch->IsMortal ()
|| vch->GetTrustLevel () > ch->GetTrustLevel ())
continue;
else {
set_char_color (AT_IGNORE, vch);
vch->SendTextf (
"You attempt to ignore %s, but are unable to do so.\n\r",
ch->GetName ());
}
}
if (! knows_language (vch, ch->GetSpeaking (), ch))
sbuf = scramble (buf, ch->GetSpeaking ());
MOBtrigger = FALSE;
act (AT_ACTION, "$n $t", ch, sbuf, vch,
(vch == ch ? TO_CHAR : TO_VICT));
}
ch->SetActFlags (actflags); // restore act flags
if (ch->GetInRoom ()->IsLogSpeech ()) {
sprintf (buf, "%s %s (emote)",
ch->IsNpc () ? ch->GetShortDescr () : ch->GetName (), argument);
append_to_file (FileTable.GetName (SM_LOG_FILE), buf);
}
}
void do_bug (CCharacter *ch, char *argument)
{
append_file (ch, FileTable.GetName (SM_BUG_FILE), argument);
ch->SendText ("Ok. Thanks.\n\r");
return;
}
void do_ide (CCharacter *ch, char *argument)
{
ch->SendText ("If you want to send an idea, type 'idea <message>'.\n\r");
ch->SendText ("If you want to identify an object and have the identify spell,\n\r");
ch->SendText ("Type 'cast identify <object>'.\n\r");
return;
}
void do_idea (CCharacter *ch, char *argument)
{
append_file (ch, FileTable.GetName (SM_IDEA_FILE), argument);
ch->SendText ("Ok. Thanks.\n\r");
return;
}
void do_typo (CCharacter *ch, char *argument)
{
append_file (ch, FileTable.GetName (SM_TYPO_FILE), argument);
ch->SendText ("Ok. Thanks.\n\r");
return;
}
void do_rent (CCharacter *ch, char *argument)
{
set_char_color (AT_WHITE, ch);
ch->SendText ("There is no rent here. Just save and quit.\n\r");
return;
}
void do_qui (CCharacter *ch, char *argument)
{
set_char_color (AT_RED, ch);
ch->SendText ("If you want to QUIT, you have to spell it out.\n\r");
return;
}
void do_quit (CCharacter *ch, char *argument)
{
int x, y;
int level;
if (ch->IsNpc () && ch->IsPolymorphed ()) {
ch->SendText ("You can't quit while polymorphed.\n\r");
return;
}
if (ch->IsNpc ())
return;
if (ch->IsFightPosition ()) {
set_char_color (AT_RED, ch);
ch->SendText ("No way! You are fighting.\n\r");
return;
}
if (ch->GetPosition () < POS_STUNNED) {
set_char_color (AT_BLOOD, ch);
ch->SendText ("You're not DEAD yet.\n\r");
return;
}
if (get_timer (ch, TIMER_RECENTFIGHT) > 0 && ch->IsMortal ()) {
set_char_color (AT_RED, ch);
ch->SendText ("Your adrenaline is pumping too hard to quit now!\n\r");
return;
}
if (auction->IsActive () && ((ch == auction->GetBuyer ())
|| (ch == auction->GetSeller ()))) {
ch->SendText ("Wait until you have bought/sold the item on auction.\n\r");
return;
}
if (ch->IsPkiller ()
&& ch->GetWimpLevel () > (int) ch->GetMaxHp () / 2.25) {
ch->SendText ("Your wimpy has been adjusted to the maximum level"
" for deadlies.\n\r");
do_wimpy (ch, "max");
}
// Get 'em dismounted until we finish mount saving -- Blodkai, 4/97
if (ch->IsMounted ())
do_dismount (ch, "");
set_char_color (AT_WHITE, ch);
ch->SendText ("Your surroundings begin to fade as a mystical swirling "
"vortex of colors\n\renvelops your body... When you come to, things"
" are not as they were.\n\r\n\r");
act (AT_SAY, "A strange voice says, 'We await your return, $n...'", ch, NULL, NULL, TO_CHAR);
act (AT_BYE, "$n has left the game.", ch, NULL, NULL, TO_ROOM);
set_char_color (AT_GREY, ch);
sprintf (log_buf, "%s has quit.", ch->GetName ());
quitting_char = ch;
save_char_obj (ch);
if (ch->HasPet ()) {
act (AT_BYE, "$N follows $S master into the Void.", ch, NULL,
ch->GetPet (), TO_ROOM);
extract_char (ch->GetPet (), TRUE);
}
// Synch clandata up only when clan member quits now. --Shaddai
if (ch->GetPcData ()->GetClan ())
ch->GetPcData ()->GetClan ()->Save ();
saving_char = NULL;
level = ch->GetTrustLevel ();
// After extract_char the ch is no longer valid!
extract_char (ch, TRUE);
for (x = 0; x < MAX_WEAR; ++x)
for (y = 0; y < MAX_LAYERS; ++y)
save_equipment [x][y] = NULL;
gpDoc->LogString (log_buf, LOG_COMM, level);
}
void send_rip_screen (CCharacter *ch)
{
FILE *rpfile;
int num=0;
char BUFF[MAX_STRING_LENGTH*2];
if ((rpfile = fopen (FileTable.GetName (SM_RIPSCREEN_FILE),"r")) !=NULL) {
while ((BUFF[num]=fgetc (rpfile)) != EOF)
num++;
fclose (rpfile);
BUFF[num] = 0;
ch->GetDesc ()->WriteToBuffer (BUFF, num);
}
}
void send_rip_title (CCharacter *ch)
{
FILE *rpfile;
int num=0;
char BUFF[MAX_STRING_LENGTH*2];
if ((rpfile = fopen (FileTable.GetName (SM_RIPTITLE_FILE),"r")) !=NULL) {
while ((BUFF[num]=fgetc (rpfile)) != EOF)
num++;
fclose (rpfile);
BUFF[num] = 0;
ch->GetDesc ()->WriteToBuffer (BUFF,num);
}
}
void send_ansi_title (CCharacter *ch)
{
FILE *rpfile;
int num=0;
char buf [MAX_STRING_LENGTH*2];
if (rpfile = fopen (FileTable.GetName (SM_ANSITITLE_FILE), "r")) {
while ((buf [num] = fgetc (rpfile)) != EOF)
++num;
fclose (rpfile);
buf [num] = 0;
ch->SendColor (buf);
}
}
void send_ascii_title (CCharacter *ch)
{
FILE *rpfile;
int num=0;
char BUFF[MAX_STRING_LENGTH];
if ((rpfile = fopen (FileTable.GetName (SM_ASCTITLE_FILE),"r")) !=NULL) {
while ((BUFF[num]=fgetc (rpfile)) != EOF)
num++;
fclose (rpfile);
BUFF[num] = 0;
ch->GetDesc ()->WriteToBuffer (BUFF,num);
}
}
void do_omenu (CCharacter *ch, char *argument)
{
CObjData *obj;
char arg1 [MAX_INPUT_LENGTH];
char arg2 [MAX_INPUT_LENGTH];
smash_tilde (argument);
argument = one_argument (argument, arg1);
argument = one_argument (argument, arg2);
if (arg1 [0] == '\0') {
ch->SendText ("Syntax: omenu <object> [page] \n\r");
ch->SendText (" Where: <object> is a prototype object \n\r");
ch->SendText (" and <page> is an optional letter to select menu-pages\n\r");
return;
}
if ((obj = get_obj_world (ch, arg1)) == NULL) {
ch->SendText ("It isn't here.\n\r");
return;
}
if (ch->IsMenuActive ())
ch->RemoveMenu ();
CObjectMenu *pOmenu = new CObjectMenu (*obj);
ch->SetMenu (pOmenu);
ch->DisplayMenu (arg2 [0]);
}
void do_rmenu (CCharacter *ch, char *argument)
{
char arg1 [MAX_INPUT_LENGTH];
smash_tilde (argument);
argument = one_argument (argument, arg1);
if (ch->IsMenuActive ())
ch->RemoveMenu ();
CRoomIndexData *idx = ch->GetInRoom ();
CRoomMenu *pRmenu = new CRoomMenu (*idx);
ch->SetMenu (pRmenu);
ch->DisplayMenu (arg1 [0]);
}
void do_cmenu (CCharacter *ch, char *argument)
{
char arg1 [MAX_INPUT_LENGTH];
smash_tilde (argument);
argument = one_argument (argument, arg1);
if (ch->IsMenuActive ())
ch->RemoveMenu ();
CSystemMenu *pCmenu = new CSystemMenu (SysData);
ch->SetMenu (pCmenu);
ch->DisplayMenu (arg1 [0]);
}
void do_mmenu (CCharacter *ch, char *argument)
{
CCharacter *victim;
char arg1 [MAX_INPUT_LENGTH];
char arg2 [MAX_INPUT_LENGTH];
smash_tilde (argument);
argument = one_argument (argument, arg1);
argument = one_argument (argument, arg2);
if (arg1 [0] == '\0') {
ch->SendText ("Syntax: mmenu <victim> [page] \n\r");
ch->SendText (" Where: <victim> is a prototype mob \n\r");
ch->SendText (" and <page> is an optional letter to select menu-pages\n\r");
return;
}
if ((victim = get_char_world (ch, arg1)) == NULL) {
ch->SendText ("They aren't here.\n\r");
return;
}
if (! victim->IsNpc ()) {
ch->SendText ("Not on players.\n\r");
return;
}
if (ch->GetTrustLevel () < victim->GetLevel ()) {
set_char_color (AT_IMMORT, ch);
ch->SendText ("Their godly glow prevents you from getting a good look .\n\r");
return;
}
if (ch->IsMenuActive ())
ch->RemoveMenu ();
CMobMenu *pMmenu = new CMobMenu (*victim);
ch->SetMenu (pMmenu);
ch->DisplayMenu (arg2 [0]);
}
void do_pmenu (CCharacter *ch, char *argument)
{
char arg1 [MAX_INPUT_LENGTH];
char arg2 [MAX_INPUT_LENGTH];
smash_tilde (argument);
argument = one_argument (argument, arg1);
argument = one_argument (argument, arg2);
if (arg1 [0] == '\0') {
ch->SendText ("Syntax: pmenu <victim> [page] \n\r");
ch->SendText (" Where: <victim> is an off-line player \n\r");
ch->SendText (" and <page> is an optional letter to select menu-pages\n\r");
return;
}
// check the world for an exact match
CCharacter *vict;
for (vict = first_char; vict; vict = vict->GetNext ())
if (! stricmp (vict->GetName (), arg1)) {
ch->SendText ("Sorry, That player is on-line.\r\n");
return;
}
CPlayerMenu *pMenu = new CPlayerMenu;
if (! pMenu->Load (*ch, arg1)) {
ch->SendTextf ("No Player File for %s.\r\n", arg1);
delete pMenu;
return;
}
if (ch->IsMenuActive ())
ch->RemoveMenu ();
ch->SetMenu (pMenu);
ch->DisplayMenu (arg2 [0]);
}
void do_rip (CCharacter *ch, char *argument)
{
char arg[MAX_INPUT_LENGTH];
one_argument (argument, arg);
if (arg[0] == '\0')
{
ch->SendText ("Rip ON or OFF?\n\r");
return;
}
if (! str_cmp (arg,"on")) {
send_rip_screen (ch);
ch->SetActBit (PLR_RIP);
ch->SetActBit (PLR_ANSI);
return;
}
if (! str_cmp (arg,"off")) {
ch->ClrActBit (PLR_RIP);
ch->SendText ("!|*\n\rRIP now off...\n\r");
return;
}
}
void do_ansi (CCharacter *ch, char *argument)
{
char arg[MAX_INPUT_LENGTH];
one_argument (argument, arg);
if (arg[0] == '\0')
{
ch->SendText ("ANSI ON or OFF?\n\r");
return;
}
if ((str_cmp (arg,"on")==0) || (str_cmp (arg,"ON") == 0)) {
ch->SetActBit (PLR_ANSI);
set_char_color (AT_WHITE + AT_BLINK, ch);
ch->SendText ("ANSI ON!!!\n\r");
return;
}
if ((str_cmp (arg,"off")==0) || (str_cmp (arg,"OFF") == 0)) {
ch->ClrActBit (PLR_ANSI);
ch->SendText ("Okay... ANSI support is now off\n\r");
return;
}
}
void do_save (CCharacter *ch, char *argument)
{
if (ch->IsNpc () && ch->IsPolymorphed ()) {
ch->SendText ("You can't save while polymorphed.\n\r");
return;
}
if (ch->IsNpc ())
return;
if (ch->GetLevel () < 2) {
set_char_color (AT_BLUE, ch);
ch->SendColor ("&BYou must be at least second level to save.\n\r");
return;
}
CRaceData &Ra = *RaceTable.GetRaceData (ch->GetRace ());
ch->SetAffectBits (Ra.GetAffectFlags ());
ch->SetResist (Ra.resist);
ch->SetSusceptible (Ra.suscept);
if (ch->GetPcData ()->deity) {
ch->SetAffectBits (ch->GetPcData ()->deity->m_Affected);
ch->SetResist (ch->GetPcData ()->deity->element);
ch->SetSusceptible (ch->GetPcData ()->deity->suscept);
}
save_char_obj (ch);
saving_char = NULL;
ch->SendText ("Ok.\n\r");
}
/*
* Something from original DikuMUD that Merc yanked out.
* Used to prevent following loops, which can cause problems if people
* follow in a loop through an exit leading back into the same room
* (Which exists in many maze areas) -Thoric
*/
BOOL circle_follow (CCharacter *ch, CCharacter *victim)
{
CCharacter *tmp;
for (tmp = victim; tmp; tmp = tmp->GetMaster ())
if (tmp == ch)
return TRUE;
return FALSE;
}
void do_dismiss (CCharacter* ch, char* argument)
{
char arg [MAX_INPUT_LENGTH];
CCharacter *victim;
one_argument (argument, arg);
if (arg [0] == '\0') {
ch->SendText ("Dismiss whom?\n\r");
return;
}
if ((victim = get_char_room (ch, arg)) == NULL) {
ch->SendText ("They aren't here.\n\r");
return;
}
if (victim->IsCharmed () && victim->IsNpc ()
&& victim->GetMaster () == ch) {
stop_follower (victim);
stop_hating (victim);
stop_hunting (victim);
stop_fearing (victim);
act (AT_ACTION, "$n dismisses $N.", ch, NULL, victim, TO_NOTVICT);
act (AT_ACTION, "You dismiss $N.", ch, NULL, victim, TO_CHAR);
}
else ch->SendText ("You cannot dismiss them.\n\r");
}
void do_follow (CCharacter *ch, char *argument)
{
char arg[MAX_INPUT_LENGTH];
CCharacter *victim;
one_argument (argument, arg);
if (arg[0] == '\0')
{
ch->SendText ("Follow whom?\n\r");
return;
}
if ((victim = get_char_room (ch, arg)) == NULL)
{
ch->SendText ("They aren't here.\n\r");
return;
}
if (ch->IsCharmed () && ch->GetMaster ())
{
act (AT_PLAIN, "But you'd rather follow $N!", ch, NULL, ch->GetMaster (), TO_CHAR);
return;
}
if (victim == ch)
{
if (!ch->GetMaster ())
{
ch->SendText ("You already follow yourself.\n\r");
return;
}
stop_follower (ch);
return;
}
if ((ch->GetLevel () - victim->GetLevel () < -10 || ch->GetLevel () - victim->GetLevel () > 10)
&& ! ch->IsHero ())
{
ch->SendText ("You are not of the right caliber to follow.\n\r");
return;
}
if (circle_follow (ch, victim))
{
ch->SendText ("Following in loops is not allowed... sorry.\n\r");
return;
}
if (ch->GetMaster ())
stop_follower (ch);
add_follower (ch, victim);
return;
}
void add_follower (CCharacter *ch, CCharacter *master)
{
if (ch->GetMaster ()) {
bug ("Add_follower: non-null master.");
return;
}
ch->SetMaster (master);
ch->SetLeader (NULL);
// Support for saving pets --Shaddai
if (ch->IsNpc () && ch->IsPet () && ! master->IsNpc ())
master->SetPet (ch);
if (can_see (master, ch))
act (AT_ACTION, "$n now follows you.", ch, NULL, master, TO_VICT);
act (AT_ACTION, "You now follow $N.", ch, NULL, master, TO_CHAR);
}
void stop_follower (CCharacter *ch)
{
if (! ch->GetMaster ()) {
bug ("Stop_follower: null master.");
return;
}
CCharacter &Master = *ch->GetMaster ();
if (ch->IsNpc () && ! Master.IsNpc () && Master.GetPet () == ch)
Master.SetPet (NULL);
if (ch->IsCharmed ()) {
ch->ClrCharmed ();
affect_strip (ch, gsn_charm_person);
}
if (can_see (&Master, ch))
act (AT_ACTION, "$n stops following you.", ch, NULL, &Master, TO_VICT);
act (AT_ACTION, "You stop following $N.", ch, NULL, &Master, TO_CHAR);
ch->SetMaster (NULL);
ch->SetLeader (NULL);
}
void die_follower (CCharacter *ch)
{
CCharacter *fch;
if (ch->GetMaster ())
stop_follower (ch);
ch->SetLeader (NULL);
for (fch = first_char; fch; fch = fch->GetNext ()) {
if (fch->GetMaster () == ch)
stop_follower (fch);
if (fch->GetLeader () == ch)
fch->SetLeader (fch);
}
}
void do_order (CCharacter *ch, char *argument)
{
char arg [MAX_INPUT_LENGTH];
char argbuf [MAX_INPUT_LENGTH];
CCharacter *victim;
CCharacter *och;
CCharacter *och_next;
BOOL found;
BOOL fAll;
strcpy (argbuf, argument);
argument = one_argument (argument, arg);
if (arg [0] == '\0' || argument [0] == '\0') {
ch->SendText ("Order whom to do what?\n\r");
return;
}
if (ch->IsCharmed ()) {
ch->SendText ("You feel like taking, not giving, orders.\n\r");
return;
}
if (! str_cmp (arg, "all")) {
fAll = TRUE;
victim = NULL;
} else {
fAll = FALSE;
if ((victim = get_char_room (ch, arg)) == NULL) {
ch->SendText ("They aren't here.\n\r");
return;
}
if (victim == ch) {
ch->SendText ("Aye aye, right away!\n\r");
return;
}
if (! victim->IsCharmed () || victim->GetMaster () != ch) {
ch->SendText ("Do it yourself!\n\r");
return;
}
}
found = FALSE;
for (och = ch->GetInRoom ()->first_person; och; och = och_next) {
och_next = och->GetNextInRoom ();
if (och->IsCharmed () && och->GetMaster () == ch
&& (fAll || och == victim)) {
found = TRUE;
act (AT_ACTION, "$n orders you to '$t'.", ch, argument, och, TO_VICT);
interpret (och, argument);
}
}
if (found) {
sprintf (log_buf, "%s: order %s.", ch->GetName (), argbuf);
gpDoc->LogString (log_buf, LOG_PLAYER, ch->GetLevel ());
ch->SendText ("Ok.\n\r");
WAIT_STATE (ch, 12);
}
else
ch->SendText ("You have no followers here.\n\r");
}
void do_group (CCharacter *ch, char *argument)
{
char arg [MAX_INPUT_LENGTH];
CCharacter *victim;
one_argument (argument, arg);
if (arg[0] == '\0') {
CCharacter *gch;
CCharacter *leader;
leader = ch->GetLeader () ? ch->GetLeader () : ch;
set_char_color (AT_GREEN, ch);
ch->SendTextf ("%s's group:\n\r", PERS (leader, ch));
// Changed so that no info revealed on possess
for (gch = first_char; gch; gch = gch->GetNext ()) {
if (is_same_group (gch, ch)) {
set_char_color (AT_DGREEN, ch);
if (gch->IsPossessed ())
ch->SendTextf (
"[%2d %s] %-16s %4s/%4s hp %4s/%4s %s %4s/%4s "
"mv %5s xp\n\r", gch->GetLevel (), gch->IsNpc () ?
"Mob" : ClassTable.GetName (gch->GetClass ()),
capitalize (PERS (gch, ch)),
"????", "????", "????", "????",
gch->IsVampire () ? "bp" : "mana",
"????", "????", "?????");
else
ch->SendTextf (
"[%2d %s] %-16s %4d/%4d hp %4d/%4d %s %4d/%4d "
"mv %5d xp\n\r", gch->GetLevel (), gch->IsNpc () ?
"Mob" : ClassTable.GetName (gch->GetClass ()),
capitalize (PERS (gch, ch)), gch->GetHp (),
gch->GetMaxHp (), gch->IsVampire () ?
gch->GetPcData ()->condition[COND_BLOODTHIRST]
: gch->GetMana (),
gch->IsVampire () ?
10 + gch->GetLevel () : gch->GetMaxMana (),
gch->IsVampire () ? "bp" : "mana",
gch->GetMove (), gch->GetMaxMove (), gch->GetExp ());
}
}
return;
}
if (!str_cmp (arg, "disband")) {
CCharacter *gch;
int count = 0;
if (ch->GetLeader () || ch->GetMaster ()) {
ch->SendText ("You cannot disband a group if you're "
"following someone.\n\r");
return;
}
for (gch = first_char; gch; gch = gch->GetNext ()) {
if (is_same_group (ch, gch) && (ch != gch)) {
gch->SetLeader (NULL);
gch->SetMaster (NULL);
count++;
gch->SendText ("Your group is disbanded.\n\r");
}
}
if (count == 0)
ch->SendText ("You have no group members to disband.\n\r");
else
ch->SendText ("You disband your group.\n\r");
return;
}
if (!str_cmp (arg, "all")) {
CCharacter *rch;
int count = 0;
for (rch = ch->GetInRoom ()->first_person; rch;
rch = rch->GetNextInRoom ()) {
if (ch != rch && !rch->IsNpc () && can_see (ch, rch)
&& rch->GetMaster () == ch && !ch->GetMaster ()
&& !ch->GetLeader ()
&& abs (ch->GetLevel () - rch->GetLevel ()) < 8
&& !is_same_group (rch, ch)
&& ch->IsPkiller () == rch->IsPkiller ()) {
rch->SetLeader (ch);
count++;
}
}
if (count == 0)
ch->SendText ("You have no eligible group members.\n\r");
else {
act (AT_ACTION, "$n groups $s followers.", ch, NULL,NULL,TO_ROOM);
ch->SendText ("You group your followers.\n\r");
}
return;
}
if ((victim = get_char_room (ch, arg)) == NULL) {
ch->SendText ("They aren't here.\n\r");
return;
}
if (ch->GetMaster () || (ch->GetLeader () && ch->GetLeader () != ch)) {
ch->SendText ("But you are following someone else!\n\r");
return;
}
if (victim->GetMaster () != ch && ch != victim) {
act (AT_PLAIN, "$N isn't following you.", ch, NULL, victim, TO_CHAR);
return;
}
if (is_same_group (victim, ch) && ch != victim) {
victim->SetLeader (NULL);
act (AT_ACTION, "$n removes $N from $s group.", ch, NULL, victim, TO_NOTVICT);
act (AT_ACTION, "$n removes you from $s group.", ch, NULL, victim, TO_VICT );
act (AT_ACTION, "You remove $N from your group.", ch, NULL, victim, TO_CHAR );
return;
}
if (ch->GetLevel () - victim->GetLevel () < -8
|| ch->GetLevel () - victim->GetLevel () > 8
|| (ch->IsPkiller () != victim->IsPkiller ())) {
act (AT_PLAIN, "$N cannot join $n's group.", ch, NULL, victim, TO_NOTVICT);
act (AT_PLAIN, "You cannot join $n's group.", ch, NULL, victim, TO_VICT );
act (AT_PLAIN, "$N cannot join your group.", ch, NULL, victim, TO_CHAR );
return;
}
victim->SetLeader (ch);
act (AT_ACTION, "$N joins $n's group.", ch, NULL, victim, TO_NOTVICT);
act (AT_ACTION, "You join $n's group.", ch, NULL, victim, TO_VICT );
act (AT_ACTION, "$N joins your group.", ch, NULL, victim, TO_CHAR );
}
/*
* 'Split' originally by Gnort, God of Chaos.
*/
void do_split (CCharacter *ch, char *argument)
{
char buf[MAX_STRING_LENGTH];
char arg[MAX_INPUT_LENGTH];
CCharacter *gch;
int members;
int amount;
int share;
int extra;
one_argument (argument, arg);
if (arg[0] == '\0')
{
ch->SendText ("Split how much?\n\r");
return;
}
amount = atoi (arg);
if (amount < 0)
{
ch->SendText ("Your group wouldn't like that.\n\r");
return;
}
if (amount == 0)
{
ch->SendText ("You hand out zero coins, but no one notices.\n\r");
return;
}
if (ch->GetGold () < amount)
{
ch->SendText ("You don't have that much gold.\n\r");
return;
}
members = 0;
for (gch = ch->GetInRoom ()->first_person; gch; gch = gch->GetNextInRoom ())
{
if (is_same_group (gch, ch))
members++;
}
if ((ch->IsAction (PLR_AUTOGOLD)) && (members < 2))
return;
if (members < 2)
{
ch->SendText ("Just keep it all.\n\r");
return;
}
share = amount / members;
extra = amount % members;
if (share == 0)
{
ch->SendText ("Don't even bother, cheapskate.\n\r");
return;
}
ch->AddGold (-amount);
ch->AddGold (share + extra);
set_char_color (AT_GOLD, ch);
ch->SendTextf (
"You split %d gold coins. Your share is %d gold coins.\n\r",
amount, share + extra);
sprintf (buf, "$n splits %d gold coins. Your share is %d gold coins.",
amount, share);
for (gch = ch->GetInRoom ()->first_person; gch; gch = gch->GetNextInRoom ())
{
if (gch != ch && is_same_group (gch, ch))
{
act (AT_GOLD, buf, ch, NULL, gch, TO_VICT);
gch->AddGold (share);
}
}
}
void do_gtell (CCharacter *ch, char *argument)
{
CCharacter *gch;
if (argument[0] == '\0')
{
ch->SendText ("Tell your group what?\n\r");
return;
}
if (ch->IsAction (PLR_NO_TELL))
{
ch->SendText ("Your message didn't get through!\n\r");
return;
}
// Note use of CCharacter.SendText, so gtell works on sleepers.
// sprintf (buf, "%s tells the group '%s'.\n\r", ch->GetName (), argument);
for (gch = first_char; gch; gch = gch->GetNext ()) {
if (is_same_group (gch, ch)) {
set_char_color (AT_GTELL, gch);
// Groups unscrambled regardless of clan language.
// Other languages still garble though. -- Altrag
if (knows_language (gch, ch->GetSpeaking (), gch))
gch->SendTextf ("%s tells the group '%s'.\n\r",
ch->GetName (), argument);
else
gch->SendTextf ("%s tells the group '%s'.\n\r",
ch->GetName (),
scramble (argument, ch->GetSpeaking ()));
}
}
}
/*
* It is very important that this be an equivalence relation:
* (1) A ~ A
* (2) if A ~ B then B ~ A
* (3) if A ~ B and B ~ C, then A ~ C
*/
BOOL is_same_group (CCharacter *ach, CCharacter *bch)
{
if (ach->GetLeader ()) ach = ach->GetLeader ();
if (bch->GetLeader ()) bch = bch->GetLeader ();
return ach == bch;
}
// this function sends raw argument over the AUCTION: channel
// I am not too sure if this method is right..
void talk_auction (const char *argument)
{
char buf [MAX_STRING_LENGTH];
sprintf (buf, "Auction: %s", argument); // last %s to reset color
POSITION pos = DList.GetHeadPosition ();
while (pos) {
CDescriptor &Ds = *DList.GetNext (pos);
if (Ds.IsDisconnecting ())
continue;
CCharacter *ch = Ds.m_pOriginal ? Ds.m_pOriginal : Ds.m_pCharacter; // if switched
if (Ds.m_Connected == CON_PLAYING
&& !IS_SET (ch->deaf, CHANNEL_AUCTION)
&& ! ch->GetInRoom ()->IsSilent ()
&& ch->IsAuthed ())
act (AT_GOSSIP, buf, ch, NULL, NULL, TO_CHAR);
}
}
// Language support functions. -- Altrag
// 07/01/96
BOOL knows_language (CCharacter *victim, int language, CCharacter *ch)
{
short sn;
// everyone KNOWS common tongue
if (language == LanguageTable.GetCommon () || ch->IsSpeaking (LANG_ALL))
return TRUE;
if (! victim->IsNpc () && victim->IsImmortal ())
return TRUE;
// SpeaksLanguage returns TRUE if speaking all.
if (victim->IsNpc () && victim->SpeaksLanguage (language))
return TRUE;
if (language == LanguageTable.GetClan ()) {
// Clan = common for mobs.. snicker.. -- Altrag
if (victim->IsNpc () || ch->IsNpc ())
return TRUE;
if (victim->GetPcData ()->GetClan () == ch->GetPcData ()->GetClan () &&
victim->GetPcData ()->GetClan () != NULL)
return TRUE;
}
if (! victim->IsNpc ()) {
// Racial languages for PCs
if (RaceTable.CanSpeak (victim->GetRace (), language))
return TRUE;
if (victim->SpeaksLanguage (language)) {
sn = SkillTable.Lookup (LanguageTable.GetName (language));
if (sn != -1 && victim->GetPcData ()->learned [sn] >= 60)
return TRUE;
}
}
return FALSE;
}
// This function is unused and may not be functional
BOOL can_learn_lang (CCharacter *ch, int language)
{
if (language == LanguageTable.GetClan ())
return FALSE;
if (ch->IsNpc () || ch->IsImmortal ())
return FALSE;
if (RaceTable.CanSpeak (ch->GetRace (), language))
return FALSE;
CLanguage &La = *LanguageTable.GetLanguageData (language);
if (ch->SpeaksLanguage (language)) {
if (La.CanLearn ()) {
int sn = SkillTable.Lookup (La.GetName ());
if (sn < 0)
bug ("Can_learn_lang: valid language without sn: %s:%d",
NCCP La.GetName (), language);
if (ch->GetPcData ()->learned [sn] >= 99)
return FALSE;
}
}
return La.CanLearn ();
}
int countlangs (const CBitVector& languages)
{
int numlangs = 0;
for (int lang=1; lang < LanguageTable.GetCount (); ++lang) {
if (lang != LanguageTable.GetClan () && languages.IsSet (lang))
++numlangs;
}
return numlangs;
}
void do_speak (CCharacter *ch, char *argument)
{
char arg [MAX_INPUT_LENGTH];
argument = one_argument (argument, arg);
if (! str_cmp (arg, "all") && ch->IsImmortal ()) {
set_char_color (AT_SAY, ch);
ch->SetSpeaking (LANG_ALL);
ch->SendText ("Now speaking all languages.\n\r");
return;
}
BOOL bKnow = FALSE;
CLanguage &La = *LanguageTable.Find (arg);
if (&La)
bKnow = knows_language (ch, La.GetLanguage (), ch);
if (bKnow) {
ch->SetSpeaking (La.GetLanguage ());
set_char_color (AT_SAY, ch);
ch->SendTextf ("You now speak %s.\n\r", NCCP La.GetName ());
} else {
set_char_color (AT_SAY, ch);
ch->SendText ("You do not know that language.\n\r");
}
}
void do_languages (CCharacter *ch, char *argument)
{
char arg [MAX_INPUT_LENGTH];
argument = one_argument (argument, arg);
if (arg [0] != '\0' && !str_prefix (arg, "learn") &&
ch->IsMortal () && !ch->IsNpc ()) {
CCharacter *sch;
char arg2 [MAX_INPUT_LENGTH];
int sn;
int prct;
int prac;
argument = one_argument (argument, arg2);
if (arg2 [0] == '\0') {
ch->SendText ("Learn which language?\n\r");
return;
}
CLanguage &La = *LanguageTable.Find (arg2);
if (! &La) {
ch->SendText ("That is not a language.\n\r");
return;
}
if (! La.CanLearn ()) {
ch->SendText ("You may not learn that language.\n\r");
return;
}
if ((sn = SkillTable.Lookup (La.GetName ())) < 0) {
ch->SendText ("That is not a language.\n\r");
return;
}
int lang = La.GetLanguage ();
if (RaceTable.CanSpeak (ch->GetRace (), lang) ||
lang == LanguageTable.GetCommon () ||
ch->GetPcData ()->learned [sn] >= 99) {
act (AT_PLAIN, "You are already fluent in $t.", ch,
NCCP La.GetName (), NULL, TO_CHAR);
return;
}
for (sch = ch->GetInRoom ()->first_person; sch; sch = sch->GetNextInRoom ())
if (sch->IsNpc () && sch->IsAction (ACT_SCHOLAR) &&
// if the mob knows the language you are speaking, and
// he knows the language you want to learn, and if you
// know the language the mob is speaking...
knows_language (sch, ch->GetSpeaking (), ch) &&
knows_language (sch, lang, sch) &&
knows_language (ch, sch->GetSpeaking (), sch))
break;
if (! sch) {
ch->SendText (
"There is no one who can teach that language here.\n\r");
return;
}
if (countlangs (ch->GetSpeaksFlags ()) >= (ch->GetLevel () / 10) &&
ch->GetPcData ()->learned [sn] <= 0) {
act (AT_TELL, "$n tells you 'You may not learn a new language yet.'",
sch, NULL, ch, TO_VICT);
return;
}
// 0..16 cha = 2 pracs, 17..25 = 1 prac. -- Altrag
prac = 2 - (get_curr_cha (ch) / 17);
if (ch->GetPractices () < prac) {
act (AT_TELL, "$n tells you 'You do not have enough practices.'",
sch, NULL, ch, TO_VICT);
return;
}
ch->AddPractices (-prac);
// Max 12% (5 + 4 + 3) at 24+ int and 21+ wis. -- Altrag
prct = 5 + (ch->GetIntelligence () / 6) + (ch->GetWisdom () / 7);
ch->GetPcData ()->learned [sn] += prct;
ch->GetPcData ()->learned [sn] =
UMIN (ch->GetPcData ()->learned [sn], 99);
ch->SetSpeaks (lang);
if (ch->GetPcData ()->learned [sn] == prct)
act (AT_PLAIN, "You begin lessons in $t.", ch,
NCCP La.GetName (), NULL, TO_CHAR);
else if (ch->GetPcData ()->learned [sn] < 60)
act (AT_PLAIN, "You continue lessons in $t.", ch,
NCCP La.GetName (), NULL, TO_CHAR);
else if (ch->GetPcData ()->learned [sn] < 60 + prct)
act (AT_PLAIN, "You feel you can start communicating in $t.", ch,
NCCP La.GetName (), NULL, TO_CHAR);
else if (ch->GetPcData ()->learned [sn] < 99)
act (AT_PLAIN, "You become more fluent in $t.", ch,
NCCP La.GetName (), NULL, TO_CHAR);
else
act (AT_PLAIN, "You now speak perfect $t.", ch,
NCCP La.GetName (), NULL, TO_CHAR);
return;
}
for (int lang=0; lang < LanguageTable.GetCount (); ++lang)
if (knows_language (ch, lang, ch)) {
if (ch->IsSpeaking (lang)
|| (ch->IsNpc () && ch->IsSpeaking (LANG_ALL)))
set_char_color (AT_RED, ch);
else
set_char_color (AT_SAY, ch);
ch->SendText (LanguageTable.GetName (lang));
ch->SendText (" ");
}
ch->SendText ("\n\r");
}
void do_wartalk (CCharacter* ch, char* argument)
{
if (! ch->IsAuthed ()) {
ch->SendText ("Huh?\n\r");
return;
}
talk_channel (ch, argument, CHANNEL_WARTALK, "war");
}
void do_racetalk (CCharacter* ch, char* argument)
{
if (! ch->IsAuthed ()) {
ch->SendText ("Huh?\n\r");
return;
}
talk_channel (ch, argument, CHANNEL_RACETALK, "racetalk");
}