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