1stMUD4.0/bin/
1stMUD4.0/doc/MPDocs/
1stMUD4.0/player/
1stMUD4.0/win32/
1stMUD4.0/win32/rom/
/**************************************************************************
*  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
*  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.   *
*                                                                         *
*  Merc Diku Mud improvements copyright (C) 1992, 1993 by Michael         *
*  Chastain, Michael Quan, and Mitchell Tse.                              *
*                                                                         *
*  In order to use any part of this Merc Diku Mud, you must comply with   *
*  both the original Diku license in 'license.doc' as well the Merc       *
*  license in 'license.txt'.  In particular, you may not remove either of *
*  these copyright notices.                                               *
*                                                                         *
*  Much time and thought has gone into this software and you are          *
*  benefiting.  We hope that you share your changes too.  What goes       *
*  around, comes around.                                                  *
***************************************************************************
*       ROM 2.4 is copyright 1993-1998 Russ Taylor                        *
*       ROM has been brought to you by the ROM consortium                 *
*           Russ Taylor (rtaylor@hypercube.org)                           *
*           Gabrielle Taylor (gtaylor@hypercube.org)                      *
*           Brian Moore (zump@rom.org)                                    *
*       By using this code, you have agreed to follow the terms of the    *
*       ROM license, in the file Rom24/doc/rom.license                    *
***************************************************************************
*       1stMUD ROM Derivative (c) 2001-2003 by Ryan Jennings              *
*            http://1stmud.dlmud.com/  <r-jenn@shaw.ca>                   *
***************************************************************************/
#include "merc.h"
#define IN_CHANNELS_C
#include "gcn.h"
#undef IN_CHANNELS_C
#include "interp.h"
#include "globals.h"
#include "recycle.h"
#include "tables.h"
#include "lookup.h"
#include "olc.h"

const struct gsn_type gcn_table[] = {
#undef GCN_H
#define MAKE_GCN_TABLE
#include "gcn.h"
#undef MAKE_GCN_TABLE
	{NULL, NULL}
};

int *gcn_lookup(const char *word)
{
	int i;

	for (i = 0; gcn_table[i].name != NULL; i++)
	{
		if (!str_cmp(word, gcn_table[i].name))
			return gcn_table[i].pgsn;
	}
	return NULL;
}

const char *gcn_name(int *pgcn)
{
	int i;

	for (i = 0; gcn_table[i].pgsn != NULL; i++)
	{
		if (pgcn == gcn_table[i].pgsn)
			return gcn_table[i].name;
	}
	return NULL;
}

const char *get_chan_colour(CHANNEL_DATA * chan)
{
	if (chan->custom_colour != -1)
		return FORMATF(CTAG(%d), chan->custom_colour);
	else
		return chan->colour;
}

const char *format_channel(CHANNEL_DATA * chan, CHAR_DATA * ch)
{
	static char buf[MSL];

	strcpy(buf, chan->format);

	switch (chan->spec_flag)
	{
	case spec_clan_flag:
		sprintf(buf, chan->format, ch->clan->name,
				ch->clan->rank[ch->rank].rankname);
		break;
	default:
		break;
	}
	strcat(buf, get_chan_colour(chan));
	return (buf);
}

bool display_channel(CHAR_DATA * ch, CHAR_DATA * victim, CHANNEL_DATA * chan,
					 chanarg_t type, bool fShow)
{

	if (!ch || !victim)
		return FALSE;

	if (IS_SET(victim->wiznet, WIZ_CHANSNOOP))
		return TRUE;

	if (!fShow)
	{
		if (chan->bit > 0 && IS_SET(victim->comm, chan->bit))
			return FALSE;

		if ((type == CHANNEL_EMOTE || type == CHANNEL_SOCIAL)
			&& IS_SET(victim->comm, COMM_NOGOCIAL))
			return FALSE;

		if (IS_SET(victim->comm, COMM_QUIET))
			return FALSE;

		if (is_ignoring(victim, ch->name, IGNORE_CHANNELS))
			return FALSE;
	}

	switch (chan->spec_flag)
	{
	case spec_clan_flag:
		if (!is_same_clan(ch, victim))
			return FALSE;
		break;
	case spec_imm_flag:
		if (!IS_IMMORTAL(victim))
			return FALSE;
		break;
	case spec_buddy_flag:
		if (victim != ch
			&& (check_buddy(ch, victim) == -1 || check_buddy(victim, ch) == -1))
			return FALSE;
		break;
	case spec_public_flag:
		return TRUE;
		break;
	case spec_none:
		return FALSE;
	}

	return TRUE;
}

