/**************************************************************************
* 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-2004 by Markanth *
* http://www.firstmud.com/ <markanth@firstmud.com> *
* By using this code you have agreed to follow the term of *
* the 1stMud license in ../doc/1stMud/LICENSE *
***************************************************************************/
#include "merc.h"
#include "interp.h"
#include "recycle.h"
#include "tables.h"
#include "olc.h"
const char *get_chan_color(ChannelData * chan)
{
if (chan->custom_color != -1)
return FORMATF(CTAG(%d), chan->custom_color);
else
return chan->color;
}
const char *format_channel(ChannelData * chan, CharData * ch)
{
static char buf[MSL];
strcpy(buf, chan->format);
switch (chan->spec_flag)
{
case spec_clan_flag:
sprintf(buf, chan->format, CharClan(ch)->name,
CharClan(ch)->rank[ch->rank].rankname);
break;
default:
break;
}
strcat(buf, get_chan_color(chan));
return (buf);
}
bool display_channel(CharData * ch, CharData * victim, ChannelData * chan,
chanarg_t type, bool fShow)
{
if (!ch || !victim)
return false;
if (IsSet(victim->wiznet, WIZ_CHANSNOOP))
return true;
if (!fShow)
{
if (chan->bit > 0 && IsSet(victim->comm, chan->bit))
return false;
if ((type == CHANNEL_EMOTE || type == CHANNEL_SOCIAL)
&& IsSet(victim->comm, COMM_NOGOCIAL))
return false;
if (IsSet(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 (!IsImmortal(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;
}
#ifndef DISABLE_WEBSRV
void init_www_history(void)
{
int x;
for (x = 0; x < 20; x++)
{
www_history[x] = &str_empty[0];
}
}
#endif
void init_channel_history(PcData * pcdata)
{
int i, x;
alloc_mem(pcdata->history, const char **, top_channel);
alloc_mem(pcdata->history_index, int, top_channel);
for (i = 0; i < top_channel; 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(PcData * pcdata, int gcn, int val, int oval)
{
int i, x;
if (gcn >= 0 && gcn < top_channel)
{
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(PcData * pcdata)
{
int i, x;
for (i = 0; i < top_channel; 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);
}
#ifndef DISABLE_WEBSRV
const char *Pers_WWW(CharData * ch)
{
if (!ch)
return "@@@";
if (IsImmortal(ch) && (ch->invis_level != 0 || ch->incog_level != 0))
return "an Immortal";
else if (IsAffected(ch, AFF_INVISIBLE))
return "someone";
return IsNPC(ch) ? ch->short_descr : ch->name;
}
#endif
void update_last_data(CharData * sender, CharData * viewer,
ChannelData * channel, const char *str, chanarg_t type)
{
char *time;
int gcn, i;
char buf[MSL];
const char *chan;
if (!channel || channel->page_length <= 0)
return;
gcn = *channel->index;
chan = format_channel(channel, sender);
if (viewer && !IsNPC(viewer))
{
++viewer->pcdata->history_index[gcn];
viewer->pcdata->history_index[gcn] %= channel->page_length;
i = viewer->pcdata->history_index[gcn];
time = str_time(-1, GetTzone(viewer), "%I:%M:%S %p");
switch (type)
{
case CHANNEL_NORMAL:
sprintf(buf, "[%s] %s{x %s %s '%s'{x", time, chan,
Pers(sender, viewer), say_verb(str, sender, viewer,
2), 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,
sender == viewer ? "You" : Pers(sender, viewer), str);
break;
case CHANNEL_THINK:
sprintf(buf, "[%s] %s %s . o O ( %s ){x", time, chan,
sender == viewer ? "You" : Pers(sender, viewer), str);
break;
default:
bugf("bad channel type [%d]", type);
buf[0] = '\0';
break;
}
replace_str(&viewer->pcdata->history[gcn][i], buf);
}
#ifndef DISABLE_WEBSRV
if (channel->spec_flag != spec_public_flag || sender == viewer)
return;
++www_index;
www_index %= 20;
time = str_time(-1, -1, "%I:%M:%S %p");
switch (type)
{
case CHANNEL_NORMAL:
sprintf(buf, "[%s] %s %s %s '%s'", time, chan, Pers_WWW(sender),
say_verb(str, sender, NULL, 2), 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_str(&www_history[www_index], buf);
#endif
}
void view_last_data(CharData * ch, ChannelData * 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 (!NullStr(ch->pcdata->history[gcn][i]))
{
found = true;
bprintln(output, ch->pcdata->history[gcn][i]);
}
}
if (!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, NEWLINE "Current time: %s Your Login Time: %s",
str_time(-1, GetTzone(ch), "%I:%M:%S %p"),
str_time(ch->logon, GetTzone(ch), "%I:%M:%S %p"));
}
sendpage(ch, buf_string(output));
free_buf(output);
}
const char *get_chan_soc_string(CharData * ch, CharData * victim,
CharData * vch, SocialData * soc)
{
if (!victim)
{
if (ch == vch)
return soc->char_no_arg;
else
return soc->others_no_arg;
}
else
{
if (victim == ch)
{
if (vch == ch)
return soc->char_auto;
else
return soc->others_auto;
}
else
{
if (victim == vch)
return soc->vict_found;
else if (ch == vch)
return soc->char_found;
else
return soc->others_found;
}
}
}
void channel_social(CharData * ch, CharData * victim, SocialData * soc,
ChannelData * chan)
{
Descriptor *d;
const char *type;
type = format_channel(chan, ch);
mud_info.stats.chan_msgs++;
for (d = descriptor_first; d; d = d->next)
{
CharData *vch = CH(d);
if (vch
&& (vch == ch || vch == victim
|| display_channel(ch, vch, chan, CHANNEL_SOCIAL, false)))
{
const char *string = get_chan_soc_string(ch, victim, vch, soc);
string = swearcheck(string, vch);
if (d->connected == CON_PLAYING)
{
perform_act(FORMATF("%s %s{x", type, string), ch, NULL,
victim, TO_CHAR, vch);
}
update_last_data(ch, vch, chan,
perform_act_string(string, ch, NULL, victim,
false), CHANNEL_SOCIAL);
}
}
}
void public_ch(const char *n_fun, CharData * ch, const char *argument,
int gcn)
{
char command[MIL + 100];
Descriptor *d;
chanarg_t chan_type = CHANNEL_NORMAL;
char arg_left[MSL];
ChannelData *chan = &channel_table[gcn];
const char *type;
if (chan == NULL)
{
chprintln(ch, "Channel is currently unavailable.");
return;
}
type = format_channel(chan, ch);
if (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", n_fun),
FORMATF("%s channel is now ON.{x", n_fun));
}
}
else
{
if (IsSet(ch->comm, COMM_QUIET))
{
chprintln(ch, "You must turn off quiet mode first.");
return;
}
if (chan->bit > 0)
RemBit(ch->comm, (chan->bit));
strcpy(arg_left, argument);
argument = one_argument(argument, command);
if (command[0] == '+')
{
CharData *victim;
SocialData *soc;
char argx[MIL];
argument = one_argument(argument, command);
if (NullStr(command))
{
cmd_syntax(ch, n_fun,
"{W%s + <social> is used for channel based socials.{x",
n_fun);
return;
}
if (!(soc = find_social(command)))
{
chprintln(ch, "{WWhat kind of social is that?!?!{x");
return;
}
one_argument(argument, argx);
victim = NULL;
if (NullStr(argx))
{
channel_social(ch, NULL, soc, 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;
}
channel_social(ch, victim, soc, chan);
}
return;
}
else if (command[0] == '!')
{
if (NullStr(argument))
{
cmd_syntax(ch, "%s ! <argument>", NULL);
return;
}
argument = str_rep(argument, "{x", get_chan_color(chan));
argument = swearcheck(argument, ch);
chan_type = CHANNEL_EMOTE;
chprintlnf(ch, "%s %s %s{x", type,
PretitOK(ch, ch) ? FORMATF("%s %s", ch->pcdata->pretit,
ch->name) : GetName(ch),
argument);
update_last_data(ch, ch, chan, argument, CHANNEL_EMOTE);
}
else if (command[0] == '@')
{
if (NullStr(argument))
{
cmd_syntax(ch, NULL, n_fun, "%s @ <argument>", NULL);
return;
}
chan_type = CHANNEL_THINK;
argument = str_rep(argument, "{x", get_chan_color(chan));
argument = swearcheck(argument, ch);
chprintlnf(ch, "%s %s . o O ( %s ){x", type,
PretitOK(ch, ch) ? FORMATF("%s %s", ch->pcdata->pretit,
ch->name) : GetName(ch),
argument);
update_last_data(ch, ch, chan, argument, CHANNEL_THINK);
}
else if (is_name(command, "-wholist -who") && NullStr(argument))
{
chan_type = CHANNEL_WHO;
chprintlnf(ch, "{WPlayers on %s{x", type);
chprintln(ch, "{C-------------------{x");
}
else if (is_name(command, "-hist -history") && NullStr(argument))
{
if (IsNPC(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 (is_name(command, "-help") && NullStr(argument))
{
cmd_syntax(ch, NULL, n_fun, "<message> - send a message",
" - toggle channel on/off",
"-history - display channel history",
"-wholist - display who is on channel",
"! <emote> - send an emote over channel",
"+ <social> [args] - do a social over channel",
"@ <message> - enclose a message in 'thought bubbles'",
"? - this message", NULL);
return;
}
else
{
chan_type = CHANNEL_NORMAL;
argument = str_rep(arg_left, "{x", get_chan_color(chan));
argument = swearcheck(argument, ch);
chprintlnf(ch, "%s You %s '%s'{x", type,
say_verb(argument, ch, ch, 0), argument);
update_last_data(ch, ch, chan, argument, CHANNEL_NORMAL);
portal_chat(ch, ch, n_fun, type, argument);
}
mud_info.stats.chan_msgs++;
for (d = descriptor_first; d != NULL; d = d->next)
{
CharData *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:
argument = swearcheck(arg_left, victim);
if (d->connected == CON_PLAYING)
chprintlnf(victim, "%s %s %s '%s'{x", type,
strip_color(Pers(ch, victim)),
say_verb(argument, ch, victim, 1),
argument);
update_last_data(ch, victim, chan, argument,
CHANNEL_NORMAL);
portal_chat(ch, victim, n_fun, type, argument);
break;
case CHANNEL_EMOTE:
case CHANNEL_THINK:
argument = swearcheck(argument, victim);
if (d->connected == CON_PLAYING)
{
if (chan_type == CHANNEL_THINK)
chprintlnf(victim, "%s %s . o O ( %s ){x", type,
strip_color(Pers(ch, victim)),
argument);
else
chprintlnf(victim, "%s %s %s{x", type,
strip_color(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;
}
}
}
}
Do_Fun(do_gossip)
{
public_ch(n_fun, ch, argument, gcn_gossip);
}
Do_Fun(do_grats)
{
public_ch(n_fun, ch, argument, gcn_grats);
}
Do_Fun(do_quote)
{
public_ch(n_fun, ch, argument, gcn_quote);
}
Do_Fun(do_question)
{
public_ch(n_fun, ch, argument, gcn_qa);
}
Do_Fun(do_answer)
{
public_ch(n_fun, ch, argument, gcn_qa);
}
Do_Fun(do_music)
{
public_ch(n_fun, ch, argument, gcn_music);
}
Do_Fun(do_ooc)
{
public_ch(n_fun, ch, argument, gcn_ooc);
}
Do_Fun(do_immtalk)
{
public_ch(n_fun, ch, argument, gcn_immtalk);
}
Do_Fun(do_barter)
{
public_ch(n_fun, ch, argument, gcn_barter);
}
Do_Fun(do_channels)
{
int i;
Buffer *buf;
buf = new_buf();
bprintlnf(buf, " %-9s %-6s{w %s", "Command", "Status", "Description");
bprintln(buf, draw_line(ch, NULL, 0));
for (i = 0; i < top_channel; i++)
{
if (!display_channel(ch, ch, &channel_table[i], CHANNEL_NORMAL, true))
continue;
bprintlnf(buf, "{G%-11s %-6s{w %s{x", channel_table[i].name,
OnOff(!IsSet(ch->comm, channel_table[i].bit)),
channel_table[i].description);
}
bprintlnf(buf, "{G%-11s %-6s{w %s{x", "shouts",
OnOff(IsSet(ch->comm, COMM_SHOUTSOFF)),
"A global channel that transmits with a delay as if there is an echo.");
bprintlnf(buf, "{G%-11s %-6s{w %s{x", "deaf",
OnOff(IsSet(ch->comm, COMM_DEAF)),
"Prevents you from hearing any tells.");
bprintlnf(buf, "{G%-11s %-6s{w %s{x", "quiet",
OnOff(IsSet(ch->comm, COMM_QUIET)),
"Toggles whether you receive any channels at all.");
bprintlnf(buf, "{G%-11s %-6s{w %s{x", "afk",
OnOff(IsSet(ch->comm, COMM_AFK)),
"Sets you Away From Keyboard.");
bprintlnf(buf, "{G%-11s %-6s{w %s{x", "nogocial",
OnOff(IsSet(ch->comm, COMM_NOGOCIAL)),
"Toggles socials/emotes over public channels.");
bprintln(buf, draw_line(ch, NULL, 0));
if (IsSet(ch->comm, COMM_SNOOP_PROOF))
bprintln(buf, "You are immune to snooping.");
if (ch->prompt != NULL)
{
bprintlnf(buf, "Your current prompt is: %s", ch->prompt);
}
if (ch->gprompt != NULL)
{
bprintlnf(buf, "Your current gprompt is: %s", ch->gprompt);
}
if (IsSet(ch->comm, COMM_NOSHOUT))
bprintln(buf, "You cannot shout.");
if (IsSet(ch->comm, COMM_NOTELL))
bprintln(buf, "You cannot use tell.");
if (IsSet(ch->comm, COMM_NOCHANNELS))
bprintln(buf, "You cannot use channels.");
if (IsSet(ch->comm, COMM_NOEMOTE))
bprintln(buf, "You cannot show emotions.");
sendpage(ch, buf_string(buf));
free_buf(buf);
do_function(ch, &do_censor, "status");
}
char *const swear[] = {
"shit", "fuck", "bitch", "bastard",
"bullshit", "pussy", "dick", "cock",
"motherfuck", "clit", "damn", "dammit",
"dumbass", "slut", "whore", "asshole", NULL
};
Do_Fun(do_censor)
{
if (!str_cmp(argument, "status"))
{
chprintlnf(ch, "Channels are currently rated %s.",
!IsSet(ch->comm, COMM_CENSOR) ? "{RR{x" : "{GPG{x");
return;
}
if (!str_cmp(argument, "list"))
{
Column c;
int x;
if (IsSet(ch->comm, COMM_CENSOR))
{
chprintln(ch, "You must be set to rated {RR{x to see the list.");
return;
}
set_cols(&c, ch, 4, COLS_CHAR, ch);
for (x = 0; swear[x] != NULL; x++)
{
print_cols(&c, swear[x]);
}
cols_nl(&c);
return;
}
set_on_off(ch, &ch->comm, COMM_CENSOR, "Channels are now rated {GPG{x.",
"Channels are now rated {RR{x.");
}
const char *swearcheck(const char *argument, CharData * ch)
{
int x;
if (ch && !CommFlag(ch, COMM_CENSOR))
return argument;
for (x = 0; swear[x] != NULL; x++)
{
if (!str_infix(swear[x], argument))
{
return stri_rep(argument, swear[x],
stringf(NULL, strlen(swear[x]), Left, "*", "*"));
}
}
return argument;
}
Olc_Fun(chanedit_gcn)
{
ChannelData *pChan;
Column Cd;
int i;
GetEdit(ch, ChannelData, pChan);
if (NullStr(argument))
{
cmd_syntax(ch, NULL, n_fun, "<gcn_name>", NULL);
return false;
}
if (is_name(argument, "clear reset none"))
{
pChan->index = &gcn_null;
olc_msg(ch, n_fun, "GCN Entry cleared.");
return true;
}
for (i = 0; channel_index[i].name != NULL; i++)
{
if (!str_cmp(argument, channel_index[i].name))
{
if (channel_index[i].index != &gcn_null
&& (!channel_index[i].index
|| !*(int *) channel_index[i].index))
{
int tmp;
for (tmp = 0; tmp < top_channel; tmp++)
if (&channel_table[tmp] == pChan)
break;
*(int *) channel_index[i].index = tmp;
}
pChan->index = (int *) channel_index[i].index;
olc_msg(ch, n_fun,
"Channel now uses global channel pointer '%s'.",
channel_index[i].name);
return true;
}
}
set_cols(&Cd, ch, 4, COLS_CHAR, ch);
for (i = 0; channel_index[i].name != NULL; i++)
print_cols(&Cd, channel_index[i].name);
cols_nl(&Cd);
olc_msg(ch, n_fun, "That GCN hasn't been coded in yet.");
return false;
}
Olc_Fun(chanedit_color)
{
ChannelData *pChan;
int slot;
GetEdit(ch, ChannelData, pChan);
if (NullStr(argument))
{
cmd_syntax(ch, NULL, n_fun, "<code>", "<custom code>", NULL);
return false;
}
if ((slot = color_lookup(argument)) != -1)
{
pChan->custom_color = color_table[slot].slot;
replace_str(&pChan->color, "");
}
else
{
replace_str(&pChan->color, argument);
pChan->custom_color = -1;
}
olc_msg(ch, n_fun, "Channel color changed.");
return true;
}