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