zim/area/
zim/bin/
zim/clans/plists/
zim/corefiles/
zim/doc/muddy/
zim/gods/
zim/log/
zim/player/
zim/skill_tree/
zim/tmp/
/*
 * $Id: channels.c 931 2006-11-08 02:24:28Z zsuzsu $
 */
#include <sys/types.h>
#include <sys/time.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <time.h>

#include "merc.h"
#include "db/lang.h"

flag_t channel_flags[] =
{
	{ "",			TABLE_BITVAL			},

	{ "dmtalk",		CHAN_DM_WIZ,		TRUE	},
	{ "immtalk",		CHAN_WIZ,		TRUE	},
	{ "immhelp",		CHAN_WIZHELP,		TRUE	},
	{ "auction",		CHAN_AUCTION,		TRUE	},
	{ "advice",		CHAN_ADVICE,		TRUE	},
	{ "newbie",		CHAN_NEWBIE,		TRUE	},
	{ "gossip",		CHAN_GOSSIP,		TRUE	},
	{ "shout",		CHAN_SHOUT,		TRUE	},
	{ "pray",		CHAN_PRAY,		TRUE	},
	{ "clan",		CHAN_CLAN,		TRUE	},
	{ "tell",		CHAN_GLOBAL_TELL,	TRUE	},
	{ "yell",		CHAN_YELL,		TRUE	},
	{ "emote",		CHAN_GLOBAL_EMOTE,	TRUE	},
	{ "ooc",		CHAN_OOC,		TRUE	},
	{ "music",		CHAN_MUSIC,		TRUE	},
	{ "quest",		CHAN_QUEST,		TRUE	},
	{ "trade",		CHAN_TRADE,		TRUE	},
	{ "death",		CHAN_DEATH,		TRUE	},

	{ NULL }
};

/*
 * Unified channels
 * by Zsuzsu
 */
