billr@saab.CNA.TEK.COM (Bill Randle) (07/30/90)
Submitted-by: James Aspnes <asp@cs.cmu.edu> Posting-number: Volume 11, Issue 11 Archive-name: tinymud2/Part07 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 7 (of 10)." # Contents: db.c game.c restart-cmu tinymud.tex # Wrapped by billr@saab on Fri Jul 27 15:27:48 1990 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'db.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'db.c'\" else echo shar: Extracting \"'db.c'\" \(9028 characters\) sed "s/^X//" >'db.c' <<'END_OF_FILE' X#include "copyright.h" X X#include <stdio.h> X#include <ctype.h> X X#include "db.h" X#include "config.h" X Xstruct object *db = 0; Xdbref db_top = 0; X X#ifdef TEST_MALLOC Xint malloc_count = 0; X#endif /* TEST_MALLOC */ X X#ifndef DB_INITIAL_SIZE X#define DB_INITIAL_SIZE 10000 X#endif /* DB_INITIAL_SIZE */ X X#ifdef DB_DOUBLING X Xdbref db_size = DB_INITIAL_SIZE; X#endif /* DB_DOUBLING */ X Xconst char *alloc_string(const char *string) X{ X char *s; X X /* NULL, "" -> NULL */ X if(string == 0 || *string == '\0') return 0; X X if((s = (char *) malloc(strlen(string)+1)) == 0) { X abort(); X } X strcpy(s, string); X return s; X} X X#ifdef DB_DOUBLING X Xstatic void db_grow(dbref newtop) X{ X struct object *newdb; X X if(newtop > db_top) { X db_top = newtop; X if(!db) { X /* make the initial one */ X db_size = DB_INITIAL_SIZE; X if((db = (struct object *) X malloc(db_size * sizeof(struct object))) == 0) { X abort(); X } X } X X /* maybe grow it */ X if(db_top > db_size) { X /* make sure it's big enough */ X while(db_top > db_size) db_size *= 2; X if((newdb = (struct object *) X realloc((void *) db, X db_size * sizeof(struct object))) == 0) { X abort(); X } X db = newdb; X } X } X} X X#else /* DB_DOUBLING */ X Xstatic void db_grow(dbref newtop) X{ X struct object *newdb; X X if(newtop > db_top) { X db_top = newtop; X if(db) { X if((newdb = (struct object *) X realloc((void *) db, X db_top * sizeof(struct object))) == 0) { X abort(); X } X db = newdb; X } else { X /* make the initial one */ X if((db = (struct object *) X malloc(DB_INITIAL_SIZE * sizeof(struct object))) == 0) { X abort(); X } X } X } X} X#endif /* DB_DOUBLING */ X Xdbref new_object(void) X{ X dbref newobj; X struct object *o; X X newobj = db_top; X db_grow(db_top + 1); X X /* clear it out */ X o = db+newobj; X o->name = 0; X o->description = 0; X o->location = NOTHING; X o->contents = NOTHING; X o->exits = NOTHING; X o->next = NOTHING; X o->key = TRUE_BOOLEXP; X o->fail_message = 0; X o->succ_message = 0; X o->ofail = 0; X o->osuccess = 0; X o->owner = NOTHING; X o->pennies = 0; X /* flags you must initialize yourself */ X o->password = 0; X X return newobj; X} X X#define DB_MSGLEN 512 X Xvoid putref(FILE *f, dbref ref) X{ X fprintf(f, "%d\n", ref); X} X Xstatic void putstring(FILE *f, const char *s) X{ X if(s) { X fputs(s, f); X } X putc('\n', f); X} X Xstatic void putbool_subexp(FILE *f, struct boolexp *b) X{ X switch(b->type) { X case BOOLEXP_AND: X putc('(', f); X putbool_subexp(f, b->sub1); X putc(AND_TOKEN, f); X putbool_subexp(f, b->sub2); X putc(')', f); X break; X case BOOLEXP_OR: X putc('(', f); X putbool_subexp(f, b->sub1); X putc(OR_TOKEN, f); X putbool_subexp(f, b->sub2); X putc(')', f); X break; X case BOOLEXP_NOT: X putc('(', f); X putc(NOT_TOKEN, f); X putbool_subexp(f, b->sub1); X putc(')', f); X break; X case BOOLEXP_CONST: X fprintf(f, "%d", b->thing); X break; X default: X break; X } X} X Xvoid putboolexp(FILE *f, struct boolexp *b) X{ X if(b != TRUE_BOOLEXP) { X putbool_subexp(f, b); X } X putc('\n', f); X} X Xint db_write_object(FILE *f, dbref i) X{ X struct object *o; X X o = db + i; X putstring(f, o->name); X putstring(f, o->description); X putref(f, o->location); X putref(f, o->contents); X putref(f, o->exits); X putref(f, o->next); X putboolexp(f, o->key); X putstring(f, o->fail_message); X putstring(f, o->succ_message); X putstring(f, o->ofail); X putstring(f, o->osuccess); X putref(f, o->owner); X putref(f, o->pennies); X putref(f, o->flags); X putstring(f, o->password); X X return 0; X} X Xdbref db_write(FILE *f) X{ X dbref i; X X for(i = 0; i < db_top; i++) { X fprintf(f, "#%d\n", i); X db_write_object(f, i); X } X fputs("***END OF DUMP***\n", f); X fflush(f); X return(db_top); X} X Xdbref parse_dbref(const char *s) X{ X const char *p; X long x; X X x = atol(s); X if(x > 0) { X return x; X } else if(x == 0) { X /* check for 0 */ X for(p = s; *p; p++) { X if(*p == '0') return 0; X if(!isspace(*p)) break; X } X } X X /* else x < 0 or s != 0 */ X return NOTHING; X} X Xdbref getref(FILE *f) X{ X static char buf[DB_MSGLEN]; X X fgets(buf, sizeof(buf), f); X return(atol(buf)); X} X Xstatic const char *getstring_noalloc(FILE *f) X{ X static char buf[DB_MSGLEN]; X char *p; X X fgets(buf, sizeof(buf), f); X for(p = buf; *p; p++) { X if(*p == '\n') { X *p = '\0'; X break; X } X } X X return buf; X} X X#define getstring(x) alloc_string(getstring_noalloc(x)) X X#ifdef COMPRESS Xextern const char *compress(const char *); X#define getstring_compress(x) alloc_string(compress(getstring_noalloc(x))); X#else X#define getstring_compress(x) getstring(x) X#endif /* COMPRESS */ X Xstatic struct boolexp *negate_boolexp(struct boolexp *b) X{ X struct boolexp *n; X X /* Obscure fact: !NOTHING == NOTHING in old-format databases! */ X if(b == TRUE_BOOLEXP) return TRUE_BOOLEXP; X X n = (struct boolexp *) malloc(sizeof(struct boolexp)); X n->type = BOOLEXP_NOT; X n->sub1 = b; X X return n; X} X Xstatic struct boolexp *getboolexp1(FILE *f) X{ X struct boolexp *b; X int c; X X c = getc(f); X switch(c) { X case '\n': X ungetc(c, f); X return TRUE_BOOLEXP; X /* break; */ X case EOF: X abort(); /* unexpected EOF in boolexp */ X break; X case '(': X b = (struct boolexp *) malloc(sizeof(struct boolexp)); X if((c = getc(f)) == '!') { X b->type = BOOLEXP_NOT; X b->sub1 = getboolexp1(f); X if(getc(f) != ')') goto error; X return b; X } else { X ungetc(c, f); X b->sub1 = getboolexp1(f); X switch(c = getc(f)) { X case AND_TOKEN: X b->type = BOOLEXP_AND; X break; X case OR_TOKEN: X b->type = BOOLEXP_OR; X break; X default: X goto error; X /* break */ X } X b->sub2 = getboolexp1(f); X if(getc(f) != ')') goto error; X return b; X } X /* break; */ X case '-': X /* obsolete NOTHING key */ X /* eat it */ X while((c = getc(f)) != '\n') if(c == EOF) abort(); /* unexp EOF */ X ungetc(c, f); X return TRUE_BOOLEXP; X /* break */ X default: X /* better be a dbref */ X ungetc(c, f); X b = (struct boolexp *) malloc(sizeof(struct boolexp)); X b->type = BOOLEXP_CONST; X b->thing = 0; X X /* NOTE possibly non-portable code */ X /* Will need to be changed if putref/getref change */ X while(isdigit(c = getc(f))) { X b->thing = b->thing * 10 + c - '0'; X } X ungetc(c, f); X return b; X } X X error: X abort(); /* bomb out */ X return TRUE_BOOLEXP; X} X Xstruct boolexp *getboolexp(FILE *f) X{ X struct boolexp *b; X X b = getboolexp1(f); X if(getc(f) != '\n') abort(); /* parse error, we lose */ X return b; X} X Xvoid free_boolexp(struct boolexp *b) X{ X if(b != TRUE_BOOLEXP) { X switch(b->type) { X case BOOLEXP_AND: X case BOOLEXP_OR: X free_boolexp(b->sub1); X free_boolexp(b->sub2); X free((void *) b); X break; X case BOOLEXP_NOT: X free_boolexp(b->sub1); X free((void *) b); X break; X case BOOLEXP_CONST: X free((void *) b); X break; X } X } X} X Xvoid db_free(void) X{ X dbref i; X struct object *o; X X if(db) { X for(i = 0; i < db_top; i++) { X o = &db[i]; X if(o->name) free((void *) o->name); X if(o->description) free((void *) o->description); X if(o->succ_message) free((void *) o->succ_message); X if(o->fail_message) free((void *) o->fail_message); X if(o->ofail) free((void *) o->ofail); X if(o->osuccess) free((void *) o->osuccess); X if(o->password) free((void *) o->password); X if(o->key) free_boolexp(o->key); X } X free((void *) db); X db = 0; X db_top = 0; X } X} X Xdbref db_read(FILE *f) X{ X dbref i; X struct object *o; X const char *end; X X#ifdef PLAYER_LIST X clear_players(); X#endif X X db_free(); X for(i = 0;; i++) { X switch(getc(f)) { X case '#': X /* another entry, yawn */ X if(i != getref(f)) { X /* we blew it */ X return -1; X } X /* make space */ X db_grow(i+1); X X /* read it in */ X o = db+i; X o->name = getstring(f); X o->description = getstring_compress(f); X o->location = getref(f); X o->contents = getref(f); X o->exits = getref(f); X o->next = getref(f); X o->key = getboolexp(f); X o->fail_message = getstring_compress(f); X o->succ_message = getstring_compress(f); X o->ofail = getstring_compress(f); X o->osuccess = getstring_compress(f); X o->owner = getref(f); X o->pennies = getref(f); X o->flags = getref(f); X o->password = getstring(f); X /* For downward compatibility with databases using the */ X /* obsolete ANTILOCK flag. */ X if(o->flags & ANTILOCK) { X o->key = negate_boolexp(o->key); X o->flags &= ~ANTILOCK; X } X#ifdef PLAYER_LIST X if(Typeof(i) == TYPE_PLAYER) { X add_player(i); X } X#endif PLAYER_LIST X break; X case '*': X end = getstring(f); X if(strcmp(end, "**END OF DUMP***")) { X free((void *) end); X return -1; X } else { X free((void *) end); X return db_top; X } X default: X return -1; X /* break; */ X } X } X} X END_OF_FILE if test 9028 -ne `wc -c <'db.c'`; then echo shar: \"'db.c'\" unpacked with wrong size! fi # end of 'db.c' fi if test -f 'game.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'game.c'\" else echo shar: Extracting \"'game.c'\" \(14143 characters\) sed "s/^X//" >'game.c' <<'END_OF_FILE' X#include "copyright.h" X X#include <stdio.h> X#include <ctype.h> X#include <signal.h> X#include <sys/wait.h> X#include <time.h> X#include <stdarg.h> X X#include "db.h" X#include "config.h" X#include "interface.h" X#include "match.h" X#include "externs.h" X X/* declarations */ Xstatic const char *dumpfile = 0; Xstatic int epoch = 0; Xstatic int alarm_triggered = 0; Xstatic int alarm_block = 0; X Xstatic void fork_and_dump(void); Xvoid dump_database(void); X Xvoid do_dump(dbref player) X{ X if(Wizard(player)) { X alarm_triggered = 1; X notify(player, "Dumping..."); X } else { X notify(player, "Sorry, you are in a no dumping zone."); X } X} X Xvoid do_shutdown(dbref player) X{ X if(Wizard(player)) { X writelog("SHUTDOWN: by %s\n", unparse_object(player, player)); X fflush(stderr); X shutdown_flag = 1; X } else { X notify(player, "Your delusions of grandeur have been duly noted."); X } X} X X/* should be void, but it's defined as int */ Xstatic int alarm_handler(void) X{ X alarm_triggered = 1; X if(!alarm_block) { X fork_and_dump(); X } X return 0; X} X Xstatic void dump_database_internal(void) X{ X char tmpfile[2048]; X FILE *f; X X sprintf(tmpfile, "%s.#%d#", dumpfile, epoch - 1); X unlink(tmpfile); /* nuke our predecessor */ X X sprintf(tmpfile, "%s.#%d#", dumpfile, epoch); X X if((f = fopen(tmpfile, "w")) != NULL) { X db_write(f); X fclose(f); X if(rename(tmpfile, dumpfile) < 0) perror(tmpfile); X } else { X perror(tmpfile); X } X} X Xvoid panic(const char *message) X{ X char panicfile[2048]; X FILE *f; X int i; X X writelog("PANIC: %s\n", message); X X /* turn off signals */ X for(i = 0; i < NSIG; i++) { X signal(i, SIG_IGN); X } X X /* shut down interface */ X emergency_shutdown(); X X /* dump panic file */ X sprintf(panicfile, "%s.PANIC", dumpfile); X if((f = fopen(panicfile, "w")) == NULL) { X perror("CANNOT OPEN PANIC FILE, YOU LOSE:"); X#ifndef NODUMPCORE X signal(SIGILL, SIG_DFL); X abort(); X#endif NODUMPCORE X _exit(135); X } else { X writelog("DUMPING: %s\n", panicfile); X db_write(f); X fclose(f); X writelog("DUMPING: %s (done)\n", panicfile); X#ifndef NODUMPCORE X signal(SIGILL, SIG_DFL); X abort(); X#endif NODUMPCORE X _exit(136); X } X} X Xvoid writelog(const char *fmt, ...) X{ X va_list list; X struct tm *tm; X long t; X char buffer[2048]; X X va_start(list, fmt); X vsprintf(buffer, fmt, list); X t = time(NULL); X tm = localtime(&t); X fprintf(stderr, "%d/%02d %02d:%02d:%02d %s", X tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, X buffer); X fflush(stderr); X va_end(list); X} X Xvoid dump_database(void) X{ X epoch++; X X writelog("DUMPING: %s.#%d#\n", dumpfile, epoch); X dump_database_internal(); X writelog("DUMPING: %s.#%d# (done)\n", dumpfile, epoch); X} X Xstatic void fork_and_dump(void) X{ X int child; X X epoch++; X X writelog("CHECKPOINTING: %s.#%d#\n", dumpfile, epoch); X#ifdef USE_VFORK X child = vfork(); X#else /* USE_VFORK */ X child = fork(); X#endif /* USE_VFORK */ X if(child == 0) { X /* in the child */ X close(0); /* get that file descriptor back */ X dump_database_internal(); X _exit(0); /* !!! */ X } else if(child < 0) { X perror("fork_and_dump: fork()"); X } X X /* in the parent */ X /* reset alarm */ X alarm_triggered = 0; X alarm(DUMP_INTERVAL); X} X Xstatic int reaper(void) X{ X union wait stat; X X while(wait3(&stat, WNOHANG, 0) > 0); X return 0; X} X Xint init_game(const char *infile, const char *outfile) X{ X FILE *f; X X if((f = fopen(infile, "r")) == NULL) return -1; X X /* ok, read it in */ X writelog("LOADING: %s\n", infile); X if(db_read(f) < 0) return -1; X writelog("LOADING: %s (done)\n", infile); X X /* everything ok */ X fclose(f); X X /* initialize random number generator */ X srandom(getpid()); X X /* set up dumper */ X if(dumpfile) free((void *) dumpfile); X dumpfile = alloc_string(outfile); X signal(SIGALRM, (void (*)) alarm_handler); X signal(SIGHUP, (void (*)) alarm_handler); X signal(SIGCHLD, (void (*)) reaper); X alarm_triggered = 0; X alarm(DUMP_INTERVAL); X X return 0; X} X X/* use this only in process_command */ X#define Matched(string) { if(!string_prefix((string), command)) goto bad; } X Xvoid process_command(dbref player, char *command) X{ X char *arg1; X char *arg2; X char *q; /* utility */ X char *p; /* utility */ X X char *index(char *, char); X X if(command == 0) abort(); X X /* robustify player */ X if(player < 0 || player >= db_top || Typeof(player) != TYPE_PLAYER) { X writelog("process_command: bad player %d\n", player); X return; X } X X#ifdef LOG_COMMANDS X writelog("COMMAND from %s(%d) in %s(%d): %s\n", X db[player].name, player, X db[db[player].location].name, db[player].location, X command); X#endif /* LOG_COMMANDS */ X X /* eat leading whitespace */ X while(*command && isspace(*command)) command++; X X /* eat extra white space */ X q = p = command; X while(*p) { X /* scan over word */ X while(*p && !isspace(*p)) *q++ = *p++; X /* smash spaces */ X while(*p && isspace(*++p)); X if(*p) *q++ = ' '; /* add a space to separate next word */ X } X /* terminate */ X *q = '\0'; X X /* block dump to prevent db inconsistencies from showing up */ X alarm_block = 1; X X /* check for single-character commands */ X if(*command == SAY_TOKEN) { X do_say(player, command+1, NULL); X } else if(*command == POSE_TOKEN) { X do_pose(player, command+1, NULL); X } else if(can_move(player, command)) { X /* command is an exact match for an exit */ X do_move(player, command); X } else { X /* parse arguments */ X X /* find arg1 */ X /* move over command word */ X for(arg1 = command; *arg1 && !isspace(*arg1); arg1++); X /* truncate command */ X if(*arg1) *arg1++ = '\0'; X X /* move over spaces */ X while(*arg1 && isspace(*arg1)) arg1++; X X /* find end of arg1, start of arg2 */ X for(arg2 = arg1; *arg2 && *arg2 != ARG_DELIMITER; arg2++); X X /* truncate arg1 */ X for(p = arg2 - 1; p >= arg1 && isspace(*p); p--) *p = '\0'; X X /* go past delimiter if present */ X if(*arg2) *arg2++ = '\0'; X while(*arg2 && isspace(*arg2)) arg2++; X X switch(command[0]) { X case '@': X switch(command[1]) { X case 'b': X case 'B': X switch (command[2]) { X case 'o': X case 'O': X switch (command[3]) { X case 'o': X case 'O': Matched("@boot"); X do_boot(player, arg1); X break; X case 'b': X case 'B': if(string_compare(command, "@bobble")) goto bad; X do_bobble(player, arg1, arg2); X break; X default: goto bad; X } X break; X default: goto bad; X } X break; X case 'c': X case 'C': X /* chown, create */ X switch(command[2]) { X case 'h': X case 'H': X Matched("@chown"); X do_chown(player, arg1, arg2); X break; X#ifdef RECYCLE X case 'o': X case 'O': X Matched("@count"); X do_count(player, arg1); X break; X#endif RECYCLE X case 'r': X case 'R': X Matched("@create"); X do_create(player, arg1, atol(arg2)); X break; X default: X goto bad; X } X break; X case 'd': X case 'D': X /* describe, dig, or dump */ X switch(command[2]) { X case 'e': X case 'E': X Matched("@describe"); X do_describe(player, arg1, arg2); X break; X case 'i': X case 'I': X Matched("@dig"); X do_dig(player, arg1); X break; X case 'u': X case 'U': X Matched("@dump"); X do_dump(player); X break; X default: X goto bad; X } X break; X case 'f': X /* fail, find, or force */ X switch(command[2]) { X case 'a': X case 'A': X Matched("@fail"); X do_fail(player, arg1, arg2); X break; X case 'i': X case 'I': X Matched("@find"); X do_find(player, arg1); X break; X case 'o': X case 'O': X Matched("@force"); X do_force(player, arg1, arg2); X break; X default: X goto bad; X } X break; X case 'l': X case 'L': X /* lock or link */ X switch(command[2]) { X case 'i': X case 'I': X Matched("@link"); X do_link(player, arg1, arg2); X break; X case 'o': X case 'O': X Matched("@lock"); X do_lock(player, arg1, arg2); X break; X default: X goto bad; X } X break; X case 'm': X case 'M': X Matched("@mass_teleport"); X do_mass_teleport(player, arg1); X break; X case 'n': X case 'N': X /* @name or @newpassword */ X switch(command[2]) { X case 'a': X case 'A': X Matched("@name"); X do_name(player, arg1, arg2); X break; X case 'e': X if(strcmp(command, "@newpassword")) goto bad; X do_newpassword(player, arg1, arg2); X break; X default: X goto bad; X } X break; X case 'o': X case 'O': X switch(command[2]) { X case 'f': X case 'F': X Matched("@ofail"); X do_ofail(player, arg1, arg2); X break; X case 'p': X case 'P': X Matched("@open"); X do_open(player, arg1, arg2); X break; X case 's': X case 'S': X Matched("@osuccess"); X do_osuccess(player, arg1, arg2); X break; X case 'w': X case 'W': X Matched("@owned"); X do_owned(player, arg1); X break; X default: X goto bad; X } X break; X case 'p': X case 'P': X switch(command[2]) { X case 'a': X case 'A': X Matched("@password"); X do_password(player, arg1, arg2); X break; X#ifdef REGISTRATION X case 'c': X case 'C': X Matched("@pcreate"); X do_pcreate(player, arg1, arg2); X break; X#endif REGISTRATION X default: goto bad; X } X break; X#ifdef RECYCLE X case 'r': X case 'R': X /* Recycle */ X Matched("@recycle"); X do_recycle(player, arg1); X break; X#endif RECYCLE X case 's': X case 'S': X /* set, shutdown, success */ X switch(command[2]) { X case 'e': X case 'E': X Matched("@set"); X do_set(player, arg1, arg2); X break; X case 'h': X if(strcmp(command, "@shutdown")) goto bad; X do_shutdown(player); X break; X case 't': X case 'T': X Matched("@stats"); X do_stats(player, arg1); X break; X case 'u': X case 'U': X Matched("@success"); X do_success(player, arg1, arg2); X break; X default: X goto bad; X } X break; X case 't': X case 'T': X switch(command[2]) { X case 'e': X case 'E': X Matched("@teleport"); X do_teleport(player, arg1, arg2); X break; X case 'o': X case 'O': X if(string_compare(command, "@toad")) goto bad; X do_bobble(player, arg1, arg2); X break; X default: X goto bad; X } X break; X case 'u': X case 'U': X if(string_prefix(command, "@unli")) { X Matched("@unlink"); X do_unlink(player, arg1); X } else if(string_prefix(command, "@unlo")) { X Matched("@unlock"); X do_unlock(player, arg1); X } else if(string_prefix(command, "@unb")) { X Matched("@unbobble"); X do_unbobble(player, arg1, arg2); X } else if(string_prefix(command, "@unt")) { X Matched("@untoad"); X do_unbobble(player, arg1, arg2); X } else { X goto bad; X } X break; X case 'w': X if(strcmp(command, "@wall")) goto bad; X do_wall(player, arg1, arg2); X break; X default: X goto bad; X } X break; X case 'd': X case 'D': X Matched("drop"); X do_drop(player, arg1); X break; X case 'e': X case 'E': X if (command[1] == 'x' || command[1] == 'X') { X Matched("examine"); X do_examine(player, arg1); X break; X } else { X goto bad; X } X case 'g': X case 'G': X /* get, give, go, or gripe */ X switch(command[1]) { X case 'e': X case 'E': X Matched("get"); X do_get(player, arg1); X break; X case 'i': X case 'I': X Matched("give"); X do_give(player, arg1, atol(arg2)); X break; X case 'o': X case 'O': X Matched("goto"); X do_move(player, arg1); X break; X case 'r': X case 'R': X Matched("gripe"); X do_gripe(player, arg1, arg2); X break; X default: X goto bad; X } X break; X case 'h': X case 'H': X Matched("help"); X do_help(player); X break; X case 'i': X case 'I': X Matched("inventory"); X do_inventory(player); X break; X case 'k': X case 'K': X Matched("kill"); X do_kill(player, arg1, atol(arg2)); X break; X case 'l': X case 'L': X Matched("look"); X do_look_at(player, arg1); X break; X case 'm': X case 'M': X Matched("move"); X do_move(player, arg1); X break; X case 'n': X case 'N': X /* news */ X if(string_compare(command, "news")) goto bad; X do_news(player); X break; X case 'p': X case 'P': X Matched("page"); X do_page(player, arg1, arg2); X break; X case 'r': X case 'R': X switch(command[1]) { X case 'e': X case 'E': X Matched("read"); /* undocumented alias for look at */ X do_look_at(player, arg1); X break; X case 'o': X case 'O': X Matched("rob"); X do_rob(player, arg1); X break; X default: X goto bad; X } X break; X case 's': X case 'S': X /* say, "score" */ X switch(command[1]) { X case 'a': X case 'A': X Matched("say"); X do_say(player, arg1, arg2); X break; X case 'c': X case 'C': X Matched("score"); X do_score(player); X break; X default: X goto bad; X } X break; X case 't': X case 'T': X switch(command[1]) { X case 'a': X case 'A': X Matched("take"); X do_get(player, arg1); X break; X case 'h': X case 'H': X Matched("throw"); X do_drop(player, arg1); X break; X default: X goto bad; X } X break; X case 'w': X case 'W': X Matched("whisper"); X do_whisper(player, arg1, arg2); X break; X default: X bad: X notify(player, "Huh? (Type \"help\" for help.)"); X#ifdef LOG_FAILED_COMMANDS X if(!controls(player, db[player].location)) { X writelog("HUH from %s(%d) in %s(%d)[%s]: %s %s\n", X db[player].name, player, X db[db[player].location].name, X db[player].location, X db[db[db[player].location].owner].name, X command, X reconstruct_message(arg1, arg2)); X } X#endif /* LOG_FAILED_COMMANDS */ X break; X } X } X X /* unblock alarms */ X alarm_block = 0; X if(alarm_triggered) { X fork_and_dump(); X } X} X X#undef Matched END_OF_FILE if test 14143 -ne `wc -c <'game.c'`; then echo shar: \"'game.c'\" unpacked with wrong size! fi # end of 'game.c' fi if test -f 'restart-cmu' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'restart-cmu'\" else echo shar: Extracting \"'restart-cmu'\" \(576 characters\) sed "s/^X//" >'restart-cmu' <<'END_OF_FILE' X#!/bin/csh -f X# X# This script assumes you have the following structure: X# X# $HOME/bin executable MUD programs X# $HOME/lib database files, daily logs X# $HOME/src source code for netmud X# X Xcd /usr/tinymud/lib Xmv tinymud.db tinymud.db.old Xif(-r tinymud.db.new) then X mv tinymud.db.new tinymud.db Xelse X cp tinymud.db.old tinymud.db Xendif X X# Use netmud instead of netmud.conc if you don't want the port concentrator Xcp ../bin/netmud.conc netmud.exe Xcp ../bin/concentrate concentrate X Xecho RESTARTED AT `date` >> tinymud.log X./netmud.exe tinymud.db tinymud.db.new >>& tinymud.log & END_OF_FILE if test 576 -ne `wc -c <'restart-cmu'`; then echo shar: \"'restart-cmu'\" unpacked with wrong size! fi chmod +x 'restart-cmu' # end of 'restart-cmu' fi if test -f 'tinymud.tex' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'tinymud.tex'\" else echo shar: Extracting \"'tinymud.tex'\" \(28102 characters\) sed "s/^X//" >'tinymud.tex' <<'END_OF_FILE' X\documentstyle[11pt,titlepage,makeidx,ragright]{article} X X\newcommand{\bs}{\char '134} % backslash character for \tt font X\newcommand{\ub}{\char '137} % underbar character for \tt font X\newcommand{\ua}{\char '136} % up arrow character for \tt font X\newcommand{\qt}{\char '175} % quotes character for \tt font X\newcommand{\tl}{\char '176} % tilde character for \tt font X\newcommand{\sh}{\char '043} % sharp character for \tt font X X\newcommand{\tinymud}{{\small Tiny}{MUD}} X\newcommand{\type}[1]{{\tt #1\/}} X X\newenvironment{simple}{\begin{list}% X{\relax}% X{\setlength{\labelwidth}{0pt}% X \setlength{\labelsep}{0pt}% X \setlength{\leftmargin}{0pt}% X \setlength{\listparindent}{0pt}}}% X{\end{list}} X X%\newenvironment{simple}{\begin{trivlist}}{\end{trivlist}} X X%\newlength{\boxwidth} X%\setlength{\boxwidth}{\textwidth} X%\addtolength{\boxwidth}{-7pt} X X\newlength{\rulewidth} X\setlength{\rulewidth}{\textwidth} X%\divide\rulewidth by 3 X X\newcommand{\dorule}{\begin{center} X\rule{\rulewidth}{1pt} X\end{center}} X X\makeindex X X\title{{\bf A brief guide to {\large\bf Tiny}MUD}} X X\author{Jennifer Stone (aka Chrysalis) \\ X{\tt jennifer@uokmax.ecn.uoknor.edu} X\and XRusty C. Wright \\ X{\tt rusty@garnet.berkeley.edu}} X X\begin{document} X X% uncomment the commented lines if you want a more formal document X% with a separate title page and table of contents. X X\ragright X X\pagenumbering{roman} X X\maketitle X X\tableofcontents X\clearpage X X\pagenumbering{arabic} X XMuch of this is from the {\tinymud} source code and the {\tt small.db} Xexample. X X\section{Ordinary commands} X\label{sec:ordinary-commands} X X\begin{simple} X X\item[] X\begin{flushleft} X{\tt drop} $<${\em object\/}$>$ \\ X{\tt throw} $<${\em object\/}$>$ X\index{drop@\type{drop}} X\index{throw@\type{throw}} X\end{flushleft} XDrops the specified object. $<${\em object\/}$>$ can be either a Xthing or exit. X X\dorule X X\item[] X\begin{flushleft} X{\tt examine} $<${\em name\/}$>$ \\ X{\tt examine} {\tt \#}$<${\em number\/}$>$ X\index{examine@\type{examine}} X\end{flushleft} XPrints a detailed description of object specified by $<${\em Xname\/}$>$ or by $<${\em number\/}$>$ giving name, description, owner, Xkeys, pennies, failure message, success message, others failure Xmessage, others success message, and exits. The location will also be Xdisplayed if you control the object's location (that is, if it's not Xbeing carried by someone else or in a room you don't control). X X\dorule X X\item[] X\begin{flushleft} X{\tt get} $<${\em object\/}$>$ \\ X{\tt take} $<${\em object\/}$>$ X\index{get@\type{get}} X\index{take@\type{take}} X\end{flushleft} XGets the specified object. $<${\em object\/}$>$ can be either a thing Xor exit. X X\dorule X X\item[] X\begin{flushleft} X{\tt give} $<${\em player\/}$>$ \verb|=| $<${\em amount\/}$>$ X\index{give@\type{give}} X\end{flushleft} XGives $<${\em player\/}$>$ the specified number of pennies. X X\dorule X X\item[] X\begin{flushleft} X{\tt go} $<${\em direction\/}$>$ \\ X{\tt go home} \\ X{\tt move} $<${\em direction\/}$>$ \\ X{\tt move home} X\index{go@\type{go}} X\index{move@\type{move}} X\index{home@\type{home}} X\end{flushleft} X XMoves in the specified direction. {\tt go home} is a special command Xthat returns you to your home (initially Limbo). If the direction is Xfully specified, the {\tt go} may be omitted. X X\dorule X X\item[] X\begin{flushleft} X{\tt gripe} $<${\em message\/}$>$ X\index{gripe@\type{gripe}} X\end{flushleft} XSends $<${\em message\/}$>$ to the system maintainer. X X\dorule X X\item[] X\begin{flushleft} X{\tt help} X\index{help@\type{help}} X\end{flushleft} XPrints a short help message. X X\dorule X X\item[] X\begin{flushleft} X{\tt inventory} X\index{inventory@\type{inventory}} X\end{flushleft} XLists what you are carrying. X X\dorule X X\item[] X\begin{flushleft} X{\tt kill} $<${\em player\/}$>$ $[$ \verb|=| $<${\em cost\/}$>$ $]$ X\index{kill@\type{kill}} X\end{flushleft} XKills the specified player. Killing costs either $<${\em cost\/}$>$ Xpennies or 10 pennies, whichever is greater. The probability of Xsuccess is proportional to the cost. X X\dorule X X\item[] X\begin{flushleft} X{\tt look} $<${\em object\/}$>$ \\ X{\tt read} $<${\em object\/}$>$ X\index{look@\type{look}} X\index{read@\type{read}} X\end{flushleft} X$<${\em object\/}$>$ can be a room, thing, player, or direction. Prints Xa description of $<${\em object\/}$>$. X X\dorule X X\item[] X\begin{flushleft} X{\tt page} $<${\em player\/}$>$ X\index{page@\type{page}} X\end{flushleft} XUsed to inform an active player that you are looking for them. The Xtargeted player will get a message telling them your name and Xlocation. X X\dorule X X\item[] X\begin{flushleft} X{\tt rob} $<${\em player\/}$>$ X\index{rob@\type{rob}} X\end{flushleft} XAttempt to steal a penny from $<${\em player\/}$>$. X X\dorule X X\item[] X\begin{flushleft} X{\tt say} $<${\em message\/}$>$ \\ X\verb|"|$<${\em message\/}$>$ \\ X\verb|:|$<${\em message\/}$>$ X\index{say@\type{say}} X\index{""@\type{""}} X\index{:@\type{:}} X\end{flushleft} XThe first two forms display the $<${\em message\/}$>$ with the Xnotification that you said it. For example, if your player's name is XBetty the other players in the same room will see X\begin{flushleft} X{\tt Betty says} ``$<${\em message\/}$>$'' X\end{flushleft} XThe third form {\sl poses} the message, preceded by your name, with no Xquotes, as in X\begin{flushleft} X{\tt Betty} $<${\em message\/}$>$ X\end{flushleft} XFor both the second and third forms, do not put a space after Xthe double quotes or colon as it will be included in the message. X X\dorule X X\item[] X\begin{flushleft} X{\tt score} X\index{score@\type{score}} X\end{flushleft} XPrints how many pennies you have. X X\dorule X X\item[] X\begin{flushleft} X{\tt whisper} $<${\em player\/}$>$ \verb|=| $<${\em message\/}$>$ X\index{whisper@\type{whisper}} X\end{flushleft} X$<${\em player\/}$>$ is presented with $<${\em message\/}$>$ saying Xthat you whispered it. The other players only see the message X\begin{flushleft} X{\tt Betty whispers something to} $<${\em player\/}$>$. X\end{flushleft} X X\end{simple} X X\section{Commands for modifying the dungeon} X\label{sec:commands-for-modifying-the-dungeon} X X\begin{simple} X X\item[] X\begin{flushleft} X{\tt @create\/} $<${\em name\/}$>$ $[$ \verb|=| $<${\em cost\/}$>$ $]$ X\index{create@\type{"@create}} X\end{flushleft} XCreates a thing with the specified name. Creation costs either X$<${\em cost\/}$>$ pennies or 10 pennies, whichever is greater. The Xvalue of a thing is proportional to its cost. X X\dorule X X\item[] X\begin{flushleft} X{\tt @describe} $<${\em object\/}$>$ \verb|=| $<${\em description\/}$>$ X\index{describe@\type{"@describe}} X\end{flushleft} X$<${\em object\/}$>$ can be a room, thing, player, or direction. Sets Xthe description a player sees when they use the command {\tt look} X$<${\em object\/}$>$. If $<${\em object\/}$>$ is {\tt Xhere}\index{here@\type{here}} it sets the description for the current Xroom that is displayed when the room is entered. If $<${\em Xobject\/}$>$ is {\tt me}\index{me@\type{me}} it sets the description for Xyour character. X X\dorule X X\item[] X\begin{flushleft} X{\tt @dig} $<${\em name\/}$>$ X\index{dig@\type{"@dig}} X\end{flushleft} XCreates a new room with the specified name, and prints the room's Xnumber. X X\dorule X X\item[] X\begin{flushleft} X{\tt @fail} $<${\em object\/}$>$ $[$ \verb|=| $<${\em message\/}$>$ X$]$ X\index{fail@\type{"@fail}} X\end{flushleft} XWithout a message argument, clears the failure message on $<${\em Xobject\/}$>$, otherwise sets it. The failure message is printed when Xa player unsuccessfully attempts to use the object. X X\dorule X X\item[] X\begin{flushleft} X{\tt @find} $<${\em name\/}$>$ X\index{find@\type{"@find}} X\end{flushleft} XPrints the name and object number of every room, thing, or player that Xyou control whose name matches $<${\em name\/}$>$. Because the {\tt X@find} command is computationally expensive, there is a small charge Xfor using it. X X\dorule X X\item[] X\begin{flushleft} X{\tt @link} $<${\em direction\/}$>$ \verb|=| $<${\em room number\/}$>$ \\ X{\tt @link} $<${\em thing\/}$>$ \verb|=| $<${\em room number\/}$>$ \\ X{\tt @link} $<${\em room\/}$>$ \verb|=| $<${\em room number\/}$>$ X\index{link@\type{"@link}} X\end{flushleft} XIn the first form links the exit specified by $<${\em direction\/}$>$ Xto the room specified by $<${\em room number\/}$>$. The exit must be Xunlinked, and you must own the target room if its X\verb|link_ok|\index{linkok@\verb,link_ok,} attribute is not set. If Xyou don't already own the exit its ownership is transferred to you. XThe second form sets the home for $<${\em thing\/}$>$\index{home}. If X$<${\em thing\/}$>$ is {\tt me}\index{me@\type{me}} it sets your home. XThe third form sets the dropto; see section~\ref{sec:droptos} for an Xexplanation of dropto's. X X\dorule X X\item[] X\begin{flushleft} X{\tt @lock} $<${\em object\/}$>$ \verb|=| $<${\em key\/}$>$ X\index{lock@\type{"@lock}} X\end{flushleft} XSets a key (another object) for an object. If $<${\em key\/}$>$ Xstarts with \verb|*| then it must be a player's name. $<${\em Xkey\/}$>$ can contain the Boolean operators \verb|!| (not or Xnegation), \verb|&| (and), and \verb:|: (or), and use parentheses for Xgrouping. X XIn order to use $<${\em object\/}$>$ you must satisfy the requirements Xof $<${\em key\/}$>$. In the simplest case you must simply have X$<${\em key\/}$>$. If $<${\em key\/}$>$ is preceded by \verb|!| then Xyou must not have $<${\em key\/}$>$ in order to use $<${\em Xobject\/}$>$. See section~\ref{sec:lock-key-boolean-examples} for Xmore complicated examples. X X\dorule X X\item[] X\begin{flushleft} X{\tt @name} $<${\em object\/}$>$ \verb|=| $<${\em name\/}$>$ \\ X{\tt @name} $<${\em player\/}$>$ \verb|=| $<${\em name\/}$>$ $<${\em Xpassword\/}$>$ X\index{name@\type{"@name}} X\end{flushleft} XChanges the name of the specified object. This can also be used to Xspecify a new direction list for an exit (see for example {\tt X@open\/}). For a player, it requires the player's password. X X\dorule X X\item[] X\begin{flushleft} X{\tt @ofail} $<${\em object\/}$>$ $[$ \verb|=| $<${\em message\/}$>$ X$]$ X\index{ofail@\type{"@ofail}} X\end{flushleft} XWithout a message argument, clears the others failure message on X$<${\em object\/}$>$, otherwise sets it. The others failure message, Xprefixed by the player's name, is shown to others when the player Xfails to use $<${\em object\/}$>$. X X\dorule X X\item[] X\begin{flushleft} X{\tt @open} $<${\em direction\/}$>$ $[$ {\tt;} $<${\em other-dir\/}$>$ X$]*$ $[$ {\tt =} $<${\em destination\/}$>$ $]$ X\index{open@\type{"@open}} X\end{flushleft} XCreates an unlinked exit in the specified direction(s). You can also Xspecify an exit to link the exit to. Once created, you (or any other Xplayer) may use the {\tt @link} command to specify the room to which Xthe exit leads. See also {\tt @name}. X X\dorule X X\item[] X\begin{flushleft} X{\tt @osuccess} $<${\em object\/}$>$ $[$ \verb|=| $<${\em Xmessage\/}$>$ $]$ X\index{osuccess@\type{"@osuccess}} X\end{flushleft} XWithout a message argument, clears the others success message on X$<${\em object\/}$>$, otherwise sets it. The others success message, Xprefixed by the player's name, is shown to others when the player Xsuccessfully uses $<${\em object\/}$>$. X X\dorule X X\item[] X\begin{flushleft} X{\tt @password} $<${\em old\/}$>$ \verb|=| $<${\em new\/}$>$ X\index{password@\type{"@password}} X\end{flushleft} XSets a new password; you must specify your old password to verify your Xidentity. X X\dorule X X\item[] X\begin{flushleft} X{\tt @set} $<${\em object\/}$>$ \verb|=| $<${\em flag\/}$>$ \\ X{\tt @set} $<${\em object\/}$>$ \verb|=| {\tt !}$<${\em flag\/}$>$ X\index{set@\type{"@set}} X\end{flushleft} XSets (first form) or resets (second form) $<${\em flag\/}$>$ on X$<${\em object\/}$>$. The current flags are \verb|dark|, X\verb|link_ok|, \verb|sticky|, \verb|temple|, and \verb|wizard|. X X\dorule X X\item[] X\begin{flushleft} X{\tt @success} $<${\em object\/}$>$ \verb|=| $<${\em message\/}$>$ X\index{success@\type{"@success}} X\end{flushleft} XWithout a message argument, clears the success message on $<${\em Xobject\/}$>$, otherwise sets it. The success message is printed when Xa player successfully uses $<${\em object\/}$>$. Without $<${\em Xmessage}$>$ it clears the success message. X X\dorule X X\item[] X\begin{flushleft} X{\tt @teleport} $<${\em object\/}$>$ {\tt =} $<${\em destination\/}$>$ X\index{teleport@\type{"@teleport}} X\end{flushleft} XTeleports the object to the specified destination. You must either Xcontrol the object or it's current location, and you must be able to Xlink to the destination. You can only teleport objects from room to Xroom, not into or out of someone's hand. X X\dorule X X\item[] X\begin{flushleft} X{\tt @unlink} $<${\em direction\/}$>$ X\index{unlink@\type{"@unlink}} X\end{flushleft} XRemoves the link on the exit in the specified $<${\em direction\/}$>$. XYou must own the exit. The exit may then be relinked by any player Xusing the {\tt @link} command and ownership of the exit transfers to Xthat player. X X\dorule X X\item[] X\begin{flushleft} X{\tt @unlock} $<${\em object\/}$>$ X\index{unlock@\type{"@unlock}} X\end{flushleft} XRemoves the lock on an object. X X\end{simple} X X\section{Miscellaneous commands} X\label{sec:miscellaneous-commands} X X\begin{simple} X X\item[] X\begin{flushleft} X{\tt @stats} X\index{stats@\type{"@stats}} XShows current total of players, rooms, objects, exits. X\end{flushleft} X X\end{simple} X X\section{Money} X\label{sec:money} X XSome actions have an associated cost: X\begin{center} X\begin{tabular}{|l|p{4in}|} X\hline X\multicolumn{1}{|c|}{{\bf Action}} & X\multicolumn{1}{c|}{{\bf Cost}} \\ X\hline X\hline X\hline X{\tt kill} & 10 pennies or more \\ X\hline X{\tt page} & 1 penny \\ X\hline X{\tt @open} & 1 penny \\ X\hline X{\tt @dig} & 10 pennies \\ X\hline X{\tt @create} & 10 pennies (or more) \\ X\hline X{\tt @link} & 1 penny, plus 1 penny to the previous owner if you Xdidn't already own the exit. \\ X\hline X\end{tabular} X\index{kill@\type{kill}} X\index{page@\type{page}} X\index{open@\type{"@open}} X\index{dig@\type{"@dig}} X\index{create@\type{"@create}} X\index{link@\type{"@link}} X\end{center} X XYou get money by finding pennies, getting killed, having someone give Xyou money, or by sacrificing a thing. The sacrifice value of a thing Xis $(\mbox{\rm cost of the thing} / 5 ) - 1$. X X\section{TinyMUD concepts} X\label{sec:tinymud-concepts} X XAn {\em object} is either a player, room, thing, or exit. X XIn addition to the commands listed above there are some built in words Xin {\tinymud}; {\tt me}\index{me@\type{me}} and {\tt Xhere}\index{here@\type{here}}. {\tt me} refers to your character or Xplayer, and {\tt here} refers to the room you are in. For example, Xyou can use the \verb|@describe| command to give yourself a Xdescription; as another example, in order to prevent yourself from Xbeing robbed use {\tt @lock me = me\/}. X X\subsection{Success and the lack thereof} X\label{sec:success-and-the-lack-thereof} X XWhen you can {\tt take} a thing, use an exit, or rob a player you are Xsuccessfull in using that object. The converse is true for failure. XThe {\tt @success\/}, {\tt @osuccess\/}, {\tt @fail\/}, and {\tt X@ofail} commands set the success and failure messages on objects.% X\index{success@\type{"@success}}% X\index{osuccess@\type{"@osuccess}}% X\index{fail@\type{"@fail}}% X\index{ofail@\type{"@ofail}} X X\subsection{Object strings} X\label{sec:object-strings} X XEvery object has six strings: X\begin{enumerate} X\item XName. This is what you use with {\tt drop\/}, {\tt examine\/}, {\tt Xget\/}, and so on. You can also use the object's number (for example, Xwhen two objects have the same name). X X\item XDescription. This is what is given when you use the {\tt look} Xcommand. X X\item XSuccess message. This is what you see when you successfully use the Xobject. X X\item XOthers success message. This is what the other players see when you Xsuccessfully use the object. X X\item XFailure message. This is what you see when you fail to use an object. X X\item XOthers failure message. This is what the other players see when you Xfail to use an object. X\end{enumerate} XThe maximum length of each string is 512 characters. X X\subsection{Object properties} X\label{sec:object-properties} X XAs listed in the \verb|@set| command, objects can have any of the Xfollowing properties: X\begin{description} X\item[{\tt dark}] X\index{dark@\type{dark}} XWhen a room has its {\tt dark} flag set you can't see things in it Xwith the {\tt look} command. When a thing or player has its {\tt Xdark} flag set it can't be seen. Only a wizard can set the {\tt dark} Xflag on a thing or player. Setting the {\tt dark} flag on exits Xcurrently has no effect. X X\item[{\tt link{\ub}ok}] X\index{linkok@\verb,link_ok,} XYou can link to a room if you control it, or if the room has its X\verb|link_ok| flag set. Being able to link to a room means that you Xcan set the homes\index{home} of things (or yourself) to that room, Xand you can set the destination of exits to that room. See also the X{\tt @link} command for additional information on linking and Xsection~\ref{sec:droptos} for droptos. Setting the X\verb|link_ok| flag on players, things, and exits currently has no Xeffect. X X\item[{\tt sticky}] X\index{sticky@\type{sticky}} XWhen an object that has its {\tt sticky} flag set is dropped it Ximmediately goes home. When a room has its {\tt sticky} flag set its Xdropto is delayed until the last person leaves the room. Setting the X{\tt sticky} flag on players and exits currently has no effect. X X\item[{\tt temple}] X\index{temple@\type{temple}} XWhen a room has its {\tt temple} flag set you can sacrifice things Xthere and receive pennies for your sacrifices. (See Xsection~\ref{sec:money} for how many pennies you receive for your Xsacrifices.) Only a wizard can set this flag. Setting this flag on Xplayers, things, and exits currently has no effect. X X\item[{\tt wizard}] X\index{wizard@\type{wizard}} XWhen a player has its {\tt wizard} flag set they are a wizard. Only a Xwizard can set this flag. Setting this flag on things, rooms, and Xexits currently has no effect. X X\end{description} X XThe flags {\tt player\/}, {\tt room\/}, and {\tt exit} are set Xautomatically when a player, room, or exit is created. They cannot be Xsubsequently unset or set with the \verb|@set| command. X X\subsection{Control} X\label{sec:control} X XThere are three rules for determining control: X\begin{enumerate} X\item XYou can control anything you own. X\item XA wizard can control anything. X\item\label{item:unlinked-exit} XAnybody can control an unlinked exit (even if it is locked). X\end{enumerate} XBuilders should watch out for item~\ref{item:unlinked-exit}. X X\subsection{Dropto's} X\label{sec:droptos} X X\index{droptos} XWhen the {\tt @link} command is used on a room, it sets a dropto Xlocation for that room. Any thing dropped in the room (if it is not X{\tt sticky\/}; see above) will go to that location. If the room has Xits {\tt sticky\/} flag set the effect of the dropto will be delayed Xuntil the last player leaves the room. The special location {\tt Xhome} may be used as a dropto, as in {\tt @link here = home\/}; in Xthat case things dropped in the room will go to their Xhomes\index{home@\type{home}}. To remove the dropto on a room go into Xthat room and use {\tt @unlink here\/}\index{here@\type{here}}. X X\subsection{Homes} X\label{sec:homes} X X\index{home} XEvery thing or player has a home. For things, this is the location Xthe thing returns to when sacrificed, when a player carrying it goes Xhome, or when (if its {\tt sticky\/} flag is set) it is dropped. For Xplayers, this is where the player goes when they issue the {\tt home} Xcommand. Homes may be set using the {\tt @link} command; for example, X{\tt @link donut =} $<${\em room-number\/}$>$ or {\tt @link me =} X$<${\em room-number\/}$>$\index{me@\type{me}}. Exits may also be Xlinked to the special location {\tt home\/}; for example, {\tt @link Xnorth = home\/}\index{home@\type{home}}. X X\subsection{Recycling} X\label{sec:recycling} X XNothing can be destroyed in {\tinymud}, but it is possible to recycle Xjust about anything. The {\tt @name} command can be used to rename Xobjects, making it easy to turn a silk purse into a sow's ear or vice Xversa. Extra exits can be unlinked and picked up by their owner using Xthe {\tt get} command, and dropped like things using the {\tt drop} Xcommand in any room controlled by the dropper. X X\subsection{Being killed} X\label{sec:being-killed} X XWhen you are killed you return to your home and any items you were Xcarrying return to their homes. As a consolation you receive 50 Xpennies from the {\tinymud} Total Life Indemnity insurance Xcompany. X X\section{Examples} X\label{sec:examples} X XHere we present examples to demonstrate some of the features of X{\tinymud}. X X\subsection{Success and failure messages} X\label{sec:success-and-failure-messages} X XSuccess and failure messages are fairly straightforward. Just Xremember that for the messages set with {\tt X@osuccess}\index{osuccess@\type{"@osuccess}} and {\tt X@ofail}\index{ofail@\type{"@ofail}} the player's name is prefixed onto Xthe message when it is printed, while the messages set with {\tt X@success}\index{success@\type{"@success}} and {\tt X@fail}\index{fail@\type{"@fail}} are printed as-is. X XPreviously we saw that you can use {\tt say}, \verb|"|, and \verb|:| Xto display messages. An older method for posing non sequiturs is to Xset the others success message on yourself and then rob yourself. For Xexample, if your character is Betty and you do X\index{say@\type{say}} X\index{""@\type{""}} X\index{:@\type{:}} X\begin{verbatim} X@osuccess me = starts picking her nose. Xrob me X\end{verbatim} Xon your screen you'll see X\begin{verbatim} XYou stole a penny. XBetty stole one of your pennies! X\end{verbatim} Xwhile the other players will see X\begin{verbatim} XBetty starts picking her nose. X\end{verbatim} XAn easier way to accomplish this is to simply do X\begin{verbatim} X:starts picking her nose. X\end{verbatim} Xthen both you and the others see X\begin{verbatim} XBetty starts picking her nose. X\end{verbatim} XWhen using \verb|"| and \verb|:| don't follow them with a space Xbecause it will be included in the output; put the message right up Xagainst the quotes or colon. X X\subsection{Making your home} X\label{sec:making-your-home} X X\index{home} XThe minimal steps for making your home are X\begin{enumerate} X\item XMake the room for your home with the {\tt @dig} command. Write down Xthe room number in case the following step takes a long time. X X\item X\label{item:exit} XMake or acquire an exit. In order to use the {\tt @open} command you Xmust own the room that you are doing the {\tt @open} in. The Xalternative is to find a room with an exit that isn't linked and use Xit. X X\item XMake a link to your home. Once you've made or found an unlinked exit Xsimply use the {\tt @link} command to link the exit to your room. X X\item X\label{item:exit-room} XFind a room to which you can make a link in order to have an exit from Xyour room (this is a room with the \verb|link_ok| flag set). For the Xsake of example we'll pretend the number of this room is 711; we'll be Xusing it in step~\ref{item:exit-link}. Without this you'd be able to Xgo to your home but you wouldn't have any way to get out of it. X X\item XSet the link from you to your home. Go into your room and do X\index{here@\type{here}} X\index{link@\type{"@link}} X\begin{verbatim} X@link me = here X\end{verbatim} X X\item X\label{item:exit-link} XMake the exit and link it to the destination X\begin{verbatim} X@open out X@link out = #711 X\end{verbatim} X(The \verb|#| isn't mandatory.) X\end{enumerate} X XOf course there are probably various details that you would want to Xtake care of in addition to the above steps. For example, if you're Xantisocial and want to prevent other people from using your home room Xyou'd do X\index{lock@\type{"@lock}} X\begin{verbatim} X@lock down = me X\end{verbatim} Xassuming that {\tt down} is the exit you made in step~\ref{item:exit}. XAlong a similar vein you might not want other people linking to your Xroom in which case you'd turn off the \verb|link_ok| flag on your Xroom. You might also set the description of your home room. If you Xown the exit you could also set the success, others success, fail, and Xothers fail messages on the exit to your home. Without the Xdescriptions places and things are boring and uninteresting. X X\subsection{Lock key boolean examples} X\label{sec:lock-key-boolean-examples} X XWhen using the {\tt @lock} command the key is either another object or Xsome boolean combination of other objects. If the key starts with a X\verb|*| then that object must be a player. X XFor example, if a room has a direction {\tt out} and you want to Xprevent players from carrying the object {\tt xyz} when they go out, Xyou would use X\begin{verbatim} X@lock out = !xyz X\end{verbatim} Xor if you want to prevent the player Julia from using the {\tt out} Xexit you would use X\begin{verbatim} X@lock out = !*Julia X\end{verbatim} XIf you want to prevent only Julia from going out with {\tt xyz} you Xwould use X\begin{verbatim} X@lock out = ( *Julia & !xyz ) X\end{verbatim} X X\subsection{Ersatz commands} X\label{sec:ersatz-commands} X XYou can make new commands by making an exit and then locking it to Xsomething impossible to have and then assigning the failure and others Xfailure messages to it. For example, assume the following commands Xhave been used X\begin{verbatim} X@open eat X@link eat = here X@lock eat = something_impossible X@fail eat = You try to eat but only gag X@ofail eat = tries to eat but instead gags X\end{verbatim} XThen when you use the command {\tt eat} the others in the room will Xsee {\tt Betty tries to eat but instead gags} and you'll see {\tt You Xtry to eat but only gag\/}. X XNote that this ``new command'' will only work in the room that you Xmade it in. X X\clearpage X X\part*{Appendix} X X\appendix X X\section{Wizard commands} X\label{sec:wizard-commands} X X\begin{simple} X X\item[] X\begin{flushleft} X{\tt @chown} $<${\em object\/}$>$ \verb|=| $<${\em player\/}$>$ X\index{chown@\type{"@chown}} X\end{flushleft} XChanges the ownership of $<${\em object\/}$>$ to $<${\em player\/}$>$. X X\dorule X X\item[] X\begin{flushleft} X{\tt @dump} X\index{dump@\type{"@dump}} X\end{flushleft} XForces a dump of the database. This command isn't really necessary Xsince {\tt @shutdown} does one as well as the regular periodic dumps. X X\dorule X X\item[] X\begin{flushleft} X{\tt examine} $<${\em name\/}$>$ \\ X{\tt examine} {\tt \#}$<${\em number\/}$>$ X\index{examine@\type{examine}} X\end{flushleft} XPrint a detailed description of object specified by $<${\em name\/}$>$ Xor by $<${\em number\/}$>$. All six strings listed in Xsection~\ref{sec:object-strings} are printed. X XWhen $<${\em name\/}$>$ is a room or {\tt Xhere}\index{here@\type{here}} it lists the owner, key, number of Xpennies, the description, contents, and exits. When $<${\em Xname\/}$>$ is a direction lists the direction number, owner, key, Xpennies, and destination. X X\dorule X X\item[] X\begin{flushleft} X{\tt @force} $<${\em victim\/}$>$ \verb|=| $<${\em command\/}$>$ X\index{force@\type{"@force}} X\end{flushleft} X X\dorule X X\item[] X\begin{flushleft} X{\tt @newpassword} $<${\em player\/}$>$ \verb|=| $<${\em Xpassword\/}$>$ X\index{newpassword@\type{"@newpassword}} X\end{flushleft} XChanges the password for $<${\em player\/}$>$. X X\dorule X X\item[] X\begin{flushleft} X{\tt @shutdown} X\index{shutdown@\type{"@shutdown}} X\end{flushleft} XShuts down the {\tinymud} server. X X\dorule X X\item[] X\begin{flushleft} X{\tt @stats} X\index{stats@\type{"@stats}} X\end{flushleft} XLists the total number of objects, which is the sum of the rooms, Xexits, things, and players, giving the count for each one. X X\dorule X X\item[] X\begin{flushleft} X{\tt @teleport} $[$ $<${\em victim\/}$>$ \verb|=| $]$ $<${\em Xdestination\/}$>$ X\index{teleport@\type{"@teleport}} X\end{flushleft} XTeleports the object to the specified destination. Object can also be X{\tt me\/}.\index{me@\type{me}} X X\dorule X X\item[] X\begin{flushleft} X{\tt @toad} $<${\em player\/}$>$ X\index{toad@\type{"@toad}} X\end{flushleft} XTurns $<${\em player\/}$>$ into an object. X X\dorule X X\item[] X\begin{flushleft} X{\tt @wall} $<${\em message\/}$>$ X\index{wall@\type{"@wall}} X\end{flushleft} XSend $<${\em message\/}$>$ to all players. X X\end{simple} X X\addcontentsline{toc}{part}{Index} X X\printindex X X\end{document} END_OF_FILE if test 28102 -ne `wc -c <'tinymud.tex'`; then echo shar: \"'tinymud.tex'\" unpacked with wrong size! fi # end of 'tinymud.tex' fi echo shar: End of archive 7 \(of 10\). cp /dev/null ark7isdone 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