#if !defined(NO_WEB)

void init_www_history(void)
{
	int x;

	for (x = 0; x < 20; x++)
	{
		www_history[x] = &str_empty[0];
	}
}
#endif

void init_channel_history(PC_DATA * pcdata)
{
	int i, x;

	alloc_mem(pcdata->history, const char **, maxChannel);
	alloc_mem(pcdata->history_index, int, maxChannel);

	for (i = 0; i < maxChannel; i++)
	{
		pcdata->history_index[i] = 0;

		if (channel_table[i].page_length <= 0)
			continue;

		alloc_mem(pcdata->history[i], const char *,
				  channel_table[i].page_length);
		for (x = 0; x < channel_table[i].page_length; x++)
			pcdata->history[i][x] = &str_empty[0];
	}
}

void realloc_channel_history(PC_DATA * pcdata, int gcn, int val, int oval)
{
	int i, x;

	if (gcn >= 0 && gcn < maxChannel)
	{
		if (oval <= 0)
		{
			if (val > 0)
			{
				alloc_mem(pcdata->history[gcn], const char *, val);
			}
		}
		else
		{
			if (val <= 0)
			{
				free_mem(pcdata->history[gcn]);
			}
			else
			{
				realloc_mem(pcdata->history[gcn], const char *, val);
				for (x = oval; x < val; x++)
					pcdata->history[gcn][x] = &str_empty[0];
			}
		}
	}
	else
	{
		realloc_mem(pcdata->history, const char **, val);
		realloc_mem(pcdata->history_index, int, val);

		for (i = oval; i < val; i++)
		{
			pcdata->history_index[i] = 0;

			if (channel_table[i].page_length <= 0)
				continue;

			alloc_mem(pcdata->history[i], const char *,
					  channel_table[i].page_length);
			for (x = 0; x < channel_table[i].page_length; x++)
				pcdata->history[i][x] = &str_empty[0];
		}
	}
}

void free_channel_history(PC_DATA * pcdata)
{
	int i, x;

	for (i = 0; i < maxChannel; i++)
	{
		if (channel_table[i].page_length <= 0)
			continue;

		for (x = 0; x < channel_table[i].page_length; x++)
			free_string(pcdata->history[i][x]);
		free_mem(pcdata->history[i]);
	}
	free_mem(pcdata->history);
	free_mem(pcdata->history_index);
}

#if !defined(NO_WEB)

const char *PERS_WWW(CHAR_DATA * ch)
{

	if (!ch)
		return "@@@";

	if (IS_IMMORTAL(ch) && (ch->invis_level != 0 || ch->incog_level != 0))
		return "an Immortal";
	else if (IS_AFFECTED(ch, AFF_INVISIBLE))
		return "someone";
	return IS_NPC(ch) ? ch->short_descr : ch->name;
}
#endif

