billr@saab.CNA.TEK.COM (Bill Randle) (07/30/90)
Submitted-by: James Aspnes <asp@cs.cmu.edu>
Posting-number: Volume 11, Issue 9
Archive-name: tinymud2/Part05
Supersedes: tinymud: Volume 8, Issue 80-83
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 5 (of 10)."
# Contents: interface.c joinspl.sh wiz.c
# Wrapped by billr@saab on Fri Jul 27 15:27:46 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'interface.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'interface.c'\"
else
echo shar: Extracting \"'interface.c'\" \(33958 characters\)
sed "s/^X//" >'interface.c' <<'END_OF_FILE'
X/* Concentrator upgraded June 1990 Robert Hood */
X
X/* modifed Concentrator to match Fuzzy & Randoms 1.5.4 changes = 6/90 Fuzzy */
X
X/* modified interface.c to support LOTS of people, using a concentrator */
X/* May 1990, Robert Hood */
X
X/* #define CHECKC /* consistency checking */
X
X#include <stdio.h>
X#include <sys/param.h>
X#include <sys/types.h>
X#include <sys/file.h>
X#include <sys/time.h>
X#include <signal.h>
X#include <sys/ioctl.h>
X#include <sys/wait.h>
X#include <fcntl.h>
X#include <sys/errno.h>
X#include <ctype.h>
X#include <sys/socket.h>
X#include <netinet/in.h>
X#include <netdb.h>
X
X#include "config.h"
X#include "db.h"
X#include "interface.h"
X
X#define BUFSIZE 0xFFFF
X
Xstruct text_block
X{
X int nchars;
X struct text_block *nxt;
X char *start;
X char *buf;
X};
X
Xstruct text_queue
X{
X struct text_block *head;
X struct text_block **tail;
X};
X
Xstruct descriptor_data
X{
X int descriptor;
X int num;
X int connected;
X dbref player;
X char *output_prefix;
X char *output_suffix;
X int output_size;
X struct text_queue output;
X struct text_queue input;
X char *raw_input;
X char *raw_input_at;
X long connected_at;
X long last_time;
X int quota;
X struct sockaddr_in address; /* added 3/6/90 SCG */
X char *hostname; /* 5/18/90 - Fuzzy */
X struct descriptor_data *next;
X};
X
X#define MALLOC(result, type, number) do { \
X if (!((result) = (type *) malloc ((number) * sizeof (type)))) \
X panic("Out of memory"); \
X } while (0)
X
X#define FREE(x) (free((void *) x))
X
Xstruct message
X{
X char *data;
X short len;
X struct message *next;
X};
X
Xstruct conc_list
X{
X struct conc_list *next;
X int sock, current, status;
X struct descriptor_data *firstd;
X struct message *first, *last;
X char *incoming, *outgoing;
X int ilen, olen;
X} *firstc = 0;
X
Xvoid queue_message(struct conc_list * c, char *data, int len);
Xvoid start_log();
Xstruct timeval timeval_sub(struct timeval now, struct timeval then);
Xstruct timeval msec_add(struct timeval t, int x);
Xstruct timeval update_quotas(struct timeval last, struct timeval current);
Xvoid main_loop();
Xint notify(dbref player, const char *msg);
Xvoid process_output(struct conc_list * c);
Xint process_input(struct descriptor_data * d, char *buf, int got);
Xvoid process_commands();
Xvoid dump_users(struct descriptor_data * e, char *user);
Xvoid free_text_block(struct text_block * t);
Xvoid main(int argc, char **argv);
Xvoid set_signals();
Xint msec_diff(struct timeval now, struct timeval then);
Xvoid clearstrings(struct descriptor_data * d);
Xvoid shutdownsock(struct descriptor_data * d);
Xstruct descriptor_data *initializesock(struct sockaddr_in * a);
Xstruct text_block *make_text_block(const char *s, int n);
Xvoid add_to_queue(struct text_queue * q, const char *b, int n);
Xint flush_queue(struct text_queue * q, int n);
Xint queue_write(struct descriptor_data * d, const char *b, int n);
Xint queue_string(struct descriptor_data * d, const char *s);
Xvoid freeqs(struct descriptor_data * d);
Xvoid welcome_user(struct descriptor_data * d);
Xvoid do_motd(dbref);
Xchar *strsave(const char *s);
Xvoid save_command(struct descriptor_data * d, const char *command);
Xvoid set_userstring(char **userstring, const char *command);
Xint do_command(struct descriptor_data * d, char *command);
Xvoid check_connect(struct descriptor_data * d, const char *msg);
Xvoid parse_connect(const char *msg, char *command, char *user, char *pass);
Xvoid close_sockets();
Xvoid emergency_shutdown(void);
Xvoid boot_off(dbref player);
Xint bailout(int sig, int code, struct sigcontext * scp);
Xchar *time_format_1(long dt);
Xchar *time_format_2(long dt);
X#ifdef CONNECT_MESSAGES
Xvoid announce_connect(dbref);
Xvoid announce_disconnect(dbref);
X#endif /* CONNECT_MESSAGES */
Xint sigshutdown(int, int, struct sigcontext *);
X
Xint logsynch();
Xchar *logfile = LOG_FILE;
X
Xint debug;
Xvoid chg_userid();
Xvoid file_date(struct descriptor_data * d, const char *file);
X
Xstatic const char *connect_fail = "Either that player does not exist, or has a different password.\n";
X#ifndef REGISTRATION
Xstatic const char *create_fail = "Either there is already a player with that name, or that name is illegal.\n";
X#endif /* REGISTRATION */
Xstatic const char *flushed_message = "<Output Flushed>\n";
Xstatic const char *shutdown_message = "Going down - Bye\n";
X
Xint sock;
Xint shutdown_flag = 0;
X
Xint port = TINYPORT;
Xint intport = INTERNAL_PORT;
X
X
Xstart_port()
X{
X int temp;
X struct sockaddr_in sin;
X
X sock = socket(AF_INET, SOCK_STREAM, 0);
X if (sock < 1)
X {
X perror("socket");
X exit(-1);
X }
X temp = 1;
X setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&temp, sizeof(temp));
X sin.sin_family = AF_INET;
X sin.sin_port = htons(intport);
X sin.sin_addr.s_addr = htonl(INADDR_ANY);
X
X temp = bind(sock, (struct sockaddr *) & sin, sizeof(sin));
X if (temp < 0)
X {
X perror("bind");
X exit(-1);
X }
X temp = listen(sock, 5);
X if (temp < 0)
X {
X perror("listen");
X exit(-1);
X }
X}
X
Xstruct timeval
X timeval_sub(struct timeval now, struct timeval then)
X{
X now.tv_sec -= then.tv_sec;
X now.tv_usec -= then.tv_usec;
X if (now.tv_usec < 0)
X {
X now.tv_usec += 1000000;
X now.tv_sec--;
X }
X return now;
X}
X
Xstruct timeval
X msec_add(struct timeval t, int x)
X{
X t.tv_sec += x / 1000;
X t.tv_usec += (x % 1000) * 1000;
X if (t.tv_usec >= 1000000)
X {
X t.tv_sec += t.tv_usec / 1000000;
X t.tv_usec = t.tv_usec % 1000000;
X }
X return t;
X}
X
Xstruct timeval
X update_quotas(struct timeval last, struct timeval current)
X{
X int nslices;
X struct descriptor_data *d;
X struct conc_list *c;
X
X nslices = msec_diff(current, last) / COMMAND_TIME_MSEC;
X
X if (nslices > 0)
X {
X for (c = firstc; c; c = c->next)
X for (d = c->firstd; d; d = d->next)
X {
X d->quota += COMMANDS_PER_TIME * nslices;
X if (d->quota > COMMAND_BURST_SIZE)
X d->quota = COMMAND_BURST_SIZE;
X }
X }
X return msec_add(last, nslices * COMMAND_TIME_MSEC);
X}
X
Xint
X notify(dbref player2, const char *msg)
X{
X struct descriptor_data *d;
X struct conc_list *c;
X int retval = 0;
X
X#ifdef COMPRESS
X extern const char *uncompress(const char *);
X
X msg = uncompress(msg);
X#endif /* COMPRESS */
X for (c = firstc; c; c = c->next)
X for (d = c->firstd; d; d = d->next)
X {
X if (d->connected && d->player == player2)
X {
X queue_string(d, msg);
X queue_write(d, "\n", 1);
X retval++;
X }
X }
X return (retval);
X}
X
Xint
X process_input(d, buf, got)
X struct descriptor_data *d;
X char *buf;
X int got;
X{
X char *p, *pend, *q, *qend;
X
X d->last_time = time(0);
X if (!d->raw_input)
X {
X MALLOC(d->raw_input, char, MAX_COMMAND_LEN);
X d->raw_input_at = d->raw_input;
X }
X p = d->raw_input_at;
X pend = d->raw_input + MAX_COMMAND_LEN - 1;
X for (q = buf, qend = buf + got; q < qend; q++)
X {
X if (*q == '\n')
X {
X *p = '\0';
X if (p > d->raw_input)
X save_command(d, d->raw_input);
X p = d->raw_input;
X } else
X if (p < pend && isascii(*q) && isprint(*q))
X {
X *p++ = *q;
X }
X }
X if (p > d->raw_input)
X {
X d->raw_input_at = p;
X } else
X {
X FREE(d->raw_input);
X d->raw_input = 0;
X d->raw_input_at = 0;
X }
X return 1;
X}
X
Xvoid process_commands()
X{
X int nprocessed;
X struct descriptor_data *d, *dnext, *dlast;
X struct conc_list *c;
X struct text_block *t;
X char header[4];
X
X do
X {
X nprocessed = 0;
X for (c = firstc; c; c = c->next)
X {
X dlast = 0;
X for (d = c->firstd; d; d = dnext)
X {
X dnext = d->next;
X if (d->quota > 0 && (t = d->input.head))
X {
X d->quota--;
X nprocessed++;
X if (!do_command(d, t->start))
X {
X header[0] = 0;
X header[1] = 2;
X header[2] = d->num;
X queue_message(c, header, 3);
X if (dlast)
X dlast->next = dnext;
X else
X c->firstd = dnext;
X shutdownsock(d);
X FREE(d);
X break;
X } else
X {
X d->input.head = t->nxt;
X if (!d->input.head)
X d->input.tail = &d->input.head;
X free_text_block(t);
X }
X }
X dlast = d;
X }
X }
X } while (nprocessed > 0);
X}
X
Xvoid dump_users(struct descriptor_data * e, char *user)
X{
X static struct conc_list *rwclist[NOFILE];
X static struct descriptor_data *rwdlist[NOFILE];
X int ccount, dcount, dloop, cloop;
X
X struct descriptor_data *d;
X struct conc_list *c;
X long now;
X int counter = 0;
X static int maxcounter = 0;
X int wizard, reversed, tabular;
X char buf[1024];
X
X
X# ifdef DO_WHOCHECK
X writelog("WHO CHECK %d\n", sizeof(rwclist));
X writelog("WHO CHECK %d\n", sizeof(rwdlist));
X# endif
X
X while (*user && isspace(*user))
X user++;
X if (!*user)
X user = NULL;
X
X reversed = e->connected && Flag(e->player, REVERSED_WHO);
X tabular = e->connected && Flag(e->player, TABULAR_WHO);
X
X time(&now);
X
X queue_string(e, tabular ? "Player Name On For Idle\n" :
X "Current Players:\n");
X#ifdef GOD_MODE
X wizard = e->connected && God(e->player);
X#else GOD_MODE
X wizard = e->connected && Wizard(e->player);
X#endif GOD_MODE
X
X if (reversed)
X {
X ccount = 0;
X for (c = firstc; c; c = c->next)
X rwclist[ccount++] = c;
X for (cloop = ccount - 1; cloop >= 0; --cloop)
X {
X dcount = 0;
X for (d = rwclist[cloop]->firstd; d; d = d->next)
X rwdlist[dcount++] = d;
X for (dloop = dcount - 1; dloop >= 0; --dloop)
X {
X d = rwdlist[dloop];
X if (d->connected &&
X ++counter && /* Count everyone connected */
X (!user || string_prefix(db[d->player].name, user)))
X {
X if (tabular)
X {
X sprintf(buf, "%-16s %10s %4s",
X db[d->player].name,
X time_format_1(now - d->connected_at),
X time_format_2(now - d->last_time));
X
X if (wizard)
X sprintf(buf, "%s %s", buf, d->hostname);
X } else
X {
X sprintf(buf, "%s idle %d seconds",
X db[d->player].name, now - d->last_time);
X if (wizard)
X sprintf(buf, "%s from host %s", buf, d->hostname);
X }
X strcat(buf, "\n");
X queue_string(e, buf);
X }
X }
X }
X } else
X {
X for (c = firstc; c; c = c->next)
X {
X for (d = c->firstd; d; d = d->next)
X {
X if (d->connected &&
X ++counter && /* Count everyone connected */
X (!user || string_prefix(db[d->player].name, user)))
X {
X if (tabular)
X {
X sprintf(buf, "%-16s %10s %4s",
X db[d->player].name,
X time_format_1(now - d->connected_at),
X time_format_2(now - d->last_time));
X
X if (wizard)
X sprintf(buf, "%s %s", buf, d->hostname);
X } else
X {
X sprintf(buf, "%s idle %d seconds",
X db[d->player].name, now - d->last_time);
X if (wizard)
X sprintf(buf, "%s from host %s", buf, d->hostname);
X }
X strcat(buf, "\n");
X queue_string(e, buf);
X }
X }
X }
X }
X
X if (counter > maxcounter)
X { maxcounter = counter;
X if (counter > 30)
X { writelog ("%d users logged in\n", counter); }
X }
X
X sprintf(buf, "%d user%s connected\n", counter,
X counter == 1 ? " is" : "s are");
X queue_string(e, buf);
X}
X
Xvoid free_text_block(struct text_block * t)
X{
X FREE(t->buf);
X FREE((char *)t);
X}
X
X#ifndef BOOLEXP_DEBUGGING
Xvoid main(int argc, char **argv)
X{
X int pid;
X
X if (argc < 3)
X {
X fprintf(stderr, "Usage: %s infile dumpfile [port iport logfile]\n", *argv);
X exit(1);
X
X }
X if (argc > 3)
X port = atoi(argv[3]);
X if (argc > 4)
X intport = atoi(argv[4]);
X if (argc > 5)
X logfile = argv[5];
X
X start_log();
X
X if (init_game(argv[1], argv[2]) < 0)
X {
X writelog("INIT: Couldn't load %s\n", argv[1]);
X exit(2);
X }
X pid = vfork();
X if (pid < 0)
X {
X perror("fork");
X exit(-1);
X }
X if (pid == 0)
X {
X char pstr[32], istr[32], clvl[32];
X
X /* Add port argument to concentrator */
X sprintf(pstr, "%d", port);
X sprintf(istr, "%d", intport);
X sprintf(clvl, "%d", 1);
X execl("concentrate", "conc", pstr, istr, clvl, 0);
X }
X set_signals();
X start_port(port);
X main_loop();
X close_sockets();
X dump_database();
X exit(0);
X}
X
X#endif
X
Xvoid start_log()
X{
X#ifdef DETACH
X if (!debug)
X {
X int i;
X
X if (fork() != 0)
X exit(0);
X
X i = open("/dev/tty", O_RDWR, 0);
X if (i != -1)
X {
X ioctl(i, TIOCNOTTY, 0);
X close(i);
X }
X }
X freopen(logfile, "a", stderr);
X setbuf(stderr, NULL);
X#endif /* DETACH */
X}
X
Xvoid set_signals(void)
X{
X int dump_status(void);
X signal(SIGPIPE, SIG_IGN);
X
X signal(SIGINT, (void *)sigshutdown);
X signal(SIGTERM, (void *)sigshutdown);
X
X#ifdef DETACH
X signal(SIGUSR2, (void *)logsynch);
X#else /* DETACH */
X signal(SIGUSR2, (void *)bailout);
X#endif /* DETACH */
X
X if (debug)
X return;
X
X# ifdef NOCOREDUMP
X signal(SIGQUIT, (void *)bailout);
X signal(SIGILL, (void *)bailout);
X signal(SIGTRAP, (void *)bailout);
X signal(SIGIOT, (void *)bailout);
X signal(SIGEMT, (void *)bailout);
X signal(SIGFPE, (void *)bailout);
X signal(SIGBUS, (void *)bailout);
X signal(SIGSEGV, (void *)bailout);
X signal(SIGSYS, (void *)bailout);
X signal(SIGTERM, (void *)bailout);
X signal(SIGXCPU, (void *)bailout);
X signal(SIGXFSZ, (void *)bailout);
X signal(SIGVTALRM, (void *)bailout);
X# endif
X}
X
Xint
X msec_diff(struct timeval now, struct timeval then)
X{
X return ((now.tv_sec - then.tv_sec) * 1000
X + (now.tv_usec - then.tv_usec) / 1000);
X}
X
Xvoid
X clearstrings(struct descriptor_data * d)
X{
X if (d->output_prefix)
X {
X FREE(d->output_prefix);
X d->output_prefix = 0;
X }
X if (d->output_suffix)
X {
X FREE(d->output_suffix);
X d->output_suffix = 0;
X }
X}
X
Xvoid
X shutdownsock(struct descriptor_data * d)
X{
X if (d->connected)
X {
X writelog("DISCONNECT descriptor %d,%d player %s(%d)\n", d->descriptor, d->num, db[d->player].name, d->player);
X#ifdef CONNECT_MESSAGES
X announce_disconnect(d->player);
X#endif /* CONNECT_MESSAGES */
X } else
X {
X writelog("DISCONNECT descriptor %d,%d never connected\n", d->descriptor, d->num);
X }
X clearstrings(d);
X freeqs(d);
X}
X
Xstruct descriptor_data *
X initializesock(struct sockaddr_in * a)
X{
X struct descriptor_data *d;
X
X MALLOC(d, struct descriptor_data, 1);
X d->connected = 0;
X d->output_prefix = 0;
X d->output_suffix = 0;
X d->output_size = 0;
X d->output.head = 0;
X d->output.tail = &d->output.head;
X d->input.head = 0;
X d->input.tail = &d->input.head;
X d->raw_input = 0;
X d->raw_input_at = 0;
X d->quota = COMMAND_BURST_SIZE;
X d->last_time = 0;
X d->address = *a; /* This will be the address of the
X * concentrator */
X d->hostname = ""; /* This will be set during connect */
X
X welcome_user(d);
X return d;
X}
X
Xstruct text_block *
X make_text_block(const char *s, int n)
X{
X struct text_block *p;
X
X MALLOC(p, struct text_block, 1);
X MALLOC(p->buf, char, n);
X bcopy(s, p->buf, n);
X p->nchars = n;
X p->start = p->buf;
X p->nxt = 0;
X return p;
X}
X
Xvoid
X add_to_queue(struct text_queue * q, const char *b, int n)
X{
X struct text_block *p;
X
X if (n == 0)
X return;
X
X p = make_text_block(b, n);
X p->nxt = 0;
X *q->tail = p;
X q->tail = &p->nxt;
X}
X
Xint
X flush_queue(struct text_queue * q, int n)
X{
X struct text_block *p;
X int really_flushed = 0;
X
X n += strlen(flushed_message);
X
X while (n > 0 && (p = q->head))
X {
X n -= p->nchars;
X really_flushed += p->nchars;
X q->head = p->nxt;
X free_text_block(p);
X }
X p = make_text_block(flushed_message, strlen(flushed_message));
X p->nxt = q->head;
X q->head = p;
X if (!p->nxt)
X q->tail = &p->nxt;
X really_flushed -= p->nchars;
X return really_flushed;
X}
X
Xint
X queue_write(struct descriptor_data * d, const char *b, int n)
X{
X int space;
X
X space = MAX_OUTPUT - d->output_size - n;
X if (space < 0)
X d->output_size -= flush_queue(&d->output, -space);
X add_to_queue(&d->output, b, n);
X d->output_size += n;
X return n;
X}
X
Xint
X queue_string(struct descriptor_data * d, const char *s)
X{
X return queue_write(d, s, strlen(s));
X}
X
Xvoid
X freeqs(struct descriptor_data * d)
X{
X struct text_block *cur, *next;
X
X cur = d->output.head;
X while (cur)
X {
X next = cur->nxt;
X free_text_block(cur);
X cur = next;
X }
X d->output.head = 0;
X d->output.tail = &d->output.head;
X
X cur = d->input.head;
X while (cur)
X {
X next = cur->nxt;
X free_text_block(cur);
X cur = next;
X }
X d->input.head = 0;
X d->input.tail = &d->input.head;
X
X if (d->raw_input)
X FREE(d->raw_input);
X d->raw_input = 0;
X d->raw_input_at = 0;
X}
X
Xvoid
X welcome_user(struct descriptor_data * d)
X{
X queue_string(d, WELCOME_MESSAGE);
X file_date(d, NEWS_FILE);
X# ifdef CONNECT_FILE
X do_connect_msg(d, CONNECT_FILE);
X# endif
X}
X
Xvoid
X goodbye_user(struct descriptor_data * d)
X{
X queue_string(d, LEAVE_MESSAGE);
X}
X
Xchar *
X strsave(const char *s)
X{
X char *p;
X
X MALLOC(p, char, strlen(s) + 1);
X
X if (p)
X strcpy(p, s);
X return p;
X}
X
Xvoid
X save_command(struct descriptor_data * d, const char *command)
X{
X add_to_queue(&d->input, command, strlen(command) + 1);
X}
X
Xvoid
X set_userstring(char **userstring, const char *command)
X{
X if (*userstring)
X {
X FREE(*userstring);
X *userstring = 0;
X }
X while (*command && isascii(*command) && isspace(*command))
X command++;
X if (*command)
X *userstring = strsave(command);
X}
X
Xint
X do_command(struct descriptor_data * d, char *command)
X{
X if (!strcmp(command, QUIT_COMMAND))
X {
X goodbye_user(d);
X return 0;
X } else
X if (!strncmp(command, WHO_COMMAND, strlen(WHO_COMMAND)))
X {
X if (d->output_prefix)
X {
X queue_string(d, d->output_prefix);
X queue_write(d, "\n", 1);
X }
X dump_users(d, command + strlen(WHO_COMMAND));
X if (d->output_suffix)
X {
X queue_string(d, d->output_suffix);
X queue_write(d, "\n", 1);
X }
X } else
X if (d->connected &&
X !strncmp(command, PREFIX_COMMAND, strlen(PREFIX_COMMAND)))
X {
X#ifdef ROBOT_MODE
X if (!Robot(d->player))
X {
X#ifndef TINKER
X notify(d->player,
X "Only robots can use OUTPUTPREFIX; contact a Wizard.");
X#else TINKER
X notify(d->player,
X "Only robots can use OUTPUTPREFIX; contact a Tinker.");
X#endif TINKER
X return 1;
X }
X if (!d->connected)
X return 1;
X#endif ROBOT_MODE
X set_userstring(&d->output_prefix, command + strlen(PREFIX_COMMAND));
X } else
X if (d->connected &&
X !strncmp(command, SUFFIX_COMMAND, strlen(SUFFIX_COMMAND)))
X {
X#ifdef ROBOT_MODE
X if (!Robot(d->player))
X {
X#ifndef TINKER
X notify(d->player,
X "Only robots can use OUTPUTSUFFIX; contact a Wizard.");
X#else TINKER
X notify(d->player,
X "Only robots can use OUTPUTSUFFIX; contact a Tinker.");
X#endif TINKER
X return 1;
X }
X#endif ROBOT_MODE
X set_userstring(&d->output_suffix, command + strlen(SUFFIX_COMMAND));
X } else
X {
X if (d->connected)
X {
X if (d->output_prefix)
X {
X queue_string(d, d->output_prefix);
X queue_write(d, "\n", 1);
X }
X process_command(d->player, command);
X if (d->output_suffix)
X {
X queue_string(d, d->output_suffix);
X queue_write(d, "\n", 1);
X }
X } else
X {
X check_connect(d, command);
X }
X }
X return 1;
X}
X
Xvoid
X check_connect(struct descriptor_data * d, const char *msg)
X{
X char command[MAX_COMMAND_LEN];
X char user[MAX_COMMAND_LEN];
X char password[MAX_COMMAND_LEN];
X dbref player;
X
X parse_connect(msg, command, user, password);
X
X if (!strncmp(command, "co", 2))
X {
X player = connect_player(user, password);
X if (player == NOTHING)
X {
X queue_string(d, connect_fail);
X writelog("FAILED CONNECT %s on descriptor %d,%d\n", user, d->descriptor, d->num);
X } else
X {
X writelog("CONNECTED %s(%d) on descriptor %d,%d %s\n",
X db[player].name, player, d->descriptor, d->num, d->hostname);
X d->connected = 1;
X d->connected_at = time(NULL);
X d->player = player;
X do_motd(player);
X do_look_around(player);
X#ifdef CONNECT_MESSAGES
X announce_connect(player);
X#endif /* CONNECT_MESSAGES */
X }
X } else
X if (!strncmp(command, "cr", 2))
X {
X#ifndef REGISTRATION
X player = create_player(user, password);
X if (player == NOTHING)
X {
X queue_string(d, create_fail);
X writelog("FAILED CREATE %s on descriptor %d,%d %s\n",
X user, d->descriptor, d->num, d->hostname);
X } else
X {
X writelog("CREATED %s(%d) on descriptor %d,%d %s\n",
X db[player].name, player, d->descriptor, d->num, d->hostname);
X d->connected = 1;
X d->connected_at = time(0);
X d->player = player;
X do_motd(player);
X do_look_around(player);
X#ifdef CONNECT_MESSAGES
X announce_connect(player);
X#endif /* CONNECT_MESSAGES */
X }
X#else
X queue_string(d, REGISTER_MESSAGE);
X#endif /* REGISTRATION */
X } else
X {
X welcome_user(d);
X }
X}
X
Xvoid
X parse_connect(const char *msg, char *command, char *user, char *pass)
X{
X char *p;
X
X while (*msg && isascii(*msg) && isspace(*msg))
X msg++;
X p = command;
X while (*msg && isascii(*msg) && !isspace(*msg))
X *p++ = *msg++;
X *p = '\0';
X while (*msg && isascii(*msg) && isspace(*msg))
X msg++;
X p = user;
X while (*msg && isascii(*msg) && !isspace(*msg))
X *p++ = *msg++;
X *p = '\0';
X while (*msg && isascii(*msg) && isspace(*msg))
X msg++;
X p = pass;
X while (*msg && isascii(*msg) && !isspace(*msg))
X *p++ = *msg++;
X *p = '\0';
X}
X
Xvoid
X close_sockets(void)
X{
X struct descriptor_data *d, *dnext;
X struct conc_list *c;
X char header[4];
X
X for (c = firstc; c; c = c->next)
X {
X /* conc.c now handles printing the Going Down - Bye message */
X shutdown(c->sock, 0);
X close(c->sock);
X }
X close(sock);
X}
X
Xvoid
X emergency_shutdown(void)
X{
X close_sockets();
X}
X
Xint
X bailout(int sig, int code, struct sigcontext * scp)
X{
X long *ptr;
X int i;
X
X writelog("BAILOUT: caught signal %d code %d", sig, code);
X ptr = (long *)scp;
X for (i = 0; i < sizeof(struct sigcontext); i++)
X writelog(" %08lx\n", *ptr);
X panic("PANIC on spurious signal");
X _exit(7);
X return 0;
X}
X
Xchar *
X time_format_1(long dt)
X{
X register struct tm *delta;
X static char buf[64];
X
X delta = gmtime(&dt);
X if (delta->tm_yday > 0)
X {
X sprintf(buf, "%dd %02d:%02d",
X delta->tm_yday, delta->tm_hour, delta->tm_min);
X } else
X {
X sprintf(buf, "%02d:%02d",
X delta->tm_hour, delta->tm_min);
X }
X return buf;
X}
X
Xchar *
X time_format_2(long dt)
X{
X register struct tm *delta;
X static char buf[64];
X
X delta = gmtime(&dt);
X if (delta->tm_yday > 0)
X {
X sprintf(buf, "%dd", delta->tm_yday);
X } else
X if (delta->tm_hour > 0)
X {
X sprintf(buf, "%dh", delta->tm_hour);
X } else
X if (delta->tm_min > 0)
X {
X sprintf(buf, "%dm", delta->tm_min);
X } else
X {
X sprintf(buf, "%ds", delta->tm_sec);
X }
X return buf;
X}
X
X#ifdef CONNECT_MESSAGES
Xvoid
X announce_connect(dbref player)
X{
X dbref loc;
X char buf[BUFFER_LEN];
X
X if ((loc = getloc(player)) == NOTHING)
X return;
X if (Dark(player) || Dark(loc))
X return;
X
X sprintf(buf, "%s has connected.", db[player].name);
X
X notify_except(db[loc].contents, player, buf);
X}
X
Xvoid
X announce_disconnect(dbref player)
X{
X dbref loc;
X char buf[BUFFER_LEN];
X
X if ((loc = getloc(player)) == NOTHING)
X return;
X if (Dark(player) || Dark(loc))
X return;
X
X sprintf(buf, "%s has disconnected.", db[player].name);
X
X notify_except(db[loc].contents, player, buf);
X}
X
X#endif /* CONNECT_MESSAGES */
X
Xint
X sigshutdown(int sig, int code, struct sigcontext * scp)
X{
X writelog("SHUTDOWN: on signal %d code %d\n", sig, code);
X shutdown_flag = 1;
X return 0;
X}
X
X#ifdef DETACH
Xint
X logsynch()
X{
X freopen(logfile, "a", stderr);
X setbuf(stderr, NULL);
X writelog("log file reopened\n");
X return 0;
X}
X
X#endif /* DETACH */
X
X#include <sys/stat.h>
X
Xvoid
X file_date(struct descriptor_data * d, char *file)
X{
X static char buf[80];
X extern char *ctime(long *clock);
X struct stat statb;
X char *tstring;
X char *cp;
X
X if (stat(file, &statb) == -1)
X return;
X
X tstring = ctime(&statb.st_mtime);
X if ((cp = (char *)index(tstring, '\n')) != NULL)
X *cp = '\0';
X
X strcpy(buf, "News last updated ");
X strcat(buf, tstring);
X strcat(buf, "\n\n");
X
X queue_string(d, (char *)buf);
X}
X
Xvoid main_loop()
X{
X struct message *ptr;
X int found, newsock, lastsock, len, loop;
X int accepting;
X struct timeval tv;
X struct sockaddr_in sin;
X fd_set in, out;
X char data[1025], *p1, *p2, buffer[1025], header[4];
X struct conc_list *c, *tempc, *nextc, *lastc;
X struct descriptor_data *d, *tempd, *nextd;
X struct timeval last_slice, current_time;
X struct timeval next_slice;
X struct timeval slice_timeout;
X short templen;
X
X accepting = 1;
X lastsock = sock + 1;
X while (!shutdown_flag)
X {
X gettimeofday(¤t_time, (struct timezone *) 0);
X last_slice = update_quotas(last_slice, current_time);
X
X process_commands();
X
X if (shutdown_flag)
X break;
X
X next_slice = msec_add(last_slice, COMMAND_TIME_MSEC);
X slice_timeout = timeval_sub(next_slice, current_time);
X
X FD_ZERO(&in);
X FD_ZERO(&out);
X
X FD_SET(sock, &in);
X for (c = firstc; c; c = c->next)
X process_output(c);
X for (c = firstc; c; c = c->next)
X if (c->sock)
X {
X if (c->ilen < BUFSIZE)
X FD_SET(c->sock, &in);
X len = c->first ? c->first->len : 0;
X while (c->first && ((c->olen + len + 2) < BUFSIZE))
X {
X templen = c->first->len;
X bcopy(&templen, c->outgoing + c->olen, 2);
X bcopy(c->first->data, c->outgoing + c->olen + 2, len);
X c->olen += len + 2;
X ptr = c->first;
X c->first = ptr->next;
X FREE(ptr->data);
X FREE(ptr);
X if (c->last == ptr)
X c->last = 0;
X len = c->first ? c->first->len : 0;
X }
X if (c->olen)
X FD_SET(c->sock, &out);
X }
X tv.tv_sec = 1000;
X tv.tv_usec = 0;
X
X found = select(lastsock, &in, &out, (fd_set *) 0, &tv);
X if (found < 0)
X continue;
X if (accepting && FD_ISSET(sock, &in))
X {
X len = sizeof(sin);
X newsock = accept(sock, (struct sockaddr *) & sin, &len);
X if (newsock >= 0)
X {
X if (newsock >= lastsock)
X lastsock = newsock + 1;
X if (fcntl(newsock, F_SETFL, FNDELAY) == -1)
X {
X perror("make_nonblocking: fcntl");
X }
X MALLOC(tempc, struct conc_list, 1);
X tempc->next = firstc;
X tempc->firstd = 0;
X tempc->first = 0;
X tempc->last = 0;
X tempc->status = 0;
X /* Imcomming and outgoing I/O buffers */
X MALLOC(tempc->incoming, char, BUFSIZE);
X tempc->ilen = 0;
X MALLOC(tempc->outgoing, char, BUFSIZE);
X tempc->olen = 0;
X firstc = tempc;
X firstc->sock = newsock;
X writelog("CONCENTRATOR CONNECT: sock %d, addr %x\n", newsock, sin.sin_addr.s_addr);
X }
X }
X for (c = firstc; c; c = nextc)
X {
X nextc = c->next;
X#ifdef CHECKC
X if (!(c->sock))
X writelog("CONSISTENCY CHECK: Concentrator found with null socket #\n");
X#endif
X if ((FD_ISSET(c->sock, &in)) && (c->ilen < BUFSIZE))
X {
X int i;
X len = recv(c->sock, c->incoming + c->ilen,
X BUFSIZE - c->ilen, 0);
X if (len == 0)
X {
X struct message *mptr, *tempm;
X writelog("CONCENTRATOR DISCONNECT: %d\n", c->sock);
X close(c->sock);
X d = c->firstd;
X while (d)
X {
X shutdownsock(d);
X tempd = d;
X d = d->next;
X FREE(tempd);
X }
X if (firstc == c)
X firstc = firstc->next;
X else
X lastc->next = c->next;
X FREE(c->incoming);
X FREE(c->outgoing);
X mptr = c->first;
X while (mptr)
X {
X tempm = mptr;
X mptr = mptr->next;
X FREE(mptr->data);
X FREE(mptr);
X }
X FREE(c);
X break;
X } else
X if (len < 0)
X {
X writelog("recv: %s\n", strerror(errno));
X } else
X {
X int num;
X
X c->ilen += len;
X while (c->ilen > 2)
X {
X bcopy(c->incoming, &templen, 2);
X#ifdef CHECKC
X if (templen < 1)
X writelog("CONSISTENCY CHECK: Message recived with lenght < 1\n");
X#endif
X if (c->ilen >= (templen + 2))
X {
X num = *(c->incoming + 2);
X /* Is it coming from the command user #? */
X if (num == 0)
X {
X /* Proccess commands */
X switch (*(c->incoming + 3))
X {
X case 1: /* connect */
X d = initializesock(&sin);
X d->descriptor = c->sock;
X d->next = c->firstd;
X c->firstd = d;
X d->num = *(c->incoming + 4);
X MALLOC(d->hostname, char,
X templen - 5);
X bcopy(c->incoming + 9, d->hostname,
X templen - 6);
X *(d->hostname + templen - 7) = 0;
X#ifdef DEBUG
X writelog("USER CONNECT %d,%d from host %s\n", c->sock, d->num, d->hostname);
X#endif
X break;
X case 2: /* disconnect */
X tempd = 0;
X d = c->firstd;
X num = *(c->incoming + 4);
X while (d)
X {
X if (d->num == num)
X {
X writelog("USER ABORTED CONNECTION %d,%d\n", c->sock, d->num);
X shutdownsock(d);
X if (c->firstd == d)
X c->firstd = d->next;
X else
X tempd->next = d->next;
X FREE(d);
X break;
X }
X tempd = d;
X d = d->next;
X }
X#ifdef CHECKC
X if (!d)
X writelog("CONSISTENCY CHECK: Disconnect Received for unknown user %d,%d\n", c->sock, num);
X#endif
X break;
X
X /*
X * This take a message from a concentrator, and logs it in
X * the log file
X */
X case 4:
X {
X char buffer[2048];
X bcopy(c->incoming + 4, buffer,
X templen - 2);
X *(buffer + templen - 1) = 0;
X writelog(buffer);
X break;
X }
X#ifdef CHECKC
X default:
X writelog("CONSISTENCY CHECK: Received unknown command from concentrator\n");
X#endif
X }
X } else
X {
X d = c->firstd;
X while (d)
X {
X if (d->num == num)
X {
X process_input(d, c->incoming + 3,
X templen - 1);
X break;
X }
X d = d->next;
X }
X#ifdef CHECKC
X if (!d)
X writelog("CONSISTENCY CHECK: Message received for unknown user %d,%d\n", c->sock, num);
X#endif
X }
X bcopy(c->incoming + templen + 2, c->incoming,
X (c->ilen - templen - 2));
X c->ilen = c->ilen - templen - 2;
X } else
X break;
X }
X }
X }
X lastc = c;
X }
X /* Send data loop */
X for (c = firstc; c; c = c->next)
X {
X if (FD_ISSET(c->sock, &out))
X {
X if (c->olen)
X {
X len = send(c->sock, c->outgoing, c->olen, 0);
X if (len > 0)
X {
X c->olen -= len;
X bcopy(c->outgoing + len, c->outgoing, c->olen);
X }
X }
X }
X }
X }
X}
X
Xvoid process_output(struct conc_list * c)
X{
X struct descriptor_data *d;
X struct text_block **qp, *cur;
X short templen;
X
X for (d = c->firstd; d; d = d->next)
X {
X qp = &d->output.head;
X cur = *qp;
X if (cur)
X {
X if (cur->nchars < 512)
X {
X if ((c->olen + cur->nchars + 3) < BUFSIZE)
X {
X templen = cur->nchars + 1;
X bcopy(&templen, c->outgoing + c->olen, 2);
X *(c->outgoing + c->olen + 2) = d->num;
X strncpy(c->outgoing + c->olen + 3, cur->start, cur->nchars);
X d->output_size -= cur->nchars;
X c->olen += cur->nchars + 3;
X if (!cur->nxt)
X d->output.tail = qp;
X *qp = cur->nxt;
X free_text_block(cur);
X }
X } else
X {
X if ((c->olen + 512 + 3) < BUFSIZE)
X {
X templen = 512 + 1;
X bcopy(&templen, c->outgoing + c->olen, 2);
X *(c->outgoing + c->olen + 2) = d->num;
X strncpy(c->outgoing + c->olen + 3, cur->start, 512);
X d->output_size -= 512;
X c->olen += 512 + 3;
X cur->nchars -= 512;
X cur->start += 512;
X }
X }
X }
X }
X}
X
Xvoid boot_off(dbref player)
X{
X struct conc_list *c;
X struct descriptor_data *d, *lastd;
X char header[4];
X
X for (c = firstc; c; c = c->next)
X {
X lastd = 0;
X for (d = c->firstd; d; d = d->next)
X {
X if (d->connected && d->player == player)
X {
X header[0] = 0;
X header[1] = 2;
X header[2] = d->num;
X queue_message(c, header, 3);
X process_output(c);
X if (lastd)
X lastd->next = d->next;
X else
X c->firstd = d->next;
X shutdownsock(d);
X FREE(d);
X return;
X }
X lastd = d;
X }
X }
X}
X
Xvoid queue_message(struct conc_list * c, char *data, int len)
X{
X struct message *ptr;
X
X MALLOC(ptr, struct message, 1);
X MALLOC(ptr->data, char, len);
X ptr->len = len;
X bcopy(data, ptr->data, len);
X ptr->next = 0;
X if (c->last == 0)
X c->first = ptr;
X else
X c->last->next = ptr;
X c->last = ptr;
X}
X
Xint do_connect_msg(struct descriptor_data * d, const char *filename)
X{
X FILE *f;
X char buf[BUFFER_LEN];
X char *p;
X
X if ((f = fopen(filename, "r")) == NULL)
X {
X return (0);
X } else
X {
X while (fgets(buf, sizeof buf, f))
X {
X queue_string(d, (char *)buf);
X
X }
X fclose(f);
X return (1);
X }
X}
END_OF_FILE
if test 33958 -ne `wc -c <'interface.c'`; then
echo shar: \"'interface.c'\" unpacked with wrong size!
fi
# end of 'interface.c'
fi
if test -f 'joinspl.sh' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'joinspl.sh'\"
else
echo shar: Extracting \"'joinspl.sh'\" \(333 characters\)
sed "s/^X//" >'joinspl.sh' <<'END_OF_FILE'
X#! /bin/sh
X#
X# join split lines in the config.h and small.db files
X#
Xecho creating config.h
Xsed -f comb.sed config_h.spl >config.h
Xecho creating small.db
Xsed -f comb.sed smalldb.spl >small.db
Xrm config_h.spl smalldb.spl
X#
X# build tinymud.ps from its three parts
X#
Xcreating tinymud.ps
Xcat tinymud.ps.xa? >tinymud.ps
Xrm tinymud.ps.xa?
END_OF_FILE
if test 333 -ne `wc -c <'joinspl.sh'`; then
echo shar: \"'joinspl.sh'\" unpacked with wrong size!
fi
chmod +x 'joinspl.sh'
# end of 'joinspl.sh'
fi
if test -f 'wiz.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'wiz.c'\"
else
echo shar: Extracting \"'wiz.c'\" \(16849 characters\)
sed "s/^X//" >'wiz.c' <<'END_OF_FILE'
X#include "copyright.h"
X
X/* Wizard-only commands */
X
X
X#include "db.h"
X#include "config.h"
X#include "interface.h"
X#include "match.h"
X#include "externs.h"
X
Xvoid do_teleport(dbref player, const char *arg1, const char *arg2)
X{
X dbref victim;
X dbref destination;
X const char *to;
X
X#ifdef RESTRICTED_TELEPORT
X if(!Wizard(player)) {
X#ifndef TINKER
X notify(player, "Only a Wizard may teleport at will.");
X#else TINKER
X notify(player, "Only a Tinker may teleport at will.");
X#endif TINKER
X return;
X }
X#endif /* RESTRICTED_TELEPORT */
X
X /* get victim, destination */
X if(*arg2 == '\0') {
X victim = player;
X to = arg1;
X } else {
X init_match(player, arg1, NOTYPE);
X match_neighbor();
X match_possession();
X match_me();
X match_absolute();
X match_player();
X
X if((victim = noisy_match_result()) == NOTHING) {
X return;
X }
X to = arg2;
X }
X
X /* get destination */
X init_match(player, to, TYPE_PLAYER);
X match_here();
X match_absolute();
X if(Wizard(player)) {
X match_neighbor();
X match_me();
X match_player();
X }
X
X switch(destination = match_result()) {
X case NOTHING:
X notify(player, "Send it where?");
X break;
X case AMBIGUOUS:
X notify(player, "I don't know which destination you mean!");
X break;
X default:
X /* check victim, destination types, teleport if ok */
X if(Typeof(destination) == TYPE_EXIT
X || Typeof(destination) == TYPE_THING
X || Typeof(victim) == TYPE_EXIT
X || Typeof(victim) == TYPE_ROOM
X || (Typeof(victim) == TYPE_PLAYER
X && Typeof(destination) != TYPE_ROOM)) {
X notify(player, "Bad destination.");
X#ifndef RESTRICTED_TELEPORT
X } else if(!Wizard(player)
X && !(Typeof(victim) == TYPE_THING
X && Typeof(destination) == TYPE_ROOM
X && (controls(player, victim)
X || (Typeof(db[victim].location) == TYPE_ROOM
X && controls(player, db[victim].location)))
X && (can_link_to(player, TYPE_PLAYER, destination)))) {
X notify(player, "Permission denied.");
X#endif /* RESTRICTED_TELEPORT */
X } else if(Typeof(victim) == TYPE_PLAYER) {
X notify(victim, "You feel a wrenching sensation...");
X enter_room(victim, destination);
X notify(player, "Teleported.");
X } else {
X /* check for non-sticky dropto */
X if(Typeof(destination) == TYPE_ROOM
X && db[destination].location != NOTHING
X && !(db[destination].flags & STICKY)) {
X /* destination has immediate dropto */
X destination = db[destination].location;
X }
X
X /* do the move */
X moveto(victim, destination);
X notify(player, "Teleported.");
X }
X }
X}
X
Xvoid do_mass_teleport(dbref player, const char *arg1)
X{
X dbref victim;
X dbref destination;
X char buf[BUFFER_LEN];
X int moved = 0;
X
X if(!God(player)) {
X#ifndef TINKER
X notify(player, "Only God can do a mass teleport.");
X#else TINKER
X notify(player, "Only the Master Tinker can do a mass teleport.");
X#endif TINKER
X return;
X }
X
X /* get destination */
X init_match(player, arg1, TYPE_ROOM);
X match_here();
X match_absolute();
X
X if ((destination = match_result()) == NOTHING) {
X notify(player, "Please specify a destination to send everyone to.");
X return;
X }
X
X switch (Typeof(destination)) {
X case NOTHING:
X notify(player, "Send them where?");
X break;
X
X case TYPE_ROOM:
X for (victim = 0; victim < db_top; victim++) {
X if (victim != player && Typeof(victim) == TYPE_PLAYER) {
X notify(victim,
X "You and everyone around you feels a wrenching sensation...");
X moveto(victim, destination);
X look_room(victim, destination);
X moved++;
X }
X }
X sprintf (buf, "Teleported %d players to %s.",
X moved, unparse_object (player, destination));
X notify(player, "Teleported.");
X break;
X
X default:
X notify(player, "Mass teleports are legal to rooms only.");
X }
X}
X
Xvoid do_force(dbref player, const char *what, char *command)
X{
X dbref victim;
X
X if(!Wizard(player)) {
X writelog ("FORCE: failed, priv, player %s(%d), who '%s', what '%s'\n",
X db[player].name, player, what, command);
X#ifndef TINKER
X notify(player, "Only Wizards may use this command.");
X#else TINKER
X notify(player, "Only Tinkers may use this command.");
X#endif TINKER
X return;
X }
X
X /* get victim */
X if((victim = lookup_player(what)) == NOTHING) {
X writelog ("FORCE: failed, victim, player %s(%d), who '%s', what '%s'\n",
X db[player].name, player, what, command);
X notify(player, "That player does not exist.");
X return;
X }
X
X#ifdef GOD_PRIV
X if(God(victim)) {
X#ifndef TINKER
X writelog ("FORCE: failed, wizard, player %s(%d), who '%s', what '%s'\n",
X#else TINKER
X writelog ("FORCE: failed, tinker, player %s(%d), who '%s', what '%s'\n",
X#endif TINKER
X db[player].name, player, what, command);
X#ifndef TINKER
X notify(player, "You can't force God.");
X#else TINKER
X notify(player, "You can't force the Master Tinker.");
X#endif TINKER
X return;
X }
X#endif GOD_PRIV
X
X /* force victim to do command */
X writelog ("FORCE: success, player %s(%d), who '%s', what '%s'\n",
X db[player].name, player, what, command);
X
X process_command(victim, command);
X}
X
Xvoid do_stats(dbref player, const char *name)
X{
X dbref rooms;
X dbref exits;
X dbref things;
X dbref players;
X dbref total;
X dbref i;
X dbref owner;
X char buf[BUFFER_LEN];
X
X if(!Wizard(player)) {
X sprintf(buf, "The universe contains %d objects.", db_top);
X notify(player, buf);
X } else {
X owner = lookup_player(name);
X total = rooms = exits = things = players = 0;
X for(i = 0; i < db_top; i++) {
X if(owner == NOTHING || owner == db[i].owner) {
X total++;
X switch(Typeof(i)) {
X case TYPE_ROOM:
X rooms++;
X break;
X case TYPE_EXIT:
X exits++;
X break;
X case TYPE_THING:
X things++;
X break;
X case TYPE_PLAYER:
X players++;
X break;
X default:
X abort();
X break;
X }
X }
X }
X sprintf(buf,
X "%d objects = %d rooms, %d exits, %d things, %d players.",
X total, rooms, exits, things, players);
X notify(player, buf);
X#ifdef TEST_MALLOC
X sprintf(buf, "Malloc count = %d.", malloc_count);
X notify(player, buf);
X#endif /* TEST_MALLOC */
X }
X}
X
Xvoid do_bobble(dbref player, const char *name, const char *rname)
X{
X dbref victim, recip, i;
X char buf[BUFFER_LEN];
X int newflags = 0;
X
X if(!Wizard(player)) {
X#ifndef TINKER
X writelog("TOAD: failed, priv %s(%d) who '%s'\n",
X db[player].name, player, name);
X notify(player, "Only a Wizard can turn a person into a toad.");
X#else TINKER
X writelog("BOBBLE: failed, priv %s(%d) who '%s'\n",
X db[player].name, player, name);
X notify(player, "Only a Tinker can bobble a person.");
X#endif TINKER
X return;
X }
X
X if (!name || !*name) {
X#ifndef TINKER
X writelog("TOAD: failed, syntax %s(%d) who '%s'\n",
X db[player].name, player, name);
X#else TINKER
X writelog("BOBBLE: failed, syntax %s(%d) who '%s'\n",
X db[player].name, player, name);
X#endif TINKER
X notify(player, "You must specify a victim.");
X return;
X }
X
X init_match(player, name, TYPE_PLAYER);
X match_neighbor();
X match_absolute();
X match_player();
X if((victim = noisy_match_result()) == NOTHING) {
X#ifndef TINKER
X writelog("TOAD: failed, victim %s(%d) who '%s'\n",
X db[player].name, player, name);
X#else TINKER
X writelog("BOBBLE: failed, victim %s(%d) who '%s'\n",
X db[player].name, player, name);
X#endif TINKER
X notify(player, "Please specify another victim.");
X return;
X }
X
X#ifdef RECYCLE
X /* Default the recipient to RECYCLER */
X if (!rname || !*rname || string_compare (rname, RECYCLER) == 0) {
X recip = lookup_player(RECYCLER);
X newflags = UNWANTED; /* Can be gotten by other players */
X } else {
X recip = lookup_player(rname);
X }
X#else
X recip = lookup_player(rname);
X#endif
X
X if(recip == NOTHING || recip == victim) {
X#ifndef TINKER
X writelog("TOAD: failed, recip %s(%d) who '%s'\n",
X db[player].name, player, name);
X#else TINKER
X writelog("BOBBLE: failed, recip %s(%d) who '%s'\n",
X db[player].name, player, name);
X#endif TINKER
X notify(player, "Please specify another player to own the victim's effects.");
X return;
X }
X
X if(Typeof(victim) != TYPE_PLAYER) {
X#ifndef TINKER
X writelog("TOAD: failed, type %s(%d) who '%s'\n",
X db[player].name, player, name);
X notify(player, "You can only turn players into toads!");
X#else TINKER
X writelog("BOBBLE: failed, type %s(%d) who '%s'\n",
X db[player].name, player, name);
X notify(player, "You can only bobble players!");
X#endif TINKER
X } else if(Wizard(victim)) {
X#ifndef TINKER
X writelog("TOAD: failed, wizard %s(%d) who '%s'\n",
X db[player].name, player, name);
X notify(player, "You can't turn a Wizard into a toad.");
X#else TINKER
X writelog("BOBBLE: failed, tinker %s(%d) who '%s'\n",
X db[player].name, player, name);
X notify(player, "You can't bobble a Tinker.");
X#endif TINKER
X } else if(db[victim].contents != NOTHING) {
X#ifndef TINKER
X writelog("TOAD: failed, contents %s(%d) who '%s'\n",
X db[player].name, player, name);
X#else TINKER
X writelog("BOBBLE: failed, contents %s(%d) who '%s'\n",
X db[player].name, player, name);
X#endif TINKER
X
X notify(player, "What about what they are carrying?");
X } else {
X#ifndef TINKER
X writelog("TOAD: success %s(%d) who '%s'\n",
X db[player].name, player, name);
X#else TINKER
X writelog("BOBBLE: success %s(%d) who '%s'\n",
X db[player].name, player, name);
X#endif TINKER
X
X /* we are ok */
X /* do it */
X if(db[victim].password) {
X free((void *) db[victim].password);
X db[victim].password = 0;
X }
X db[victim].flags = TYPE_THING;
X
X /* Give the sphere and all old belongings to recipient */
X db[victim].owner = recip;
X for (i=0; i<db_top; i++) {
X if (db[i].owner == victim) {
X db[i].owner = recip;
X db[i].flags |= newflags;
X }
X }
X
X db[victim].pennies = 1; /* dont let him keep his immense wealth */
X
X /* notify people */
X#ifndef TINKER
X sprintf(buf, "You have been turned into a toad by %s.",
X db[player].name);
X#else TINKER
X sprintf(buf, "You have been encased in a stasis sphere by %s.",
X db[player].name);
X#endif TINKER
X notify(victim, buf);
X#ifndef TINKER
X sprintf(buf, "You turned %s into a toad!", db[victim].name);
X#else TINKER
X sprintf(buf, "You bobbled %s!", db[victim].name);
X#endif TINKER
X notify(player, buf);
X
X /* reset name */
X#ifdef PLAYER_LIST
X delete_player(victim);
X#endif PLAYER_LIST
X#ifndef TINKER
X sprintf(buf, "a slimy toad named %s", db[victim].name);
X#else TINKER
X sprintf(buf, "a silvery sphere containing %s", db[victim].name);
X#endif TINKER
X free((void *) db[victim].name);
X db[victim].name = alloc_string(buf);
X }
X}
X
Xvoid do_unbobble(dbref player, const char *name, const char *newname)
X{
X dbref victim;
X char buf[BUFFER_LEN];
X
X if(!Wizard(player)) {
X#ifndef TINKER
X writelog("UNTOAD: failed, priv %s(%d) who '%s'\n",
X db[player].name, player, name);
X notify(player, "Only a Wizard can turn a toad into a person.");
X#else TINKER
X writelog("UNBOBBLE: failed, priv %s(%d) who '%s'\n",
X db[player].name, player, name);
X notify(player, "Only a Tinker can unbobble a person.");
X#endif TINKER
X return;
X }
X
X if (!name || !*name) {
X#ifndef TINKER
X writelog("UNTOAD: failed, syntax %s(%d) who '%s'\n",
X db[player].name, player, name);
X#else TINKER
X writelog("UNBOBBLE: failed, syntax %s(%d) who '%s'\n",
X db[player].name, player, name);
X#endif TINKER
X notify(player, "You must specify a thing.");
X return;
X }
X
X if (!newname || !*newname) {
X#ifndef TINKER
X writelog("UNTOAD: failed, syntax %s(%d) who '%s'\n",
X db[player].name, player, name);
X notify(player,"You must specify a new name: @untoad <thing> = <name>");
X#else TINKER
X writelog("UNBOBBLE: failed, syntax %s(%d) who '%s'\n",
X db[player].name, player, name);
X notify(player,
X "You must specify a new name: @unbobble <thing> = <name>");
X#endif TINKER
X return;
X }
X
X init_match(player, name, TYPE_THING);
X match_neighbor();
X match_absolute();
X match_player();
X if((victim = noisy_match_result()) == NOTHING) {
X#ifndef TINKER
X writelog("UNTOAD: failed, victim %s(%d) who '%s'\n",
X db[player].name, player, name);
X#else TINKER
X writelog("UNBOBBLE: failed, victim %s(%d) who '%s'\n",
X db[player].name, player, name);
X#endif TINKER
X notify(player, "Please specify another thing.");
X return;
X }
X
X if(Typeof(victim) != TYPE_THING) {
X#ifndef TINKER
X writelog("UNTOAD: failed, type %s(%d) who '%s'\n",
X db[player].name, player, name);
X notify(player, "You can only turn players into toads!");
X#else TINKER
X writelog("UNBOBBLE: failed, type %s(%d) who '%s'\n",
X db[player].name, player, name);
X notify(player, "You can only bobble players!");
X#endif TINKER
X } else if (!ok_player_name(newname)) {
X#ifndef TINKER
X writelog("UNTOAD: failed, name %s(%d) who '%s'\n",
X db[player].name, player, name);
X#else TINKER
X writelog("UNBOBBLE: failed, name %s(%d) who '%s'\n",
X db[player].name, player, name);
X#endif TINKER
X notify(player, "You can't give a player that name!");
X } else {
X#ifndef TINKER
X writelog("UNTOAD: success %s(%d) who '%s'\n",
X db[player].name, player, name);
X#else TINKER
X writelog("UNBOBBLE: success %s(%d) who '%s'\n",
X db[player].name, player, name);
X#endif TINKER
X
X /* we are ok */
X /* do it */
X db[victim].flags = TYPE_PLAYER;
X db[victim].owner = victim;
X db[victim].pennies = KILL_BONUS;
X
X /* reset name */
X free((void *) db[victim].name);
X db[victim].name = alloc_string(newname);
X
X#ifndef TINKER
X sprintf(buf, "You turned the toad back into %s!", db[victim].name);
X#else TINKER
X sprintf(buf, "You unbobbled %s!", db[victim].name);
X#endif TINKER
X notify(player, buf);
X
X sprintf(buf, "Use @newpassword to give %s a password",
X db[victim].name);
X notify(player, buf);
X
X#ifdef PLAYER_LIST
X add_player(victim);
X#endif PLAYER_LIST
X }
X}
X
Xvoid do_newpassword(dbref player, const char *name, const char *password)
X{
X dbref victim;
X char buf[BUFFER_LEN];
X
X if(!Wizard(player)) {
X writelog("PASSWORD: failed, priv %s(%d) who '%s'\n",
X db[player].name, player, name);
X notify(player, "Your delusions of grandeur have been duly noted.");
X return;
X } else if((victim = lookup_player(name)) == NOTHING) {
X writelog("PASSWORD: failed, victim %s(%d) who '%s'\n",
X db[player].name, player, name);
X notify(player, "No such player.");
X } else if(*password != '\0' && !ok_password(password)) {
X /* Wiz can set null passwords, but not bad passwords */
X writelog("PASSWORD: failed, password %s(%d) who '%s'\n",
X db[player].name, player, name);
X notify(player, "Bad password");
X#ifdef GOD_PRIV
X } else if (God(victim) && !God(player)) {
X#ifndef TINKER
X writelog("PASSWORD: failed, wizard %s(%d) who '%s'\n",
X#else TINKER
X writelog("PASSWORD: failed, tinker %s(%d) who '%s'\n",
X#endif TINKER
X db[player].name, player, name);
X notify(player, "You cannot change that player's password.");
X#endif GOD_PRIV
X } else {
X writelog("PASSWORD: success %s(%d) who '%s'\n",
X db[player].name, player, name);
X /* it's ok, do it */
X if(db[victim].password) free((void *) db[victim].password);
X db[victim].password = alloc_string(password);
X notify(player, "Password changed.");
X sprintf(buf, "Your password has been changed by %s.", db[player].name);
X notify(victim, buf);
X }
X}
X
Xvoid do_boot(dbref player, const char *name)
X{
X dbref victim;
X char buf[BUFFER_LEN];
X
X if(!Wizard(player)) {
X writelog ("BOOT: failed, priv player %s(%d), who '%s'\n",
X db[player].name, player, name);
X
X#ifndef TINKER
X notify(player, "Only a Wizard can boot another player off!");
X#else TINKER
X notify(player, "Only a Tinker can boot another player off!");
X#endif TINKER
X return;
X }
X
X init_match(player, name, TYPE_PLAYER);
X match_neighbor();
X match_absolute();
X match_player();
X if((victim = noisy_match_result()) == NOTHING) return;
X
X#ifdef GOD_PRIV
X if(God(victim)) {
X#ifndef TINKER
X writelog ("BOOT: failed, wizard, player %s(%d), who '%s'\n",
X#else TINKER
X writelog ("BOOT: failed, tinker, player %s(%d), who '%s'\n",
X#endif TINKER
X db[player].name, player, name);
X
X notify(player, "You can't boot that player!");
X return;
X }
X#endif GOD_PRIV
X
X if(Typeof(victim) != TYPE_PLAYER) {
X writelog ("BOOT: failed, victim, player %s(%d), who '%s'\n",
X db[player].name, player, name);
X
X notify(player, "You can only boot off other players!");
X } else {
X writelog ("BOOT: success, player %s(%d), who '%s'\n",
X db[player].name, player, name);
X
X /* we are ok */
X /* do it */
X /* notify people */
X sprintf(buf, "You have been booted off the game by %s.",
X db[player].name);
X notify(victim, buf);
X sprintf(buf, "You booted %s off!", db[victim].name);
X notify(player, buf);
X boot_off(victim);
X /* reset name */
X }
X}
END_OF_FILE
if test 16849 -ne `wc -c <'wiz.c'`; then
echo shar: \"'wiz.c'\" unpacked with wrong size!
fi
# end of 'wiz.c'
fi
echo shar: End of archive 5 \(of 10\).
cp /dev/null ark5isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 10 archives.
echo ">>> now type 'sh joinspl.sh'"
rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0