/***************************************************************************
* Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, *
* Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. *
* *
* Merc Diku Mud improvments 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. *
* *
* Dystopia Mud improvements copyright (C) 2000, 2001 by Brian Graversen *
* *
* Much time and thought has gone into this software and you are *
* benefitting. We hope that you share your changes too. What goes *
* around, comes around. *
***************************************************************************/
/***************************************************************************
* _/ _/ *
* _/_/_/ _/_/ _/_/_/ _/ _/_/ _/ _/ _/_/_/ *
* _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ *
* _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ *
* _/ _/ _/ _/_/_/ _/ _/_/ _/_/_/ _/_/_/ *
***************************************************************************
* Mindcloud Copyright 2001-2003 by Jeff Boschee (Zarius), *
* Additional credits are in the help file CODECREDITS *
* All Rights Reserved. *
***************************************************************************/
/*
* Communication storage system. Ye Jobo.
*/
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#include "merc.h"
HISTORY_DATA *history_free;
HISTORY_DATA *stored_tells;
void init_channel_storage()
{
int i, j;
for (i = 1; i < STORE_MAX; i++)
{
for (j = 1; j <= MAX_STORAGE; j++)
{
old_messages[i].last[j] = str_dup("");
}
}
}
void update_channel_storage(char *buf, int chan)
{
char xbuf[MAX_STRING_LENGTH];
char tbuf[20];
int i;
if (chan != STORE_TELL)
{
xprintf(tbuf, "%-18.18s", buf);
xprintf(xbuf, "%s %s", tbuf, line_indent(&buf[19], 15, 85));
}
else
xprintf(xbuf, buf);
if (chan >= STORE_MAX)
{
bug("update_channel_storage : Bad channel", 0);
return;
}
for (i = MAX_STORAGE; i > 1; i--)
{
free_string(old_messages[chan].last[i]);
old_messages[chan].last[i] =
str_dup(old_messages[chan].last[i - 1]);
}
free_string(old_messages[chan].last[1]);
old_messages[chan].last[1] = str_dup(xbuf);
}
void do_lastmessage(CHAR_DATA * ch, char *argument)
{
char arg[MAX_INPUT_LENGTH];
one_argument(argument, arg);
if (IS_NPC(ch))
return;
if (!str_cmp(arg, "chat"))
showchannel(ch, STORE_CHAT);
else if (!str_cmp(arg, "newbie"))
showchannel(ch, STORE_NEWBIE);
else if (!str_cmp(arg, "flame"))
showchannel(ch, STORE_FLAME);
else if (!str_cmp(arg, "roleplay"))
showchannel(ch, STORE_ROLEPLAY);
else if (!str_cmp(arg, "tell") && ch->level > 6)
showchannel(ch, STORE_TELL);
else if (ch->level < 7)
send_to_char
("Show the last chat/newbie/flame/roleplay messages ?\n\r",
ch);
else
send_to_char
("Show the last chat/newbie/flame/roleplay/tell messages ?\n\r",
ch);
return;
}
void showchannel(CHAR_DATA * ch, int chan)
{
char buf[MAX_STRING_LENGTH];
int i;
for (i = MAX_STORAGE; i > 0; i--)
{
if (strlen(old_messages[chan].last[i]) < 1)
continue;
xprintf(buf, "%s\n\r", old_messages[chan].last[i]);
send_to_char(buf, ch);
}
}
void init_tell_storage()
{
HISTORY_DATA *history_new;
HISTORY_DATA *history_prev = NULL;
int i;
for (i = 0; i < MAX_STORAGE; i++)
{
if (history_free == NULL)
{
history_new = alloc_perm(sizeof(*history_new));
}
else
{
history_new = history_free;
history_free = history_free->next;
}
history_new->message = str_dup("");
history_new->next = history_prev;
history_prev = history_new;
}
stored_tells = history_new;
}
char *makedrunk(char *string, CHAR_DATA * ch)
{
/* This structure defines all changes for a character */
struct struckdrunk drunk[] = {
{3, 10,
{"a", "a", "a", "A", "aa", "ah", "Ah", "ao", "aw", "oa",
"ahhhh"}},
{8, 5,
{"b", "b", "b", "B", "B", "vb"}},
{3, 5,
{"c", "c", "C", "cj", "sj", "zj"}},
{5, 2,
{"d", "d", "D"}},
{3, 3,
{"e", "e", "eh", "E"}},
{4, 5,
{"f", "f", "ff", "fff", "fFf", "F"}},
{8, 2,
{"g", "g", "G"}},
{9, 6,
{"h", "h", "hh", "hhh", "Hhh", "HhH", "H"}},
{7, 6,
{"i", "i", "Iii", "ii", "iI", "Ii", "I"}},
{9, 5,
{"j", "j", "jj", "Jj", "jJ", "J"}},
{7, 2,
{"k", "k", "K"}},
{3, 2,
{"l", "l", "L"}},
{5, 8,
{"m", "m", "mm", "mmm", "mmmm", "mmmmm", "MmM", "mM", "M"}},
{6, 6,
{"n", "n", "nn", "Nn", "nnn", "nNn", "N"}},
{3, 6,
{"o", "o", "ooo", "ao", "aOoo", "Ooo", "ooOo"}},
{3, 2,
{"p", "p", "P"}},
{5, 5,
{"q", "q", "Q", "ku", "ququ", "kukeleku"}},
{4, 2,
{"r", "r", "R"}},
{2, 5,
{"s", "ss", "zzZzssZ", "ZSssS", "sSzzsss", "sSss"}},
{5, 2,
{"t", "t", "T"}},
{3, 6,
{"u", "u", "uh", "Uh", "Uhuhhuh", "uhU", "uhhu"}},
{4, 2,
{"v", "v", "V"}},
{4, 2,
{"w", "w", "W"}},
{5, 6,
{"x", "x", "X", "ks", "iks", "kz", "xz"}},
{3, 2,
{"y", "y", "Y"}},
{2, 9,
{"z", "z", "ZzzZz", "Zzz", "Zsszzsz", "szz", "sZZz", "ZSz",
"zZ", "Z"}}
};
char buf[MSL];
char temp;
int pos = 0;
int drunklevel;
int randomnum;
/*
* Check how drunk a person is...
*/
if (ch == NULL)
drunklevel = 5;
else if (IS_NPC(ch))
drunklevel = 0;
else
drunklevel = ch->pcdata->condition[COND_DRUNK];
if (drunklevel > 0)
{
do
{
temp = toupper(*string);
if ((temp >= 'A') && (temp <= 'Z'))
{
if (drunklevel >
drunk[temp - 'A'].min_drunk_level)
{
randomnum =
number_range(0,
drunk[temp -
'A'].
number_of_rep);
strcpy(&buf[pos],
drunk[temp -
'A'].
replacement[randomnum]);
pos += strlen(drunk[temp - 'A'].
replacement[randomnum]);
}
else
buf[pos++] = *string;
}
else
{
if ((temp >= '0') && (temp <= '9'))
{
temp = '0' + number_range(0, 9);
buf[pos++] = temp;
}
else
buf[pos++] = *string;
}
}
while (*string++);
buf[pos] = '\0'; /* Mark end of the string... */
strcpy(string, buf);
return (string);
}
return (string);
}
void talk_channel(CHAR_DATA * ch, char *argument, int channel,
int sub_channel, const char *verb)
{
char buf[MAX_STRING_LENGTH];
DESCRIPTOR_DATA *d;
if (RTIMER(ch->in_room, RTIMER_SILENCE) != 0)
{
send_to_char
("Something prevents you from speaking in this room.\n\r",
ch);
return;
}
if (argument[0] == '\0')
{
xprintf(buf, "%s what?\n\r", verb);
buf[0] = UPPER(buf[0]);
send_to_char(buf, ch);
return;
}
if (IS_HEAD(ch, LOST_TONGUE))
{
xprintf(buf, "You can't %s without a tongue!\n\r", verb);
send_to_char(buf, ch);
return;
}
if (IS_EXTRA(ch, GAGGED))
{
xprintf(buf, "You can't %s with a gag on!\n\r", verb);
send_to_char(buf, ch);
return;
}
//if (IS_POLYAFF(ch, POLY_ZULOFORM))
// argument = darktongue(ch, argument);
// if (ch->pcdata->condition[COND_DRUNK] > 10)
// argument = makedrunk(argument, ch);
if (IS_SPEAKING(ch, DIA_OLDE))
argument = oldelang(ch, argument);
else if (IS_SPEAKING(ch, DIA_BAD))
argument = badlang(ch, argument);
//argument = makedrunk ( argument, ch );
//if (channel == CHANNEL_CHAT)
//mud_message(ch, argument);
REMOVE_BIT(ch->deaf, channel);
switch (channel)
{
default:
if (ch->flag4 == 1)
{
xprintf(buf, "#nYou whine '#R%s#n'.\n\r", argument);
send_to_char(buf, ch);
xprintf(buf, "#n%s #Pwhines#n '#R$t#n'.", ch->name);
}
else if (channel == CHANNEL_FLAME)
{
xprintf(buf, "#nYou %s '#W%s#n'.\n\r", verb, argument);
send_to_char(buf, ch);
xprintf(buf, "#n%s %ses '#W$t#n'.", ch->name, verb);
}
else if (channel == CHANNEL_CHAT)
{
//argument = pcolor(ch, argument, 0);
xprintf(buf, "#nYou %s '#R%s#n'.\n\r", verb, argument);
send_to_char(buf, ch);
if (ch->trust > 6)
xprintf(buf,
"#Y(#G*#Y)#C%s#Y(#G*#Y)#n '#1$t#n'.",
ch->name);
else if (IS_NPC(ch))
xprintf(buf, "%s chats '#R$t#n'.",
ch->short_descr);
else if (IS_CLASS(ch, CLASS_WEREWOLF))
xprintf(buf, "%s barks '#R$t#n'.", ch->name);
else if (IS_CLASS(ch, CLASS_MAGE))
xprintf(buf, "%s chants '#R$t#n'.", ch->name);
else if (IS_CLASS(ch, CLASS_SHAPESHIFTER))
xprintf(buf, "%s whispers '#R$t#n'.",
ch->name);
else if (IS_CLASS(ch, CLASS_VAMPIRE))
xprintf(buf, "%s snarls '#R$t#n'.", ch->name);
else if (IS_CLASS(ch, CLASS_DRONE))
xprintf(buf, "%s drools '#R$t#n'.", ch->name);
else if (IS_CLASS(ch, CLASS_ANGEL))
xprintf(buf, "%s preaches '#R$t#n'.",
ch->name);
else if (IS_CLASS(ch, CLASS_TANARRI))
xprintf(buf, "%s booms '#R$t#n'.", ch->name);
else if (IS_CLASS(ch, CLASS_LICH))
xprintf(buf, "%s squicks '#R$t#n'.",
ch->name);
else if (IS_CLASS(ch, CLASS_HOBBIT))
xprintf(buf, "%s burps '#R$t#n'.", ch->name);
else if (IS_CLASS(ch, CLASS_DEMON))
xprintf(buf, "%s growls '#R$t#n'.", ch->name);
else if (IS_CLASS(ch, CLASS_CYBORG))
xprintf(buf, "%s chitters '#R$t#n'.",
ch->name);
else if (IS_CLASS(ch, CLASS_GIANT))
xprintf(buf, "%s rumbles '#R$t#n'.",
ch->name);
else if (IS_CLASS(ch, CLASS_SKYBLADE))
xprintf(buf, "%s hollars '#R$t#n'.",
ch->name);
else
xprintf(buf, "%s %ss '#R$t#n'.", ch->name,
verb);
}
else
{
xprintf(buf, "You %s '#R%s#n'.\n\r", verb, argument);
send_to_char(buf, ch);
xprintf(buf, "%s %ss '#R$t#n'.", ch->name, verb);
}
break;
case CHANNEL_IMMTALK:
xprintf(buf, "#Y.:#P%s#Y:.#C $t.#n", ch->name);
act(buf, ch, argument, NULL, TO_CHAR);
break;
case CHANNEL_CLASS:
switch (sub_channel)
{
case CC_ANGEL:
xprintf(buf, "#0[#7%s#0]#C '$t'.#n", ch->name);
act(buf, ch, argument, NULL, TO_CHAR);
break;
case CC_DEMON:
xprintf(buf, "#0[#R%s#0]#C '$t'.#n", ch->name);
act(buf, ch, argument, NULL, TO_CHAR);
break;
case CC_MAGE:
xprintf(buf, "#n{{#0%s#n}}#C '$t'.#n", ch->name);
act(buf, ch, argument, NULL, TO_CHAR);
break;
case CC_SHIFTER:
xprintf(buf, "#G*#C(>#R%s#C<)#G* #C'$t'.#n",
ch->name);
act(buf, ch, argument, NULL, TO_CHAR);
break;
case CC_CYBORG:
xprintf(buf, "#p{#0-#p}#0%s#p{#0-#p} #C'$t'.#n",
ch->name);
act(buf, ch, argument, NULL, TO_CHAR);
break;
case CC_WW:
xprintf(buf, "#Y((#L%s#Y))#C '$t'.#n", ch->name);
act(buf, ch, argument, NULL, TO_CHAR);
break;
case CC_NINJA:
xprintf(buf, "#Y-*(#0%s#Y)*-#C '$t'.#n", ch->name);
act(buf, ch, argument, NULL, TO_CHAR);
break;
case CC_SAMURAI:
xprintf(buf, "#C-=#R%s#C=- '$t'.#n", ch->name);
act(buf, ch, argument, NULL, TO_CHAR);
break;
case CC_KNIGHT:
xprintf(buf, "#0.x.#7%s#0.x.#C '$t'.#n", ch->name);
act(buf, ch, argument, NULL, TO_CHAR);
break;
case CC_FAE:
xprintf(buf, "#G>>#R(#Y%s#R)#G<<#C '$t'.#n",
ch->name);
act(buf, ch, argument, NULL, TO_CHAR);
break;
case CC_GIANT:
xprintf(buf, "#G<:>#o%s#G<:>#C '$t'.#n", ch->name);
act(buf, ch, argument, NULL, TO_CHAR);
break;
case CC_HOBBIT:
xprintf(buf, "#o(#c*#o)#R%s#o(#c*#o)#C '$t'.#n",
ch->name);
act(buf, ch, argument, NULL, TO_CHAR);
break;
case CC_TANARRI:
xprintf(buf, "#Y{#R%s#Y}#C '$t'.#n", ch->name);
act(buf, ch, argument, NULL, TO_CHAR);
break;
case CC_LICH:
xprintf(buf, "#G>*<#7%s#G>*<#C '$t'.#n", ch->name);
act(buf, ch, argument, NULL, TO_CHAR);
break;
case CC_DRONE:
xprintf(buf, "#G<#0=#Y{#0%s#Y}#0=#G> #C'$t'.#n",
ch->name);
act(buf, ch, argument, NULL, TO_CHAR);
break;
case CC_SKYBLADE:
xprintf(buf, "#B=#R*#w>#0%s#w<#R*#B= #W'$t#W'.#n",
ch->name);
act(buf, ch, argument, NULL, TO_CHAR);
break;
case CC_DROW:
xprintf(buf, "#P.o0#0%s#P0o.#C '$t'.#n", ch->name);
act(buf, ch, argument, NULL, TO_CHAR);
break;
case CC_MONK:
xprintf(buf, "#0.x[#l%s#0]x. #C '$t'.#n", ch->name);
act(buf, ch, argument, NULL, TO_CHAR);
break;
case CC_VAMPIRE:
xprintf(buf, "#R<<#0%s#R>>#C $t.#n", ch->name);
act(buf, ch, argument, NULL, TO_CHAR);
break;
case CC_ZOMBIE:
xprintf(buf, "#R[#y%s#R]#C $t.#n", ch->name);
act (buf, ch, argument, NULL, TO_CHAR);
break;
case CC_DRAGON:
{
if (IS_CLASS(ch, CLASS_DRAGON))
{
xprintf(buf, "#R[#y%s#R] #L'#7$t#L'", ch->name);
act (buf, ch, argument, NULL, TO_CHAR);
break;
}
else if (IS_CLASS(ch, CLASS_DRAGON) && IS_POLYAFF(ch, POLY_DRAGON))
{
xprintf(buf, "#R:=#n %s #R=: #L'#7$t#L'", ch->morph);
act (buf, ch, argument, NULL, TO_CHAR);
break;
}
}
}
break;
case CHANNEL_ROLEPLAY:
xprintf(buf, "#o(#R%s#o) #n'#Y$t#n'.", ch->name);
act(buf, ch, argument, NULL, TO_CHAR);
break;
case CHANNEL_RELIGION:
xprintf(buf, religion_table[ch->pcdata->religion].channel,
ch->name);
act(buf, ch, argument, NULL, TO_CHAR);
break;
case CHANNEL_KINGDOM:
xprintf(buf, "#n%s#n: #P%s #n '#7$t#n'.#n", kingdom_table[ch->pcdata->kingdom].whoname, ch->name);
act(buf, ch, argument, NULL, TO_CHAR);
break;
}
/*
* silenced, and they don't know it :)
*/
if (!IS_NPC(ch) && IS_SET(ch->act, PLR_SILENCE))
return;
/*
* anti spamming
*/
//if (!IS_NPC(ch) && (channel == CHANNEL_CHAT || channel == CHANNEL_NEWBIE))
//{
// if (!str_cmp(ch->pcdata->last_global, argument)) return;
// free_string(ch->pcdata->last_global);
// ch->pcdata->last_global = str_dup(argument);
//}
for (d = descriptor_list; d != NULL; d = d->next)
{
CHAR_DATA *gch;
if (d->connected != CON_PLAYING)
continue;
if ((gch = d->character) == NULL)
continue;
if (gch == ch)
continue;
if (IS_SET(gch->deaf, channel))
continue;
if (channel == CHANNEL_IMMTALK && !IS_IMMORTAL(gch))
continue;
if (channel == CHANNEL_CLASS && !IS_IMMORTAL(gch)
&& (gch->class != ch->class || gch->level < 3))
continue;
if (channel == CHANNEL_RELIGION && !IS_IMMORTAL(gch) &&
gch->pcdata->religion != ch->pcdata->religion)
continue;
if ( channel == CHANNEL_KINGDOM && (!IS_NPC(gch) &&
gch->pcdata->kingdom != ch->pcdata->kingdom && !IS_IMMORTAL(gch)))
continue;
if (channel == CHANNEL_YELL && gch->in_room
&& gch->in_room->area != ch->in_room->area)
continue;
if (!IS_NPC(gch) && !IS_NPC(ch))
{
bool ignore = FALSE;
int i;
for (i = 0; i < MAX_IGNORE; i++)
if (gch->pcdata->ignore[i] ==
ch->pcdata->playerid)
ignore = TRUE;
if (ignore)
continue;
}
act(buf, ch, argument, gch, TO_VICT);
}
return;
}
HISTORY_DATA *generate_history()
{
HISTORY_DATA *history_new;
HISTORY_DATA *history_prev = NULL;
int i;
for (i = 0; i < MAX_HISTORY; i++)
{
if (history_free == NULL)
{
history_new = alloc_perm(sizeof(*history_new));
}
else
{
history_new = history_free;
history_free = history_free->next;
}
history_new->message = str_dup("");
history_new->next = history_prev;
history_prev = history_new;
}
return history_new;
}
void strip_history(CHAR_DATA * ch)
{
HISTORY_DATA *pHistory;
HISTORY_DATA *pHistory_next;
for (pHistory = ch->pcdata->history; pHistory;
pHistory = pHistory_next)
{
pHistory_next = pHistory->next;
free_string(pHistory->message);
pHistory->next = history_free;
history_free = pHistory;
}
}
void do_history(CHAR_DATA * ch, char *argument)
{
HISTORY_DATA *history;
char buf[MAX_STRING_LENGTH];
if (IS_NPC(ch))
return;
for (history = ch->pcdata->history; history; history = history->next)
{
if (strlen(history->message) > 3)
{
xprintf(buf, " %s\n\r", history->message);
send_to_char(buf, ch);
}
}
}
void update_history(CHAR_DATA * ch, CHAR_DATA * talker, char *buf,
char *argument, bool tell)
{
char message[MAX_STRING_LENGTH];
char tbuf[MAX_STRING_LENGTH];
char xbuf[MAX_STRING_LENGTH];
int i = 0;
if (IS_NPC(ch))
return;
xprintf(xbuf, "%s", line_indent(strip_ansi(argument), 22, 80));
if (!tell)
{
xprintf(tbuf, strip_ansi(buf));
while (tbuf[i] != '\0' && tbuf[i] != ' ')
i++;
tbuf[i] = '\0';
xprintf(message, "#C%-18s #0: #R%-s#n", tbuf, xbuf);
}
else
{
xprintf(message, "#0[#GT#0] #C%-14s #0: #R%-s#n",
talker->name, xbuf);
}
attach_history(ch, message);
return;
}
void attach_history(CHAR_DATA * ch, char *message)
{
HISTORY_DATA *history;
HISTORY_DATA *history_prev1 = NULL;
HISTORY_DATA *history_prev2 = NULL;
if (history_free == NULL)
{
history = alloc_perm(sizeof(*history));
}
else
{
history = history_free;
history_free = history_free->next;
}
history->message = str_dup(message);
history->next = ch->pcdata->history;
ch->pcdata->history = history;
for (history = ch->pcdata->history; history; history = history->next)
{
if (history_prev1)
history_prev2 = history_prev1;
history_prev1 = history;
}
history_prev2->next = NULL;
free_string(history_prev1->message);
history_prev1->next = history_free;
history_free = history_prev1;
}
/*
* Will remove the last line in the current note,
* if there is a note, and it has a line to remove.
*/
void delete_last_line_in_note(CHAR_DATA * ch)
{
char buf[4 * MAX_STRING_LENGTH];
char *ptr;
bool found = FALSE;
int nCount = 0;
buf[0] = '\0';
if (IS_NPC(ch))
return;
if (ch->pcdata->in_progress->text == NULL)
{
send_to_char("No note to delete lines in.\n\r", ch);
return;
}
if (strlen(ch->pcdata->in_progress->text) < 1)
{
send_to_char("Empty note, nothing to delete.\n\r", ch);
return;
}
strcpy(buf, ch->pcdata->in_progress->text);
ptr = buf;
while (*ptr != '\0')
{
if (*ptr == '\n')
nCount++;
ptr++;
}
if (nCount == 1)
{
free_string(ch->pcdata->in_progress->text);
ch->pcdata->in_progress->text = NULL;
send_to_char("Entire note deleted.\n\r", ch);
return;
}
else
{
while (*ptr != '\n' || !found)
{
if (*ptr == '\n')
found = TRUE;
ptr--;
}
}
ptr++;
*ptr = '\0';
free_string(ch->pcdata->in_progress->text);
ch->pcdata->in_progress->text = str_dup(buf);
send_to_char("Line deleted.\n\r", ch);
}