void update_last_data(CHAR_DATA * sender, CHAR_DATA * viewer,
					  CHANNEL_DATA * channel, const char *str, chanarg_t type)
{
	char *time;
	int gcn, i;
	char buf[MSL];
	const char *chan;

	if (IS_NPC(viewer) || !channel || channel->page_length <= 0)
		return;

	gcn = *channel->index;
	chan = format_channel(channel, sender);

	++viewer->pcdata->history_index[gcn];
	viewer->pcdata->history_index[gcn] %= channel->page_length;

	i = viewer->pcdata->history_index[gcn];

	time = str_time(current_time, GET_TZONE(viewer), "%I:%M:%S %p");
	switch (type)
	{
	case CHANNEL_NORMAL:
		sprintf(buf, "[%s] %s{x %s %s '%s'{x", time, chan, PERS(sender,
																viewer),
				sender == viewer ? "say" : "says", str);
		break;
	case CHANNEL_SOCIAL:
		sprintf(buf, "[%s] %s{x %s{x", time, chan, str);
		break;
	case CHANNEL_EMOTE:
		sprintf(buf, "[%s] %s{x %s %s{x",
				time, chan, PERS(sender, viewer), str);
		break;
	case CHANNEL_THINK:
		sprintf(buf,
				"[%s] %s %s . o O ( %s ){x", time, chan, PERS(sender,
															  viewer), str);
		break;
	default:
		bugf("bad channel type [%d]", type);
		buf[0] = '\0';
		break;
	}

	replace_string(viewer->pcdata->history[gcn][i], buf);

#if !defined(NO_WEB)

	if (channel->spec_flag != spec_public_flag || sender != viewer)
		return;

	++www_index;
	www_index %= 20;

	time = str_time(current_time, -1, "%I:%M:%S %p");

	switch (type)
	{
	case CHANNEL_NORMAL:
		sprintf(buf, "[%s] %s %s says '%s'", time, chan, PERS_WWW(sender), str);
		break;
	case CHANNEL_SOCIAL:
		sprintf(buf, "[%s] %s %s", time, chan, str);
		break;
	case CHANNEL_EMOTE:
		sprintf(buf, "[%s] %s %s %s", time, chan, PERS_WWW(sender), str);
		break;
	case CHANNEL_THINK:
		sprintf(buf, "[%s] %s %s . o O ( %s )",
				time, chan, PERS_WWW(sender), str);
		break;
	default:
		bugf("bad channel type [%d]", type);
		buf[0] = '\0';
		break;
	}
	replace_string(www_history[www_index], buf);
#endif

}

void view_last_data(CHAR_DATA * ch, CHANNEL_DATA * chan)
{
	int i, gcn;
	bool found = FALSE;
	BUFFER *output;

	if (!chan || chan->page_length <= 0)
		return;

	output = new_buf();
	gcn = *chan->index;
	for (i = (ch->pcdata->history_index[gcn] + 1) % chan->page_length;
		 i != ch->pcdata->history_index[gcn]; i = (i + 1) % chan->page_length)
	{
		if (!IS_NULLSTR(ch->pcdata->history[gcn][i]))
		{
			found = TRUE;
			bprintln(output, ch->pcdata->history[gcn][i]);
		}
	}
	if (!IS_NULLSTR(ch->pcdata->history[gcn][ch->pcdata->history_index[gcn]]))
	{
		bprintln(output,
				 ch->pcdata->history[gcn][ch->pcdata->history_index[gcn]]);
		found = TRUE;
	}

	if (!found)
		bprintln(output, "None.");
	else
	{
		bprintlnf(output, "\n\rCurrent time: %s   Your Login Time: %s",
				  str_time(current_time, GET_TZONE(ch), "%I:%M:%S %p"),
				  str_time(ch->logon, GET_TZONE(ch), "%I:%M:%S %p"));
	}
	sendpage(ch, buf_string(output));
	free_buf(output);
}

void channel_social(CHAR_DATA * ch, CHAR_DATA * victim, OBJ_DATA * obj,
					const char *string, CHANNEL_DATA * chan)
{
	DESCRIPTOR_DATA *d;
	const char *type = format_channel(chan, ch);

	for (d = descriptor_first; d; d = d->next)
	{
		CHAR_DATA *vch = CH(d);

		if (vch && (vch != ch) && (vch != victim)
			&& display_channel(ch, vch, chan, CHANNEL_SOCIAL, FALSE))
		{
			if (d->connected == CON_PLAYING)
			{
				char buf[MSL];

				sprintf(buf, "%s %s{x", type, string);
				perform_act(buf, ch, obj, victim, FALSE, vch);
			}
			update_last_data(ch, vch, chan,
							 perform_act_string(string, ch, obj, victim, FALSE),
							 CHANNEL_SOCIAL);
		}
	}
	update_last_data(ch, ch, chan,
					 perform_act_string(string, ch, obj, victim, FALSE),
					 CHANNEL_SOCIAL);
}