channel_t channel_table[] = 
{
	/*
	{ name,		chan_flag,	prefix,
		default_emote,	default_emote_only,	quotes,
		read,	write,	show name,
		K.O.,	garb,	deaf,	clear,	anon,	lag,
		color,
		act_flags,
		locale,
		room_flag,
	}
	*/
	{ "advice",	CHAN_ADVICE,	"{M[{Cadvice{M]{m: ",
		CHAN_EMOTE_NONE,	TRUE,	FALSE,
		0,	IM,	TRUE,
		TRUE,	TRUE,	TRUE,	TRUE,	TRUE,	FALSE,
		'C',
		ACT_TOBUF,
		CHAN_LOCALE_GLOBAL,
		NONE,
	},
	{ "yell",	CHAN_YELL,	"",
		CHAN_EMOTE_YELL,	TRUE,	TRUE,
		0,	0, 	FALSE,
		FALSE,	TRUE,	FALSE,	FALSE,	TRUE,	FALSE,
		'M',
		ACT_STRANS | ACT_NODEAF,
		CHAN_LOCALE_AREA,
		NONE,
	},
	{ "gossip",	CHAN_GOSSIP,	"",
		CHAN_EMOTE_GOSSIP,	FALSE,	TRUE,
		0,	0, 	FALSE,
		FALSE,	TRUE,	FALSE,	FALSE,	TRUE,	TRUE,
		'R',
		ACT_NOTWIT | ACT_STRANS | ACT_NODEAF,
		CHAN_LOCALE_GLOBAL,
		NONE,
	},
	{ "ooc",	CHAN_OOC,	"{b[{BOoC{b] ",
		CHAN_EMOTE_COLON,	TRUE,	FALSE,
		0,	0, 	FALSE,
		FALSE,	FALSE,	FALSE,	FALSE,	TRUE,	TRUE,
		'B',
		ACT_NOTWIT | ACT_NODEAF | ACT_REALNAME,
		CHAN_LOCALE_GLOBAL,
		NONE,
	},
	{ "newbie",	CHAN_NEWBIE,	"{m[{Mnewbie{m] ",
		CHAN_EMOTE_COLON,	TRUE,	FALSE,
		0,	0, 	FALSE,
		FALSE,	FALSE,	FALSE,	FALSE,	TRUE,	TRUE,
		'M',
		ACT_NOTWIT | ACT_NODEAF | ACT_REALNAME,
		CHAN_LOCALE_GLOBAL,
		NONE,
	},
	{ "clan",	CHAN_CLAN,	"{C[{c%s{C] ",
		CHAN_EMOTE_SAY,		FALSE,	TRUE,
		0,	0, 	FALSE,
		FALSE,	TRUE,	FALSE,	FALSE,	FALSE,	FALSE,
		'C',
		ACT_TOBUF | ACT_STRANS | ACT_NOTWIT | ACT_NODEAF | ACT_REALNAME,
		CHAN_LOCALE_CLAN,
		NONE,
	},
	{ "dmtalk",	CHAN_DM_WIZ,	"{R[{rdm{R]{x ",
		CHAN_EMOTE_COLON,	TRUE,	FALSE,
		L1,	L1, 	FALSE,
		TRUE,	TRUE,	TRUE,	TRUE,	FALSE,	FALSE,
		'r',
		ACT_TOBUF,
		CHAN_LOCALE_GLOBAL,
		NONE,
	},
	{ "immtalk",	CHAN_WIZ,	"{y[{Yimm{y]{x ",
		CHAN_EMOTE_COLON,	TRUE,	FALSE,
		IM,	IM, 	FALSE,
		TRUE,	TRUE,	TRUE,	TRUE,	FALSE,	FALSE,
		'Y',
		ACT_TOBUF,
		CHAN_LOCALE_GLOBAL,
		NONE,
	},
	{ "immhelp",	CHAN_WIZHELP,	"{g[{Gimmhelp{g] ",
		CHAN_EMOTE_COLON,	TRUE,	FALSE,
		IM,	0, 	FALSE,
		TRUE,	TRUE,	TRUE,	TRUE,	TRUE,	TRUE,
		'G',
		ACT_TOBUF | ACT_REALNAME,
		CHAN_LOCALE_GLOBAL,
		NONE,
	},
	{ "pray",	CHAN_PRAY,	"{M[{m%s{M] ",
		CHAN_EMOTE_PRAY,	FALSE,	TRUE,
		0,	0, 	FALSE,
		FALSE,	TRUE,	FALSE,	FALSE,	FALSE,	FALSE,
		'm',
		ACT_TOBUF | ACT_STRANS | ACT_NOTWIT | ACT_NODEAF,
		CHAN_LOCALE_RELIGION,
		NONE,
	},
	{ "quest",	CHAN_QUEST,	"{C[{MQ{muest{C]{M:{x ",
		CHAN_EMOTE_COLON,	TRUE,	FALSE,
		0,	0,	TRUE,
		FALSE,	TRUE,	TRUE,	TRUE,	TRUE,	FALSE,
		'c',
		ACT_TOBUF,
		CHAN_LOCALE_GLOBAL,
		NONE,
	},
	{ "shout",	CHAN_SHOUT,	"",
		CHAN_EMOTE_SHOUT,	TRUE,	TRUE,
		0,	0, 	FALSE,
		FALSE,	TRUE,	FALSE,	FALSE,	TRUE,	TRUE,
		'Y',
		ACT_NOTWIT | ACT_STRANS | ACT_NODEAF,
		CHAN_LOCALE_GLOBAL,
		NONE,
	},
	{ "music",	CHAN_MUSIC,	"{w[{Wmusic{w] ",
		CHAN_EMOTE_SING,	TRUE,	TRUE,
		0,	IM, 	FALSE,
		FALSE,	TRUE,	FALSE,	FALSE,	TRUE,	TRUE,
		'W',
		ACT_NOTWIT | ACT_STRANS | ACT_NODEAF,
		CHAN_LOCALE_GLOBAL,
		NONE,
	},
	{ "trade",	CHAN_TRADE,	"{Y[{ytrade{Y] ",
		CHAN_EMOTE_TRADE,	FALSE,	TRUE,
		0,	0, 	FALSE,
		FALSE,	TRUE,	FALSE,	FALSE,	TRUE,	TRUE,
		'y',
		ACT_NOTWIT | ACT_STRANS | ACT_NODEAF,
		CHAN_LOCALE_GLOBAL,
		NONE,
	},

	{ "death",	CHAN_DEATH,	"{x[{DDeath{x]:{x ",
		CHAN_EMOTE_COLON,	TRUE,	FALSE,
		0,	0,	TRUE,
		FALSE,	TRUE,	TRUE,	TRUE,	TRUE,	FALSE,
		'r',
		ACT_TOBUF,
		CHAN_LOCALE_GLOBAL,
		NONE,
	},

	{ NULL }
};

