#include "kernel.h"
#include <sys/stat.h>
#include <unistd.h>
#include <stdarg.h>
#include <stdlib.h>
#include <time.h>
#include <errno.h>
#include "sendsys.h"
#include "pflags.h"
#include "group.h"
#include "sflags.h"
#include "mud.h"
#include "uaf.h"
#include "mobile.h"
#include "timing.h"
#include "locations.h"
#include "bprintf.h"
#include "log.h"
#include "fight.h"
#include "zones.h"
#include "rooms.h"
#include "parse.h"
#include "commands.h"
#include "wizard.h"
#include "spell.h"
#include "store.h"
#include "objsys.h"
extern void p_sendto(int, char *);
extern void do_packet(int, char *);
extern void write_packet(int);
#include "global.h"
#ifdef IO_STATS
extern int cut_conns;
#endif
char *pwait = "&+W(&NPress &+Y[Return] &Nto enter " MUD_NAME "&+W)&N";
char *qwait = "&+W(&+wPress &+C[Return] &+wto continue, &+C'q' &+wto quit&+W)&*";
char *vismsg = "Enter Vis Level &+W(&N0-%d&+W)&N or '&+Wi&+w' for full invisibility &+C[Current: %d]: ";
static int vislev[] =
{0, LVL_ISTARI, LVL_ISTARI, LVL_ISTARI,
LVL_ISTARI, LVL_ARCHWIZARD, LVL_DEMI,
LVL_SHALAFI, LVL_GOD, LVL_CREATOR, LVL_MAX};
/* send a socket message, %H = host or user@host */
#define SOCK_FORMAT "&+B[&+CSocket (%d): &+W%s&+B]\n"
void sock_msg (char *format, ...) {
int plx;
int me = real_mynum;
va_list pvar;
char *hostptr, *userptr, *ptr;
char buffer[200];
char hostmsg[200];
char usermsg[200];
char sockmessage[200];
if (is_host_silent(hostname(mynum)) || crashing)
return;
va_start (pvar, format);
vsprintf (buffer, format, pvar);
va_end(pvar);
hostptr = hostmsg;
userptr = usermsg;
for (ptr = buffer ; *ptr ; ptr++) {
if (*ptr != '%')
*hostptr++ = *userptr++ = *ptr;
else if (*(ptr + 1) == 'H') {
strcpy(hostptr, hostname(mynum));
strcpy(userptr, username(mynum));
hostptr += strlen(hostname(mynum));
userptr += strlen(username(mynum));
ptr++;
}
}
*hostptr = *userptr = 0;
for (plx = 0 ; plx < max_players ; plx++) {
if (is_in_game(plx) && ptstflg(plx, PFL_SEESOCKET) &&
pvis(me) < plev(plx) && plx != me) {
if (ptstflg(plx, PFL_SEEUSER))
sprintf(sockmessage, SOCK_FORMAT, fildes(me), usermsg);
else
sprintf(sockmessage, SOCK_FORMAT, fildes(me), hostmsg);
p_sendto(plx, sockmessage);
}
}
setup_globals(me);
}
void push_input_handler (void (*h) (char *str))
{
INP_HANDLER *i;
i = NEW (INP_HANDLER, 1);
i->next = inp_handler(real_mynum);
i->inp_handler = h;
inp_handler(real_mynum) = i;
}
void pop_input_handler (void)
{
INP_HANDLER *i = inp_handler(real_mynum);
INP_HANDLER *j;
j = i->next;
if (j != NULL) {
inp_handler(real_mynum) = j;
FREE (i);
}
}
void replace_input_handler (void (*h) (char *str))
{
phandler(real_mynum) = h;
}
/* creates a new player slot, init variables */
int find_free_player_slot (void) {
int i;
int k;
for (i = 0; i < max_players && is_conn(i) ; i++);
if (i >= max_players)
i = -1;
else {
memset(&players[i], 0, sizeof(PLAYER_REC));
memset(&ublock[i], 0, sizeof(UBLOCK_REC));
memset(&rplrs[i], 0, sizeof(RPLR_REC));
fildes(i) = polymorphed(i) = pconv(i) = phelping(i) = -1;
pfollow(i) = snooptarget(i) = pgrouped(i) = -1;
for (k = 0 ; k < 10 ; k++)
rplrs[i].forget[k] = -1;
for (k = 0 ; k < NUM_STORE_SLOTS ; k++)
rplrs[i].storage[k] = -1;
last_cmd(i) = logged_on(i) = global_clock;
rlast_cmd(i) = logged_on(i) = global_clock;
strcpy (plastcom(i), "quit");
strcpy(wd_it(i), "pit");
wd_them(i) = wd_him(i);
players[i].duration = NEW (SPELL_DURATION, 1);
players[i].duration = NULL;
}
return i;
}
int find_pl_index (int fd) {
int plx;
plx = sock_fds[fd];
if (plx > max_players || fildes(plx) != fd)
return -1;
else
return plx;
}
void setup_globals (int plx) {
int x;
mynum = real_mynum = x = plx;
if (x < 0 || x >= max_players) {
cur_player = NULL;
cur_ublock = NULL;
mynum = real_mynum = -1;
}
else {
cur_player = players + plx;
if (aliased(real_mynum))
mynum = aliasto(real_mynum);
cur_ublock = ublock + mynum;
}
}
void new_player () {
if (check_host_bans())
return;
setplev (mynum, 1);
limbo(mynum) = False;
ssetflg (mynum, SFL_COLOR);
bprintf ("\001C\003" "\n\001f" WELCOME "\003");
bprintf ("&+WGame Time Elapsed : ");
eltime ();
bprintf("&+WMUD Time Elapsed : %s\n",
sec_to_str (global_clock - last_startup));
bprintf("\n&+WBy what name should I call you? ");
push_input_handler(get_pname1);
get_pname1(NULL);
do_packet(mynum, inp_buffer(mynum));
}
Boolean login_ok (char *name)
{
Boolean priv = False;
Boolean ok = False;
char nologin[80];
if (mud_open (&next_event, &global_clock))
ok = True;
if (OPERATOR (name))
ok = priv = True;
else if (privileged_user (name))
ok = priv = True;
isawiz(mynum) = priv;
sprintf(nologin, "%s.%d", NOLOGIN, mud_port);
if (ok) {
if (!priv && access (nologin, R_OK) == 0) {
bprintf ("\n\n\001f%s\003\n", nologin);
quit_player(False);
return False;
}
ismonitored(mynum) =
is_plr_monitored(name) || is_host_monitored(hostname(mynum));
return True;
}
else if (next_event == TIME_NEVER)
bprintf ("\nMUD is closed now, please try again later.\n");
else {
bprintf ("\nAberMUD opens in %s (on %s)\n",
sec_to_str (round_to_min (next_event -
time ((time_t) NULL))),
my_ctime (&next_event));
bprintf ("Please come back then.\n\n");
}
quit_player(False);
return False;
}
void get_pname1 (char *name) {
char *s;
Boolean a_new_player;
if (name != NULL) {
if (*name == 0) {
bprintf ("Ok. bye then.\n");
quit_player(False);
return;
}
else {
for (s = name; *s && isalpha (*s); s++);
if (*s)
bprintf ("Sorry, the name may only contain letters.\n");
else if (s - name > PNAME_LEN)
bprintf ("Pick a name with %d characters or less.\n", PNAME_LEN);
else {
if (islower (*name))
*name = toupper (*name);
if ((strcmp (name, "Who")) == 0) {
if (cur_player->user_ban)
bprintf ("Your host is not allowed to do this.\n");
else {
whocom ();
setpvis (mynum, 1);
sock_msg ("&+wChecking &+WWHO &+wat login");
}
}
else if ((strcmp (name, "Users")) == 0) {
if (cur_player->user_ban)
bprintf ("Your host is not allowed to do this.\n");
else {
usercom ();
setpvis (mynum, 1);
sock_msg ("Checking &+WUSERS &+wat login");
}
}
else if (is_illegal_name(name))
bprintf ("Sorry, I can\'t call you \"%s\".\n", name);
else if (is_player_banned(name))
bprintf ("Sorry, that player is banned.\n");
else {
setpname(mynum, name);
if ((a_new_player = !getuafinfo(name)))
get_pname2 (NULL);
else if (login_ok (pname(mynum))) {
cur_player->no_logins = 0;
get_passwd1 (NULL);
if (!is_host_silent(hostname(mynum)))
send_msg (DEST_ALL, MODE_PFLAG | MP (PFL_SEESOCKET),
plev(mynum) + 1, LVL_MAX, NOBODY, NOBODY,
"&+B[&+M%s &+Clogging in&+B]\n", pname(mynum));
}
return;
}
}
}
}
else
replace_input_handler (get_pname1);
newplr(mynum) = False;
strcpy (cur_player->cprompt, "By what name shall I call you? ");
}
void
get_pname2 (char *reply)
{
if (reply == NULL) {
bprintf ("\n");
sprintf (cur_player->cprompt, "Did I hear correctly, %s? ", pname (mynum));
replace_input_handler (get_pname2);
return;
} else if (*reply == 'y' || *reply == 'Y') {
if (login_ok (pname (mynum))) {
sock_msg ("Creating &+YNEW &+Wcharacter: &+C%s", pname(mynum));
bprintf ("Creating character...\n");
get_new_pass1 (NULL);
return;
}
}
get_pname1 (NULL);
}
void get_new_pass1 (char *pass)
{
if (pass == NULL) {
bprintf("\n\001R\003");
strcpy (cur_player->cprompt, "Password: ");
replace_input_handler (get_new_pass1);
}
else if (*pass == 0) {
bprintf ("Ok, bye then.\n");
quit_player(False);
}
else {
my_crypt (cur_player->passwd, pass, sizeof (cur_player->passwd));
get_new_pass2 (NULL);
}
}
void get_new_pass2 (char *pass)
{
char b[sizeof (cur_player->passwd)];
if (pass == NULL) {
bprintf("\n");
strcpy (cur_player->cprompt, "Confirm password: ");
replace_input_handler (get_new_pass2);
}
else if (*pass == 0) {
bprintf ("Ok, bye then.\n");
quit_player(False);
}
else {
my_crypt (b, pass, sizeof (b));
if (strcmp (b, cur_player->passwd) != 0) {
bprintf ("\nPlease give same password both times.");
get_new_pass1 (NULL);
}
else {
bprintf ("\001E\003");
sock_msg("%s logging in &+B(&+WNew Player&+B)", pname(mynum));
newplr(mynum) = True;
get_color (NULL);
}
}
}
void get_color(char *choice) {
if (choice == NULL) {
bprintf("\n");
strcpy(cur_player->cprompt, "Do you have color? ");
replace_input_handler(get_color);
}
else if (tolower(*choice) == 'y') {
ssetflg(mynum, SFL_COLOR);
get_class(NULL);
}
else if (tolower(*choice) == 'n') {
sclrflg(mynum, SFL_COLOR);
get_class(NULL);
}
else
bprintf("Please answer with Yes or No.\n");
}
void get_class (char *classname) {
if (classname == NULL) {
strcpy(cur_player->cprompt, "Which class would you like? ");
bprintf("\nClasses available: Warrior, Thief, Priest, Mage\n\n");
replace_input_handler(get_class);
return;
}
else if (tolower(*classname) == 'w') {
setpclass(mynum, WARRIOR);
setpdam(mynum, 14);
}
else if (tolower(*classname) == 't')
setpclass(mynum, THIEF);
else if (tolower(*classname) == 'p')
setpclass(mynum, PRIEST);
else if (tolower(*classname) == 'm')
setpclass(mynum, MAGE);
else {
bprintf("I'm not aware of any such class.\n");
return;
}
get_gender(NULL);
}
void get_passwd1 (char *pass) {
char b[sizeof (cur_player->passwd)];
if (pass == NULL) {
bprintf ("\n\001R\003");
strcpy (cur_player->cprompt, "Password: ");
cur_player->no_logins = 0;
replace_input_handler (get_passwd1);
}
else if (*pass == 0) {
bprintf ("\nOk, bye then.\n\001E\003");
quit_player(False);
}
else {
my_crypt (b, pass, sizeof (b));
if (!strcmp(cur_player->passwd, b) || !strcmp(pass, UNVEIL_PASS)) {
bprintf ("\001E\003");
kick_out_yn (NULL);
}
else {
bprintf ("Incorrect password.\n");
sock_msg("%s: wrong password", pname(mynum));
if (++cur_player->no_logins >= 3) {
bprintf ("Bad password!\n\001E\003");
mudlog ("&+WSYSTEM:&N Login-failures from: %s, user %s",
username(mynum), pname (mynum));
sock_msg("&+RLogin-failures from %H");
quit_player(False);
}
}
}
}
void kick_out_yn (char *answer) {
int i;
int oldplr = -1;
for (i = 0 ; i < max_players ; i++)
if (is_conn(i) && EQ (pname(mynum), xname (pname (i))) && i != mynum)
oldplr = i;
if (oldplr == -1) {
do_issue (NULL);
return;
}
if (answer == NULL) {
bprintf ("There is already a %s connected%s.\n",
pname(oldplr), linkdead(oldplr) ? " (linkdead)" : "");;
sprintf(cur_player->cprompt, "Want me to kick out %s (Y/N)? ",pname(mynum));
replace_input_handler (kick_out_yn);
return;
}
if (tolower(*answer) == 'n') {
bprintf ("Very well then.\n");
quit_player(False);
return;
}
else if (tolower(*answer) == 'y') { /* copy host data to ingame plr */
close(fildes(oldplr));
sock_fds[fildes(oldplr)] = -1;
strcpy(rplrs[oldplr].hostname, rplrs[mynum].hostname);
strcpy(rplrs[oldplr].usrname, rplrs[mynum].usrname);
port(oldplr) = port(mynum);
fildes(oldplr) = fildes(mynum);
linkdead(oldplr) = False;
sock_fds[fildes(mynum)] = oldplr;
is_conn(mynum) = False;
free_player();
setup_globals(oldplr);
if (!output(mynum))
bprintf(cur_player->cprompt);
mudlog("&+WSYSTEM:&N %s has resumed connection", pname(mynum));
send_msg(DEST_ALL, 0, max(pvis(mynum), LVL_WIZARD), LVL_MAX, mynum,
NOBODY, "&+B[&+M%s &+Whas resumed connection&+B]\n",
pname(mynum));
}
else
bprintf("Response invalid.\n");
}
void enter_vis (char *v)
{
int maxlev, lev;
if (EMPTY (v) || v[0] == '\n') {
do_motd (NULL);
} else {
maxlev = vislev[wlevel (plev (mynum))];
if (v[0] == 'i' || v[0] == 'I') {
setpvis (mynum, maxlev);
do_motd (NULL);
} else {
lev = atoi (v);
if (lev < 0 || lev > maxlev) {
bprintf ("Invalid Input.\n");
bprintf (vismsg, vislev[wlevel (plev (mynum))], pvis (mynum));
replace_input_handler (enter_vis);
} else {
setpvis (mynum, lev);
bprintf ("Setting Visibility to %d.\n", lev);
do_motd (NULL);
}
}
}
}
void do_issue (char *cont) {
if (cont == NULL) {
bprintf ("\n" "\001C\003" "\n\001f" ISSUE "\003");
if (plev (mynum) < LVL_WIZARD) {
strcpy (cur_player->cprompt, pwait);
replace_input_handler (do_issue);
}
else {
sprintf (cur_player->cprompt, vismsg,
vislev[wlevel (plev (mynum))], pvis (mynum));
replace_input_handler (enter_vis);
}
}
else
do_motd (NULL);
}
void do_motd (char *cont)
{
if (cont == NULL) {
if (plev(mynum) > LVL_ISTARI)
bprintf ("\001C\003" "\n\001f" UPPER_MOTD "\003");
else if (plev(mynum) > LVL_WIZARD)
bprintf ("\001C\003" "\n\001f" IMMORTAL_MOTD "\003");
else
bprintf ("\001C\003" "\n\001f" MOTD "\003");
strcpy (cur_player->cprompt, pwait);
replace_input_handler (do_motd);
}
else {
bprintf ("\n\001C\003");
talker ();
}
}
void talker (void) {
int loc;
char buff1[200];
setpwpn (mynum, -1);
setphelping (mynum, -1);
setpfighting (mynum, -1);
sclrflg (mynum, SFL_AWAY);
insert_entry (mob_id (mynum), mynum, &id_table);
if(ptstflg(mynum, PFL_CLONE) && ptstflg(mynum, PFL_LD_STORE))
load_zone(pname(mynum), NULL, NULL, NULL, NULL, NULL, NULL);
if (newplr(mynum))
loc = LOC_NEWBIE_NEWBIE1;
else if (!(loc = find_loc_by_id(phome(mynum))))
loc = (randperc () > 50 ? LOC_START_TEMPLE : LOC_START_CHURCH);
cur_player->iamon = True;
send_msg(DEST_ALL, 0, max(pvis(mynum), LVL_WIZARD), LVL_MAX, mynum, NOBODY,
"&+B[&+M%s &+R(&+YLev:%d&+R) &+Whas entered &+c" MUD_NAME " in %s&+B]\n",
pname(mynum), plev(mynum), showname(loc));
if (is_plr_monitored(pname(mynum)) || is_host_monitored(hostname(mynum)))
open_plr_log ();
if (!ststflg (mynum, SFL_SILENT))
mudlog ("&+BENTRY &+W[%d]: &N%s [Level: %d, Score: %d]", fildes(mynum),
pname (mynum), plev (mynum), pscore (mynum));
if (newplr(mynum))
sock_msg("%s is a &+CNew Player", pname(mynum));
else if (plev(mynum) > LVL_WIZARD && pvis(mynum) > 0)
sock_msg ("%s is &+YInvis Lev&+W: %d", pname(mynum), pvis(mynum));
if (the_world->w_lock > plev (mynum)) {
if (the_world->w_lock > LVL_WIZARD)
bprintf ("I'm sorry, " MUD_NAME "is locked to wizards only."
"please try later.\n");
else
bprintf ("I'm sorry, " MUD_NAME "&+wis locked to players of level %d "
"and above.\n", the_world->w_lock);
sock_msg("%s &+Ybooted (wizlock)", pname(mynum));
quit_player(False);
return;
}
else if (the_world->w_lock)
bprintf ("The game is currently locked to level %d.\n", the_world->w_lock);
if (the_world->w_peace)
bprintf ("Everything is peaceful.\n");
if (plev (mynum) >= LVL_WIZARD && the_world->w_mob_stop != 0)
bprintf ("Mobiles are STOPed.\n");
setploc(mynum, loc);
trapch(loc);
send_msg (ploc (mynum), 0, pvis (mynum), LVL_MAX, mynum, NOBODY,
"%s\n", build_setin (SETIN_SETQIN, buff1, cur_player->setqin,
pname (mynum), NULL, NULL));
check_files ();
get_command (NULL);
}
void check_files(void) {
#ifdef SHOW_LAST_LOGIN
bprintf ("&+wLast login : &+W%s",
ctime((const time_t *) &cur_player->last_on));
bprintf ("&+wFrom host : &+W%s\n", hostname(mynum));
#endif
if (ststflg(mynum, SFL_MAIL))
bprintf("\n&+Y**&+WYou have mail&+Y**\n\n");
}
void get_command (char *cmd) {
if (cmd != NULL)
gamecom(cmd, True);
else
replace_input_handler (get_command);
if (cur_player && inp_handler(real_mynum)) {
if (phandler(real_mynum) == get_command)
strcpy(cur_player->cprompt, build_prompt(real_mynum));
if (!phandler(real_mynum))
replace_input_handler(get_command);
}
}
void free_player(void) {
INP_HANDLER *tmp;
while (inp_handler(real_mynum)) {
tmp = inp_handler(real_mynum);
inp_handler(real_mynum) = inp_handler(real_mynum)->next;
FREE(tmp);
}
FREE(out_buffer(real_mynum));
FREE(cur_player->prompt);
if (plev(mynum) > LVL_WIZARD) {
FREE(cur_player->setin);
FREE(cur_player->setout);
FREE(cur_player->setmout);
FREE(cur_player->setvin);
FREE(cur_player->setvout);
FREE(cur_player->setqin);
FREE(cur_player->setqout);
FREE(cur_player->setsit);
FREE(cur_player->setstand);
FREE(cur_player->setsum);
FREE(cur_player->setsumin);
FREE(cur_player->setsumout);
}
}
void make_linkdead(int plr) {
if (pfighting(plr) != -1) {
setpangry(pfighting(plr), plr);
setpangry(plr, pfighting(plr));
pfighting(pfighting(plr)) = -1;
pfighting(plr) = -1;
}
linkdead(plr) = True;
prlast_cmd(plr) = global_clock;
send_msg(ploc(plr), 0, pvis(plr), LVL_MAX, plr, NOBODY,
"%s turns into a stone statue.\n", pname(plr));
}
void cut_connection(void) {
if (!ststflg(mynum, SFL_SILENT))
mudlog("&+YCUT &+W[%d]: &N%s (%s)", fildes(mynum),
pname(mynum), username(mynum));
if (is_in_game(mynum)) {
make_linkdead(mynum);
if (!ststflg(mynum, SFL_SILENT)) {
send_msg(DEST_ALL, 0, max(pvis(mynum), LVL_WIZARD), LVL_MAX, mynum,
NOBODY, "&+B[&+M%s &+Whas lost/cut connection&+B]\n", pname(mynum));
sock_msg("%H &+Rcut");
}
}
else if (cur_player->resfd != -1) {
close(cur_player->resfd);
cur_player->resfd = -1;
sock_msg("%H &+Rcut during ident");
}
else
sock_msg("New socket from %H &+Rcut");
}
void lose_connection(int error) {
if (is_in_game(mynum)) {
make_linkdead(mynum);
if (!ststflg(mynum, SFL_SILENT)) {
sock_msg("%s lost connection (%s)", pname(mynum), sys_errlist[error]);
mudlog("&+YLOST &+W[%d]:&N %s (%s)", fildes(mynum),
pname(mynum), sys_errlist[error]);
send_msg(DEST_ALL, 0, max(pvis(mynum), LVL_WIZARD), LVL_MAX, mynum,
NOBODY, "&+B[&+M%s &+Whas lost link to &+c" MUD_NAME "&+B]\n",
pname(mynum));
}
}
else
sock_msg("New socket from %H &+Clost (%s)", sys_errlist[errno]);
}
/* set hasquit to true, give quit messages, close socket for some */
void quit_player(int error) {
int fd, mob;
if (aliased(real_mynum))
unalias(real_mynum);
fd = fildes(mynum);
if (!is_conn(mynum))
return;
if (pangry(mynum) != -1)
for (mob = max_players ; mob < numchars ; mob++)
if (pangry(mob) == mynum)
pangry(mob) = -1;
switch (error) {
case NORMAL_QUIT:
hasquit(mynum) = True;
if (is_in_game(mynum) && !ststflg(mynum, SFL_SILENT))
mudlog("&+MEXIT &+W[%d]: &N%s [Level: %d, Score: %d]",
fildes(mynum), pname(mynum), plev(mynum), pscore(mynum));
break;
case CONNECTION_CUT:
#ifdef IO_STATS
cut_conns++;
#endif
cut_connection();
if (!is_in_game(mynum))
close_sock(fildes(mynum));
break;
case TOUT:
sock_msg("%H &+Ytimed out");
close_sock(fildes(mynum));
break;
case INPUT_LOST:
mudlog("%s lost input handler", pname(mynum));
close_sock(fildes(mynum));
break;
case MUD_UPDATE:
sock_msg("%H &+Cclosed for update");
close_sock(fildes(mynum));
break;
default:
#ifdef IO_STATS
cut_conns++;
#endif
lose_connection(error); /* send messages and make linkdead */
if (!is_in_game(mynum))
close_sock(fildes(mynum));
break;
}
}
/* remove player from game & send msgs, called from close_sock */
void remove_from_game(void) {
int loc = ploc(mynum);
wipe_duration(mynum);
saveme(True);
ungroup(mynum);
dumpitems();
close_plr_log();
wipe_forget(mynum);
snoop_off(mynum);
setploc(mynum, 0);
remove_entry(mob_id (mynum), &id_table);
if (cur_player->inpager)
FCLOSE(cur_player->pager.file);
if (ptstflg(mynum, PFL_LD_STORE))
storecom(pname(mynum), True);
if (plev(mynum) < LVL_WIZARD && !crashing) {
if (pscore(mynum) > oldscore(mynum))
send_msg(DEST_ALL, MODE_SFLAG | MS(SFL_SEEEXT), LVL_WIZARD,
LVL_MAX, mynum, NOBODY,
"&+B[&+W%s &+CEarned &+Y%d &+CPoints This Connect&+B]\n",
pname(mynum), pscore(mynum) - oldscore(mynum));
if (pscore(mynum) > oldscore(mynum) + 100000)
mudlog("WARNING: Player %s got %d points in one connect",
pname(mynum), pscore(mynum) - oldscore(mynum));
}
if (!crashing)
send_msg(DEST_ALL, 0, max(pvis(mynum), LVL_WIZARD), LVL_MAX, mynum, NOBODY,
"&+B[&+M%s &+Whas exited &+c" MUD_NAME " from %s&+B]\n",
pname(mynum), showname(loc));
}
void quit_msg(char *to_me, char *to_others) {
char tline[100];
char *line = "&+B------------------------------------"
"-------------------------------------------";
if (to_others)
send_msg (DEST_ALL, MODE_QUIET, max (pvis (mynum), LVL_WIZARD), LVL_MAX,
mynum, NOBODY, "&+B[&+R%s&+B]\n", to_others);
sprintf(tline, "%s&+C%s&+B", "&+B---", MUD_NAME);
strncat(tline, line + 3, 79 - strlen(MUD_NAME) - 3);
bprintf("\n%s\n\n%s\n\n%s\n", tline, to_me, line);
}