void public_ch(CHAR_DATA * ch, const char *argument, int gcn)
{
	char command[MIL + 100];
	DESCRIPTOR_DATA *d;
	chanarg_t chan_type = CHANNEL_NORMAL;
	char arg_left[MSL];
	CHANNEL_DATA *chan = &channel_table[gcn];
	const char *type;

	if (chan == NULL)
	{
		chprintln(ch, "Channel is currently unavailable.");
		return;
	}

	type = format_channel(chan, ch);

	if (IS_NULLSTR(argument))
	{
		if (chan->bit <= 0)
			chprintln(ch, "What do you want to say?");
		else
		{
			set_on_off(ch, &ch->comm, chan->bit,
					   FORMATF("%s channel is now OFF.{x", type),
					   FORMATF("%s channel is now ON.{x", type));
		}
	}
	else
	{
		if (IS_SET(ch->comm, COMM_QUIET))
		{
			chprintln(ch, "You must turn off quiet mode first.");
			return;
		}
		if (chan->bit > 0)
			REMOVE_BIT(ch->comm, (chan->bit));

		strcpy(arg_left, argument);

		argument = one_argument(argument, command);
		if (command[0] == '+')
		{
			CHAR_DATA *victim;
			char buf[MIL + 200];
			SOCIAL_DATA *soc;
			char argx[MIL];

			argument = one_argument(argument, command);
			if (IS_NULLSTR(command))
			{
				chprintln
					(ch, "{W+ <social> is used for channel based socials.{x");
				return;
			}
			if (!(soc = find_social(command)))
			{
				chprintln(ch, "{WWhat kind of social is that?!?!{x");
				return;
			}
			one_argument(argument, argx);
			victim = NULL;
			if (IS_NULLSTR(argx))
			{
				sprintf(buf, "%s %s{x", type, soc->char_no_arg);
				act_new(buf, ch, NULL, NULL, TO_CHAR, POS_DEAD);
				channel_social(ch, NULL, NULL, soc->others_no_arg, chan);
			}
			else if ((victim = get_char_world(ch, argx)) == NULL)
			{
				chprintln(ch, "They aren't here.");
				return;
			}
			else
			{
				if (is_ignoring(victim, ch->name, IGNORE_SOCIALS))
				{
					act("$N is ignoring socials from you.", ch, NULL, victim,
						TO_CHAR);
					return;
				}
				if (!display_channel(ch, victim, chan, CHANNEL_SOCIAL, FALSE))
				{
					chprintln(ch, "They can't use that channel.");
					return;
				}
				if (victim == ch)
				{
					sprintf(buf, "%s %s{x", type, soc->char_auto);
					act_new(buf, ch, NULL, NULL, TO_CHAR, POS_DEAD);
					channel_social(ch, victim, NULL, soc->others_auto, chan);
				}
				else
				{
					sprintf(buf, "%s %s{x", type, soc->char_found);
					act_new(buf, ch, NULL, victim, TO_CHAR, POS_DEAD);
					if (display_channel
						(ch, victim, chan, CHANNEL_SOCIAL, FALSE))
					{
						sprintf(buf, "%s %s{x", type, soc->vict_found);
						act_new(buf, ch, NULL, victim, TO_VICT, POS_DEAD);
					}
					channel_social(ch, victim, NULL, soc->others_found, chan);
				}
			}
			return;
		}
		else if (command[0] == '!')
		{
			if (IS_NULLSTR(argument))
			{
				chprintln(ch, "Syntax: ! <argument>");
				return;
			}

			chan_type = CHANNEL_EMOTE;
			chprintlnf(ch, "%s %s %s{x", type,
					   IS_NPC(ch) ? ch->short_descr : ch->name, argument);
			update_last_data(ch, ch, chan, argument, CHANNEL_EMOTE);
		}
		else if (command[0] == '@')
		{
			if (IS_NULLSTR(argument))
			{
				chprintln(ch, "Syntax: @ <argument>");
				return;
			}

			chan_type = CHANNEL_THINK;
			chprintlnf(ch, "%s %s . o O ( %s ){x", type,
					   IS_NPC(ch) ? ch->short_descr : ch->name, argument);
			update_last_data(ch, ch, chan, argument, CHANNEL_THINK);
		}
		else if (is_exact_name(command, "wholist -who -w")
				 && IS_NULLSTR(argument))
		{
			chan_type = CHANNEL_WHO;
			chprintlnf(ch, "{WPlayers on %s{x", type);
			chprintln(ch, "{C-------------------{x");
		}
		else if (is_name(command, "/last -hist") && IS_NULLSTR(argument))
		{
			if (IS_NPC(ch) || chan->page_length <= 0)
			{
				chprintln(ch, "Channel history unavailable.");
				return;
			}
			chprintlnf(ch, "{WLast %d messages on %s{x", chan->page_length,
					   type);
			chprintln(ch, "{C------------------------------{x");
			view_last_data(ch, chan);
			return;
		}
		else if (command[0] == '?' && IS_NULLSTR(argument))
		{
			chprintln(ch, "Syntax: <message>          - send a message");
			if (chan->bit > 0)
				chprintln(ch,
						  "      :                    - toggle channel on/off");
			chprintln(ch,
					  "      : -hist              - display channel history");
			chprintln(ch,
					  "      : -who               - display who is on channel");
			chprintln(ch,
					  "      : ! <emote>          - send an emote over channel");
			chprintln(ch,
					  "      : + <social> [args]  - do a social over channel");
			chprintln(ch,
					  "      : @ <message>        - enclose a message in 'thought bubbles'");
			chprintln(ch, "      : ?                  - this message");
			return;
		}
		else
		{
			chan_type = CHANNEL_NORMAL;
			chprintlnf(ch, "%s You say '%s'{x", type, arg_left);
			update_last_data(ch, ch, chan, arg_left, CHANNEL_NORMAL);
		}
		for (d = descriptor_first; d != NULL; d = d->next)
		{
			CHAR_DATA *victim;

			if ((victim = d->character) == NULL)
				continue;
			if (victim == ch)
				continue;
			if (!display_channel(ch, victim, chan, chan_type, FALSE))
				continue;

			switch (chan_type)
			{
			default:
			case CHANNEL_NORMAL:
				if (d->connected == CON_PLAYING)
					chprintlnf(victim, "%s %s says '%s'{x", type,
							   smash_colour(PERS(ch, victim)), arg_left);
				update_last_data(ch, victim, chan, arg_left, CHANNEL_NORMAL);
				break;
			case CHANNEL_EMOTE:
			case CHANNEL_THINK:
				if (d->connected == CON_PLAYING)
				{
					if (chan_type == CHANNEL_THINK)
						chprintlnf(victim, "%s %s . o O ( %s ){x", type,
								   smash_colour(PERS(ch, victim)), argument);
					else
						chprintlnf(victim, "%s %s %s{x", type,
								   smash_colour(PERS(ch, victim)), argument);
				}
				update_last_data(ch, victim, chan, argument, chan_type);
				break;
			case CHANNEL_WHO:
				if (can_see(ch, victim))
					chprintlnf(ch, "{W%s{x", PERS(victim, ch));
				break;
			}
		}
	}
}