channel_t * get_channel_type (flag64_t flag) 
{
	channel_t *ct;

	for (ct = channel_table; ct->name; ct++)
		if (ct->flag == flag)
			return ct;
	return NULL;
}

channel_t *channel_lookup (const char *name) 
{
	channel_t *ct;

	for (ct = channel_table; ct->name; ct++)
		if (!str_prefix(name, ct->name))
			return ct;

	return NULL;
}

channel_emote_t channel_emote_table[] =
{
	{ CHAN_EMOTE_NONE,	NULL,
		"",		"",		},
	{ CHAN_EMOTE_DEFAULT,	NULL,
		"say",		"says", 	},
	{ CHAN_EMOTE_COLON,	NULL,
		":",		":",		},
	{ CHAN_EMOTE_SAY,	"say",
		"say",		"says",	 	},
	{ CHAN_EMOTE_GOSSIP,	"gossip",
		"gossip",	"gossips",	},
	{ CHAN_EMOTE_YELL,	"yell",
		"yell",		"yells",	},
	{ CHAN_EMOTE_SHOUT,	"shout",
		"shout",	"shouts",	},
	{ CHAN_EMOTE_SING,	"sing",
		"sing",		"sings",	},
	{ CHAN_EMOTE_PRAY,	"pray",
		"pray",		"prays",	},
	{ CHAN_EMOTE_TRADE,	"offer",
		"offer",	"offers",	},
	{ -1 }
};

int channel_emote_lookup (const char *emote) 
{
	int i;

	for (i=0; channel_emote_table[i].type != -1; i++) {
		if (channel_emote_table[i].name == NULL)
			continue;
		if (!str_prefix(emote, channel_emote_table[i].name))
			return channel_emote_table[i].type;
	}

	return CHAN_EMOTE_DEFAULT;
}

channel_emote_t *channel_emote (int idx)
{
	int i = 0;
	for (i=0; channel_emote_table[i].type != -1; i++)
		if (idx == channel_emote_table[i].type)
			return &channel_emote_table[i];

	return NULL;
}

void display_channel_raw (CHAR_DATA *ch, int chan_flag)
{
	channel_t *channel = CHANNEL(chan_flag);

	if (!channel) return;

	if (channel->read_level > ch->level
	&& channel->write_level > ch->level)
		return;

	if (IS_IMMORTAL(ch)) 
		char_printf(ch, "{%c%12s %-5s     {x%2d{D/{x%2d %-10s{x\n",
			!IS_SET(global_channels, chan_flag) ? 'D' : 'x',
			flag_string(channel_flags, chan_flag),
			IS_SET(ch->channels, chan_flag) ? "{GON" : "{ROFF",
			channel->read_level,
			channel->write_level,
			!IS_SET(global_channels, chan_flag) ? "{BDISABLED" 
			: IS_SET(ch->restricted_channels, chan_flag) ?  "{rFORBIDDEN" 
			: "");
	else
		char_printf(ch, "{%c%12s %-5s    %-10s{x\n",
			!IS_SET(global_channels, chan_flag) ? 'D' : 'x',
			flag_string(channel_flags, chan_flag),
			IS_SET(ch->channels, chan_flag) ? "{GON" : "{ROFF",
			!IS_SET(global_channels, chan_flag) ? "{BDISABLED" 
			: IS_SET(ch->restricted_channels, chan_flag) ?  "{rFORBIDDEN" 
			: "");
}

