/****************************************************************************
* AFKMud Copyright 1997-2002 Alsherok. Contributors: Samson, Dwip, Whir, *
* Cyberfox, Karangi, Rathian, Cam, Raine, and Tarl. *
* Original SMAUG 1.4a written by Thoric (Derek Snider) with Altrag, *
* Blodkai, Haus, Narn, Scryn, Swordbearer, Tricops, Gorog, Rennard, *
* Grishnakh, Fireblade, and Nivek. *
* Original MERC 2.1 code by Hatchet, Furey, and Kahn. *
* Original DikuMUD code by: Hans Staerfeldt, Katja Nyboe, Tom Madsen, *
* Michael Seifert, and Sebastian Hammer. *
****************************************************************************
* Dynamic Channel System *
****************************************************************************/
#include <stdarg.h>
#include <sys/types.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#ifdef REGEX
#include <regex.h>
#endif
#ifdef FREEBSD
#include <unistd.h>
#include <regex.h>
#endif
#include "h/key.h"
#include "h/mud.h"
#include "h/files.h"
#include "h/channels.h"
#include "h/languages.h"
#include "h/clans.h"
#include "h/city.h"
#include "h/polymorph.h"
#ifdef REGEX
extern int re_exec _RE_ARGS((const char *));
#endif
MUD_CHANNEL *first_channel;
MUD_CHANNEL *last_channel;
const char *const chan_types[] = {
"Global", "Zone", "Alliance", "Council", "PK", "Log", "Room", "Secret", "Throng",
"Halcyon", "Paleon", "Dakar", "Forbidden"
};
int get_chantypes(char *name)
{
unsigned int x;
for(x = 0; x < (sizeof(chan_types) / sizeof(chan_types[0])); x++)
if(!str_cmp(chan_types[x], name))
return x;
return -1;
}
/* Provided by Remcon to stop crashes with channel history */
char *add_percent(char *str)
{
static char newstr[MSL];
int i, j;
for(i = j = 0; str[i] != '\0'; i++)
{
if(str[i] == '%')
newstr[j++] = '%';
newstr[j++] = str[i];
}
newstr[j] = '\0';
return newstr;
}
void read_channel(MUD_CHANNEL * channel, FILE * fp)
{
const char *word;
bool fMatch;
for(;;)
{
word = feof(fp) ? "End" : fread_word(fp);
fMatch = FALSE;
switch (UPPER(word[0]))
{
case '*':
fMatch = TRUE;
fread_to_eol(fp);
break;
case 'C':
KEY("ChanName", channel->name, fread_string(fp));
KEY("ChanLevel", channel->level, fread_number(fp));
KEY("ChanType", channel->type, fread_number(fp));
KEY("ChanHistory", channel->keephistory, fread_number(fp));
break;
case 'D':
KEY("DoScramble", channel->doscramble, fread_number(fp));
break;
case 'E':
if(!str_cmp(word, "End"))
return;
break;
}
if(!fMatch)
{
bug("read_channel: no match: %s", word);
fread_to_eol(fp);
}
}
}
void load_mudchannels(void)
{
FILE *fp;
MUD_CHANNEL *channel;
first_channel = NULL;
last_channel = NULL;
log_string("Loading mud channels...");
if((fp = FileOpen(CHANNEL_FILE, "r")) == NULL)
{
log_string("No channel file found.");
return;
}
for(;;)
{
char letter;
char *word;
letter = fread_letter(fp);
if(letter == '*')
{
fread_to_eol(fp);
continue;
}
if(letter != '#')
{
bug("%s", "load_channels: # not found.");
break;
}
word = fread_word(fp);
if(!str_cmp(word, "CHANNEL"))
{
CREATE(channel, MUD_CHANNEL, 1);
read_channel(channel, fp);
LINK(channel, first_channel, last_channel, next, prev);
continue;
}
else if(!str_cmp(word, "END"))
break;
else
{
bug("load_channels: bad section: %s.", word);
continue;
}
}
FileClose(fp);
return;
}
void save_mudchannels(void)
{
FILE *fp;
MUD_CHANNEL *channel;
if((fp = FileOpen(CHANNEL_FILE, "w")) == NULL)
{
log_string("Couldn't write to channel file.");
return;
}
for(channel = first_channel; channel; channel = channel->next)
{
if(channel->name)
{
fprintf(fp, "#CHANNEL\n");
fprintf(fp, "ChanName %s~\n", channel->name);
fprintf(fp, "ChanLevel %d\n", channel->level);
fprintf(fp, "ChanType %d\n", channel->type);
fprintf(fp, "ChanHistory %d\n", channel->keephistory);
fprintf(fp, "DoScramble %d\n", channel->doscramble);
fprintf(fp, "End\n\n");
}
}
fprintf(fp, "#END\n");
FileClose(fp);
}
MUD_CHANNEL *find_channel(const char *name)
{
MUD_CHANNEL *channel = NULL;
for(channel = first_channel; channel; channel = channel->next)
{
if(!str_cmp(channel->name, name))
return channel;
}
return NULL;
}
void do_makechannel(CHAR_DATA *ch, char *argument)
{
MUD_CHANNEL *channel;
if(!argument || argument[0] == '\0')
{
send_to_char("&GSyntax: makechannel <name>\r\n", ch);
return;
}
if((channel = find_channel(argument)))
{
send_to_char("&RA channel with that name already exists.\r\n", ch);
return;
}
CREATE(channel, MUD_CHANNEL, 1);
channel->name = STRALLOC(argument);
channel->level = LEVEL_IMMORTAL;
channel->type = CHAN_GLOBAL;
channel->keephistory = FALSE;
channel->doscramble = FALSE;
LINK(channel, first_channel, last_channel, next, prev);
ch_printf(ch, "&YNew channel &G%s &Ycreated.\r\n", argument);
save_mudchannels();
return;
}
void do_setchannel(CHAR_DATA *ch, char *argument)
{
MUD_CHANNEL *channel;
char arg[MIL], arg2[MIL], arg3[MIL];
if(!argument || argument[0] == '\0')
{
send_to_char("&GSyntax: setchannel <channel> <field> <value>\r\n\r\n", ch);
send_to_char("&YField may be one of the following:\r\n", ch);
send_to_char("name level type history invite\r\n", ch);
return;
}
argument = one_argument(argument, arg);
if(!(channel = find_channel(arg)))
{
send_to_char("&RNo channel by that name exists.\r\n", ch);
return;
}
argument = one_argument(argument, arg2);
if(!arg || arg2[0] == '\0')
{
do_setchannel(ch, (char *)"");
return;
}
if(!str_cmp(arg2, "name"))
{
ch_printf(ch, "&YChannel &G%s &Yrenamed to &G%s\r\n", channel->name, argument);
STRFREE(channel->name);
channel->name = STRALLOC(argument);
save_mudchannels();
return;
}
if(!str_cmp(arg2, "level"))
{
int level;
if(!is_number(argument))
{
send_to_char("&RLevel must be numerical.\r\n", ch);
return;
}
level = atoi(argument);
if(level < 1 || level > MAX_LEVEL)
{
ch_printf(ch, "&RInvalid level. Acceptable range is 1 to %d.\r\n", MAX_LEVEL);
return;
}
channel->level = level;
ch_printf(ch, "&YChannel &G%s &Ylevel changed to &G%d\r\n", channel->name, level);
save_mudchannels();
return;
}
// working in the 6d channel for selected private users. -Taon
argument = one_argument(argument, arg3);
if(!str_cmp(arg2, "invite"))
{
CHAR_DATA *victim;
if(!is_number(arg3) && (victim = get_char_world(ch, arg3)))
{
if(str_cmp(ch->name, "Vladaar"))
{
send_to_char("Only the game admin can invite others to this channel.\r\n", ch);
return;
}
}
if(arg3[0] == '\0')
{
send_to_char("You must select a target.\r\n", ch);
return;
}
if((victim = get_char_world(ch, arg3)) == NULL)
{
send_to_char("That player doesn't exist.\r\n", ch);
return;
}
if(victim->chan_invite != 1)
victim->chan_invite = 1;
else // toggle off. -Taon
{
victim->chan_invite = 0;
ch_printf(victim, "&wYou've been removed from &Y%s&w channel.&d\r\n", channel->name);
ch_printf(ch, "&wYou removed %s from the &Y%s&w channel.&d\r\n", victim->name, channel->name);
return;
}
ch_printf(victim, "&wYou've been invited to join the &Y%s&w channel. Usually, only the Game Admin, and Heads of Councils may use this channel.&d\r\n", channel->name);
ch_printf(ch, "&wYou invited %s to join the &Y%s&w channel.&d\r\n", victim->name, channel->name);
interpret(victim, (char *)"listen 6d");
return;
}
if(!str_cmp(arg2, "type"))
{
int type = get_chantypes(arg3);
if(type == -1)
{
send_to_char("&RInvalid channel type.\r\n", ch);
return;
}
channel->type = type;
send_to_char("New type set.\r\n", ch);
save_mudchannels();
return;
}
if(!str_cmp(arg2, "history"))
{
channel->keephistory = !channel->keephistory;
if(channel->keephistory)
ch_printf(ch, "&YChannel &G%s &Ywill now keep a history.\r\n", channel->name);
else
ch_printf(ch, "&YChannel &G%s &Ywill no longer keep a history.\r\n", channel->name);
save_mudchannels();
return;
}
if(!str_cmp(arg2, "scramble"))
{
channel->doscramble = !channel->doscramble;
if(channel->doscramble)
ch_printf(ch, "&YChannel &G%s &Ywill now scramble the text by languages.\r\n", channel->name);
else
ch_printf(ch, "&YChannel &G%s &Ywill no longer scramble the text.\r\n", channel->name);
save_mudchannels();
return;
}
do_setchannel(ch, (char *)"");
}
void do_destroychannel(CHAR_DATA *ch, char *argument)
{
MUD_CHANNEL *channel;
if(!argument || argument[0] == '\0')
{
send_to_char("&GSyntax: destroychannel <name>\r\n", ch);
return;
}
if(!(channel = find_channel(argument)))
{
send_to_char("&RNo channel with that name exists.\r\n", ch);
return;
}
STRFREE(channel->name);
UNLINK(channel, first_channel, last_channel, next, prev);
DISPOSE(channel);
ch_printf(ch, "&YChannel &G%s &Ydestroyed.\r\n", argument);
save_mudchannels();
return;
}
void do_showchannels(CHAR_DATA *ch, char *argument)
{
MUD_CHANNEL *channel;
send_to_char("&WName &YLevel &BType &GHistory? &GScramble?\r\n", ch);
send_to_char("&W--------------------------------------------------------\r\n", ch);
for(channel = first_channel; channel; channel = channel->next)
ch_printf(ch, "&W%-18s &Y%-4d &B%-10s &G%8s &G%9s\r\n", capitalize(channel->name),
channel->level, chan_types[channel->type], channel->keephistory ? "Yes" : "No", channel->doscramble ? "Yes" : "No");
}
/* Stuff borrowed from I3/MUD-Net code to handle channel listening */
/* changetarg: extract a single argument (with given max length) from
* argument to arg; if arg==NULL, just skip an arg, don't copy it out
*/
const char *getarg(const char *argument, char *arg, int length)
{
int len = 0;
while(*argument && isspace(*argument))
argument++;
if(arg)
while(*argument && !isspace(*argument) && len < length - 1)
*arg++ = *argument++, len++;
else
while(*argument && !isspace(*argument))
argument++;
while(*argument && !isspace(*argument))
argument++;
while(*argument && isspace(*argument))
argument++;
if(arg)
*arg = 0;
return argument;
}
/* Check for a name in a list */
int hasname(const char *list, const char *name)
{
const char *p;
char arg[MIL];
if(!list)
return (0);
p = getarg(list, arg, MIL);
while(arg[0])
{
if(!strcasecmp(name, arg))
return 1;
p = getarg(p, arg, MIL);
}
return 0;
}
/* Add a name to a list */
void addname(char **list, const char *name)
{
char buf[MSL];
if(hasname(*list, name))
return;
if(*list && *list[0] != '\0')
snprintf(buf, MSL, "%s %s", *list, name);
else
mudstrlcpy(buf, name, MSL);
if(*list)
STRFREE(*list);
*list = STRALLOC(buf);
}
/* Remove a name from a list */
void removename(char **list, const char *name)
{
char buf[MSL];
char arg[MIL];
const char *p;
buf[0] = 0;
p = getarg(*list, arg, MIL);
while(arg[0])
{
if(strcasecmp(arg, name))
{
if(buf[0])
mudstrlcat(buf, " ", MSL);
mudstrlcat(buf, arg, MSL);
}
p = getarg(p, arg, MIL);
}
STRFREE(*list);
*list = STRALLOC(buf);
}
void do_listen(CHAR_DATA *ch, char *argument)
{
MUD_CHANNEL *channel;
if(IS_NPC(ch))
{
send_to_char("Mobs can't use this command.\r\n", ch);
return;
}
if(!argument || argument[0] == '\0')
{
send_to_char("&GSyntax: listen \r\n", ch);
send_to_char("&GSyntax: listen all\r\n", ch);
send_to_char("&GSyntax: listen none\r\n", ch);
send_to_char("&GFor a list of channels, type &Wchannels\r\n", ch);
send_to_char("&YYou are listening to the following local mud channels:\r\n\r\n", ch);
ch_printf(ch, "&W%s\r\n", ch->pcdata->chan_listen);
return;
}
if(!str_cmp(argument, "all"))
{
for(channel = first_channel; channel; channel = channel->next)
{
if(((ch->level >= channel->level) || (ch->trust >= channel->level)) && !hasname(ch->pcdata->chan_listen, channel->name))
addname(&ch->pcdata->chan_listen, channel->name);
}
send_to_char("&YYou are now listening to all available channels.\r\n", ch);
return;
}
if(!str_cmp(argument, "none"))
{
for(channel = first_channel; channel; channel = channel->next)
{
if(((ch->level >= channel->level) || (ch->trust >= channel->level)) && hasname(ch->pcdata->chan_listen, channel->name))
removename(&ch->pcdata->chan_listen, channel->name);
}
channel = find_channel("say");
addname(&ch->pcdata->chan_listen, channel->name);
/*
* Volk - still should listen to the SAY channel
*/
send_to_char("&YYou no longer listen to any available channel.\r\n", ch);
return;
}
if(hasname(ch->pcdata->chan_listen, argument))
{
if(!str_cmp(argument, "say") && !IS_IMMORTAL(ch))
{
send_to_char("Mortals can not turn off the SAY channel.\r\n", ch);
return;
}
removename(&ch->pcdata->chan_listen, argument);
ch_printf(ch, "&YYou no longer listen to &W%s\r\n", argument);
}
else
{
if(!(channel = find_channel(argument)))
{
send_to_char("No such channel.\r\n", ch);
return;
}
if((channel->level > ch->level) && (channel->level > ch->trust))
{
send_to_char("That channel is above your level.\r\n", ch);
return;
}
addname(&ch->pcdata->chan_listen, argument);
ch_printf(ch, "&YYou now listen to &W%s\r\n", channel->name);
}
return;
}
/* Revised channel display by Zarius */
void do_channels(CHAR_DATA *ch, char *argument)
{
MUD_CHANNEL *channel;
if(IS_NPC(ch))
{
send_to_char("Mobs can't use this command.\r\n", ch);
return;
}
send_to_char("&YThe following channels are available:\r\n", ch);
send_to_char("To toggle a channel, use the &Wlisten &Ycommand.\r\n\r\n", ch);
send_to_char("&WChannel On/Off&D\r\n", ch);
send_to_char("&B-----------------------&D\r\n", ch);
for(channel = first_channel; channel; channel = channel->next)
{
if((ch->level >= channel->level) || (ch->trust >= channel->level))
{
ch_printf(ch, "&w%-17s%s&D\r\n", capitalize(channel->name), (hasname(ch->pcdata->chan_listen, channel->name)) ? "&GOn" : "&ROff");
}
}
send_to_char("\r\n", ch);
}
void invert(char *arg1, char *arg2)
{
int i = 0;
int len = strlen(arg1) - 1;
while(i <= len)
{
*(arg2 + i) = *(arg1 + (len - i));
i++;
}
*(arg2 + i) = '\0';
}
/* Duplicate of to_channel from act_comm.c modified for dynamic channels */
void send_tochannel(CHAR_DATA *ch, MUD_CHANNEL * channel, char *argument)
{
char buf[MSL], buf2[MSL], col[MIL], word[MIL];
char logbuf[MSL];
char *arg, *socbuf_char = NULL, *socbuf_vict = NULL, *socbuf_other = NULL;
CHAR_DATA *victim = NULL;
SOCIALTYPE *social = NULL;
CHAR_DATA *vch = NULL;
int position, x;
short color;
struct tm *local;
time_t t;
bool emote = FALSE;
if(!ch)
return;
#ifndef SCRAMBLE
int speaking = -1, lang;
for(lang = 0; lang_array[lang] != LANG_UNKNOWN; lang++)
if(ch->speaking & lang_array[lang])
{
speaking = lang;
break;
}
#endif
if(ch->chan_invite != 1 && channel->type == CHAN_SECRET)
{
send_to_char("You're not invited to talk on this channel.\r\n", ch);
return;
}
if(channel->type == CHAN_ROOM && ch->position == POS_SLEEPING && !IS_IMMORTAL(ch))
{
send_to_char("Your sleeping, and cannot do that right now.\r\n", ch);
return;
}
if(!str_cmp(channel->name, "shout") && ch->position == POS_SLEEPING && !IS_IMMORTAL(ch))
{
send_to_char("Your sleeping, and cannot do that right now.\r\n", ch);
return;
}
if(!IS_CLANNED(ch) && !IS_IMMORTAL(ch))
{
if(!str_cmp(channel->name, "alliance") || !str_cmp(channel->name, "throng") || !str_cmp(channel->name, "halcyon"))
{
send_to_char("Huh?\r\n", ch);
return;
}
}
if(!IS_CITY(ch) && !IS_IMMORTAL(ch))
{
if(!str_cmp(channel->name, "halcyon") || !str_cmp(channel->name, "paleon") || !str_cmp(channel->name, "forbidden"))
{
send_to_char("Huh?\r\n", ch);
return;
}
}
if(IS_CLANNED(ch) && !IS_IMMORTAL(ch))
{
if(str_cmp(ch->pcdata->clan_name, "throng") && !str_cmp(channel->name, "throng"))
{
send_to_char("Huh?\r\n", ch);
return;
}
if(str_cmp(ch->pcdata->clan_name, "halcyon") && !str_cmp(channel->name, "halcyon"))
{
send_to_char("Huh?\r\n", ch);
return;
}
if(str_cmp(ch->pcdata->clan_name, "alliance") && !str_cmp(channel->name, "alliance"))
{
send_to_char("Huh?\r\n", ch);
return;
}
}
if(IS_CITY(ch) && !IS_IMMORTAL(ch))
{
if(str_cmp(ch->pcdata->city_name, "paleon city") && !str_cmp(channel->name, "paleon"))
{
send_to_char("Huh?\r\n", ch);
return;
}
if(str_cmp(ch->pcdata->city_name, "dakar city") && !str_cmp(channel->name, "dakar"))
{
send_to_char("Huh?\r\n", ch);
return;
}
if(str_cmp(ch->pcdata->city_name, "forbidden city") && !str_cmp(channel->name, "forbidden"))
{
send_to_char("Huh?\r\n", ch);
return;
}
}
if(ch->in_room && IS_SET(ch->in_room->room_flags, ROOM_SILENCE) && !IS_IMMORTAL(ch))
{
if(!IS_NPC(ch))
send_to_char("The room absorbs your words!\r\n", ch);
return;
}
if(ch->position == POS_MEDITATING && strcmp(channel->name, "ooc"))
{
send_to_char("You are concentrating too much for that!\r\n", ch);
return;
}
if(IS_NPC(ch) && IS_AFFECTED(ch, AFF_CHARM))
{
if(ch->master)
send_to_char("I don't think so...\r\n", ch->master);
return;
}
if(!str_cmp(argument, "8ball") && !strcmp(channel->name, "ooc"))
{
CHAR_DATA *mob;
short chance;
chance = number_range(1, 6);
if((mob = get_char_world(ch, (char *)"magic 8 ball")) == NULL)
return;
interpret(ch, (char *)"ooc Oh magic 8 ball we seek an answer.");
if(chance == 1)
snprintf(buf, MSL, "ooc %s It is doubtful.", ch->name);
else if(chance == 2)
snprintf(buf, MSL, "ooc %s Concentrate and ask again.", ch->name);
else if(chance == 3)
snprintf(buf, MSL, "ooc %s Outlook not good.", ch->name);
else if(chance == 4)
snprintf(buf, MSL, "ooc %s Reply hazy, try again.", ch->name);
else if(chance == 5)
snprintf(buf, MSL, "ooc %s Outlook good.", ch->name);
else
snprintf(buf, MSL, "ooc %s Signs point to yes.", ch->name);
interpret(mob, buf);
return;
}
if(!VLD_STR(argument))
{
const char *name;
if (IS_PUPPET(ch)) {
return; // stop crashing from channel history search
}
if(ch->desc->original)
{
send_to_char("You cannot be switched to check the history.\r\n", ch);
return;
}
if(!channel->keephistory)
{
ch_printf(ch, "%s what?\r\n", capitalize(channel->name));
return;
}
ch_printf(ch, "&cThe last 20 %s messages:\r\n", channel->name);
if(!str_cmp(channel->name, "say"))
{
for(x = 0; x < 20; x++)
{
if(ch->pcdata->say_history[x] == NULL)
break;
ch_printf(ch, "%s &D\r\n", ch->pcdata->say_history[x]);
}
return;
}
else
{
for(x = 0; x < 20; x++)
{
if(channel->history[x][0] != NULL)
{
switch (channel->hlevel[x])
{
case 0:
name = channel->history[x][0];
break;
case 1:
if(IS_AFFECTED(ch, AFF_DETECT_INVIS) || IS_IMMORTAL(ch))
name = channel->history[x][0];
else
name = "Someone";
break;
case 2:
if(ch->level >= channel->hinvis[x] || ch->trust >= channel->hinvis[x])
name = channel->history[x][0];
else
name = "Someone";
break;
default:
name = "Someone";
}
ch_printf(ch, channel->history[x][1], name);
}
else
break;
}
return;
}
}
if(xIS_SET(ch->act, PLR_SILENCE))
{
ch_printf(ch, "You can't %s.\r\n", channel->name);
return;
}
if(IS_AFFECTED(ch, AFF_BURROW) && strcmp(channel->name, "ooc"))
{
send_to_char("You cannot speak while burrowed, but you hear things telepathically.\r\n", ch);
return;
}
/*
* OK, this is hackish - until I can figure out a better method
*/
color = -1;
if(xIS_SET(ch->act, PLR_COMMUNICATION) && (!str_cmp(channel->name, "ooc") || !str_cmp(channel->name, "chat") || !str_cmp(channel->name, "icc")))
ch_printf(ch, "!!SOUND(sound/ooc.wav)\r\n");
if(xIS_SET(ch->act, PLR_COMMUNICATION) && IS_IMMORTAL(ch) && !str_cmp(channel->name, "sooc"))
ch_printf(ch, "!!SOUND(sound/sooc.wav)\r\n");
if(!str_cmp(channel->name, "chat"))
color = AT_LBLUE;
if(!str_cmp(channel->name, "ooc"))
color = AT_LBLUE;
if(!str_cmp(channel->name, "alliance"))
color = AT_LBLUE;
if(!str_cmp(channel->name, "throng"))
color = AT_RED;
if(!str_cmp(channel->name, "halcyon"))
color = AT_LBLUE;
if(!str_cmp(channel->name, "dakar"))
color = AT_LBLUE;
if(!str_cmp(channel->name, "paleon"))
color = AT_LBLUE;
if(!str_cmp(channel->name, "forbidden"))
color = AT_LBLUE;
if(!str_cmp(channel->name, "osay"))
color = AT_CYAN;
if(!str_cmp(channel->name, "say"))
color = AT_LBLUE;
if(!str_cmp(channel->name, "icc"))
color = AT_LBLUE;
if(!str_cmp(channel->name, "avtalk"))
color = AT_YELLOW;
if(!str_cmp(channel->name, "sooc"))
color = AT_PINK;
if(!str_cmp(channel->name, "6d"))
color = AT_YELLOW;
if(!str_cmp(channel->name, "yell"))
color = AT_ORANGE;
if(!str_cmp(channel->name, "shout"))
color = AT_DGREEN;
if(!str_cmp(channel->name, "muse"))
color = AT_MUSE;
if(!str_cmp(channel->name, "think"))
color = AT_THINK;
if(!str_cmp(channel->name, "auction"))
color = AT_AUCTION;
if(!str_cmp(channel->name, "wartalk"))
color = AT_WARTALK;
if(!str_cmp(channel->name, "hint"))
color = AT_LBLUE;
if(!str_cmp(channel->name, "quest"))
color = AT_CYAN;
if(color == -1)
color = AT_GOSSIP;
snprintf(col, MIL, "%s", color_str(color, ch));
arg = argument;
arg = one_argument(arg, word);
if(word[0] == '@' && (social = find_social(word + 1)) != NULL)
{
if(arg && *arg)
{
char name[MIL];
one_argument(arg, name);
if((victim = get_char_world(ch, name)))
arg = one_argument(arg, name);
if(!victim)
{
socbuf_char = social->char_no_arg;
socbuf_vict = social->others_no_arg;
socbuf_other = social->others_no_arg;
if(!socbuf_char && !socbuf_other)
social = NULL;
}
else if(victim == ch)
{
socbuf_char = social->char_auto;
socbuf_vict = social->others_auto;
socbuf_other = social->others_auto;
if(!socbuf_char && !socbuf_other)
social = NULL;
}
else if(victim != ch)
{
socbuf_char = social->char_found;
socbuf_vict = social->vict_found;
socbuf_other = social->others_found;
if(!socbuf_char && !socbuf_other && !socbuf_vict)
social = NULL;
}
else
social = NULL;
}
else
{
socbuf_char = social->char_no_arg;
socbuf_vict = social->others_no_arg;
socbuf_other = social->others_no_arg;
if(!socbuf_char && !socbuf_other)
social = NULL;
}
}
if(word[0] == ',')
emote = TRUE;
if((!str_cmp(channel->name, "say")) || (!str_cmp(channel->name, "osay")))
{
ch_printf(ch, "%sYou %s '%s'\r\n", col, channel->name, argument);
}
else
{
if(social)
{
act_printf(AT_PLAIN, ch, argument, victim, TO_CHAR, " &W[%s%s&W] %s%s", col, capitalize(channel->name), col, socbuf_char);
}
else if(emote)
{
argument = argument + 1;
ch_printf(ch, " &W[%s%s&W] %s%s %s\r\n", col, capitalize(channel->name), col, ch->name, argument);
}
else if(!str_cmp(channel->name, "hint"))
{
ch_printf(ch, "%s %s&c '%s'\r\n", col, channel->name, argument);
}
else
ch_printf(ch, "%s [%s] '%s'\r\n", col, capitalize(channel->name), argument);
}
if(!str_cmp(channel->name, "sooc"))
{
snprintf(buf2, MSL, "&P%s: %s (%s)&D", IS_NPC(ch) ? ch->short_descr : ch->name, argument, channel->name);
append_to_file(CSAVE_FILE, buf2);
}
if(!str_cmp(channel->name, "muse"))
{
snprintf(buf2, MSL, "&g%s: %s (%s)&D", IS_NPC(ch) ? ch->short_descr : ch->name, argument, channel->name);
append_to_file(CSAVE_FILE, buf2);
}
if(!str_cmp(channel->name, "ooc"))
{
snprintf(buf2, MSL, "&C%s: %s (%s)&D", IS_NPC(ch) ? ch->short_descr : ch->name, argument, channel->name);
append_to_file(CSAVE_FILE, buf2);
}
if(!str_cmp(channel->name, "chat"))
{
snprintf(buf2, MSL, "&C%s: %s (%s)&D", IS_NPC(ch) ? ch->short_descr : ch->name, argument, channel->name);
append_to_file(CSAVE_FILE, buf2);
}
if(!str_cmp(channel->name, "think"))
{
snprintf(buf2, MSL, "&R%s: %s (%s)&D", IS_NPC(ch) ? ch->short_descr : ch->name, argument, channel->name);
append_to_file(CSAVE_FILE, buf2);
}
if(!str_cmp(channel->name, "6d"))
{
snprintf(buf2, MSL, "&Y%s: %s (%s)&D", IS_NPC(ch) ? ch->short_descr : ch->name, argument, channel->name);
append_to_file(CSAVE_FILE, buf2);
}
if(IS_SET(ch->in_room->room_flags, ROOM_LOGSPEECH))
{
snprintf(buf2, MSL, "%s: %s (%s)", IS_NPC(ch) ? ch->short_descr : ch->name, argument, channel->name);
append_to_file(LOG_FILE, buf2);
}
/*
* Channel history. Records the last 20 messages to channels which keep historys
*/
if(channel->keephistory)
{
for(x = 0; x < 20; x++)
{
int type;
MORPH_DATA *morph;
type = 0;
if(IS_AFFECTED(ch, AFF_INVISIBLE))
type = 1;
if(ch->pcdata && xIS_SET(ch->act, PLR_WIZINVIS))
type = 2;
if(!ch->pcdata && xIS_SET(ch->act, ACT_MOBINVIS))
type = 3;
if(channel->history[x][0] == NULL)
{
if(VLD_STR(channel->history[x][0]))
STRFREE(channel->history[x][0]);
if(VLD_STR(channel->history[x][1]))
STRFREE(channel->history[x][1]);
/* Volk Jan-16: bug fix, hopefully this will prevent unknown history[x][0] */
if(IS_AFFECTED(ch, AFF_DISGUISE) || IS_AFFECTED(ch, AFF_SHAPESHIFT))
channel->history[x][0] = STRALLOC(ch->morph->morph->name);
else if(IS_NPC(ch) && !IS_AFFECTED(ch, AFF_DISGUISE) && !IS_AFFECTED(ch, AFF_SHAPESHIFT))
channel->history[x][0] = STRALLOC(ch->short_descr);
else if(!IS_NPC(ch) && !IS_AFFECTED(ch, AFF_DISGUISE) && !IS_AFFECTED(ch, AFF_SHAPESHIFT))
channel->history[x][0] = STRALLOC(ch->name);
else
channel->history[x][0] = STRALLOC("somebody");
t = time(NULL);
local = localtime(&t);
argument = add_percent(argument);
snprintf(logbuf, MSL, " &R[%-2.2d:%-2.2d] &G%%s%s %s\r\n", local->tm_hour, local->tm_min, emote ? "" : ":", argument);
channel->history[x][1] = STRALLOC(logbuf);
channel->hlevel[x] = type;
channel->hinvis[x] = 0;
if(type == 3)
channel->hinvis[x] = ch->mobinvis;
else if(type == 2)
channel->hinvis[x] = ch->pcdata->wizinvis;
break;
}
if(x == 19)
{
int y;
for(y = 1; y < 20; y++)
{
int z = y - 1;
if(channel->history[z][0] && channel->history[z][1] && channel->history[z][0] != NULL && channel->history[z][1] != NULL)
{
STRFREE(channel->history[z][0]);
STRFREE(channel->history[z][1]);
channel->history[z][0] = STRALLOC(channel->history[y][0]);
channel->history[z][1] = STRALLOC(channel->history[y][1]);
channel->hlevel[z] = channel->hlevel[y];
channel->hinvis[z] = channel->hinvis[y];
}
}
if(VLD_STR(channel->history[x][0]))
STRFREE(channel->history[x][0]);
if(VLD_STR(channel->history[x][1]))
STRFREE(channel->history[x][1]);
if(IS_NPC(ch))
channel->history[x][0] = STRALLOC(ch->short_descr);
else
channel->history[x][0] = STRALLOC(ch->name);
t = time(NULL);
local = localtime(&t);
argument = add_percent(argument);
snprintf(logbuf, MSL, " &R[%-2.2d:%-2.2d] &G%%s%s %s\r\n", local->tm_hour, local->tm_min, emote ? "" : ":", argument);
channel->history[x][1] = STRALLOC(logbuf);
channel->hlevel[x] = type;
channel->hinvis[x] = 0;
if(type == 3)
channel->hinvis[x] = ch->mobinvis;
else if(type == 2)
channel->hinvis[x] = ch->pcdata->wizinvis;
}
}
}
for(vch = first_char; vch; vch = vch->next)
{
if(vch == ch)
continue;
if(!IS_NPC(ch))
{
if(xIS_SET(ch->act, PLR_COMMUNICATION) && !str_cmp(channel->name, "say") && vch->in_room->vnum == ch->in_room->vnum)
ch_printf(ch, "!!SOUND(sound/say.wav)\r\n");
}
/*
* So puppets can redirect says and that
*/
if(IS_PUPPET(vch))
{
char *sbuf = argument;
char lbuf[MIL + 4];
position = vch->position;
set_position(vch, POS_STANDING);
if(vch->level < channel->level && vch->trust < channel->level)
continue;
/*
* Make it skip the ooc and chat for puppets
*/
if(!str_cmp(channel->name, "ooc") || !str_cmp(channel->name, "chat"))
continue;
if(IS_SET(vch->in_room->room_flags, ROOM_SILENCE))
continue;
if(channel->type == CHAN_ZONE && vch->in_room->area != ch->in_room->area)
continue;
if(channel->type == CHAN_ROOM && vch->in_room != ch->in_room)
continue;
if(channel->type == CHAN_PK && !IS_PKILL(vch) && !IS_IMMORTAL(vch))
continue;
if((vch->position == POS_SLEEPING) && channel->type == CHAN_ROOM && !IS_IMMORTAL(vch))
continue;
if(channel->type == CHAN_SECRET)
{
if(IS_NPC(vch))
continue;
if(vch->chan_invite != 1)
continue;
}
if(channel->type == CHAN_ALLIANCE)
{
if(IS_NPC(vch))
continue;
if(!vch->pcdata->clan_name || str_cmp(vch->pcdata->clan_name, "alliance"))
continue;
}
if(channel->type == CHAN_THRONG)
{
if(IS_NPC(vch))
continue;
if(!vch->pcdata->clan_name || str_cmp(vch->pcdata->clan_name, "throng"))
continue;
}
if(channel->type == CHAN_HALCYON)
{
if(IS_NPC(vch))
continue;
if(!vch->pcdata->clan_name || str_cmp(vch->pcdata->clan_name, "halcyon"))
continue;
}
if(channel->type == CHAN_PALEON)
{
if(IS_NPC(vch))
continue;
if(!vch->pcdata->city_name || str_cmp(vch->pcdata->city_name, "paleon city"))
continue;
}
if(channel->type == CHAN_DAKAR)
{
if(IS_NPC(vch))
continue;
if(!vch->pcdata->city_name || str_cmp(vch->pcdata->city_name, "dakar city"))
continue;
}
if(channel->type == CHAN_FORBIDDEN)
{
if(IS_NPC(vch))
continue;
if(!vch->pcdata->city_name || str_cmp(vch->pcdata->city_name, "forbidden city"))
continue;
}
snprintf(col, MIL, "%s", color_str(color, vch));
if(((IS_NPC(ch) && xIS_SET(ch->act, ACT_MOBINVIS)) || (!IS_NPC(ch) && xIS_SET(ch->act, PLR_WIZINVIS))) && can_see(vch, ch) && IS_IMMORTAL(vch))
snprintf(lbuf, sizeof(lbuf), "%s(%d) ", col, (!IS_NPC(ch)) ? ch->pcdata->wizinvis : ch->mobinvis);
else
lbuf[0] = '\0';
if((!str_cmp(channel->name, "say")) || (!str_cmp(channel->name, "osay")))
{
if(!social && !emote)
{
snprintf(buf, MSL, "$n %ss '$t'", channel->name);
act(AT_SAY, strcat(lbuf, buf), ch, sbuf, vch, TO_VICT);
}
}
else if(!social && !emote)
{
if(!str_cmp(channel->name, "hint"))
{
snprintf(buf, MSL, "%s %s $t%s", col, channel->name, col);
act(AT_PLAIN, strcat(lbuf, buf), ch, sbuf, vch, TO_VICT);
}
else
snprintf(buf, MSL, "%s [%s] $n '$t%s'", col, capitalize(channel->name), col);
act(AT_PLAIN, strcat(lbuf, buf), ch, sbuf, vch, TO_VICT);
}
if(emote)
{
snprintf(buf, MSL, " &W[%s%s&W] %s$n $t", col, capitalize(channel->name), col);
act(AT_PLAIN, strcat(lbuf, buf), ch, sbuf, vch, TO_VICT);
}
if(social)
{
if(vch == victim)
act_printf(AT_PLAIN, ch, NULL, vch, TO_VICT, " &W[%s%s&W] %s%s", col, capitalize(channel->name), col, socbuf_vict);
else
act_printf(AT_PLAIN, ch, vch, victim, TO_THIRD, " &W[%s%s&W] %s%s", col, capitalize(channel->name), col, socbuf_other);
}
set_position(vch, position);
}
if(!vch->desc)
continue;
if(!IS_NPC(ch) && (!str_cmp(channel->name, "ooc") || !str_cmp(channel->name, "chat") || !str_cmp(channel->name, "icc")))
{
if(xIS_SET(vch->act, PLR_COMMUNICATION))
ch_printf(vch, "!!SOUND(sound/ooc.wav)\r\n");
}
if(!IS_NPC(vch) && IS_IMMORTAL(vch) && !str_cmp(channel->name, "sooc"))
{
if(xIS_SET(vch->act, PLR_COMMUNICATION))
ch_printf(vch, "!!SOUND(sound/sooc.wav)\r\n");
}
if(!IS_NPC(ch))
{
if(xIS_SET(vch->act, PLR_COMMUNICATION) && !str_cmp(channel->name, "say") && vch->in_room->vnum == ch->in_room->vnum)
ch_printf(vch, "!!SOUND(sound/say.wav)\r\n");
}
if(vch->desc->connected == CON_PLAYING && (IS_NPC(vch) || hasname(vch->pcdata->chan_listen, channel->name)))
{
char *sbuf = argument;
char lbuf[MIL + 4]; /* invis level string + buf */
if((vch->level < channel->level) && (vch->trust < channel->level))
continue;
if(IS_SET(vch->in_room->room_flags, ROOM_SILENCE))
continue;
if(channel->type == CHAN_ZONE && vch->in_room->area != ch->in_room->area)
continue;
if(channel->type == CHAN_ROOM && vch->in_room != ch->in_room)
continue;
if(channel->type == CHAN_PK && !IS_PKILL(vch) && !IS_IMMORTAL(vch))
continue;
if((vch->position == POS_SLEEPING) && channel->type == CHAN_ROOM && !IS_IMMORTAL(vch))
{
continue;
}
if(channel->type == CHAN_SECRET)
{
if(IS_NPC(vch))
continue;
if(vch->chan_invite != 1)
continue;
}
if(channel->type == CHAN_ALLIANCE)
{
if(IS_NPC(vch))
continue;
if(vch->pcdata->clan != ch->pcdata->clan)
continue;
}
if(channel->type == CHAN_HALCYON)
{
if(IS_NPC(vch))
continue;
if(vch->pcdata->clan != ch->pcdata->clan)
continue;
}
if(channel->type == CHAN_THRONG)
{
if(IS_NPC(vch))
continue;
if(vch->pcdata->clan != ch->pcdata->clan)
continue;
}
if(channel->type == CHAN_COUNCIL)
{
if(IS_NPC(vch))
continue;
if(vch->pcdata->council != ch->pcdata->council)
continue;
}
if(channel->type == CHAN_PALEON)
{
if(IS_NPC(vch))
continue;
if(!vch->pcdata->city_name || str_cmp(vch->pcdata->city_name, "paleon city"))
continue;
}
if(channel->type == CHAN_DAKAR)
{
if(IS_NPC(vch))
continue;
if(!vch->pcdata->city_name || str_cmp(vch->pcdata->city_name, "dakar city"))
continue;
}
if(channel->type == CHAN_FORBIDDEN)
{
if(IS_NPC(vch))
continue;
if(!vch->pcdata->city_name || str_cmp(vch->pcdata->city_name, "forbidden city"))
continue;
}
position = vch->position;
set_position(vch, POS_STANDING);
snprintf(col, MIL, "%s", color_str(color, vch));
if(((IS_NPC(ch) && xIS_SET(ch->act, ACT_MOBINVIS)) || (!IS_NPC(ch) && xIS_SET(ch->act, PLR_WIZINVIS))) && can_see(vch, ch) && IS_IMMORTAL(vch))
snprintf(lbuf, sizeof(lbuf), "%s(%d) ", col, (!IS_NPC(ch)) ? ch->pcdata->wizinvis : ch->mobinvis);
else
lbuf[0] = '\0';
/*
* Should we scramble the channel?
*/
if(channel->doscramble)
{
#ifndef SCRAMBLE
if(speaking != -1 && (!IS_NPC(ch) || ch->speaking))
{
int speakswell = UMIN(knows_language(vch, ch->speaking, ch),
knows_language(ch, ch->speaking, vch));
if(speakswell < 85)
sbuf = translate(speakswell, argument, lang_names[speaking]);
}
#else
if(!knows_language(vch, ch->speaking, ch) && (!IS_NPC(ch) || ch->speaking != 0))
sbuf = scramble(argument, ch->speaking);
#endif
}
/*
* Check to see if target is ignoring the sender
*/
if(is_ignoring(vch, ch))
{
/*
* If the sender is an imm then they cannot be ignored
*/
if(!IS_IMMORTAL(ch) || vch->level > ch->level || vch->trust > ch->level)
{
/*
* Off to oblivion!
*/
continue;
}
else
set_char_color(AT_IGNORE, vch);
}
MOBtrigger = FALSE;
/*
* Hackish solution to stop that damned "someone chat" bug - Matarael 17.3.2002
* Volk looking into this crashing the mud over and over..
*/
if((!str_cmp(channel->name, "say")) /* || (!str_cmp(channel->name, * * "osay")) */ )
{
if(!social && !emote)
{
snprintf(buf, MSL, "$n %ss '$t'", channel->name);
act(AT_SAY, strcat(lbuf, buf), ch, sbuf, vch, TO_VICT);
}
else
{
act_printf(AT_PLAIN, ch, vch, victim, TO_THIRD, "%s%ss, %s%s", col, socbuf_other, col, channel->name);
}
if(!IS_NPC(vch))
{
snprintf(logbuf, MSL, "&R[%-2.2d/%-2.2d %-2.2d:%-2.2d] &B%s said '&W %s &D&B'&D", local->tm_mon + 1, local->tm_mday, local->tm_hour, local->tm_min, PERS(ch, vch), sbuf);
for(x = 0; x < 20; x++)
{
if(vch->pcdata->say_history[x] == NULL)
{
vch->pcdata->say_history[x] = STRALLOC(logbuf);
break;
}
if(x == 19)
{
int i;
for(i = 1; i < 20; i++)
{
STRFREE(vch->pcdata->say_history[i - 1]);
vch->pcdata->say_history[i - 1] = STRALLOC(vch->pcdata->say_history[i]);
}
STRFREE(vch->pcdata->say_history[x]);
vch->pcdata->say_history[x] = STRALLOC(logbuf);
}
}
}
}
else if(!social && !emote)
{
snprintf(buf, MSL, "%s [%s] $n '$t%s'", col, capitalize(channel->name), col);
act(AT_PLAIN, strcat(lbuf, buf), ch, sbuf, vch, TO_VICT);
}
if(emote)
{
snprintf(buf, MSL, " &W[%s%s&W] %s$n $t", col, capitalize(channel->name), col);
act(AT_PLAIN, strcat(lbuf, buf), ch, sbuf, vch, TO_VICT);
}
if(social)
{
if(vch == victim)
act_printf(AT_PLAIN, ch, NULL, vch, TO_VICT, " &W[%s%s&W] %s%s", col, capitalize(channel->name), col, socbuf_vict);
else
act_printf(AT_PLAIN, ch, vch, victim, TO_THIRD, " &W[%s%s&W] %s%s", col, capitalize(channel->name), col, socbuf_other);
}
set_position(vch, position);
/*
* Hackish solution to stop that damned "someone chat" bug - Matarael 17.3.2002
*/
}
}
/*
* Do programs
*/
if(!str_cmp(channel->name, "osay") || !str_cmp(channel->name, "say"))
{
mprog_speech_trigger(argument, ch);
oprog_speech_trigger(argument, ch);
rprog_speech_trigger(argument, ch);
}
}
void to_channel(const char *argument, const char *xchannel, int level)
{
MUD_CHANNEL *channel;
char buf[MSL];
DESCRIPTOR_DATA *d;
if(!first_descriptor || argument[0] == '\0')
return;
if(!(channel = find_channel(xchannel)))
return;
if(channel->type != CHAN_LOG)
return;
snprintf(buf, MSL, "%s: %s\r\n", capitalize(channel->name), argument);
for(d = first_descriptor; d; d = d->next)
{
CHAR_DATA *vch;
vch = d->original ? d->original : d->character;
if(!vch)
continue;
if(d->original)
continue;
/*
* This could be coming in higher than the normal level, so check first
*/
if((vch->level < level) && (vch->trust < level))
continue;
if(d->connected == CON_PLAYING && hasname(vch->pcdata->chan_listen, channel->name))
{
set_char_color(AT_LOG, vch);
send_to_char_color(buf, vch);
}
}
return;
}
bool local_channel_hook(CHAR_DATA *ch, const char *command, char *argument)
{
MUD_CHANNEL *channel;
if(!(channel = find_channel(command)))
return FALSE;
if((ch->level < channel->level) && (ch->trust < channel->level))
return FALSE;
/*
* Logs are meant to be seen, not talked on
*/
if(channel->type == CHAN_LOG)
return FALSE;
if(!IS_NPC(ch) && !hasname(ch->pcdata->chan_listen, command))
{
ch_printf(ch, "&RYou are not listening to the &G%s &Rchannel.\r\n", channel->name);
return TRUE;
}
send_tochannel(ch, channel, argument);
return TRUE;
}
/* Volk 10-8-06 - Pretty colours, used for global announcements like births and deaths, clan stuff. */
void announce(const char *argument)
{
char buf[MSL];
snprintf(buf, MSL, "\r\n&W[&RAnnouncement&W]&C %s&D", argument);
announce_all(AT_RED, buf, ECHOTAR_ALL);
return;
}
void to_channel_printf(const char *channel, int level, const char *fmt, ...)
{
char buf[MSL * 2];
va_list args;
va_start(args, fmt);
vsnprintf(buf, MSL * 2, fmt, args);
va_end(args);
to_channel(buf, channel, level);
}