CH_CMD(do_gossip)
{
	public_ch(ch, argument, gcn_gossip);
}

CH_CMD(do_grats)
{
	public_ch(ch, argument, gcn_grats);
}

CH_CMD(do_quote)
{
	public_ch(ch, argument, gcn_quote);
}

CH_CMD(do_question)
{
	public_ch(ch, argument, gcn_qa);
}

CH_CMD(do_answer)
{
	public_ch(ch, argument, gcn_qa);
}

CH_CMD(do_music)
{
	public_ch(ch, argument, gcn_music);
}

CH_CMD(do_ooc)
{
	public_ch(ch, argument, gcn_ooc);
}

CH_CMD(do_immtalk)
{
	public_ch(ch, argument, gcn_immtalk);
}

/* RT code to display channel status */

CH_CMD(do_channels)
{
	int i;

	/* lists all channels and their status */
	chprintlnf(ch, " %-9s %-6s{w %s", "Command", "Status", "Description");
	chprintln(ch, draw_line(ch, NULL, 0));

	for (i = 0; i < maxChannel; i++)
	{
		if (!display_channel(ch, ch, &channel_table[i], CHANNEL_NORMAL, TRUE))
			continue;

		print_on_off(ch, !IS_SET(ch->comm, channel_table[i].bit),
					 channel_table[i].name, channel_table[i].description);
	}

	print_on_off(ch, IS_SET(ch->comm, COMM_SHOUTSOFF), "shouts",
				 "A global channel that transmits with a delay as if there is an echo.");
	print_on_off(ch, IS_SET(ch->comm, COMM_DEAF), "deaf",
				 "Prevents you from hearing any tells.");
	print_on_off(ch, IS_SET(ch->comm, COMM_QUIET), "quiet",
				 "Toggles whether you receive any channels at all.");
	print_on_off(ch, IS_SET(ch->comm, COMM_AFK), "afk",
				 "Sets you Away From Keyboard.");
	print_on_off(ch, IS_SET(ch->comm, COMM_NOGOCIAL), "nogocial",
				 "Toggles socials/emotes over public channels.");
	chprintln(ch, draw_line(ch, NULL, 0));

	if (IS_SET(ch->comm, COMM_SNOOP_PROOF))
		chprintln(ch, "You are immune to snooping.");

	if (ch->prompt != NULL)
	{
		chprintlnf(ch, "Your current prompt is: %s", ch->prompt);
	}

	if (IS_SET(ch->comm, COMM_NOSHOUT))
		chprintln(ch, "You cannot shout.");

	if (IS_SET(ch->comm, COMM_NOTELL))
		chprintln(ch, "You cannot use tell.");

	if (IS_SET(ch->comm, COMM_NOCHANNELS))
		chprintln(ch, "You cannot use channels.");

	if (IS_SET(ch->comm, COMM_NOEMOTE))
		chprintln(ch, "You cannot show emotions.");
}