/*
 * re-written by Zsuzsu
 */
void do_channels(CHAR_DATA *ch, const char *argument)
{
	int flag = 0;

	/* lists all channels and their status */
	if (IS_IMMORTAL(ch)) {
		char_puts("     channel status   r{D/{xw\n",ch);
		char_puts("    {D-------- ------- -----{x\n",ch);
	}
	else {
		char_puts("     channel status\n",ch);
		char_puts("    {D-------- -------{x\n",ch);
	}

	for (flag =1; channel_flags[flag].name; flag++) {
		display_channel_raw(ch, channel_flags[flag].bit);
	}

	if (IS_SET(ch->comm, COMM_QUIET))
		 char_puts("Quiet mode has been set.\n", ch);

	if (IS_SET(ch->comm, COMM_SNOOP_PROOF))
		char_puts("You are immune to snooping.\n", ch);
	
	char_printf(ch, "You display %d lines of scroll.\n", ch->lines+2);

}

/*
 * Unified public channels
 * by Zsuzsu
 */
void public_channel (CHAR_DATA *ch, const char *argument, int chan_flag)
{
	DESCRIPTOR_DATA *d;
	channel_t *channel = NULL;
	char buf[MAX_INPUT_LENGTH];
	char prefix[30];
	char mesg[MAX_INPUT_LENGTH];
	char *adverb = NULL;
	char *ptr = NULL;
	int  emote = CHAN_EMOTE_DEFAULT;
	char *emote_self = NULL;
	char *emote_other = NULL;
	char delim = '^';

	if (IS_NPC(ch) && IS_AFFECTED(ch, AFF_CHARM))
		return;

	if (IS_NPC(ch) && IS_SET(ch->pIndexData->act, ACT_MUTE))
		return;

	if (argument[0] == '\0') {
		TOGGLE_BIT(ch->channels, chan_flag);
		char_printf(ch, "Your {W%s{x channel is now %s{x\n",
			flag_string(channel_flags, chan_flag),
			IS_SET(ch->channels, chan_flag) ? "{GON" : "{ROFF");
		return;
	}

	if (IS_SET(ch->restricted_channels, chan_flag)) {
		char_puts("{RThe gods have revoked your privilege to that channel.{x\n", 
			ch);
		return;
	}

	/* turn the channel on if they don't have it on already */
	if (!IS_SET(ch->channels, chan_flag))
		public_channel(ch, str_empty, chan_flag);

	channel = CHANNEL(chan_flag);

	if (channel == NULL) {
		bug("public_channel: illegal channel flag (%d)",
			chan_flag);
		char_puts("Sorry, not sure what channel that is.\n", ch);
		return;
	}

	if (!channel->knockedout_ok 
	&& IS_AFFECTED(ch, AFF_SLEEP)) {
		char_puts("In your dreams?\n", ch);
		return;
	}

	/* figure out if there is a custom emote with adverbs
	 * in the form of: command adverb "message
	 */
	if (!channel->default_emote_only
	&& !channel->anonymous
	&& ((ptr = strchr(argument, delim)) != NULL)) {
		*ptr = '\0';
		adverb = (char *) argument;
		strncpy(mesg, ++ptr, sizeof(mesg));
		chomp(adverb);
		chomp(mesg);

		if (*adverb == '\0')
			adverb = NULL;
	}
	else {
		strncpy(mesg, argument, sizeof(mesg));
	}

	emote = channel->default_emote;

	if (channel->lag)
		WAIT_STATE(ch, PULSE_VIOLENCE);

	if (!IS_SET(global_channels, chan_flag) && !IS_IMMORTAL(ch)) {
		if (chan_flag == CHAN_OOC)
			char_puts("Perhaps you could find a way to say"
				" that in character.\n", ch);
		else 
			char_puts("This channel is not currently available.\n", 
				ch);
		return;
	}

	if (ch->level < channel->write_level) {
		if (chan_flag == CHAN_OOC)
			char_puts("Perhaps you could find a way to say"
				" that in character.\n", ch);
		else 
			char_printf(ch, "Communication on that channel is currently"
				" reserved for people level %d and higher.\n", 
				channel->write_level);
		return;
	}

	if (is_affected(ch, gsn_garble)) {
		if (!channel->garbled_ok) {
			char_puts("You probably wouldn't be understood anyway.\n",ch);
			return;
		}
		if (!channel->clear_speech) {
			strncpy(mesg, garble(ch, mesg), sizeof(mesg));
			adverb = NULL;
		}
	}

	emote_self = (char *) channel_emote(emote)->self;
	emote_other = (char *) channel_emote(emote)->other;

	if (channel->anonymous)
		snprintf(buf, sizeof(buf), 
			"%s{%c$t",
			channel->prefix, 
			channel->color);

	/* if the prefix has a %s (assume 's')
	 * then do something special for certain cases
	 */
	if (strchr(channel->prefix, '%') != NULL) {
		switch (channel->flag) {
			case CHAN_PRAY:
				/*specifically for our atheist clan*/
				if (ch->religion == RELIGION_ATHEIST)
					snprintf(prefix, sizeof(prefix),
						channel->prefix,
						"ElidoDi");
				else
					snprintf(prefix, sizeof(prefix),
						channel->prefix,
						religion_table[ch->religion].leader);
				break;
			case CHAN_CLAN:
				snprintf(prefix, sizeof(prefix),
					channel->prefix,
					clan_name(ch->clan));
				break;
			default:
				BUG("public_channel: unknown"
					" prefix '%%' in chan %s",
					channel->name);
				strncpy(prefix, channel->prefix, sizeof(prefix));
		}
	}
	else {
		strncpy(prefix, channel->prefix, sizeof(prefix));
	}

	/* anonymous color 
	 * so morts can keep track of how many wizi immorts
	 * are talking
	 */
	if (channel->anonymous) {
		snprintf(buf, sizeof(buf), 
			"%s{%c$t{x",
			prefix, 
			channel->color
			);
	}
	else if (channel->imm_anon_color
	&& IS_IMMORTAL(ch)
	&& (ch->invis_level > 0 || ch->incog_level > 0))
		snprintf(buf, sizeof(buf), 
			"%s{%cYou{x%s%s%s%s%s{%c$t{x%s",
			prefix, 
			ch->pcdata->anon_color
				? ch->pcdata->anon_color
				: 'x',
			emote != CHAN_EMOTE_COLON ? " " : "",
			emote_self,
			adverb ? " " : "",
			adverb ? adverb : "",
			channel->quote ? ", '" : " ",
			channel->color,
			channel->quote ? "'" : ""
			);
	else
		snprintf(buf, sizeof(buf), "%s{%cYou{x%s%s%s%s%s{%c$t{x%s",
			prefix,
			(IS_IMMORTAL(ch) && chan_flag != CHAN_WIZ 
			 && chan_flag != CHAN_DM_WIZ)
			? 'W' : 'x',
			emote != CHAN_EMOTE_COLON ? " " : "",
			emote_self,
			adverb ? " " : "",
			adverb ? adverb : "",
			channel->quote ? ", '" : " ",
			channel->color,
			channel->quote ? "'" : ""
			);

	/*
	act_puts(buf, ch, mesg, NULL,
		 TO_CHAR | ACT_NODEAF, POS_DEAD);
	 */
	act_puts(buf, ch, mesg, NULL,
		 TO_CHAR | channel->act_flags, POS_DEAD);

	if (channel->anonymous) { }

	else if (channel->imm_anon_color
	&& IS_IMMORTAL(ch) 
	&& (ch->invis_level > 0 || ch->incog_level > 0))
		snprintf(buf, sizeof(buf), 
			"%s{%c$n{x%s%s%s%s%s{%c$t{x%s",
			prefix, 
			ch->pcdata->anon_color
				? ch->pcdata->anon_color
				: 'x',
			emote != CHAN_EMOTE_COLON ? " " : "",
			emote_other,
			adverb ? " " : "",
			adverb ? adverb : "",
			channel->quote ? ", '" : " ",
			channel->color,
			channel->quote ? "'" : ""
			);
	else
		snprintf(buf, sizeof(buf), 
			"%s{%c$n{x%s%s%s%s%s{%c$t{x%s",
			prefix, 
			(IS_IMMORTAL(ch) && chan_flag != CHAN_WIZ 
			 && chan_flag != CHAN_DM_WIZ)
			? 'W' : 'x',
			emote != CHAN_EMOTE_COLON ? " " : "",
			emote_other,
			adverb ? " " : "",
			adverb ? adverb : "",
			channel->quote ? ", '" : " ",
			channel->color,
			channel->quote ? "'" : ""
			);

	/* now, send it to everyone on the channel */
	for (d = descriptor_list; d; d = d->next) {
                if (d->connected == CON_PLAYING
                &&  d->character != ch
                &&  IS_SET(d->character->channels, chan_flag)
		&&  d->character->level >= channel->read_level) {

			/* character must be in the same room */
			if (IS_SET(channel->locale, CHAN_LOCALE_ROOM)
			&& ch->in_room != d->character->in_room)
				continue;

			/* character must be in the same area */
			if (IS_SET(channel->locale, CHAN_LOCALE_AREA)
			&& (!d->character->in_room
			|| ch->in_room->area != d->character->in_room->area))
				continue;

			/* character must be in rooms with a certain flag */
			if (IS_SET(channel->locale, CHAN_LOCALE_ROOM_FLAG)
			&& (!d->character->in_room
			|| !IS_SET(d->character->in_room->room_flags, 
			channel->room_flags)))
				continue;

			/* character must believe in the same god */
			if (IS_SET(channel->locale, CHAN_LOCALE_RELIGION)
			&& (ch->religion != d->character->religion
			&& !(IS_IMMORTAL(d->character)
			&& IS_SET(d->character->pcdata->wiznet, WIZ_PRAY_CHAN)
			&& d->character->level == ML
			&& d->character->race == RACE_GNOME)))
				continue;

			/* character must be in the same clan */
			if (IS_SET(channel->locale, CHAN_LOCALE_CLAN)
			&& (ch->clan != d->character->clan
			&& !(IS_IMMORTAL(d->character)
			&& IS_SET(d->character->pcdata->wiznet, WIZ_CLAN_CHAN)
			&& d->character->level == ML
			&& d->character->race == RACE_GNOME)))
				continue;

                        act_puts(buf,
                                 ch, mesg, d->character,
				 TO_VICT | channel->act_flags,
                                 POS_DEAD);
		}
	}
}  

/*
 * from Anatolia MUD
 */
const char *garble(CHAR_DATA *ch, const char *i)
{
	static char not_garbled[] = "?!()[]{},.:;'\" ";
	static char buf[MAX_STRING_LENGTH];
	char *o;

	if (!is_affected(ch, gsn_garble))
		return i;

	for (o = buf; *i && o-buf < sizeof(buf)-1; i++, o++) {
		if (strchr(not_garbled, *i))
			*o = *i;
		else
			*o = number_range(' ', 254);
	}
	*o = '\0';
	return buf;
}