From bacchus.pa.dec.com!decwrl!wuarchive!cs.utexas.edu!uunet!zephyr.ens.tek.com!tekred!saab!billr Mon Jul 30 17:54:36 PDT 1990 Article 1050 of comp.sources.games: Path: bacchus.pa.dec.com!decwrl!wuarchive!cs.utexas.edu!uunet!zephyr.ens.tek.com!tekred!saab!billr From: billr@saab.CNA.TEK.COM (Bill Randle) Newsgroups: comp.sources.games Subject: v11i013: tinymud2 - user-extendible multi-user adventure (v1.5.4), Part09/10 Message-ID: <6058@tekred.CNA.TEK.COM> Date: 30 Jul 90 16:46:44 GMT Sender: news@tekred.CNA.TEK.COM Lines: 2088 Approved: billr@saab.CNA.TEK.COM Submitted-by: James Aspnes Posting-number: Volume 11, Issue 13 Archive-name: tinymud2/Part09 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 'CHANGES' <<'END_OF_FILE' X------------------------------------------------------------------------ X XChanges in Islandia Version (1.5.4) by Fuzzy (Michael Mauldin) X X25-Jun-90 Allow people to drop exits they are carrying that X have location -1 (this fixes a problem with exits X that get recycled while they are carried). X X9-Jun-90 Added failure message for whispers to objects X Made DUMPCORE on error the default (writes DB, X then calls abort() with SIGILL enabled). Set X -DNODUMPCORE to inhibit core dumps. X Unified Islandia & TinyHELL sources, with switch X in config.h X Added Virus (Robert Hood's) port concentrator. X Added connect.txt, for messages before the connect. X X There are now 5 text files associated with TinyMUD: X connect.txt before logging in X motd.txt after logging in X tinker.txt after logging in for tinkers X news.txt News command X help.txt Help command X X17-Jun-90 Added Virus's concentrator code. X Fixed extract to allow player names instead of numbers, X and added special commands: reachable, players, X norecycle a b X X------------------------------------------------------------------------ X XChanges in Islandia/Hell Version (1.5.3C) by Random (Russ Smith) X X5-Jun-90 Made ABODE govern dropto X Allow players to DARKen objects that they own and are X carrying, but not let them drop DARK objects in an X area they couldn't link to. X Added UNWANTED flag, which allows people to @chown X objects to themselves, subject to locking; X Made @chown understand 'me' X Made @recycle set its object to be UNWANTED X Made page and whisper check the WHO list and X respond appropriately. X X------------------------------------------------------------------------ X XChanges in Islandia Version (1.5.3B) by Fuzzy (Michael Mauldin) X X31-May-90 Added casts to signal arguments to get rid of X annoying warnings from gcc. X X28-May-90 Added @count & @recycle...@count is redundant with X @stat for players, but it can also be run by X non-tinkers, and @count of a room summarizes X contents: a new feature. Note that @count is X less work than @find, because only the db array X is used, no strings are referenced. X X Also fixed bug in extract: X X extract all - X X now extracts player and his contents...before, X a bug/feature/omission caused only the player X to be extracted. X X Syntax: X X @count X @count X X @recycle = X @recycle defaults to Recycler. X X Recycling an object destroys its strings, and chowns X the object to a player called Recycler. The idea is X that periodically you can "extract all -" X to remove the recycled objects. X X Added code to extract to check for isolated rooms X (no entrances, or no entrances, exits, or contents). X X Fixed bug/feature in extract that caused it to complain X aboute unlinked exits being carried by players. It no X longer complains about them. X X28-May-90 Added NOFAKES switch to forbid use of names that X are really first words from important system messages X (A, An, The, You, Your, Going, Huh?) X X25-May-90: Added code to @bobble to chown all the players X objects to another user. X X20-May-90: Added ROBOT flag...enables OUTPUTPREFIX/SUFFIX, X prevents ROBOT players from getting objects, X using exits, or entering rooms with ROBOT set. X X Changed Wizards to Tinkers, Temples to Junkpiles, X and 'sacrifice' to 'donate'. Added special X MOTD for Tinkers (file ../lib/tinker.txt). X X Also changed @toad to @bobble. X X Fixed problem with @link on links that are X set to *home*. X X Fixed security hole that allowed a Wizard to X @force God...thus preventing X X @force Wizard = @set *Apprentice = WIZARD X X Changed game.c so that on errors both a database X dump and a regular core dump are written. X X17-May-90: Fixed bug where @name guest = foo bar caused X a crash because guest has no password (file set.c) X X Added MOTD function, file ../lib/motd.txt X (files help.c, interface.c) X X Added caching of hostnames so that Tinkers can do a X WHO without bogging down the server. X X11-May-90 Added Random's "page = " command, to allow X sending messages simply...people otherwise used X X @name me = / @page / @name me = X X anyway, so why not make it easy. X X------------------------------------------------------------------------ X XChanges in Firefoot version (1.5.3A) (Scott Goehring): X XAdded code to detach netmud from the terminal on startup (-DDETACH). X XNetmud now writes to a log file instead of stderr when detached. XSIGUSR2 will close and reopen the log file. X XSIGTERM and SIGINT now cause netmud to shutdown cleanly instead of Xpanicking (good for when your system is /etc/shutdown'd). X XAdded parallel compile support to the makefile (if you're on a XSequent, compile with 'make P=\&'). X XLog file entries are now preceded by the time of day. X XThe status dumper (SIGUSR1) has been removed. X XAdded Random's preregistration support (disabled create, @pcreate). X XAdded OJ's examine hack. X XAdded Random's @owned command. X XPanics now dump the contents of the sigcontext struct in hex to the Xlogfile for debugging purposes. X X XChanges in version 1.5.3-FF.1 (Scott Goehring): X XWHO can take an argument; only names with the same prefix as the Xargument are displayed. X XLINK_OK code modified; ABODE flag added. X XPlayer may select format and order of WHO listing. X X!-bug fixed properly. X X------------------------------------------------------------------------ X XChanges in version 1.5.3: X XGripes now get sent immediately to GOD when GOD_PRIV is defined. They Xcan be blocked by setting HAVEN. X XLimited @newpassword command to GOD when GOD_PRIV is defined. Otherwise Xany WIZARD could subvert GOD. X XAdded special case to do_name for changing the case of a player name. X XAdded interface changes, GOD_PRIV hacks, and HAVEN bit. [These Changes Xfrom Random at TinyHELL] X XGot rid of LOOKUP_COST; replaced it with special FIND_COST and PAGE_COST. Xfind defaults to being very expensive. X XAdded hash table for player name lookups. This change should Xeliminate a lot of thrashing. X XFixed ok_name test so that ! can appear after the beginning of a name. X X XChanges in version 1.5.2: X XAdded Stephen White's pronoun substitution code under #ifdef GENDER. X XChanged test for setting a created object's home to current room to Xrequire control of the room instead of linkability. X XObjects sent to rooms with @teleport go through dropto's. X XBoolean operators can no longer appear in names. X XAdded rudimentary string compression under #ifdef COMPRESS. X XFixed missing OUTPUTPREFIX and OUTPUTSUFFIX on WHO command in interface. X XFixed various small bugs not caught in 1.5.1. X X XChanges in version 1.5.1: X X@newpassword command added. Password checking added. 1p charge for Xchanging your own name eliminated to prevent confusion. X XDatabase structure modified to allow for boolean expressions as keys. XUSE_VFORK, DB_INITIAL_SIZE, and DB_DOUBLING #defines added to allow Xfor greater system-dependent configuration. X XWhisper command added. X XName formatting centralized. Names now include flags. X Xok_player_name() modified to reject names longer than XPLAYER_NAME_LIMIT. X XBoolean lock code added. X X XChanges in version 1.4.2: X XSmall bug fixes; okname() modified to reject names containing XARG_DELIMITER, democratized teleport added under #ifndef XRESTRICTED_TELEPORT. X X XChanges in version 1.4.1: X XRadically rewritten interface.c with fair command processing, command limits. X X------------------------------------------------------------------------ END_OF_FILE if test 7507 -ne `wc -c <'CHANGES'`; then echo shar: \"'CHANGES'\" unpacked with wrong size! fi # end of 'CHANGES' fi if test -f 'compress.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'compress.c'\" else echo shar: Extracting \"'compress.c'\" \(2725 characters\) sed "s/^X//" >'compress.c' <<'END_OF_FILE' X/* Compression routines */ X X/* These use a pathetically simple encoding that takes advantage of the */ X/* eighth bit on a char; if you are using an international character set, */ X/* they may need substantial patching. */ X X#ifdef COMPRESS X X#define BUFFER_LEN 16384 /* nice big buffer */ X X#define TOKEN_BIT 0x80 /* if on, it's a token */ X#define TOKEN_MASK 0x7f /* for stripping out token value */ X#define NUM_TOKENS (128) X#define MAX_CHAR (128) X X/* Top 128 bigrams in the CMU TinyMUD database as of 2/13/90 */ Xstatic const char *tokens[NUM_TOKENS] = { X "e ", " t", "th", "he", "s ", " a", "ou", "in", X "t ", " s", "er", "d ", "re", "an", "n ", " i", X " o", "es", "st", "to", "or", "nd", "o ", "ar", X "r ", ", ", "on", " b", "ea", "it", "u ", " w", X "ng", "le", "is", "te", "en", "at", " c", "y ", X "ro", " f", "oo", "al", ". ", "a ", " d", "ut", X " h", "se", "nt", "ll", "g ", "yo", " l", " y", X " p", "ve", "f ", "as", "om", "of", "ha", "ed", X "h ", "hi", " r", "lo", "Yo", " m", "ne", "l ", X "li", "de", "el", "ta", "wa", "ri", "ee", "ti", X "no", "do", "Th", " e", "ck", "ur", "ow", "la", X "ac", "et", "me", "il", " g", "ra", "co", "ch", X "ma", "un", "so", "rt", "ai", "ce", "ic", "be", X " n", "k ", "ge", "ot", "si", "pe", "tr", "wi", X "e.", "ca", "rs", "ly", "ad", "we", "bo", "ho", X "ir", "fo", "ke", "us", "m ", " T", "di", ".." }; X Xstatic char token_table[MAX_CHAR][MAX_CHAR]; Xstatic int table_initialized = 0; X Xstatic void init_compress(void) X{ X int i; X int j; X X for(i = 0; i < MAX_CHAR; i++) { X for(j = 0; j < MAX_CHAR; j++) { X token_table[i][j] = 0; X } X } X X for(i = 0; i < NUM_TOKENS; i++) { X token_table[tokens[i][0]][tokens[i][1]] = i | TOKEN_BIT; X } X X table_initialized = 1; X} X Xstatic int compressed(const char *s) X{ X while(*s) { X if(*s++ & TOKEN_BIT) return 1; X } X return 0; X} X Xconst char *compress(const char *s) X{ X static char buf[BUFFER_LEN]; X char *to; X char token; X X if(!table_initialized) init_compress(); X X if(compressed(s)) return s; /* already compressed */ X X /* tokenize the first characters */ X for(to = buf; s[0] && s[1]; to++) { X if(token = token_table[s[0]][s[1]]) { X *to = token; X s += 2; X } else { X *to = s[0]; X s++; X } X } X X /* copy the last character (if any) and null */ X while(*to++ = *s++); X X return buf; X} X Xconst char *uncompress(const char *s) X{ X static char buf[BUFFER_LEN]; X char *to; X const char *token; X X for(to = buf; *s; s++) { X if(*s & TOKEN_BIT) { X token = tokens[*s & TOKEN_MASK]; X *to++ = *token++; X *to++ = *token; X } else { X *to++ = *s; X } X } X X *to++ = *s; X X return buf; X} X X#endif /* COMPRESS */ X END_OF_FILE if test 2725 -ne `wc -c <'compress.c'`; then echo shar: \"'compress.c'\" unpacked with wrong size! fi # end of 'compress.c' fi if test -f 'create.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'create.c'\" else echo shar: Extracting \"'create.c'\" \(8647 characters\) sed "s/^X//" >'create.c' <<'END_OF_FILE' X#include "copyright.h" X X/* Commands that create new objects */ X X#include "db.h" X#include "config.h" X#include "interface.h" X#include "externs.h" X X/* utility for open and link */ Xstatic dbref parse_linkable_room(dbref player, object_flag_type thing, X const char *room_name) X{ X dbref room; X X /* skip leading NUMBER_TOKEN if any */ X if(*room_name == NUMBER_TOKEN) room_name++; X X /* parse room */ X if(!string_compare(room_name, "here")) { X room = db[player].location; X } else if(!string_compare(room_name, "home")) { X return HOME; /* HOME is always linkable */ X } else { X room = parse_dbref(room_name); X } X X /* check room */ X if(room < 0 || room >= db_top X || Typeof(room) != TYPE_ROOM) { X notify(player, "That's not a room!"); X return NOTHING; X } else if(!can_link_to(player, thing, room)) { X notify(player, "You can't link to that."); X return NOTHING; X } else { X return room; X } X} X X/* use this to create an exit */ Xvoid do_open(dbref player, const char *direction, const char *linkto) X{ X dbref loc; X dbref exit; X X#ifdef RESTRICTED_BUILDING X if(!Builder(player)) { X notify(player, "That command is restricted to authorized builders."); X return; X } X#endif /* RESTRICTED_BUILDING */ X X if((loc = getloc(player)) == NOTHING) return; X if(!*direction) { X notify(player, "Open where?"); X return; X } else if(!ok_name(direction)) { X notify(player, "That's a strange name for an exit!"); X return; X } X X if(!controls(player, loc)) { X notify(player, "Permission denied."); X } else if(!payfor(player, EXIT_COST)) { X notify(player, X "Sorry, you don't have enough pennies to open an exit."); X } else { X /* create the exit */ X exit = new_object(); X X /* initialize everything */ X db[exit].name = alloc_string(direction); X db[exit].owner = player; X db[exit].flags = TYPE_EXIT; X X /* link it in */ X PUSH(exit, db[loc].exits); X X /* and we're done */ X notify(player, "Opened."); X X /* check second arg to see if we should do a link */ X if(*linkto != '\0') { X notify(player, "Trying to link..."); X if((loc = parse_linkable_room(player, TYPE_EXIT, linkto)) != X NOTHING) { X if(!payfor(player, LINK_COST)) { X notify(player, "You don't have enough pennies to link."); X } else { X /* it's ok, link it */ X db[exit].location = loc; X notify(player, "Linked."); X } X } X } X } X} X X/* use this to link to a room that you own */ X/* it seizes ownership of the exit */ X/* costs 1 penny */ X/* plus a penny transferred to the exit owner if they aren't you */ X/* you must own the linked-to room AND specify it by room number */ Xvoid do_link(dbref player, const char *name, const char *room_name) X{ X dbref thing; X dbref room; X X init_match(player, name, TYPE_EXIT); X match_exit(); X match_neighbor(); X match_possession(); X match_me(); X match_here(); X if(Wizard(player)) { X match_absolute(); X match_player(); X } X X if((thing = noisy_match_result()) != NOTHING) { X if((room = parse_linkable_room(player, Typeof(thing), room_name)) == X NOTHING) X return; X switch(Typeof(thing)) { X case TYPE_EXIT: X /* we're ok, check the usual stuff */ X if(db[thing].location != NOTHING) { X if(controls(player, thing)) { X X /* X * Changed 5/18/90 Fuzzy - exits linked to *home* X * break 'Typeof() call' X */ X X if(db[thing].location >= 0 && X Typeof(db[thing].location) == TYPE_PLAYER) { X notify(player, "That exit is being carried."); X } else { X notify(player, "That exit is already linked."); X } X } else { X notify(player, "Permission denied."); X } X } else { X /* handle costs */ X if(db[thing].owner == player) { X if(!payfor(player, LINK_COST)) { X notify(player, X "It costs a penny to link this exit."); X return; X } X } else { X if(!payfor(player, LINK_COST + EXIT_COST)) { X notify(player, X "It costs two pennies to link this exit."); X return; X#ifdef RESTRICTED_BUILDING X } else if(!Builder(player)) { X notify(player, X "Only authorized builders may seize exits."); X#endif /* RESTRICTED_BUILDING */ X } else { X /* pay the owner for his loss */ X db[db[thing].owner].pennies += EXIT_COST; X } X } X X /* link has been validated and paid for; do it */ X db[thing].owner = player; X db[thing].location = room; X X /* notify the player */ X notify(player, "Linked."); X } X break; X case TYPE_PLAYER: X case TYPE_THING: X if(!controls(player, thing)) { X notify(player, "Permission denied."); X } else if(room == HOME) { X notify(player, "Can't set home to home."); X } else { X /* do the link */ X db[thing].exits = room; /* home */ X notify(player, "Home set."); X } X break; X case TYPE_ROOM: X if(!controls(player, thing)) { X notify(player, "Permission denied."); X } else { X /* do the link, in location */ X db[thing].location = room; /* dropto */ X notify(player, "Dropto set."); X } X break; X default: X notify(player, "Internal error: weird object type."); X writelog("PANIC weird object: Typeof(%d) = %d\n", X thing, Typeof(thing)); X break; X } X } X} X X/* use this to create a room */ Xvoid do_dig(dbref player, const char *name) X{ X dbref room; X char buf[BUFFER_LEN]; X X#ifdef RESTRICTED_BUILDING X if(!Builder(player)) { X notify(player, "That command is restricted to authorized builders."); X return; X } X#endif /* RESTRICTED_BUILDING */ X X /* we don't need to know player's location! hooray! */ X if(*name == '\0') { X notify(player, "Dig what?"); X } else if(!ok_name(name)) { X notify(player, "That's a silly name for a room!"); X } else if(!payfor(player, ROOM_COST)) { X notify(player, "Sorry, you don't have enough pennies to dig a room."); X } else { X room = new_object(); X X /* Initialize everything */ X db[room].name = alloc_string(name); X db[room].owner = player; X db[room].flags = TYPE_ROOM; X X sprintf(buf, "%s created with room number %d.", name, room); X notify(player, buf); X } X} X X/* use this to create an object */ Xvoid do_create(dbref player, char *name, int cost) X{ X dbref loc; X dbref thing; X X#ifdef RESTRICTED_BUILDING X if(!Builder(player)) { X notify(player, "That command is restricted to authorized builders."); X return; X } X#endif /* RESTRICTED_BUILDING */ X X if(*name == '\0') { X notify(player, "Create what?"); X return; X } else if(!ok_name(name)) { X notify(player, "That's a silly name for a thing!"); X return; X } else if(cost < 0) { X notify(player, "You can't create an object for less than nothing!"); X return; X } else if(cost < OBJECT_COST) { X cost = OBJECT_COST; X } X X if(!payfor(player, cost)) { X notify(player, "Sorry, you don't have enough pennies."); X } else { X /* create the object */ X thing = new_object(); X X /* initialize everything */ X db[thing].name = alloc_string(name); X db[thing].location = player; X db[thing].owner = player; X db[thing].pennies = OBJECT_ENDOWMENT(cost); X db[thing].flags = TYPE_THING; X X /* endow the object */ X if(db[thing].pennies > MAX_OBJECT_ENDOWMENT) { X db[thing].pennies = MAX_OBJECT_ENDOWMENT; X } X X /* home is here (if we can link to it) or player's home */ X if((loc = db[player].location) != NOTHING X && controls(player, loc)) { X db[thing].exits = loc; /* home */ X } else { X db[thing].exits = db[player].exits; /* home */ X } X X /* link it in */ X PUSH(thing, db[player].contents); X X /* and we're done */ X notify(player, "Created."); X } X} X X#ifdef REGISTRATION Xvoid do_pcreate (dbref player, char *newplayer, char *newpass) X{ X dbref ptmp; X X#ifdef GOD_MODE && GOD_ONLY_PCREATE X if (!God(player)) X#ifndef TINKER X notify (player, "Only GOD can create a new player."); X#else TINKER X notify (player, "Only the Master Tinker can create a new player."); X#endif TINKER X#else GOD_MODE && GOD_ONLY_PCREATE X if (!Wizard(player)) X#ifndef TINKER X notify (player, "Only a Wizard can create a new player."); X#else TINKER X notify (player, "Only a Tinker can create a new player."); X#endif TINKER X#endif GOD_MODE && GOD_ONLY_PCREATE X else if (!*newplayer || !*newpass) X notify (player, "You must specify name and password."); X else { X ptmp = create_player (newplayer, newpass); X if (ptmp == NOTHING) { X notify(player, "Either there is already a player with that name, or that name is illegal."); X writelog("FAILED CREATE %s by %s\n",newplayer,db[player].name); X } else { X char buf[512]; X sprintf(buf, "%s created as object #%d.",db[ptmp].name,ptmp); X notify(player, buf); X writelog("CREATED %s(%d) by %s\n",db[ptmp].name,ptmp, X db[player].name); X } X } X} X#endif REGISTRATION END_OF_FILE if test 8647 -ne `wc -c <'create.c'`; then echo shar: \"'create.c'\" unpacked with wrong size! fi # end of 'create.c' fi if test -f 'db.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'db.h'\" else echo shar: Extracting \"'db.h'\" \(5703 characters\) sed "s/^X//" >'db.h' <<'END_OF_FILE' X#include "copyright.h" X X#ifndef __DB_H X#define __DB_H X#include X Xextern void *malloc(unsigned long); Xextern void *realloc(void *, unsigned long); Xextern void free(void *); X X#ifdef TEST_MALLOC Xextern int malloc_count; X#define malloc(x) (malloc_count++, malloc(x)) X#define free(x) (malloc_count--, free(x)) X#endif /* TEST_MALLOC */ X Xtypedef int dbref; /* offset into db */ X X#define TYPE_ROOM 0x0 X#define TYPE_THING 0x1 X#define TYPE_EXIT 0x2 X#define TYPE_PLAYER 0x3 X#define NOTYPE 0x7 /* no particular type */ X#define TYPE_MASK 0x7 /* room for expansion */ X#define ANTILOCK 0x8 /* negates key (*OBSOLETE*) */ X#define WIZARD 0x10 /* gets automatic control */ X#define LINK_OK 0x20 /* anybody can link exits to this room */ X#define DARK 0x40 /* contents of room are not printed */ X#define TEMPLE 0x80 /* objects dropped in this room go home */ X#define STICKY 0x100 /* this object goes home when dropped */ X X#ifdef RESTRICTED_BUILDING X#define BUILDER 0x200 /* this player can use construction commands */ X#endif /* RESTRICTED_BUILDING */ X X#define HAVEN 0x400 /* this room prohibits killing */ X#define ABODE 0x800 /* can link objects or players here */ X X#ifdef GENDER X#define GENDER_MASK 0x3000 /* 2 bits of gender */ X#define GENDER_SHIFT 12 /* 0x1000 is 12 bits over (for shifting) */ X#define GENDER_UNASSIGNED 0x0 /* unassigned - the default */ X#define GENDER_NEUTER 0x1 /* neuter */ X#define GENDER_FEMALE 0x2 /* for women */ X#define GENDER_MALE 0x3 /* for men */ X X#ifdef ROBOT_MODE X#define ROBOT 0x4000 /* Can set OUTPUTPREFIX */ X#endif ROBOT_MODE X X#define UNWANTED 0x8000 /* can be chowned */ X X#define TABULAR_WHO 0x10000 X#define REVERSED_WHO 0x20000 X X#define Genderof(x) ((db[(x)].flags & GENDER_MASK) >> GENDER_SHIFT) X#endif /* GENDER */ X Xtypedef int object_flag_type; X X#define Flag(x,f) ((db[(x)].flags & (f)) != 0) X X#define Typeof(x) (db[(x)].flags & TYPE_MASK) X#define Wizard(x) ((db[(x)].flags & WIZARD) != 0) X#ifdef ROBOT_MODE X#define Robot(x) ((db[(x)].flags & ROBOT) != 0) X#endif ROBOT_MODE X#define Dark(x) ((db[(x)].flags & DARK) != 0) X#ifdef GOD_PRIV X#define GOD ((dbref)1) X#define God(x) ((x)==GOD) X#endif GOD_PRIV X X#ifdef RECYCLE X#define RECYCLER "Recycler" X#endif X X#ifdef RESTRICTED_BUILDING X#define Builder(x) ((db[(x)].flags & (WIZARD|BUILDER)) != 0) X#endif /* RESTRICTED_BUILDING */ X X/* Boolean expressions, for locks */ Xtypedef char boolexp_type; X X#define BOOLEXP_AND 0 X#define BOOLEXP_OR 1 X#define BOOLEXP_NOT 2 X#define BOOLEXP_CONST 3 X Xstruct boolexp { X boolexp_type type; X struct boolexp *sub1; X struct boolexp *sub2; X dbref thing; X}; X X#define TRUE_BOOLEXP ((struct boolexp *) 0) X X/* special dbref's */ X#define NOTHING (-1) /* null dbref */ X#define AMBIGUOUS (-2) /* multiple possibilities, for matchers */ X#define HOME (-3) /* virtual room, represents mover's home */ X Xstruct object { X const char *name; X const char *description; X dbref location; /* pointer to container */ X /* for exits, pointer to destination */ X dbref contents; /* pointer to first item */ X dbref exits; /* pointer to first exit for rooms */ X /* pointer to home for things and players */ X dbref next; /* pointer to next in contents/exits chain */ X X /* the following are used for pickups for things, entry for exits */ X struct boolexp *key; /* if not NOTHING, must have this to do op */ X const char *fail_message; /* what you see if op fails */ X const char *succ_message; /* what you see if op succeeds */ X /* other messages get your name prepended, so if your name is "Foo", */ X /* and osuccess = "disappears in a blast of gamma radiation." */ X /* then others see "Foo disappears in a blast of gamma radiation." */ X /* (At some point I may put in Maven-style %-substitutions.) */ X const char *ofail; /* what others see if op fails */ X const char *osuccess; /* what others see if op succeeds */ X X dbref owner; /* who controls this object */ X int pennies; /* number of pennies object contains */ X object_flag_type flags; X const char *password; /* password for players */ X}; X Xextern struct object *db; Xextern dbref db_top; X Xextern const char *alloc_string(const char *s); X Xextern dbref new_object(); /* return a new object */ X Xextern dbref getref (FILE *); /* Read a database reference from a file. */ X Xextern void putref (FILE *, dbref); /* Write one ref to the file */ X Xextern struct boolexp *getboolexp(FILE *); /* get a boolexp */ Xextern void putboolexp(FILE *, struct boolexp *); /* put a boolexp */ X Xextern int db_write_object(FILE *, dbref); /* write one object to file */ X Xextern dbref db_write(FILE *f); /* write db to file, return # of objects */ X Xextern dbref db_read(FILE *f); /* read db from file, return # of objects */ X /* Warning: destroys existing db contents! */ X Xextern void free_boolexp(struct boolexp *); Xextern void db_free(void); X Xextern dbref parse_dbref(const char *); /* parse a dbref */ X X#define DOLIST(var, first) \ X for((var) = (first); (var) != NOTHING; (var) = db[(var)].next) X#define PUSH(thing, locative) \ X ((db[(thing)].next = (locative)), (locative) = (thing)) X#define getloc(thing) (db[thing].location) X X/* X Usage guidelines: X X To refer to objects use db[object_ref]. Pointers to objects may X become invalid after a call to new_object(). X X The programmer is responsible for managing storage for string X components of entries; db_read will produce malloc'd strings. The X alloc_string routine is provided for generating malloc'd strings X duplicates of other strings. Note that db_free and db_read will X attempt to free any non-NULL string that exists in db when they are X invoked. X*/ X#endif /* __DB_H */ END_OF_FILE if test 5703 -ne `wc -c <'db.h'`; then echo shar: \"'db.h'\" unpacked with wrong size! fi # end of 'db.h' fi if test -f 'match.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'match.c'\" else echo shar: Extracting \"'match.c'\" \(5261 characters\) sed "s/^X//" >'match.c' <<'END_OF_FILE' X#include "copyright.h" X X/* Routines for parsing arguments */ X#include X X#include "db.h" X#include "config.h" X#include "match.h" X X#define DOWNCASE(x) (isupper(x) ? tolower(x) : (x)) X Xstatic dbref exact_match = NOTHING; /* holds result of exact match */ Xstatic int check_keys = 0; /* if non-zero, check for keys */ Xstatic dbref last_match = NOTHING; /* holds result of last match */ Xstatic int match_count; /* holds total number of inexact matches */ Xstatic dbref match_who; /* player who is being matched around */ Xstatic const char *match_name; /* name to match */ Xstatic int preferred_type = NOTYPE; /* preferred type */ X Xvoid init_match(dbref player, const char *name, int type) X{ X exact_match = last_match = NOTHING; X match_count = 0; X match_who = player; X match_name = name; X check_keys = 0; X preferred_type = type; X} X Xvoid init_match_check_keys(dbref player, const char *name, int type) X{ X init_match(player, name, type); X check_keys = 1; X} X Xstatic dbref choose_thing(dbref thing1, dbref thing2) X{ X int has1; X int has2; X X if(thing1 == NOTHING) { X return thing2; X } else if(thing2 == NOTHING) { X return thing1; X } X X if(preferred_type != NOTYPE) { X if(Typeof(thing1) == preferred_type) { X if(Typeof(thing2) != preferred_type) { X return thing1; X } X } else if(Typeof(thing2) == preferred_type) { X return thing2; X } X } X X if(check_keys) { X has1 = could_doit(match_who, thing1); X has2 = could_doit(match_who, thing2); X X if(has1 && !has2) { X return thing1; X } else if (has2 && !has1) { X return thing2; X } X /* else fall through */ X } X X return (random() % 2 ? thing1 : thing2); X} X Xvoid match_player(void) X{ X dbref match; X const char *p; X X if(*match_name == LOOKUP_TOKEN) { X for(p = match_name + 1; isspace(*p); p++); X if((match = lookup_player(p)) != NOTHING) { X exact_match = match; X } X } X} X X/* returns nnn if name = #nnn, else NOTHING */ Xstatic dbref absolute_name(void) X{ X dbref match; X X if(*match_name == NUMBER_TOKEN) { X match = parse_dbref(match_name+1); X if(match < 0 || match >= db_top) { X return NOTHING; X } else { X return match; X } X } else { X return NOTHING; X } X} X Xvoid match_absolute(void) X{ X dbref match; X X if((match = absolute_name()) != NOTHING) { X exact_match = match; X } X} X Xvoid match_me(void) X{ X if(!string_compare(match_name, "me")) { X exact_match = match_who; X } X} X Xvoid match_here(void) X{ X if(!string_compare(match_name, "here") X && db[match_who].location != NOTHING) { X exact_match = db[match_who].location; X } X} X Xstatic void match_list(dbref first) X{ X dbref absolute; X X absolute = absolute_name(); X if(!controls(match_who, absolute)) absolute = NOTHING; X X DOLIST(first, first) { X if(first == absolute) { X exact_match = first; X return; X } else if(!string_compare(db[first].name, match_name)) { X /* if there are multiple exact matches, randomly choose one */ X exact_match = choose_thing(exact_match, first); X } else if(string_match(db[first].name, match_name)) { X last_match = first; X match_count++; X } X } X} X Xvoid match_possession(void) X{ X match_list(db[match_who].contents); X} X Xvoid match_neighbor(void) X{ X dbref loc; X X if((loc = db[match_who].location) != NOTHING) { X match_list(db[loc].contents); X } X} X Xvoid match_exit(void) X{ X dbref loc; X dbref exit; X dbref absolute; X const char *match; X const char *p; X X if((loc = db[match_who].location) != NOTHING) { X absolute = absolute_name(); X if(!controls(match_who, absolute)) absolute = NOTHING; X X DOLIST(exit, db[loc].exits) { X if(exit == absolute) { X exact_match = exit; X } else { X match = db[exit].name; X while(*match) { X /* check out this one */ X for(p = match_name; X (*p X && DOWNCASE(*p) == DOWNCASE(*match) X && *match != EXIT_DELIMITER); X p++, match++); X /* did we get it? */ X if(*p == '\0') { X /* make sure there's nothing afterwards */ X while(isspace(*match)) match++; X if(*match == '\0' || *match == EXIT_DELIMITER) { X /* we got it */ X exact_match = choose_thing(exact_match, exit); X goto next_exit; /* got this match */ X } X } X /* we didn't get it, find next match */ X while(*match && *match++ != EXIT_DELIMITER); X while(isspace(*match)) match++; X } X } X next_exit: X ; X } X } X} X Xvoid match_everything(void) X{ X match_exit(); X match_neighbor(); X match_possession(); X match_me(); X match_here(); X if(Wizard(match_who)) { X match_absolute(); X match_player(); X } X} X Xdbref match_result(void) X{ X if(exact_match != NOTHING) { X return exact_match; X } else { X switch(match_count) { X case 0: X return NOTHING; X case 1: X return last_match; X default: X return AMBIGUOUS; X } X } X} X X/* use this if you don't care about ambiguity */ Xdbref last_match_result(void) X{ X if(exact_match != NOTHING) { X return exact_match; X } else { X return last_match; X } X} X Xdbref noisy_match_result(void) X{ X dbref match; X X switch(match = match_result()) { X case NOTHING: X notify(match_who, NOMATCH_MESSAGE); X return NOTHING; X case AMBIGUOUS: X notify(match_who, AMBIGUOUS_MESSAGE); X return NOTHING; X default: X return match; X } X} X END_OF_FILE if test 5261 -ne `wc -c <'match.c'`; then echo shar: \"'match.c'\" unpacked with wrong size! fi # end of 'match.c' fi if test -f 'move.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'move.c'\" else echo shar: Extracting \"'move.c'\" \(8534 characters\) sed "s/^X//" >'move.c' <<'END_OF_FILE' X#include "copyright.h" X X#include "db.h" X#include "config.h" X#include "interface.h" X#include "match.h" X#include "externs.h" X Xvoid moveto(dbref what, dbref where) X{ X dbref loc; X X /* remove what from old loc */ X if((loc = db[what].location) != NOTHING) { X db[loc].contents = remove_first(db[loc].contents, what); X } X X /* test for special cases */ X switch(where) { X case NOTHING: X db[what].location = NOTHING; X return; /* NOTHING doesn't have contents */ X case HOME: X where = db[what].exits; /* home */ X break; X } X X /* now put what in where */ X PUSH(what, db[where].contents); X X db[what].location = where; X} X Xstatic void send_contents(dbref loc, dbref dest) X{ X dbref first; X dbref rest; X X first = db[loc].contents; X db[loc].contents = NOTHING; X X /* blast locations of everything in list */ X DOLIST(rest, first) { X db[rest].location = NOTHING; X } X X while(first != NOTHING) { X rest = db[first].next; X if(Typeof(first) != TYPE_THING) { X moveto(first, loc); X } else { X moveto(first, (db[first].flags & STICKY) ? HOME : dest); X } X first = rest; X } X X db[loc].contents = reverse(db[loc].contents); X} X Xvoid maybe_dropto(dbref loc, dbref dropto) X{ X dbref thing; X X if(loc == dropto) return; /* bizarre special case */ X X /* check for players */ X DOLIST(thing, db[loc].contents) { X if(Typeof(thing) == TYPE_PLAYER) return; X } X X /* no players, send everything to the dropto */ X send_contents(loc, dropto); X} X Xvoid enter_room(dbref player, dbref loc) X{ X dbref old; X dbref dropto; X char buf[BUFFER_LEN]; X X /* check for room == HOME */ X if(loc == HOME) loc = db[player].exits; /* home */ X X /* get old location */ X old = db[player].location; X X /* check for self-loop */ X /* self-loops don't do move or other player notification */ X /* but you still get autolook and penny check */ X if(loc != old) { X X if(old != NOTHING) { X /* notify others unless DARK */ X if(!Dark(old) && !Dark(player)) { X sprintf(buf, "%s has left.", db[player].name); X notify_except(db[old].contents, player, buf); X } X } X X /* go there */ X moveto(player, loc); X X /* if old location has STICKY dropto, send stuff through it */ X if(old != NOTHING X && (dropto = db[old].location) != NOTHING X && (db[old].flags & STICKY)) { X maybe_dropto(old, dropto); X } X X /* tell other folks in new location if not DARK */ X if(!Dark(loc) && !Dark(player)) { X sprintf(buf, "%s has arrived.", db[player].name); X notify_except(db[loc].contents, player, buf); X } X } X X /* autolook */ X look_room(player, loc); X X /* check for pennies */ X if(!controls(player, loc) X && db[player].pennies <= MAX_PENNIES X && random() % PENNY_RATE == 0) { X notify(player, "You found a penny!"); X db[player].pennies++; X } X} X Xvoid send_home(dbref thing) X{ X switch(Typeof(thing)) { X case TYPE_PLAYER: X /* send his possessions home first! */ X /* that way he sees them when he arrives */ X send_contents(thing, HOME); X enter_room(thing, db[thing].exits); /* home */ X break; X case TYPE_THING: X moveto(thing, db[thing].exits); /* home */ X break; X default: X /* no effect */ X break; X } X} X Xint can_move(dbref player, const char *direction) X{ X if(!string_compare(direction, "home")) return 1; X X /* otherwise match on exits */ X init_match(player, direction, TYPE_EXIT); X match_exit(); X return(last_match_result() != NOTHING); X} X Xvoid do_move(dbref player, const char *direction) X{ X dbref exit; X dbref loc; X char buf[BUFFER_LEN]; X X if(!string_compare(direction, "home")) { X /* send him home */ X /* but steal all his possessions */ X if((loc = db[player].location) != NOTHING) { X /* tell everybody else */ X sprintf(buf, "%s goes home.", db[player].name); X notify_except(db[loc].contents, player, buf); X } X /* give the player the messages */ X notify(player, "There's no place like home..."); X notify(player, "There's no place like home..."); X notify(player, "There's no place like home..."); X notify(player, "You wake up back home, without your possessions."); X send_home(player); X } else { X /* find the exit */ X init_match_check_keys(player, direction, TYPE_EXIT); X match_exit(); X switch(exit = match_result()) { X case NOTHING: X notify(player, "You can't go that way."); X break; X case AMBIGUOUS: X notify(player, "I don't know which way you mean!"); X break; X default: X /* we got one */ X /* check to see if we got through */ X if(can_doit(player, exit, "You can't go that way.")) { X enter_room(player, db[exit].location); X } X break; X } X } X} X Xvoid do_get(dbref player, const char *what) X{ X dbref loc; X dbref thing; X X init_match_check_keys(player, what, TYPE_THING); X match_neighbor(); X match_exit(); X if(Wizard(player)) match_absolute(); /* the wizard has long fingers */ X X if((thing = noisy_match_result()) != NOTHING) { X if(db[thing].location == player) { X notify(player, "You already have that!"); X return; X } X switch(Typeof(thing)) { X case TYPE_THING: X if(can_doit(player, thing, "You can't pick that up.")) { X moveto(thing, player); X notify(player, "Taken."); X } X break; X case TYPE_EXIT: X if(!controls(player, thing)) { X notify(player, "You can't pick that up."); X } else if(db[thing].location != NOTHING) { X notify(player, "You can't pick up a linked exit."); X#ifdef RESTRICTED_BUILDING X } else if(!Builder(player)) { X notify(player, "Only authorized builders may pick up exits."); X#endif /* RESTRICTED_BUILDING */ X } else { X /* take it out of location */ X if((loc = getloc(player)) == NOTHING) return; X if(!member(thing, db[loc].exits)) { X notify(player, X "You can't pick up an exit from another room."); X return; X } X db[loc].exits = remove_first(db[loc].exits, thing); X PUSH(thing, db[player].contents); X db[thing].location = player; X notify(player, "Exit taken."); X } X break; X default: X notify(player, "You can't take that!"); X break; X } X } X} X Xvoid do_drop(dbref player, const char *name) X{ X dbref loc; X dbref thing; X char buf[BUFFER_LEN]; X int reward; X X if((loc = getloc(player)) == NOTHING) return; X X init_match(player, name, TYPE_THING); X match_possession(); X X switch(thing = match_result()) { X case NOTHING: X notify(player, "You don't have that!"); X break; X case AMBIGUOUS: X notify(player, "I don't know which you mean!"); X break; X default: X if(db[thing].location != player && X !(Typeof(thing) == TYPE_EXIT) && db[thing].location == NOTHING) { X /* Should not ever happen. */ X notify(player, "You can't drop that."); X } else if(Typeof(thing) == TYPE_EXIT) { X /* special behavior for exits */ X if(!controls(player, loc)) { X notify(player, "You can't put an exit down here."); X return; X } X /* else we can put it down */ X moveto(thing, NOTHING); /* take it out of the pack */ X PUSH(thing, db[loc].exits); X notify(player, "Exit dropped."); X } else if(db[loc].flags & TEMPLE) { X /* sacrifice time */ X send_home(thing); X sprintf(buf, X "%s is consumed in a burst of flame!", db[thing].name); X notify(player, buf); X#ifndef TINKER X sprintf(buf, "%s sacrifices %s.", db[player].name, db[thing].name); X#else TINKER X sprintf(buf, "%s donates %s.", db[player].name, db[thing].name); X#endif TINKER X notify_except(db[loc].contents, player, buf); X X /* check for reward */ X if(!controls(player, thing)) { X reward = db[thing].pennies; X if(reward < 1 || db[player].pennies > MAX_PENNIES) { X reward = 1; X } else if(reward > MAX_OBJECT_ENDOWMENT) { X reward = MAX_OBJECT_ENDOWMENT; X } X X db[player].pennies += reward; X sprintf(buf, X "You have received %d %s for your donation.", X reward, X reward == 1 ? "penny" : "pennies"); X notify(player, buf); X } X } else if(db[thing].flags & STICKY) { X send_home(thing); X notify(player, "Dropped."); X } else if(db[loc].location != NOTHING && !(db[loc].flags & STICKY)) { X /* location has immediate dropto */ X moveto(thing, db[loc].location); X notify(player, "Dropped."); X } else if((db[thing].flags & DARK) && !can_link_to(player,Typeof(thing),loc)) { X notify(player, "You cannot drop that DARK object here."); X } else { X moveto(thing, loc); X notify(player, "Dropped."); X sprintf(buf, "%s dropped %s.", db[player].name, db[thing].name); X notify_except(db[loc].contents, player, buf); X } X break; X } X} END_OF_FILE if test 8534 -ne `wc -c <'move.c'`; then echo shar: \"'move.c'\" unpacked with wrong size! fi # end of 'move.c' fi if test -f 'predicates.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'predicates.c'\" else echo shar: Extracting \"'predicates.c'\" \(6557 characters\) sed "s/^X//" >'predicates.c' <<'END_OF_FILE' X#include "copyright.h" X X/* Predicates for testing various conditions */ X X#include X X#include "db.h" X#include "interface.h" X#include "config.h" X#include "externs.h" X Xvoid pronoun_substitute(char *result, dbref player, const char *str); X Xint can_link_to(dbref who, object_flag_type what, dbref where) X{ X return(where >= 0 && X where < db_top && X Typeof(where) == TYPE_ROOM && X (controls(who, where) || X (what == NOTYPE && X (Flag(where,LINK_OK|ABODE))) || X (what == TYPE_ROOM && X (Flag(where,ABODE))) || X (what == TYPE_EXIT && X (Flag(where,LINK_OK))) || X ((what == TYPE_PLAYER || what == TYPE_THING) && X#ifdef ROBOT_MODE X (what != TYPE_PLAYER || !Robot(who) || !Robot(where)) && X#endif ROBOT_MODE X Flag(where,ABODE)))); X } X X/* X * Check whether a player can perform an action...robotic players are X * now implicitly barred from performing actions on things with the X * robot flag set. 5/18/90 - Fuzzy X */ X Xint could_doit(dbref player, dbref thing) X{ X if(Typeof(thing) != TYPE_ROOM && db[thing].location == NOTHING) return 0; X X#ifdef ROBOT_MODE X if(Typeof(thing) != TYPE_PLAYER && Robot(player) && Robot(thing)) return 0; X if(Typeof(thing) == TYPE_EXIT && Robot(player) && X db[thing].location >= 0 && Robot(db[thing].location)) return 0; X#endif ROBOT_MODE X X return(eval_boolexp (player, db[thing].key)); X} X Xint can_doit(dbref player, dbref thing, const char *default_fail_msg) X{ X dbref loc; X char buf[BUFFER_LEN]; X X if((loc = getloc(player)) == NOTHING) return 0; X X if(!could_doit(player, thing)) { X /* can't do it */ X if(db[thing].fail_message) { X notify(player, db[thing].fail_message); X } else if(default_fail_msg) { X notify(player, default_fail_msg); X } X X if(db[thing].ofail && !Dark(player)) { X#ifdef GENDER X pronoun_substitute(buf, player, db[thing].ofail); X#else X sprintf(buf, "%s %s", db[player].name, db[thing].ofail); X#endif /* GENDER */ X notify_except(db[loc].contents, player, buf); X } X X return 0; X } else { X /* can do it */ X if(db[thing].succ_message) { X notify(player, db[thing].succ_message); X } X X if(db[thing].osuccess && !Dark(player)) { X#ifdef GENDER X pronoun_substitute(buf, player, db[thing].osuccess); X#else X sprintf(buf, "%s %s", db[player].name, db[thing].osuccess); X#endif /* GENDER */ X notify_except(db[loc].contents, player, buf); X } X X return 1; X } X} X Xint can_see(dbref player, dbref thing, int can_see_loc) X{ X if(player == thing || Typeof(thing) == TYPE_EXIT) { X return 0; X } else if(can_see_loc) { X return(!Dark(thing) || controls(player, thing)); X } else { X /* can't see loc */ X return(controls(player, thing)); X } X} X Xint controls(dbref who, dbref what) X{ X /* Wizard controls everything */ X /* owners control their stuff */ X return(what >= 0 X && what < db_top X && (Wizard(who) X || who == db[what].owner)); X} X Xint can_link(dbref who, dbref what) X{ X return((Typeof(what) == TYPE_EXIT && db[what].location == NOTHING) X || controls(who, what)); X} X Xint payfor(dbref who, int cost) X{ X if(Wizard(who)) { X return 1; X } else if(db[who].pennies >= cost) { X db[who].pennies -= cost; X return 1; X } else { X return 0; X } X} X Xint word_start (const char *str, const char let) X{ X int chk; X X for (chk = 1; *str; str++) { X if (chk && *str == let) return 1; X chk = *str == ' '; X } X return 0; X} X X Xint ok_name(const char *name) X{ X return (name X && *name X && *name != LOOKUP_TOKEN X && *name != NUMBER_TOKEN X && !index(name, ARG_DELIMITER) X && !index(name, AND_TOKEN) X && !index(name, OR_TOKEN) X && !word_start(name, NOT_TOKEN) X#ifdef NOFAKES X && string_compare(name, "A") X && string_compare(name, "An") X && string_compare(name, "The") X && string_compare(name, "You") X && string_compare(name, "Your") X && string_compare(name, "Going") X && string_compare(name, "Huh?") X#endif NOFAKES X && string_compare(name, "me") X && string_compare(name, "home") X && string_compare(name, "here")); X} X Xint ok_player_name(const char *name) X{ X const char *scan; X X if(!ok_name(name) || strlen(name) > PLAYER_NAME_LIMIT) return 0; X X for(scan = name; *scan; scan++) { X if(!(isprint(*scan) && !isspace(*scan))) { /* was isgraph(*scan) */ X return 0; X } X } X X /* lookup name to avoid conflicts */ X return (lookup_player(name) == NOTHING); X} X Xint ok_password(const char *password) X{ X const char *scan; X X if(*password == '\0') return 0; X X for(scan = password; *scan; scan++) { X if(!(isprint(*scan) && !isspace(*scan))) { X return 0; X } X } X X return 1; X} X X#ifdef GENDER X/* X * pronoun_substitute() X * X * %-type substitutions for pronouns X * X * %s/%S for subjective pronouns (he/she/it, He/She/It) X * %o/%O for objective pronouns (him/her/it, Him/Her/It) X * %p/%P for possessive pronouns (his/her/its, His/Her/Its) X * %n for the player's name. X */ Xvoid pronoun_substitute(char *result, dbref player, const char *str) X{ X char c; X X const static char *subjective[4] = { "", "it", "she", "he" }; X const static char *possessive[4] = { "", "its", "her", "his" }; X const static char *objective[4] = { "", "it", "her", "him" }; X X#ifdef COMPRESS X str = uncompress(str); X#endif /* COMPRESS */ X strcpy(result, db[player].name); X result += strlen(result); X *result++ = ' '; X while (*str) { X if(*str == '%') { X *result = '\0'; X c = *(++str); X if (Genderof(player) == GENDER_UNASSIGNED) { X switch(c) { X case 'n': X case 'N': X case 'o': X case 'O': X case 's': X case 'S': X strcat(result, db[player].name); X break; X case 'p': X case 'P': X strcat(result, db[player].name); X strcat(result, "'s"); X break; X default: X result[0] = *str; X result[1] = 0; X break; X } X str++; X result += strlen(result); X } else { X switch (c) { X case 's': X case 'S': X strcat(result, subjective[Genderof(player)]); X break; X case 'p': X case 'P': X strcat(result, possessive[Genderof(player)]); X break; X case 'o': X case 'O': X strcat(result, objective[Genderof(player)]); X break; X case 'n': X case 'N': X strcat(result, db[player].name); X break; X default: X *result = *str; X result[1] = '\0'; X break; X } X if(isupper(c) && islower(*result)) { X *result = toupper(*result); X } X X result += strlen(result); X str++; X } X } else { X *result++ = *str++; X } X } X *result = '\0'; X} X X#endif /* GENDER */ END_OF_FILE if test 6557 -ne `wc -c <'predicates.c'`; then echo shar: \"'predicates.c'\" unpacked with wrong size! fi # end of 'predicates.c' fi if test -f 'speech.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'speech.c'\" else echo shar: Extracting \"'speech.c'\" \(5423 characters\) sed "s/^X//" >'speech.c' <<'END_OF_FILE' X#include "copyright.h" X X/* Commands which involve speaking */ X X#include "db.h" X#include "interface.h" X#include "match.h" X#include "config.h" X#include "externs.h" X X/* this function is a kludge for regenerating messages split by '=' */ Xconst char *reconstruct_message(const char *arg1, const char *arg2) X{ X static char buf[BUFFER_LEN]; X X if(arg2 && *arg2) { X strcpy(buf, arg1); X strcat(buf, " = "); X strcat(buf, arg2); X return buf; X } else { X return arg1; X } X} X Xvoid do_say(dbref player, const char *arg1, const char *arg2) X{ X dbref loc; X const char *message; X char buf[BUFFER_LEN]; X X if((loc = getloc(player)) == NOTHING) return; X X message = reconstruct_message(arg1, arg2); X X /* notify everybody */ X sprintf(buf, "You say \"%s\"", message); X notify(player, buf); X sprintf(buf, "%s says \"%s\"", db[player].name, message); X notify_except(db[loc].contents, player, buf); X} X Xvoid do_whisper(dbref player, const char *arg1, const char *arg2) X{ X#ifndef QUIET_WHISPER X dbref loc; X#endif QUIET_WHISPER X dbref who; X char buf[BUFFER_LEN]; X char *det; X int result; X X init_match(player, arg1, TYPE_PLAYER); X match_neighbor(); X match_me(); X if(Wizard(player)) { X match_absolute(); X match_player(); X } X switch(who = match_result()) { X case NOTHING: X notify(player, "Whisper to whom?"); X break; X case AMBIGUOUS: X notify(player, "I don't know who you mean!"); X break; X default: X if (Typeof(who) == TYPE_PLAYER) { X sprintf(buf, "%s whispers \"%s\"", db[player].name, arg2); X if (notify(who, buf)) { X sprintf(buf, "You whisper \"%s\" to %s.", arg2, db[who].name); X notify(player, buf); X#ifndef QUIET_WHISPER X sprintf(buf, "%s whispers something to %s.", X db[player].name, db[who].name); X if((loc = getloc(player)) != NOTHING) { X notify_except2(db[loc].contents, player, who, buf); X } X#endif /* QUIET_WHISPER */ X } X else X notify(player, "That person is not connected."); X } else { X if (string_prefix (db[who].name, "a ") || X string_prefix (db[who].name, "an ") || X string_prefix (db[who].name, "the ") || X string_prefix (db[who].name, "some ")) { X det = ""; X } else if (lookup_player (db[who].name) != NOTHING) { X det = "the thing called "; X } else { X det = "the "; X } X sprintf(buf, "You feel silly about whispering to %s%s.", X det, db[who].name); X notify(player, buf); X } X break; X } X} X Xvoid do_pose(dbref player, const char *arg1, const char *arg2) X{ X dbref loc; X const char *message; X char buf[BUFFER_LEN]; X X if((loc = getloc(player)) == NOTHING) return; X X message = reconstruct_message(arg1, arg2); X X /* notify everybody */ X sprintf(buf, "%s %s", db[player].name, message); X notify_except(db[loc].contents, NOTHING, buf); X} X Xvoid do_wall(dbref player, const char *arg1, const char *arg2) X{ X dbref i; X const char *message; X char buf[512]; X X message = reconstruct_message(arg1, arg2); X if(Wizard(player)) { X writelog("WALL from %s(%d): %s\n", X db[player].name, player, message); X sprintf(buf, "%s shouts \"%s\"", db[player].name, message); X for(i = 0; i < db_top; i++) { X if(Typeof(i) == TYPE_PLAYER) { X notify(i, buf); X } X } X } else { X notify(player, "But what do you want to do with the wall?"); X } X} X Xvoid do_gripe(dbref player, const char *arg1, const char *arg2) X{ X dbref loc; X const char *message; X X loc = db[player].location; X message = reconstruct_message(arg1, arg2); X writelog("GRIPE from %s(%d) in %s(%d): %s\n", X db[player].name, player, X db[loc].name, loc, X message); X fflush(stderr); X X#ifdef GOD_PRIV X /* try telling GOD about it */ X if (!Flag(GOD,HAVEN)) { X char buf[BUFFER_LEN]; X sprintf(buf, "%s gripes: \"%s\"", X unparse_object(GOD, player), message); X notify(GOD, buf); X } X#endif GOD_PRIV X X notify(player, "Your complaint has been duly noted."); X} X X/* doesn't really belong here, but I couldn't figure out where else */ Xvoid do_page(dbref player, const char *arg1, const char *arg2) X{ X char buf[BUFFER_LEN]; X dbref target; X int result; X X if(!payfor(player, PAGE_COST)) { X notify(player, "You don't have enough pennies."); X } else if((target = lookup_player(arg1)) == NOTHING) { X notify(player, "I don't recognize that name."); X } else if (db[target].flags & HAVEN) { X notify(player, "That player is not accepting pages."); X } else if (arg2 && *arg2) { X sprintf(buf, "%s pages: %s", db[player].name, arg2); X result = notify(target, buf); X if (result) X notify(player, "Your message has been sent."); X else X notify(player, "That person is not connected."); X } else { X sprintf(buf, "You sense that %s is looking for you in %s.", X db[player].name, db[db[player].location].name); X result = notify(target, buf); X if (result) X notify(player, "Your message has been sent."); X else X notify(player, "That person is not connected."); X } X} X Xvoid notify_except(dbref first, dbref exception, const char *msg) X{ X DOLIST (first, first) { X if ((db[first].flags & TYPE_MASK) == TYPE_PLAYER X && first != exception) { X notify (first, msg); X } X } X} X Xvoid notify_except2(dbref first, dbref exc1, dbref exc2, const char *msg) X{ X DOLIST (first, first) { X if ((db[first].flags & TYPE_MASK) == TYPE_PLAYER X && first != exc1 X && first != exc2) { X notify (first, msg); X } X } X} END_OF_FILE if test 5423 -ne `wc -c <'speech.c'`; then echo shar: \"'speech.c'\" unpacked with wrong size! fi # end of 'speech.c' fi echo shar: End of archive 9 \(of 10\). cp /dev/null ark9isdone 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