OLCED(chanedit_show)
{
	CHANNEL_DATA *pChan;

	EDIT_CHAN(ch, pChan);

	chprintlnf(ch, "Index: %d (%s)", *pChan->index, gcn_name(pChan->index));
	chprintlnf(ch, "Name: %s", pChan->name);
	chprintlnf(ch, "Description: %s", pChan->description);
	chprintlnf(ch, "Type: %s", flag_string(chan_types, pChan->spec_flag));
	chprintlnf(ch, "Bit: %s", flag_string(comm_flags, pChan->bit));
	chprintlnf(ch, "Hist Length: %d", pChan->page_length);
	chprintlnf(ch, "Format: %s{x", pChan->format);
	chprintlnf(ch, "Colour: %s(looks like this){x", get_chan_colour(pChan));
	return TRUE;
}

OLCED(chanedit_create)
{
	int j, i = maxChannel;
	CHANNEL_DATA *pChan;
	struct channel_type *new_table;
	CHAR_DATA *pch;

	maxChannel++;

	alloc_mem(new_table, struct channel_type, maxChannel);

	if (!new_table)
	{
		chprintln(ch, "Memory Allocation Failed!!! Unable to create channel.");
		return FALSE;
	}

	for (j = 0; j < i; j++)
		new_table[j] = channel_table[j];

	free_mem(channel_table);
	channel_table = new_table;

	channel_table[i].index = &gcn_null;
	channel_table[i].bit = 0;
	channel_table[i].spec_flag = spec_none;
	channel_table[i].page_length = 20;
	channel_table[i].format = &str_empty[0];
	channel_table[i].colour = &str_empty[0];
	channel_table[i].name = str_dup(argument);
	channel_table[i].description = &str_empty[0];
	channel_table[i].custom_colour = -1;

	for (pch = player_first; pch; pch = pch->next_player)
		realloc_channel_history(pch->pcdata, -1, maxChannel, i);

	pChan = &channel_table[i];
	edit_start(ch, pChan, ED_CHAN);
	chprintln(ch, "Channel created.");
	return TRUE;
}

OLCED(chanedit_gcn)
{
	CHANNEL_DATA *pChan;
	int i;

	EDIT_CHAN(ch, pChan);

	if (IS_NULLSTR(argument))
	{
		chprintln(ch, "Syntax: gcn <gcn-name>");
		return FALSE;
	}

	if (is_name(argument, "clear reset none"))
	{
		pChan->index = &gcn_null;
		chprintln(ch, "GCN Entry cleared.");
		return TRUE;
	}

	for (i = 0; gcn_table[i].name != NULL; i++)
	{
		if (!str_cmp(argument, gcn_table[i].name))
		{
			pChan->index = gcn_table[i].pgsn;
			chprintlnf(ch, "Channel now uses global channel pointer '%s'.",
					   gcn_table[i].name);
			return TRUE;
		}
	}

	chprintln(ch, "That GCN hasn't been coded in yet.");
	return FALSE;
}

OLCED(chanedit_colour)
{
	CHANNEL_DATA *pChan;
	int slot;
	int cslot_lookup(const char *);

	EDIT_CHAN(ch, pChan);

	if (IS_NULLSTR(argument))
	{
		chprintln(ch, "Syntax: colour <colour code>");
		chprintln(ch, "      : colour <custom colour name>");
		return FALSE;
	}

	if ((slot = cslot_lookup(argument)) != -1)
	{
		pChan->custom_colour = slot;
		replace_string(pChan->colour, "");
	}
	else
	{
		replace_string(pChan->colour, argument);
		pChan->custom_colour = -1;
	}

	chprintln(ch, "Channel colour changed.");
	return TRUE;
}

OLCED(chanedit_delete)
{
	CHANNEL_DATA *pChan;

	EDIT_CHAN(ch, pChan);

	if (str_cmp(argument, "confirm"))
	{
		chprintln
			(ch,
			 "Typing 'delete confirm' will permanetely remove this channel!\n\r"
			 "-or- 'delete' with any argument will cancel the deletion.");
		return FALSE;
	}
	else
	{
		int i, j = 0, c, old = maxChannel;
		struct channel_type *new_table;
		int channel_lookup(const char *);
		CHAR_DATA *pch;

		maxChannel--;

		alloc_mem(new_table, struct channel_type, maxChannel);

		if (!new_table)
		{
			chprintln(ch,
					  "Memory Allocation error!!! Unable to delete channel.");
			return FALSE;
		}

		c = channel_lookup(pChan->name);
		if (c == -1 && pChan->index != NULL)
			c = *pChan->index;

		for (i = 0; i < old; i++)
			if (i != c)
				new_table[j++] = channel_table[i];

		free_mem(channel_table);
		channel_table = new_table;

		for (pch = player_first; pch != NULL; pch = pch->next_player)
			realloc_channel_history(pch->pcdata, -1, maxChannel, old);

		pChan = &channel_table[0];
		ch->desc->pEdit = (void *) pChan;

		chprintln(ch, "Channel deleted.");
	}

	return TRUE;
}

OLCED(chanedit_list)
{
	int i;

	for (i = 0; i < maxChannel; i++)
		chprintlnf(ch, "%2d) %s{x", i, format_channel(&channel_table[i], ch));

	return TRUE;
}