/**************************************************************** * robot.c: Common robot code for TinyMUD automata * * HISTORY * 22-Dec-90 Michael Mauldin (mlm) at Carnegie-Mellon University * Mods for TinyMUCK, Brigadoon. * * 29-Nov-90 Michael Mauldin (mlm) at Carnegie-Mellon University * Eleventh remedial release. * Mods for DragonMud, especially visible exits. * * 19-Sep-90 Michael Mauldin (mlm) at Carnegie-Mellon University * Ninth official release. * Mods for TinyHELL, especially paged messages. * * 05-May-90 Michael Mauldin (mlm) at Carnegie-Mellon University * Seventh sequential release. * Mods for TinyHELL, especially paged messages. * * 27-Mar-90 Michael Mauldin (mlm) at Carnegie-Mellon University * Handle new WHO format. * * 26-Feb-90 Michael Mauldin (mlm) at Carnegie-Mellon University * Sixth experimental release. Changed file formats, added lots * of info to room memory. Found a memory allocation bug. * * 10-Feb-90 Michael Mauldin (mlm) at Carnegie-Mellon University * Fifth special release (deal with WHO suffix/prefix mismatch * between TinyMUD and TinyHELL) * * 09-Jan-90 Michael Mauldin (mlm) at Carnegie-Mellon University * Fourth general release (save room contents, trap ignore) * * 25-Jan-90 Michael Mauldin (mlm) at Carnegie-Mellon University * Third interim release (allow numeric IP addresses) * * 05-Jan-90 Michael Mauldin (mlm) at Carnegie-Mellon University * Second General Release. * * 31-Dec-89 Michael Mauldin (mlm) at Carnegie-Mellon University * Created. ****************************************************************/ # include <stdio.h> # include <ctype.h> # include <sys/types.h> # include <sys/time.h> # include <sys/ioctl.h> # include <sys/socket.h> # include <setjmp.h> # include <netinet/in.h> # include <netdb.h> # include <ctype.h> # include <varargs.h> # include "robot.h" # define HUH1 "Huh? (Type \"help\" for help.)" # define HUH2 "You're NOT _IN_ a PROGRAM!!!" # define OUTPUTPREFIX "<<norm" # define OUTPUTSUFFIX ">>norm" # define MOVEPREFIX "<<move" # define MOVESUFFIX ">>move" # define LOOKPREFIX "<<look" # define LOOKSUFFIX ">>look" # define SCRPREFIX "<<score" # define SCRSUFFIX ">>score" # define PAGEPREFIX "<<page" # define PAGESUFFIX ">>page" # define WHOPREFIX "<<who" # define WHOSUFFIX ">>who" # define NUMBPREFIX "<<numb" # define NUMBSUFFIX ">>numb" # define PLYPREFIX "<<player" # define PLYSUFFIX ">>player" # define MINPEN 100 # define MAXPEN 300 # define READ 0 # define WRITE 1 int fmud, tmud; int flisp, tlisp; long debug=0, testing=0, terse=0, usedesc=0, quiet=1, debug_conv=0; long playing = 1, dead = 0, hanging = 0, pgoal = 0; long speed = 5, generous = 0, exploring = 0, vindictive = 0; long realmsg = 1, visitold = 1; /*---- Variables for recording memory usage ----*/ long string_sp = 0; long string_ct = 0; long exit_sp = 0; long exit_ct = 0; long player_sp = 0; long room_sp = 0; long path_sp = 0; long dialog_sp = 0; long dialog_ct = 0; long msgs_sp = 0; long freed = 0; /* Prefixes and suffixes */ char *opre = "OUTPUTPREFIX"; char *osuf = "OUTPUTSUFFIX"; char outpre[SMABUF]; char outsuf[SMABUF]; char movpre[SMABUF]; char movsuf[SMABUF]; char loopre[SMABUF]; char loosuf[SMABUF]; char whopre[SMABUF]; char whosuf[SMABUF]; char scrpre[SMABUF]; char scrsuf[SMABUF]; char pagpre[SMABUF]; char pagsuf[SMABUF]; char numpre[SMABUF]; char numsuf[SMABUF]; char plypre[SMABUF]; char plysuf[SMABUF]; char code[64] = ""; char *codeword(), *add_name(); long codeset = 0; char plname[MSGSIZ] = "Judge"; /* Results from star matcher */ extern char res1[], res2[], res3[], res4[]; extern char res5[], res6[], res7[], res8[]; extern char *result[]; extern char room1[], room2[], room3[], room4[]; extern char *roomstr[]; extern char tmp1[], tmp2[], tmp3[], tmp4[]; extern char tmp5[], tmp6[], tmp7[], tmp8[]; extern char *tmpstr[]; O_ROOM *room = NULL; PATH *path = NULL; long rooms = 0, maxrooms = 0; long lastrm = 0, exits = 0; char *stexits[] = { "north", "south", "east", "west", "n", "s", "e", "w", "ne", "nw", "se", "sw", "nne", "nnw", "ene", "wnw", "sse", "ssw", "ese", "wsw", "nn", "ss", "ee", "ww", "nnn", "www", "eee", "sss", "in", "out", "leave", "back", "up", "down", "left", "right", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "open", "close", "rec", "cw", "ccw", "wait", "move around", "look around", "door", "arch", "port", "starboard", "fore", "aft", "sideways", NULL }; long numexits = (sizeof (stexits) / sizeof (*stexits)) - 1; char *mname[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; char typecmd[TOKSIZ]; PLAYER *player; long players = 0, maxplayer = 0; char glasthere[TOKSIZ] = "", glastdir[TOKSIZ] = ""; long glastrm = -1; char *modestr[] = { "NORMAL", "MOVE", "WHO", "PAGE", "LOOK", "SCORE", "NUMBER", "COMMAND", "PLAYER" }; /*-------- Current statistics --------*/ char world[MSGSIZ] = "unknown"; long msgtype = M_ACTION; long pagedmsgs = 0; char mydesc[MSGSIZ]; long mlnum = -1; long pennies = 0; long objs = 0; long gave = -1; long msgstat = 0; /* 0=no msg, 1=success, -1=failed */ long needpsynch = 0; char killer[MSGSIZ] = ""; char speaker[MSGSIZ] = ""; char postcmd[BUFSIZ] = ""; char here[TOKSIZ] = ""; char desc[TOKSIZ] = ""; char contents[BIGBUF] = ""; char exlist[MSGSIZ] = ""; char herald[MSGSIZ] = ""; long heraldtime = 0; long heraldpriority = 0; long hererm = -1; long hereid = -1; long hereispl = 0; long recrm = -1; char home[TOKSIZ] = ""; char homedesc[TOKSIZ] = ""; long homerm = -1; char move1[TOKSIZ] = ""; char move2[TOKSIZ] = ""; char move3[TOKSIZ] = ""; char move4[TOKSIZ] = ""; char pathto[TOKSIZ] = ""; long pagedfrom = -1; long pagedto = -1; char pagedby[MSGSIZ] = ""; long pagedat = 0; long now = 0; long mode = NORMAL; long doing_works = 0; long speaktime = 0; long me = -1; long alone = 0; long awake = 0; long atdesk = 0; long inmove = 0; long confused = 0; long inwsynch = 0; long lastwsynch = 0; long naked = 0; long incontents = 0; long checkfreq = 60 * MINUTES; long lastcheck = 0; long newrooms = 0; long newexits = 0; long printedloc = 0; long paging = 0; long nextwait = 120; long takingnotes = 0; long playinghearts = 0; long lastheartsplay = 0; long first_turn = 1; long meetingroom = -1; long termwarn = 0; long termtarg = -1; long termat = 0; char termloc[MSGSIZ] = ""; char thief[MSGSIZ] = ""; long lastlock = 0; char lastobj[MSGSIZ] = ""; extern long contest_mode; extern long tty_interface; /*---- Variables for maintaining RM_REACH flags ----*/ long reach_added = 0; long reach_changed = 0; /*-------- Configuration Variables --------*/ long male = 0; char *myname = NULL; long creation = 0; char *owner = NULL; char *whoami = NULL; char *mudhost = NULL; char *lisphost = NULL; long mudport = 0; char *mapfile = NULL; char *plyfile = NULL; long statuscmd = 0; long pagecmd = 0; long posecmd = 0; long scorecmd = 0; long ismuck = 0; long trusting = 0; long doecho = 1; extern long fasttype; jmp_buf start_state; /**************************************************************** * Main routine ****************************************************************/ # define SKIPARG while (*++(*argv)); --(*argv) main (argc, argv) int argc; char *argv[]; { char *pname = argv[0]; char logname[256]; struct tm *t; char *program = argv[0]; if (streq (argv[0], "-contest")) { doecho = 0; } /* Get the options from the command line */ while (--argc > 0 && (*++argv)[0] == '-') { while (*++(*argv)) { switch (**argv) { case 'H': mudhost = *argv+1; SKIPARG; break; case 'L': lisphost = *argv+1; SKIPARG; break; case 'P': mudport = atol (*argv+1); SKIPARG; break; case 'M': mapfile = *argv+1; SKIPARG; break; case 'F': plyfile = *argv+1; SKIPARG; break; case 'E': doecho = 0; break; case 'S': speed = atol (*argv+1); SKIPARG; break; case 'f': fasttype++; break; case 'c': contest_mode = 0; break; case 'C': tty_interface = 0; break; case 'T': testing++; break; case 'd': debug++; break; case 'n': quiet=0; break; case 'D': usedesc++; break; case 'e': exploring++; break; case 'g': generous++; break; case 'p': paging++; break; case 't': terse++; break; case 'v': vindictive++; break; case 'V': visitold = 0; break; default: fprintf (stderr, "Usage: %s [ options ]\n\n", pname); fprintf (stderr, " -d debug\n"); fprintf (stderr, " -e exploring\n"); fprintf (stderr, " -g generous\n"); fprintf (stderr, " -p paging\n"); fprintf (stderr, " -t terse\n"); fprintf (stderr, " -v vindictive\n"); fprintf (stderr, " -V no visit old\n"); fprintf (stderr, " -D use descriptions for exits\n"); fprintf (stderr, " -C contest mode on\n"); fprintf (stderr, " -T testing (connect to stdin/stdout)\n\n"); fprintf (stderr, " -H'host' Host to connect to game\n"); fprintf (stderr, " -P<port> Port number\n"); fprintf (stderr, " -M'mapfile' Map file name\n"); fprintf (stderr, " -F'playfile' File for player information\n"); exit (1); } } } /* If running directly on terminal, put stderr elsewhere */ if (tty_interface) { /* Pick unique log file name */ now = time (0); t = localtime (&now); sprintf (logname, "log.%02d%02d.%02d%02d", t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min); if (access (logname, 0) == 0) { int ver = 'a'; do { sprintf (logname, "log.%02d%02d.%02d%02d%c", t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, ver++); } while (access (logname, 0) == 0); } umask (0); freopen (logname, "a", stderr); } fprintf (stderr, "Running program %s\n", program); setconfig (); if (testing || tty_interface) { tmud = 1; fmud = 0; } else { tmud = fmud = connectmud (); } if (tmud < 0) { now = time (0); fprintf (stderr,"Connect failed at %15.15s\n", ctime (&now)+4); exit (-1); } /* For Loebner contest, open connection to Lisp process */ # ifdef DO_LISP if (contest_mode) { tlisp = flisp = connectlisp (); if (tty_interface) { printf ("[ %s ]\r\n", (tlisp >= 0) ? "Lisp based talk program" : "C based talk program..."); } } else # endif { tlisp = flisp = -1; } /* Start random generator */ srand (time (0) + 40169 * getpid () + 58741 * getuid ()); init_prefix (); lastcheck = now = time (0); robot (); now = time (0); fprintf (stderr, "\nReturned from Robot main program at %15.15s.\n", ctime (&now) + 4); quit_robot (); } /**************************************************************** * lsynch: Guarantee room direction by paging ****************************************************************/ lsynch () { if (debug) fprintf (stderr, "In lsynch()...\n"); pennies--; sendmud ("%s %s\npage %s\n%s %s", opre, pagpre, myname, opre, outpre); waitfor (outsuf); } /**************************************************************** * psynch: Simple sync for stationary commands ****************************************************************/ psynch () { if (debug) fprintf (stderr, "In psynch()...\n"); if (ismuck && scorecmd) { sendmud ("%s %s\n#%d\n%s %s", opre, scrpre, scorecmd, opre, outpre); } else { sendmud ("%s %s\nscore\n%s %s", opre, scrpre, opre, outpre); } waitfor (outsuf); needpsynch = 0; } /**************************************************************** * usynch: Simple sync for number of objects ****************************************************************/ usynch () { if (debug) fprintf (stderr, "In usynch()...\n"); sendmud ("%s %s\n@stats = 0\n%s %s", opre, scrpre, opre, outpre); waitfor (outsuf); } /**************************************************************** * msynch: Complex sync for moving commands commands ****************************************************************/ msynch () { if (debug) fprintf (stderr, "In msynch()...\n"); if (ismuck && statuscmd) { sendmud ("%s %s\n#%d\n%s %s", opre, loopre, statuscmd, opre, outpre); } else { sendmud ("%s %s\nlook\n%s %s", opre, loopre, opre, outpre); } waitfor (outsuf); } /**************************************************************** * wsynch: Complex sync for moving commands commands ****************************************************************/ wsynch () { if (debug) fprintf (stderr, "In wsynch()...\n"); inwsynch++; sendmud ("%s %s\n%sWHO\n%s %s", opre, whopre, streq (world, "HoloMuck") ? "!" : "", opre, outpre); waitfor (outsuf); inwsynch--; lastwsynch = now; if (me >= 0) player[me].active = player[me].present = 0; } /**************************************************************** * waitfor: ****************************************************************/ waitfor (pat) char *pat; { char *msg; long start = time (0); while (1) { if (msg = getmud ()) { procmsg (msg); if (stlmatch (msg, pat)) return (1); if (streq (pat, "Welcome to ") && sindex (msg, "Mail sjade")) return(1); if (streq (pat, "Welcome to ") && sindex (msg, "> Welcome to")) return(1); /* Reset dead man timer */ start = now = time (0); } else { /* Check timer, if 10 minutes since last IO, timeout */ if ((now = time (0)) > start + 10 * MINUTES) { fprintf (stderr, "%s(%s) after %s, here '%s', %s '%s'(%d), lastdir '%s'\n", "Quit: timed out in waitfor", pat, exact_dur (now-start), here, "lasthere", glasthere, glastrm, glastdir); lost_connect (pat, now-start); quit_robot (); } sleep (1); } } } /**************************************************************** * hangaround: Wait here a specified number of seconds, but * keep processing incoming messages; ****************************************************************/ hangaround (sec) long sec; { char *msg; long alarm; long tick=0; if (*typecmd) sec = 1; alarm = time (0) + sec; hanging = 1; if (!terse && sec > speed) { fprintf (stderr, "Hang: %ld seconds\n", sec); } while (1) { while (msg = getmud ()) { procmsg (msg); } if ((now = time (0)) >= alarm || dead || !hanging) break; sleep (1); if (tick++ > 10) { do_msgs(); tick = 0; } } return (1); } /**************************************************************** * quit_robot: We are exiting. Write out any long term memory first. ****************************************************************/ quit_robot () { close (tmud); checkpoint (); now = time (0); fprintf (stderr, "Quit: %s quitting at %15.15s\n", myname, ctime (&now)+4); exit (0); } /**************************************************************** * connectmud: Open the MUD socket ****************************************************************/ connectmud() { struct sockaddr_in sin; struct hostent *hp; int fd; if (debug) { fprintf (stderr, "Connecting to %s, port %ld...\n", mudhost, mudport); } bzero((char *) &sin, sizeof(sin)); sin.sin_port = htons(mudport); /* Handle numeric or host name addresses */ if (isdigit (*mudhost)) { sin.sin_addr.s_addr = inet_addr (mudhost); sin.sin_family = AF_INET; } else { if ((hp = gethostbyname(mudhost)) == 0) return (-1); bcopy(hp->h_addr, (char *) &sin.sin_addr, hp->h_length); sin.sin_family = hp->h_addrtype; } fd = socket(AF_INET, SOCK_STREAM, 0); if (fd < 0) return -1; if (connect(fd,(struct sockaddr *) &sin, sizeof(sin)) < 0) return -1; return fd; } /**************************************************************** * sendmud: Send a command to the TinyMUD process * * WARNING: possible 16/32 bit int problems here - fuzzy ****************************************************************/ sendmud (fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) char *fmt; int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10; { int len; char buf[BIGBUF], *sindex(); register char *s; static int hcnt = 0; if (!fmt) crash_robot ("Null fmt in sendmud"); sprintf (buf, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); strcat (buf, "\n"); len = strlen (buf); /* Log sends */ if (debug) { fprintf (stderr, "\nSend: "); for (s=buf; *s; s++) fputc ((*s == '\n' ? '|' : *s), stderr); fprintf (stderr, "\n\n"); } else if (!terse) { int comma = 0; fprintf (stderr, "Send: "); for (s=buf; *s; s++) { if (stlmatch (s, "OUTPUT")) { while (*s && s[0] != '\n') s++; } else if (*s == '\n') { comma++; } else { if (comma) fprintf (stderr, ", "); comma=0; fputc (*s, stderr); } } fprintf (stderr, "\n"); } if (tty_interface) { fakeprint (buf); } else { if (write (tmud, buf, len) != len) { fprintf (stderr, "Write failed: %s", buf); quit_robot (); } } fflush (stderr); } /**************************************************************** * command: Send a command to Tinymud and wait for the response * * WARNING: possible 16/32 bit int problems here - fuzzy ****************************************************************/ command (fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) char *fmt; int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10; { static cmdlevel = 0; char buf[BIGBUF]; sprintf (buf, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); if (debug || cmdlevel) { fprintf (stderr, "Cmnd: level %ld\n", ++cmdlevel); } sendmud ("%s", buf); if (!tty_interface) waitfor (outsuf); if (debug || cmdlevel > 1) { fprintf (stderr, "Ackn: level %ld\n", cmdlevel--); } fflush (stderr); } /**************************************************************** * movemud: Send a movement command to the TinyMUD process ****************************************************************/ movemud (dirstr) char *dirstr; { long len; char buf[BIGBUF], insert[BUFSIZ], lasthere[MSGSIZ], lastdesc[TOKSIZ]; char dir[MSGSIZ]; static char lbuf[128]; long oldrm = -1, waspl = 0; long wenthome = 0; char *lcmd, *wstr = outsuf; static long entered = 0; register long pl; if (!isprint (*dirstr)) { crash_robot ("Bogus direction in movemud, first char was %03o\n", *dirstr); } # ifdef MAP_NEWS if (strfoldeq (world, "Time Traveller") && strfoldeq (dirstr, "news")) { dirstr = "read"; add_exit (hererm, dir, hererm); } # endif strcpy (dir, dirstr); if (debug) { fprintf (stderr, "In movemud(%s), here is '%s'\n", dir, here); } /*---- Set post move command ----*/ if (ismuck && statuscmd && streq (world, "HoloMuck")) { lcmd = sprintf (lbuf, "pgm10823"); } else if (ismuck && streq (world, "HoloMuck")) { lcmd = sprintf (lbuf, "#2735"); } else if (ismuck && statuscmd) { lcmd = sprintf (lbuf, "#%d", statuscmd); } else { lcmd = "look"; } /*---- Build an atomic prefix/suffix/move command ----*/ /* Build a suffix command */ if (*postcmd) { sprintf (insert, "%s\n%s\n%s\n", opre, osuf, postcmd); } else { strcpy (insert, ""); } if (ismuck) { if (streq (dir, "home")) { sprintf (buf, "%s\n%s\n%s\n%s %s\nhome\n%s %s\n%s %s\n%s\n%s%s %s\n%s %s", opre, osuf, randint (100) < 50 ? "@q" : "@q\n@q", opre, movpre, osuf, movsuf, opre, loopre, lcmd, insert, opre, outpre, osuf, outsuf); wenthome++; } else { sprintf (buf, "%s %s\ngo %s\n%s\n%s\n%s\n%s %s\n%s %s\n%s\n%s%s %s\n%s %s", opre, movpre, dir, opre, osuf, randint (100) < 50 ? "@q" : "@q\n@q", osuf, movsuf, opre, loopre, lcmd, insert, opre, outpre, osuf, outsuf); } } else { if (streq (dir, "home")) { sprintf (buf, "%s %s\nhome\n%s %s\n%s %s\n%s\n%s%s %s\n%s %s", opre, movpre, osuf, movsuf, opre, loopre, lcmd, insert, opre, outpre, osuf, outsuf); wenthome++; } else { sprintf (buf, "%s %s\ngo %s\n%s %s\n%s %s\n%s\n%s%s %s\n%s %s", opre, movpre, dir, osuf, movsuf, opre, loopre, lcmd, insert, opre, outpre, osuf, outsuf); } } /* Actions upon leaving a room */ before_move_hook (); /* Actually send the MOVE command */ if (debug) fprintf (stderr, "Move: %s\n", dir); strcpy (lasthere, here); strcpy (glasthere, here); strcpy (glastdir, dir); strcpy (lastdesc, desc); oldrm = hererm; glastrm = hererm; waspl = hereispl; len = strlen (buf); strcpy (here, ""); strcpy (desc, ""); hereid = -1; inmove++; sendmud ("%s", buf); waitfor (movsuf); while (*here == '\0') { int tries = 0; debug++; fprintf (stderr, "Here: After look %d, here '%s', desc '%s'\n", ++tries, here, desc); if (!ismuck || tries >= 10) { crash_robot ("Can't find current room after %d tries.", tries); } sprintf (buf, "%s\n%s\n%s\n%s %s\n%s %s\n%s\n%s %s\n%s %s", opre, osuf, randint (100) < 50 ? "@q" : "@q\n@q", osuf, movsuf, opre, loopre, lcmd, opre, outpre, osuf, outsuf); sendmud ("%s", buf); waitfor (movsuf); debug--; } inmove--; confused = 0; /*---- Determine where we think we are, match MOVE and LOOK output ----*/ if (ismuck) { /* Everything is okay */ if (*here == '\0') { crash_robot ("After loop, could not exit MUF program."); } } /* If LOOK matches first line, everything is cool */ else if (streq (move1, here)) { if (debug) fprintf (stderr, "Okay: move matches look '%s'\n", move1); } /* If LOOK matches second line, everything is still cool */ else if (streq (move2, here)) { if (debug) fprintf (stderr, "Okay: had @su message '%s'\n", move1); } /* If LOOK matches third line, everything is still cool */ else if (streq (move3, here)) { if (debug) { fprintf (stderr, "Okay: had @su messages '%s' & '%s'\n", move1, move2); } } /* If MOVE1 is fail message, then we are probably in the same place */ else if (streq (move1, "You can't go that way.")) { if (debug) { fprintf (stderr, "Okay: didn't move, got error '%s'\n", move1); } } /* If here is eq to LASTHERE, we are in the same place */ else if (streq (here, lasthere)) { if (debug) { fprintf (stderr, "Okay: didn't move, got error '%s'\n", move1); } } /* Trouble: LOOK and MOVE gave different messages */ else { /* Page myself to find out where I really am */ if (pennies > 10) { lsynch (); fprintf (stderr, "Conf: Lsynch returns '%s'\n", here); } fprintf (stderr, "Conf: confusing room, don't believe exit\n"); confused++; } /* Handle confusing rooms by cowardice */ if (confused) { if (wenthome) { fprintf (stderr, "Conf: confused after going home, quitting.\n"); quit_robot (); } else if (!dead) { /* Must mark exit as used, to avoid infinite loops */ fprintf (stderr, "Conf: erasing exit '%s' from room %s(%d)\n", dir, room_name (oldrm), oldrm); add_exit (oldrm, dir, oldrm); } else { /* Must mark exit as used, to avoid infinite loops */ fprintf (stderr, "Dead: would have erased exit '%s' from room %s(%d)\n", dir, room_name (oldrm), oldrm); } *lasthere = '\0'; hererm = -1; *here = '\0'; if (!dead) { fprintf (stderr, "Conf: going home from '%s'(%ld)\n", here, hererm); movemud ("home"); } return; } /* Set current location: special for rec room */ if (streq (world, "TinyMUD Classic") && oldrm == homerm && recrm >= 0 && streq (dir, "rec")) { long roomnum; hererm = recrm; /* Strip off room number from name */ if (smatch (here, "* (#*)", roomstr) && isdigit (*room2)) { roomnum = atoi (room2); } else if (smatch (here, "*(#*)", roomstr) && isdigit (*room2)) { roomnum = atoi (room2); } else { strcpy (room1, here); roomnum = -1; } /* Check for name change */ if (!streq (room[hererm].name, room1)) { fprintf (stderr, "Warn: Changing room name '%s' to '%s' (%ld)\n", room[hererm].name, room1, hererm); freestring (room[hererm].name); room[hererm].name = makestring (room1); } /* Check for desc change */ if (desc && (!room[hererm].desc || !streq (room[hererm].desc, desc))) { fprintf (stderr, "Warn: Changing room desc for %s from '%s' to '%s' (%ld)\n", room[hererm].name, room[hererm].desc, desc, hererm); freestring (room[hererm].desc); room[hererm].desc = makestring (desc); } /* Check for number change */ if (room[hererm].number < 0 && roomnum >= 0) room[hererm].number = roomnum; } else { hererm = add_room (here, desc); } /* Cant add new room? Crash */ if (hererm < 0) { crash_robot ("Bad room returned from add_room(\"%s\", \"%s\") -> %d\n", *here ? here : "(null)", *desc ? desc : "(null)", hererm); } /* Now set room times */ room[hererm].lastin = now = time (0); /* If we think we found a penny, must do a psynch */ if (needpsynch) psynch (); /* No matter what we did, add the exit to our map */ if (!confused && *here && *lasthere && !wenthome) { if (hereispl) { fprintf (stderr, "Warn: ignoring exit '%s' from %s(%d) to player %s(%d)\n", dir, room_name (oldrm), oldrm, room_name (hererm), hererm); add_exit (oldrm, dir, oldrm); } else if (waspl) { fprintf (stderr, "Warn: ignoring exit '%s' from player %s(%d) to %s(%d)\n", dir, room_name (oldrm), oldrm, room_name (hererm), hererm); add_exit (oldrm, dir, oldrm); } else { add_exit (oldrm, dir, hererm); } } /* Handle home room changing somehow */ if (wenthome && hererm != homerm) { if (homerm >= 0) { fprintf (stderr, "Home: uh oh... home went to '%s'(%ld), not '%s'(%ld)\n", here, hererm, home, homerm); } strcpy (home, here); strcpy (homedesc, desc); homerm = hererm; } /* Set room contents */ if (*contents) { if (room[hererm].contents) { freestring (room[hererm].contents); } room[hererm].contents = makestring (contents); } else if (room[hererm].contents) { freestring (room[hererm].contents); room[hererm].contents = NULL; } /* Set room exits */ if (*exlist) { if (room[hererm].exlist) { freestring (room[hererm].exlist); } room[hererm].exlist = makestring (exlist); } else if (room[hererm].exlist) { freestring (room[hererm].exlist); room[hererm].exlist = NULL; } /* If we went home, call home_hook */ if (wenthome) home_hook (); /* If we queued any messages during the move, process them */ procmsg (NULL); /* Actions after sending a move command (may still be in old room) */ after_move_hook (); /* If we ARE in a new room, perform new room actions */ if (hererm != oldrm) { printedloc = 0; # ifdef VERBOSE_TERSE if (terse) { fprintf (stderr, "Move: <%s> to %s(%ld)\n", dir, room_name (hererm), hererm); } # endif /* Track total visits to this room, total time in old room */ if (hererm >= 0) room[hererm].cntin++; if (entered && oldrm >= 0) { room[oldrm].totalin += (now - entered); } entered = now; /* Count players present */ player[me].active = player[me].present = 0; for (pl = 0, alone = 0; pl<players; pl++) { if (player[pl].present) { if (player[pl].active) { alone++; room[hererm].awakesum++; } else { room[hererm].sleepsum++; } } } new_room_hook (); } } /**************************************************************** * reply: Send and echo a command * * WARNING: possible 16/32 bit int problems here - fuzzy ****************************************************************/ reply (fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) char *fmt; int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10; { int len; long pl; char buf[BIGBUF], cmd[BIGBUF]; register char *s; char *ntype = "Rply"; /* Log our reply */ if (!printedloc) print_locn (); sprintf (buf, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); s = (*buf == '"') ? buf+1 : buf; if (*speaker && (pl = find_player (speaker)) >= 0 && (now - player[pl].firstsaw) < 3 * DAYS) { ntype = "NewR"; } if (*speaker && (pl = find_player (speaker)) >= 0 && sindex (buf, "{")) { strcpy (buf, add_name (buf)); } if (terse && msgtype > M_SPOKEN && *speaker) { fprintf (stderr, "%s: [%c to %s] %s\n", ntype, MTYPESTR[msgtype], speaker, s); } else if (terse) { fprintf (stderr, "%s: %s\n", ntype, s); } /* Various commands */ if (*buf == '"') { switch (msgtype) { /* Basic case: say the command using '"' */ case M_UNKNOWN: case M_ACTION: case M_SPOKEN: send_say (buf+1); break; /* Whisper: whisper back */ case M_WHISPER: if (*speaker) send_whisper (speaker, buf+1); break; /* Page, shout: page a message back (1.5.4 & later) */ case M_PAGE: case M_SHOUT: if (*speaker) send_page (speaker, buf+1); break; } } else if (*buf == ':' || *buf == '|') { switch (msgtype) { /* Basic case: perform the action using ':' */ case M_UNKNOWN: case M_ACTION: case M_SPOKEN: send_pose (buf+1); break; /* Whisper: whisper back */ case M_WHISPER: if (index (buf+1, ':') || !isalpha (buf[1]) || *buf == '|') { if (*speaker) send_whisper (speaker, buf+1); } else { sprintf (cmd, "%s %s", myname, buf+1); if (*speaker) send_whisper (speaker, cmd); } break; /* Page, shout: page a message back (1.5.4 & later) */ case M_PAGE: case M_SHOUT: if (index (buf+1, ':') || !isalpha (buf[1]) || *buf == '|') { if (!buf[1]) { if (*speaker) send_page (speaker, "."); } else { if (*speaker) send_page (speaker, buf+1); } } else { sprintf (cmd, "%s %s", myname, buf+1); if (*speaker) send_page (speaker, cmd); } break; } } /* Not a say/pose/whisper/page */ else if (*buf != '"' && *buf != ':') { command ("%s", buf); } } /**************************************************************** * unlogged: Like reply, but dont log the command * * WARNING: possible 16/32 bit int problems here - fuzzy ****************************************************************/ unlogged (fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) char *fmt; int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10; { int len; char buf[BIGBUF], cmd[BIGBUF]; register char *s; long pl; sprintf (buf, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); s = (*buf == '"') ? buf+1 : buf; /* Various commands */ if (*buf == '"') { if (*speaker && (pl = find_player (speaker)) >= 0 && sindex (buf, "{")) { strcpy (buf, add_name (buf)); } switch (msgtype) { /* Basic case: say the command using '"' */ case M_UNKNOWN: case M_ACTION: case M_SPOKEN: send_say (buf+1); break; /* Whisper: whisper back */ case M_WHISPER: if (*speaker) send_whisper (speaker, buf+1); break; /* Page, shout: page a message back (1.5.4 & later) */ case M_PAGE: case M_SHOUT: if (*speaker) send_page (speaker, buf+1); break; } } else if (*buf == ':' || *buf == '|') { switch (msgtype) { /* Basic case: perform the action using ':' */ case M_UNKNOWN: case M_ACTION: case M_SPOKEN: send_pose (buf+1); break; /* Whisper: whisper back */ case M_WHISPER: if (index (buf+1, ':') || !isalpha (buf[1])) { if (*speaker) send_whisper (speaker, buf+1); } else { sprintf (cmd, "%s %s", myname, buf+1); if (*speaker) send_whisper (speaker, cmd); } break; /* Page, shout: page a message back (1.5.4 & later) */ case M_PAGE: case M_SHOUT: if (index (buf+1, ':') || !isalpha (buf[1])) { if (!buf[1]) { if (*speaker) send_page (speaker, "."); } else { if (*speaker) send_page (speaker, buf+1); } } else { sprintf (cmd, "%s %s", myname, buf+1); if (*speaker) send_page (speaker, cmd); } break; } } /* Not a say/pose/whisper/page */ else if (*buf != '"' && *buf != ':') { command ("%s", buf); } } /**************************************************************** * zinger: Same as reply, but different log * * WARNING: possible 16/32 bit int problems here - fuzzy ****************************************************************/ zinger (fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) char *fmt; int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10; { int len; char buf[BIGBUF], cmd[BIGBUF]; register char *s; long pl; char *ntype = "Zing"; /* Log our reply */ if (!printedloc) print_locn (); sprintf (buf, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); s = (*buf == '"') ? buf+1 : buf; if (*speaker && (pl = find_player (speaker)) >= 0 && sindex (buf, "{")) { strcpy (buf, add_name (buf)); } if (*speaker && (pl = find_player (speaker)) >= 0 && (now - player[pl].firstsaw) < 3 * DAYS) { ntype = "NewZ"; } if (terse && msgtype > M_SPOKEN && *speaker) { fprintf (stderr, "%s: [%c to %s] %s\n", ntype, MTYPESTR[msgtype], speaker, s); } else if (terse) { fprintf (stderr, "%s: %s\n", ntype, s); } /* Various commands */ if (*buf == '"') { switch (msgtype) { /* Basic case: say the command using '"' */ case M_UNKNOWN: case M_ACTION: case M_SPOKEN: send_say (buf+1); break; /* Whisper: whisper back */ case M_WHISPER: if (*speaker) send_whisper (speaker, buf+1); break; /* Page, shout: page a message back (1.5.4 & later) */ case M_PAGE: case M_SHOUT: if (*speaker) send_page (speaker, buf+1); break; } } else if (*buf == ':' || *buf == '|') { switch (msgtype) { /* Basic case: perform the action using ':' */ case M_UNKNOWN: case M_ACTION: case M_SPOKEN: send_pose (buf+1); break; /* Whisper: whisper back */ case M_WHISPER: if (index (buf+1, ':') || !isalpha (buf[1])) { if (*speaker) send_whisper (speaker, buf+1); } else { sprintf (cmd, "%s %s", myname, buf+1); if (*speaker) send_whisper (speaker, cmd); } break; /* Page, shout: page a message back (1.5.4 & later) */ case M_PAGE: case M_SHOUT: if (index (buf+1, ':') || !isalpha (buf[1])) { if (!buf[1]) { if (*speaker) send_page (speaker, "."); } else { if (*speaker) send_page (speaker, buf+1); } } else { sprintf (cmd, "%s %s", myname, buf+1); if (*speaker) send_page (speaker, cmd); } break; } } /* Not a say/pose/whisper/page */ else if (*buf != '"' && *buf != ':') { command ("%s", buf); } } /**************************************************************** * add_name: find special name insertion commands, replace with * speakers name ****************************************************************/ char *add_name (str) char *str; { static char buf[BIGBUF]; register char *s = str, *t = buf; while (*s) { if (*s == '{') { /* * If not a contest, and speaking out loud, and more than * one other player, include recipients name */ if (!contest_mode && msgtype == M_SPOKEN && alone > 1 && *speaker) { if (debug) { fprintf (stderr, "Name: adding name %s, alone %d\n", speaker, alone); } for (s++; *s && *s != '}'; s++) { switch (*s) { case 'n': strcpy (t, speaker); t += strlen (speaker); case '{': case '}': break; default: *t++ = *s; } } } else if (debug) { fprintf (stderr, "Name: skipping name %s, alone %d\n", speaker, alone); } /* Now skip over command */ while (*s && *s != '}') s++; s++; } else { *t++ = *s++; } } *t = '\0'; return (s = buf); } /**************************************************************** * getmud: Read one line from TinyMUD ****************************************************************/ char *getmud () { long len; static long havecnt = 0; static char buf[BUFSIZ], rbuf[4], plybuf[MSGSIZ]; char junk[MSGSIZ], pname[MSGSIZ]; long pnumber = -1; register char *s=buf, *tail=buf+MSGSIZ-1; static long pl; if (tty_interface) { crash_robot ("Error, called getmud during tty_interface mode"); } /* No input waiting */ if (!charsavail (fmud)) return (NULL); /* Read one line, save printing chars only */ while ((len = read (fmud, rbuf, 1)) > 0) { if (*rbuf == '\n') break; if (isprint (*rbuf) && s < tail) *s++ = *rbuf; } *s = '\0'; /* Check for error */ if (len < 0) { fprintf (stderr, "Error %ld reading from mud\n", len); quit_robot (); } /* Detect World Name */ if (!awake && (MATCH (buf, "*Welcome to *,*") || MATCH (buf, "*Welcome to *!") || MATCH (buf, "*Welcome to *.") || MATCH (buf, "*Welcome to *") || MATCH (buf, "DruidMuck:*") && strcpy (res2, "DruidMuck") || MATCH (buf, "*Mail sjade*") && strcpy (res2, "HoloMuck")) && !sindex (lcstr (res2), "port concentrator")) { strcpy (world, res2); now = time (0); fprintf (stderr, "\n-------- %s: %s log starts at %15.15s --------\n\n", world, myname, ctime (&now) + 4); } else if (!awake && debug) { fprintf (stderr, "Smsg: %s\n", buf); } /*-------- Number output lines --------*/ if (streq (buf, outpre)) { mlnum = havecnt = 0; mode = COMMAND;} else if (streq (buf, outsuf)) { mlnum = -1; mode = NORMAL; } else if (streq (buf, loopre)) { mlnum = havecnt = 0; mode = LOOK; } else if (streq (buf, movpre)) { mlnum = havecnt = 0; mode = MOVE; } else if (streq (buf, numpre)) { mlnum = havecnt = 0; mode = NUMBER; } else if (streq (buf, pagpre)) { mlnum = havecnt = 0; mode = PAGE; } else if (streq (buf, scrpre)) { mlnum = havecnt = 0; mode = SCORE; } else if (streq (buf, whopre)) { mlnum = havecnt = 0; mode = WHO; } else if (stlmatch (buf, plypre)) { mlnum = havecnt = 0; mode = PLYLOOK; } else if (streq (buf, loosuf)) { mlnum = -1; mode = NORMAL; } else if (streq (buf, movsuf)) { mlnum = -1; mode = NORMAL; } else if (streq (buf, numsuf)) { mlnum = -1; mode = NORMAL; } else if (streq (buf, pagsuf)) { mlnum = -1; mode = NORMAL; } else if (streq (buf, scrsuf)) { mlnum = -1; mode = NORMAL; } else if (streq (buf, whosuf)) { mlnum = -1; mode = NORMAL; } else if (streq (buf, plysuf)) { mlnum = -1; mode = NORMAL; } else if (mlnum == 0 && mode == MOVE && (stlmatch (buf, "There's no place like home..."))) { } else if (mlnum >= 0) { mlnum++; } /*-------- Debugging: log input --------*/ if (debug) { if (mlnum >= 0) { fprintf (stderr, "%s%03d: %s\n", ((mode == NORMAL) ? "N" : (mode == NUMBER) ? "I" : (mode == COMMAND) ? "C" : (mode == LOOK) ? "L" : (mode == PLYLOOK) ? "V" : (mode == SCORE) ? "S" : (mode == PAGE) ? "P" : (mode == MOVE) ? "M" : "W"), mlnum, buf); } else { fprintf (stderr, "Mud: %s\n", buf); } } /*-------- Certain parts of the input are parsed here --------*/ /*---- Handle implicit look (and @os msg) from movement ----*/ if (mode == MOVE) { if (mlnum == 1) { strcpy (move1, buf); *move2 = *move3 = *move4 = '\0'; } else if (mlnum == 2) { strcpy (move2, buf); } else if (mlnum == 3) { strcpy (move3, buf); } else if (mlnum == 4) { strcpy (move4, buf); } if (mlnum > 1 && streq (buf, "You found a penny!")) { needpsynch++; } else if (mlnum > 1 && streq (buf, "You found a cookie!")) { needpsynch++; } } /*---- Handle output from looking at a room (using "look") ----*/ else if (mode == LOOK) { if (ismuck && statuscmd) { if (*buf == '=') { if (stlmatch (buf, "=numb=")) { hereid = atoi (buf+6); } else if (stlmatch (buf, "=ispl=")) { hereispl = atoi (buf+6); } else if (stlmatch (buf, "=name=")) { strcpy (here, buf+6); } else if (stlmatch (buf, "=penn=")) { pennies = atoi (buf+6); } else if (stlmatch (buf, "=desc=")) { if (buf[6] == '@' && isdigit (buf[7])) { if (streq (here, move1)) { strcpy (desc, move2); if (!terse) { fprintf (stderr, "Look: using move2 for desc '%s'\n", move2); } } else if (streq (here, move2)) { strcpy (desc, move3); if (!terse) { fprintf (stderr, "Look: using move3 for desc '%s'\n", move3); } } else if (streq (here, move3)) { strcpy (desc, move4); if (!terse) { fprintf (stderr, "Look: using move4 for desc '%s'\n", move4); } } else { strcpy (desc, buf+6); if (debug) { fprintf (stderr, "Look: using real desc '%s', can't match MOVE/LOOK\n", desc); fprintf (stderr, "Look:\tname: %s\n\tmove1: %s\n\tmove2: %s\n\tmove3: %s\n\tmove4: %s\n", here, move1, move2, move3, move4); } } } else { strcpy (desc, buf+6); } /* Now add the room number */ if (hereid >= 0) sprintf (here, "%s(#%d)", here, hereid); } else if (streq (buf, "=contents=")) { *contents = '\0'; havecnt++; } else if (streq (buf, "=players=")) { clear_present (); } else if (sscanf (buf, "=plyr=%d=%[^\n]", &pnumber, pname)) { player[add_player (pname)].number = pnumber; saw_player (pname, here, desc); if (debug) fprintf (stderr, "Plyr: %s[%d]\n", pname, pnumber); } else if (sscanf (buf, "=thng=%[^\n]", pname)) { if ((strlen (contents) + strlen (pname) + 2) < BIGBUF) { if (*contents) strcat (contents, ", "); strcat (contents, pname); } } else { fprintf (stderr, "Look: unknown '=' message '%s'\n", buf); } } else if (*buf != '<' && !streq (buf, HUH1) && !streq (buf, HUH2)) { fprintf (stderr, "Look: unexpected response '%s', here '%s'\n", buf, *here ? here : "(unknown)"); } } else if (!havecnt) { switch (mlnum) { case 1: strcpy (here, buf); if (debug) { fprintf (stderr, "Here: setting here to line1 '%s'\n", buf);} *desc = '\0'; *contents = '\0'; *exlist = '\0'; clear_present (); break; case 2: if (streq (buf, "Contents:")) { havecnt++; } else if (stlmatch (buf, "Exits: ")) { strcpy (exlist, buf+7); if (debug) { fprintf (stderr, "Here: setting exits to line2 '%s'\n", exlist); } } else { strcpy (desc, buf); if (debug) { fprintf (stderr, "Here: setting desc to line2 '%s'\n", buf); } } break; default: if (streq (buf, "Contents:")) { havecnt++; } else if (!havecnt && stlmatch (buf, "Exits:")) { strcpy (exlist, buf); if (debug) { fprintf (stderr, "Here: setting exits to '%s'\n", exlist); } } break; } } else /* Strip object numbers from things */ { if (!(smatch (buf, "* (#*)", roomstr) && isdigit (*room2) || smatch (buf, "*(#*)", roomstr) && isdigit (*room2))) { strcpy (room1, buf); } if (find_player (room1) >= 0) { saw_player (room1, here, desc); } else { if (debug) fprintf (stderr, "Obj: %s\n", room1); if ((strlen (contents) + strlen (room1) + 2) < BIGBUF) { if (*contents) strcat (contents, ", "); strcat (contents, room1); } } } } /*---- Handle output from 'find player id' ----*/ else if (mode == NUMBER) { # ifdef OLD_EXAMINE if (streq (buf, "I can't find that key!")) { lastlock = -1; } else if (lastlock == 0 && smatch (buf, "*(#*)*Key: *(#*)*", tmpstr)) { lastlock = atol (tmp5); strcpy (lastobj, tmp4); } # endif } /*---- Handle output from look_at_thing ----*/ else if (mode == PLYLOOK) { /* Line 0 contains the name of the player being viewed */ if (mlnum == 0) { if (stlmatch (buf, plypre) && (strlen (buf) > strlen (plypre) + 1) && strcpy (plybuf, buf + strlen (plypre) + 1) && (pl = find_player (plybuf)) >= 0) { /* have a valid look at player prefix */ if (player[pl].carry) strcpy (player[pl].carry, ""); } else { pl = -1; *plybuf = 0; } if (debug) fprintf (stderr, "Look: got output '%s', player '%s'(%ld)\n", buf, plybuf, pl); } /* Line one is players description */ else if (mlnum == 1 && pl >= 0) { if (*buf && !streq (buf, "I don't see that here.") && !streq (buf, "I don't know which one you mean!") && !streq (buf, "You see nothing special.")) { if (player[pl].desc == NULL || !streq (player[pl].desc, buf)) { freestring (player[pl].desc); player[pl].desc = (*buf ? makestring (buf) : NULL); fprintf (stderr, "Look: player '%s'(%ld), desc: %s\n", plybuf, pl, buf); } else if (!terse) { fprintf (stderr, "Look: player '%s'(%ld), old desc: %-32.32s\n", plybuf, pl, buf); } } else if (!terse) { fprintf (stderr, "Ignoring look output for %s: '%s'\n", plybuf, buf); } } /* Lines 3 and following are players inventory */ else if ((mlnum > 2) && pl >= 0) { if (player[pl].carry == NULL) { player[pl].carry = makefixstring ("", DIALOGSIZE); } if (player[pl].carry[0]) { if ((strlen (buf) + strlen (player[pl].carry) + 2) < DIALOGSIZE) { strcat (player[pl].carry, ", "); strcat (player[pl].carry, buf); } } else { strncpy (player[pl].carry, buf, DIALOGSIZE); player[pl].carry[DIALOGSIZE-1] = '\0'; } } } /*-------- Now return message --------*/ return (s = buf); } /**************************************************************** * procmsg: send messages to the robots readmsg function ****************************************************************/ # define MAXQ 256 int dont_drop = 1; procmsg (msg) char *msg; { static long msgrm = -1, dropped = 0, inproc = 0; static msgqueue[MAXQ][MSGSIZ]; static int i=0; /* debugging */ if (inproc && !terse) { fprintf (stderr, "Proc: entering procmsg %d, msg: %s\n", inproc, msg); /* debug++; */ } /*---- Queue messages that happen "between rooms" ----*/ if (inmove && msg) { /* Ignore output fropm @Q command in MUCKs */ if (streq (msg, HUH1) || streq (msg, HUH2)) { /* Ignore */ return; } /* Special case for WHO mode output */ if (MATCH (msg, "* idle * seconds")) { if (debug) fprintf (stderr, "Who: [%s] %s seconds\n", res1, res2); idle_player (res1, atol (res2)); return; } /* Special case for Hearts page */ if (mode == NORMAL && MATCH (msg, "(> *There is a Hearts game starting*")) { hearts_msg (raw_car (msg), msg, lcstr (msg)); return; } /* Only queue NORMAL mode messages */ if (mode == NORMAL) { if (stlmatch (msg, ">>")) return; if (inproc) { fprintf (stderr, "Ignr: recursive proc, dropping '%s' from rm %s(%ld)\n", msg, room_name (msgrm), msgrm); } else { if (msgrm != hererm) { dropped = 0; msgrm = hererm; } /* If too many messages to queue, at least send to log */ if (dropped >= MAXQ) { if (!stlmatch (msg, "I don't see that")) { fprintf (stderr, "Ignr: dropping message '%s' from %s(%ld), dropped %d\n", msg, room_name (msgrm), msgrm, dropped); } } /* Add the message to the queue, only log if not terse */ else { strncpy (msgqueue[dropped++], msg, MSGSIZ); if (!terse) { fprintf (stderr, "Ignr: queuing message '%s' from %s(%ld)\n", msg, room_name (msgrm), msgrm); } } } } return; } if (dropped > 0) { inproc++; if (hererm == msgrm) { while (i<dropped) readmsg (msgqueue[i++]); } else { while (i<dropped) { if (dont_drop || (stlmatch (msgqueue[i], "You sense") || stlmatch (msgqueue[i], "You killed") || (stlmatch (msgqueue[i], "Tinker") || stlmatch (msgqueue[i], "Fuzzy")) && (sindex (msgqueue[i], " off") || sindex (msgqueue[i], " on")) || ematch (msgqueue[i], "killed you!") || sindex (msgqueue[i], " pages: ") || stlmatch (msgqueue[i], "Your insurance policy pays") || stlmatch (msgqueue[i], "Your insurance policy has been revoked"))) { if (dont_drop && debug) { fprintf (stderr, "Proc: processing queued message '%s'\n", msgqueue[i]); } readmsg (msgqueue[i++]); } else if (!stlmatch (msgqueue[i], "I don't see that player")) { fprintf (stderr, "Ignr: dropping msg '%s' from %s(%ld)\n", msgqueue[i], room_name (msgrm), msgrm); i++; } else { i++; } } } inproc--; dropped = 0, msgrm = -1; } i=0; if (msg) readmsg (msg); /* Turn off debugging */ if (inproc && !terse) { fprintf (stderr, "Proc: exiting procmsg %d\n", inproc); /* debug--; */ } } /***************************************************************** * charsavail: check for input available from 'fd' *****************************************************************/ charsavail (fd) int fd; { long n; long retc; if (retc = ioctl (fd, FIONREAD, &n)) { fprintf (stderr, "Ioctl returns %ld, n=%ld.\n", retc, n); quit_robot (); } return ((int) n); } /**************************************************************** * swap_files: Do a pointer swap with a temp file and a real file ****************************************************************/ swap_files (tmp, real) char *tmp, *real; { char bakfile[MSGSIZ]; sprintf (bakfile, "%s.BAK", real); unlink (bakfile); if (link (real, bakfile) < 0) { fprintf (stderr, "Warn: cannot link old %s to %s in swap_files\n", real, bakfile); fprintf (stderr, " New file left in %s\n", tmp); return (0); } if (unlink (real) < 0) { fprintf (stderr, "Warn: cannot unlink old %s in swap_files\n", real); fprintf (stderr, " New file left in %s\n", tmp); return (0); } if (link (tmp, real) < 0) { fprintf (stderr, "Warn: cannot link new %s to %s in swap_files\n", tmp, real); fprintf (stderr, " New file left in %s\n", tmp); return (0); } unlink (tmp); return (1); } /**************************************************************** * makestring: ****************************************************************/ char *makestring (str) char *str; { register char *s; register long len = strlen (str) + 1; if (s = ralloc (len)) { string_sp += len; string_ct++; strcpy (s, str); return (s); } else { crash_robot ("malloc returns NULL in makestring"); } } /**************************************************************** * makefixstring: Make a string that must be a fixed size ****************************************************************/ char *makefixstring (str, size) char *str; long size; { register char *s; register long len = strlen (str); if (s = ralloc (size)) { dialog_sp += size; dialog_ct++; if (len > size) { strncpy (s, str, size); s[size-1] = '\0'; fprintf (stderr, "Warn: truncating string '%32.32s...' to %ld bytes\n", str, size); } else { strcpy (s, str); } return (s); } else { crash_robot ("malloc returns NULL in makefixstring"); } } /**************************************************************** * ralloc: Malloc replacement for debugging ****************************************************************/ char *ralloc (len) long len; { char *str; str = (char *) malloc (len); if (debug > 1) { fprintf (stderr, "Mall: %08x %ld bytes\n", str, len); } return (str); } /**************************************************************** * freestring: ****************************************************************/ freestring (str) char *str; { register char *s; register long len; if (str == NULL) return; len = strlen (str) + 1; string_sp -= len; string_ct--; freed++; if (debug) { fprintf (stderr, "Free: %08x, at least %ld bytes.\n", str, len); } free (str); } /**************************************************************** * clear_page: Clear the paging variables ****************************************************************/ clear_page () { strcpy (pagedby, ""); pagedto = -1; pagedfrom = -1; pagedat = 0; } /**************************************************************** * crash_robot: ****************************************************************/ crash_robot (fmt, a1, a2, a3, a4) char *fmt; { long now; static long crashing = 0; char msg[TOKSIZ]; /* Handle recursive failures */ if (crashing++) abort (); /* Log error */ sprintf (msg, fmt, a1, a2, a3, a4); /* Get out of Mud somewhat cleanly */ sendmud ("@desc me = %s has crashed.", myname); sendmud ("QUIT"); /* Attemp to save state */ checkpoint (); now = time (0); fprintf (stderr, "\n\nCrash at %15.15s: %s\n", ctime (&now)+4, msg); /* Get a core dump */ abort (); } /**************************************************************** * init_prefix: Use random numbers to build spoof-proof prefixes ****************************************************************/ init_prefix () { long cookie = rand (); sprintf (outpre, "%s-%08x", OUTPUTPREFIX, cookie); sprintf (outsuf, "%s-%08x", OUTPUTSUFFIX, cookie); sprintf (movpre, "%s-%08x", MOVEPREFIX, cookie); sprintf (movsuf, "%s-%08x", MOVESUFFIX, cookie); sprintf (loopre, "%s-%08x", LOOKPREFIX, cookie); sprintf (loosuf, "%s-%08x", LOOKSUFFIX, cookie); sprintf (whopre, "%s-%08x", WHOPREFIX, cookie); sprintf (whosuf, "%s-%08x", WHOSUFFIX, cookie); sprintf (scrpre, "%s-%08x", SCRPREFIX, cookie); sprintf (scrsuf, "%s-%08x", SCRSUFFIX, cookie); sprintf (pagpre, "%s-%08x", PAGEPREFIX, cookie); sprintf (pagsuf, "%s-%08x", PAGESUFFIX, cookie); sprintf (numpre, "%s-%08x", NUMBPREFIX, cookie); sprintf (numsuf, "%s-%08x", NUMBSUFFIX, cookie); sprintf (plypre, "%s-%08x", PLYPREFIX, cookie); sprintf (plysuf, "%s-%08x", PLYSUFFIX, cookie); } /**************************************************************** * ignore_msg: ****************************************************************/ ignore_msg (msg) char *msg; { if (debug) { fprintf (stderr, "Ignr: %-8s %s\n", modestr[mode], msg); } } /**************************************************************** * do_typecmd: Execute an order ****************************************************************/ do_typecmd () { char buf[MSGSIZ]; /* Follow orders */ if (*typecmd && !dead) { strcpy (buf, typecmd); strcpy (typecmd, ""); if (stlmatch (buf, "home")) { fprintf (stderr, "Warn: typing '%s'\n", buf); movemud (buf); } else if (stlmatch (buf, "give ") || stlmatch (buf, "go give ") || stlmatch (buf, "rob ") || stlmatch (buf, "go rob ") || stlmatch (buf, "p ") || stlmatch (buf, "go p ") || stlmatch (buf, "pa ") || stlmatch (buf, "go pa ") || stlmatch (buf, "pag ") || stlmatch (buf, "go pag ") || stlmatch (buf, "page ") || stlmatch (buf, "go page ") || stlmatch (buf, "ki ") || stlmatch (buf, "go ki ") || stlmatch (buf, "kil ") || stlmatch (buf, "go kil ") || stlmatch (buf, "kill ") || stlmatch (buf, "go kill ") || stlmatch (buf, "say ") || stlmatch (buf, "go say") || stlmatch (buf, "po ") || stlmatch (buf, "go po ") || stlmatch (buf, "pos ") || stlmatch (buf, "go pos ") || stlmatch (buf, "pose ") || stlmatch (buf, "go pose") || stlmatch (buf, "wh ") || stlmatch (buf, "go wh") || stlmatch (buf, "whi ") || stlmatch (buf, "go whi") || stlmatch (buf, "whis ") || stlmatch (buf, "go whis") || stlmatch (buf, "whisp ") || stlmatch (buf, "go whisp") || stlmatch (buf, "whispe ") || stlmatch (buf, "go whispe") || stlmatch (buf, "whisper ") || stlmatch (buf, "go whisper") || stlmatch (buf, "QUIT") || stlmatch (buf, "go QUIT") || stlmatch (buf, "WHO") || stlmatch (buf, "go WHO") || stlmatch (buf, "OUTPUT") || stlmatch (buf, "go OUTPUT") || index (buf, '@') || index (buf, '#') || index (buf, '=') || *buf == ':' || *buf == '"') { msgtype = M_ACTION; reply (":decides not to type <%s>.", buf); } else if (stlmatch (buf, "go ")) { if (ismuck) fprintf (stderr, "Type: movemud <%s>\n", buf + 3); movemud (buf + 3); } else { msgtype = M_UNKNOWN; reply (":types <%s>", buf); reply ("%s", buf); psynch (); } return (1); } return (0); } /**************************************************************** * do_page: Handle page (also used to implement movement goals) ****************************************************************/ do_page () { long pl, from, to; char *dir; /* answer pages */ if (*pagedby && !*typecmd && !dead) { if (!*here) { static long cnt=0; if (++cnt > 10) { crash_robot ("In main, no location"); } else { fprintf (stderr, "Waiting for location to appear\n"); hangaround (60); msynch (); return (1); } } pl = (*pagedby == '<') ? -1 : find_player (pagedby); /* Are we there, yet? Stop if we find our caller */ if (hererm == pagedto || pl >= 0 && player[pl].present) { if (doing_works) { command ("@doing hanging around in %s", room_name (hererm)); } if (streq (pagedby, "<EXPLORING>") || streq (pagedby, "<AUTORETURN>")) { /* Dont say anything */ } else if (streq (pagedby, "<HEARTS>")) { strcpy (speaker, ""); msgtype = M_SPOKEN; switch (nrrint (188, 4)) { case 0: reply ("\"I'd like to play"); break; case 1: reply ("\"Please add me to the game"); break; case 2: reply ("\"I'm up for a game of hearts"); break; case 3: reply ("\"Me, me, me!"); break; } } else if (streq (pagedby, "<WHIM>") || streq (pagedby, "<HOME>") || streq (pagedby, "<COMMAND>")) { if (takingnotes && !quiet) { msgtype = M_UNKNOWN; unlogged (":scribbles on %s pad.", male ? "his" : "her"); } } else if (pl >= 0) { if (player[pl].present) { strcpy (speaker, pagedby); spoke_player (speaker); speaktime = now; reply ("\"Here I am, %s.", pagedby); if (nextwait < 180) nextwait = 180; } else { strcpy (speaker, ""); msgtype = M_SPOKEN; reply ("\"I was called here by %s.", player[pl].name); nextwait = 30; } } clear_page (); return (1); } else { dir = NULL; if (now > pagedat + 20 * MINUTES) { fprintf (stderr, "%s: timing out search for %s in %s after %s.\n", *pagedby == '<' ? "Path" : "Page", pagedby, room_name (pagedto), exact_dur (now - pagedat)); clear_page (); return (1); } else if ((from = hererm) < 0 || /* find here */ (to = pagedto) < 0 || /* find there*/ (dir = find_path (from, to, NEXTMOVEHOME)) == NULL) /* find path */ { fprintf (stderr, "Path: couldn't find path (%s)%ld -> (%s)%ld\n", here, from, room_name (pagedto), pagedto); if (from == to) { crash_robot ("In paging, from == to == %ld, room_match failed", from); } if (to >= 0 && ((homerm == to) || (dir = find_path (homerm, to, NEXTMOVE)))) { if (homerm != to) { fprintf (stderr, "Path: could find path %ld -> %ld (%s), going 'home'\n", homerm, to, dir); } else { fprintf (stderr, "Warn: going home from %ld to %ld\n", hererm, to); } movemud ("home"); strcpy (here, home); return (1); } if (to != from) { fprintf (stderr, "%s: %s for %s in %s(%ld) (from %ld, to %ld, dir %s).\n", *pagedby == '<' ? "Path" : "Page", "giving up search", pagedby, room_name (pagedto), pagedto, from, to, dir ? dir : "(nil)"); cant_reach (to); } takingnotes = 0; meetingroom = -1; clear_page (); return (1); } else /* Make the move */ { movemud (dir); hangaround (1); return (1); } } } return (0); } /**************************************************************** * set_page: Set page (if its okay) ****************************************************************/ set_page (tmp_caller, tmp_loc) char *tmp_caller, *tmp_loc; { static lastownpage = 0; static char lastcaller[MSGSIZ], lastloc[MSGSIZ]; static long lastat = -1, lastpage = 0; char caller[MSGSIZ], loc[MSGSIZ]; long rm, pl; /* Make local copies of variables, just in case */ strcpy (caller, tmp_caller); strcpy (loc, tmp_loc); /* Avoid generating infinite page loops */ if (!isowner (caller) && lastat == hererm && lastpage + 60 > now && streq (caller, lastcaller) && streq (loc, lastloc)) { if (!terse) { fprintf (stderr, "Page: redundant page by %s to %s from %s(%ld)\n", caller, loc, room_name (hererm), hererm); } return (1); } strcpy (lastcaller, caller); strcpy (lastloc, loc); lastat = hererm; lastpage = now; /* Now find target room */ rm = find_room (loc, NULL); if (!printedloc) print_locn (); fprintf (stderr, "Page: [%s] %s\n", caller, loc); active_player (caller, ((rm < 0) ? NULL : loc), NULL); /* Check for double pages from owner */ if (isowner (caller)) { /* Two pages within 15 seconds turns off paging */ if (lastownpage + 15 > (now = time (0))) { paging = 0; } lastownpage = now; clear_page (); nextwait = 180; takingnotes = 0; meetingroom = -1; } if (rm == hererm) { if ((pl = find_player (caller)) >= 0 && player[pl].present) { msgtype = M_WHISPER; strcpy (speaker, caller); reply ("\"I'm right here, %s.", caller); } else if (pennies > MINPEN && !pagedmsgs) { pennies--; send_page (caller, NULL); psynch (); } else if (pennies > MINPEN) { pennies--; msgtype = M_PAGE; strcpy (speaker, caller); reply ("\"I'm here in %s.", room_name (hererm)); psynch (); } nextwait = 180; return (1); } if (page_okay (caller, loc) == 0) { return (1); } /* If we are busy taking notes, say so */ if (!isowner (caller) && (takingnotes || playinghearts)) { if (!quiet) { reply ("\"Oh dear, %s is paging me from %s, but I'm busy %s.", caller, loc, takingnotes ? "taking notes" : "playing hearts"); } if (pennies > MINPEN) { if (!pagedmsgs) { pennies -= 2; send_page (caller, NULL); send_page (caller, NULL); } else { pennies --; msgtype = M_PAGE; strcpy (speaker, caller); reply ("\"Sorry, %s, I'm %s in %s right now", caller, takingnotes ? "taking notes" : "playing hearts", room_name (hererm)); } psynch (); } return (1); } /* If we are not taking calls, say so */ if (!isowner (caller) && !paging) { if (!quiet) { reply ("\"Oh dear, %s is paging me from %s, but %s.", caller, loc, "I'm not taking calls right now"); } if (pennies > MINPEN) { if (!pagedmsgs) { pennies -= 2; send_page (caller, NULL); send_page (caller, NULL); } else { pennies --; msgtype = M_PAGE; strcpy (speaker, caller); reply ("\"Sorry, I can't take pages right now, %s", caller); } psynch (); } return (1); } /* If we are ignoring player, say so */ if (!isowner (caller) && is_jerk (caller)) { if (!quiet) { reply ("\"Oh dear, %s is paging me from %s, but %s.", caller, loc, "I'm ignoring jerks"); } return (1); } /* If we are already on a call, say so */ if (!isowner (caller) && *pagedby && *pagedby != '<' && !streq (caller, pagedby)) { /* Special case, if the two rooms are the same */ if (streq (room[pagedto].name, loc)) { pennies --; send_page (caller, NULL); psynch (); return (1); } /* Double page to indicate unavailability */ if (!quiet) { reply ("\"Oh dear, %s is paging me from %s, but %s to %s for %s.", caller, loc, "I'm on my way", room_name (pagedto), pagedby); } if (pennies > MINPEN) { if (!pagedmsgs) { pennies -= 2; send_page (caller, NULL); send_page (caller, NULL); } else { pennies --; msgtype = M_PAGE; strcpy (speaker, caller); reply ("\"Sorry, %s, I'm on my way to %s for %s.", caller, room_name (pagedto), pagedby); } psynch (); } return (1); } /* If paged to home, go there directly */ if (rm == homerm) { if (*speaker && speaktime + 60 < now) { if (quiet) msgtype = M_WHISPER; reply ("\"Excuse me, %s is paging me from %s.", caller, room_name (rm)); } send_page (caller, NULL); hanging = 0; pgoal = 0; fprintf (stderr, "Warn: paged to home by %s, going 'home'\n", caller); if (isowner (caller) && streq (typecmd, "go home")) { fprintf (stderr, "Warn: double page to home, resetting...\n"); reset_robot ("page to home twice"); } strcpy (typecmd, "go home"); clear_page (); nextwait = 180; return (1); } /* We do not know the room, say so */ if (rm < 0) { if (!quiet) { reply ("\"Oh dear, %s is paging me from %s, but %s.", caller, loc, "I've never been there"); } fprintf (stderr, "Page: can't find room '%s' for %s\n", loc, caller); if (pennies > MINPEN) { if (!pagedmsgs) { pennies -= 2; send_page (caller, NULL); send_page (caller, NULL); } else { pennies--; msgtype = M_PAGE; strcpy (speaker, caller); reply ("\"I've never been to %s, before, %s.", loc, caller); } psynch (); } return (1); } /* If we do not have a path, say so */ if (find_path (hererm, rm, NEXTMOVEHOME) == NULL && find_path (homerm, rm, NEXTMOVE) == NULL) { if (!quiet) { reply ("\"Oh dear, %s is paging me from %s, but %s.", caller, room_name (rm), "I don't know how to get there"); } fprintf (stderr, "Page: can't find path from %s(%ld) or %s(%ld) to %s(%ld)\n", here, hererm, home, homerm, room_name (rm), rm); if (pennies > MINPEN) { if (!pagedmsgs) { pennies -= 2; send_page (caller, NULL); send_page (caller, NULL); } else { pennies--; msgtype = M_PAGE; strcpy (speaker, caller); reply ("\"I don't know how to get to %s, %s", loc, caller); } psynch (); } return (1); } /* Okay, everything is okay, set the goal */ strcpy (pagedby, caller); pagedto = rm; pagedfrom = hererm; pagedat = now = time (0); nextwait = 180; fprintf (stderr,"Page: by %s, to %s(%ld), from %s(%ld)\n", pagedby, room_name (pagedto), pagedto, room_name (pagedfrom), pagedfrom); if (doing_works) { command ("@doing heading to %s", room_name (pagedto)); } if (*speaker && speaktime + 240 > now) { if (quiet) msgtype = M_WHISPER; reply ("\"Excuse me, %s is paging me from %s.", pagedby, room_name (pagedto)); } hanging = 0; pgoal = 0; /* Page back a single time to signal caller */ if (pennies > MINPEN || isowner (caller)) { pennies--; if (!pagedmsgs) { send_page (caller, NULL); } else { msgtype = M_PAGE; strcpy (speaker, caller); reply ("\"I'm on my way to you, %s.", caller); } psynch (); } return (1); } /**************************************************************** * do_notes: Take notes somwhere ****************************************************************/ do_notes () { /* Take notes */ if (takingnotes && !dead) { if (!terse) { fprintf (stderr, "Note: taking notes in %s(%ld)\n", room_name (meetingroom), meetingroom); } if (hererm != meetingroom) { pagedto = meetingroom; pagedfrom = hererm; strcpy (pagedby, "<COMMAND>"); pagedat = now; hangaround (1); return (1); } else { if (doing_works) { command ("@doing taking notes in %s", room_name (hererm)); } hangaround (300); msgtype = M_UNKNOWN; unlogged (":scribbles on %s pad.", male ? "his" : "her"); return (1); } } return (0); } /**************************************************************** * reset_dead: We died, reset ****************************************************************/ reset_dead () { extern long first_turn; if (dead) { fprintf (stderr, "Dead: killed by %s, restarting\n", killer); if (pagedto < 0 && hererm >= 0 && hererm != homerm && randint (100) < 90) { pagedto = hererm; pagedfrom = homerm; pagedat = now; strcpy (pagedby, "<AUTORETURN>"); } dead = 0; nextwait = 0; # ifdef NOLONGJMP hererm = homerm; strcpy (here, home); strcpy (desc, homedesc); movemud ("home"); # else reset_robot ("Killed, restarting"); # endif playinghearts = 0; first_turn = 1; return (1); } return (0); } /**************************************************************** * reset_teleported: We were teleported, reset ****************************************************************/ reset_teleported () { if (dead) return (0); nextwait = 0; # ifdef NOLONGJMP hererm = homerm; strcpy (here, home); strcpy (desc, homedesc); movemud ("home"); # else reset_robot ("Teleported, restarting"); # endif return (1); } /**************************************************************** * special_mode: Handle special TinyMUD output (LOOK, SCORE, WHO) ****************************************************************/ special_mode (name, msg, lcmsg) char *name, *msg, *lcmsg; { static long oldobjs = 0; /* Ignore message that might be spoofing, or are junk */ if (msg == NULL || *msg == '\0') { ignore_msg (msg); return (1); } if (stlmatch (msg, "<<") || stlmatch (msg, ">>")) { ignore_msg (msg); return (1); } if (stlmatch (msg, "You say \"") || stlmatch (msg, "You whisper \"") || (mode != NORMAL && stlmatch (msg, myname))) { return (1); } /*---------------- SCORE mode output ----------------*/ if (mode == SCORE) { if (MATCH (msg, "You have * pennies.") || MATCH (msg, "You have * penny.") || MATCH (msg, "You have * cookies.") || MATCH (msg, "You have * cookie.")) { if (isdigit (res1[0])) { pennies = atol (res1); } else { fprintf (stderr, "Bgus: '%s', non integer pennies.\n", msg); } } else if (MATCH (msg, "The universe contains * objects.")) { objs = atol (res1); if (objs != oldobjs) { if (!terse) { fprintf (stderr, "Objs: %8.8s @stat = %ld, %ld new\n", ctime (&now) + 11, objs, objs - oldobjs); } oldobjs = objs; do_number (); } else if (debug) { fprintf (stderr, "Same: still %ld objects\n", objs); } } else { ignore_msg (msg); } return (1); } /*---------------- COMMAND mode output ----------------*/ if (mode == COMMAND) { /* If we kill someone, they leave during our command listing */ if (MATCH (msg, "* has left.")) { fprintf (stderr, "Dprt: [%s]\n", res1); leave_player (res1, here, desc); alone--; } else if (MATCH (lcmsg, "that player is not accepting pages*")) { msgstat = -4; } else if (MATCH (lcmsg, "i don't recognize that name*") || MATCH (lcmsg, "i don't recognize that player*")) { msgstat = -3; } else if (MATCH (lcmsg, "that person is not connected*") || (MATCH (lcmsg, "* is not connected*") && find_player (res1) >= 0)) { msgstat = -2; } else if (MATCH (lcmsg, "whisper to whom?*")) { msgstat = -1; } else if (MATCH (lcmsg, "you whisper \"*") || MATCH (lcmsg, "you whisper, \"*") || MATCH (lcmsg, "your message has been sent*")) { msgstat = 1; } else { ignore_msg (msg); } return (1); } /*---------------- PAGE mode output ----------------*/ if (mode == PAGE) { if (MATCH (msg, "You sense that * is looking for you in *.")) { if (streq (res1, myname)) { if (!room_match (here, res2)) { fprintf (stderr, "Bgus: paging myself returns '%s', look '%s'\n", res1, here); strcpy (here, res2); } else { fprintf (stderr, "Good: paging myself gives '%s'\n", res2); } return (1); } } ignore_msg (msg); return (1); } /*---------------- WHO mode output ----------------*/ if (mode == WHO) { if (MATCH (lcmsg, "current players*") || MATCH (lcmsg, "player name*on for*idle*")) { clear_active (); } else if (MATCH (lcmsg, "* players are connected*") || MATCH (lcmsg, "1 player is connected*") || MATCH (lcmsg, "* users are connected*") || MATCH (lcmsg, "1 user is connected*")) { /* ignore */ } else if (MATCH (msg, "* idle * seconds")) { if (debug) fprintf (stderr, "Who: [%s] %s seconds\n", res1, res2); idle_player (res1, atol (res2)); } else if (MATCH (msg, "You have * pennies.") || MATCH (msg, "You have * penny.") || MATCH (msg, "You have * cookies.") || MATCH (msg, "You have * cookie.") ) { if (isdigit (res1[0])) { pennies = atol (res1); } else { fprintf (stderr, "Bgus: '%s', non integer pennies.\n", msg); } } /* Parse new format of idle, from tinymud 1.5.2 on */ else if (msg[24] == ':' || msg[27] == ':') { char pname[TOKSIZ], idlestr[TOKSIZ]; long idletim; register char *s, *t; /* Strip off first word (name) */ s=msg; while (*s && isspace (*s)) s++; if (streq (world, "HoloMuck") && *s == '+') s++; for (t=pname; *s && !isspace (*s); ) *t++ = *s++; *t = '\0'; /* Find idle time (last token or ends at col 35 in Holo) */ if (doing_works && strlen (msg) > 35) { s = msg+35; } else { s = msg + strlen (msg) - 1; } while (s>msg && !isspace (s[-1])) s--; strcpy (idlestr, s); idletim = atol (idlestr); for (s=idlestr; *s && isdigit (*s); s++); switch (*s) { case 's': /* base case */ break; case 'm': idletim *= MINUTES; break; case 'h': idletim *= HOURS; break; case 'd': idletim *= DAYS; break; default: fprintf (stderr, "Can't parse time modifer '%s', msg '%s'\n", idlestr, msg); break; } if (!terse) fprintf (stderr, "Who: [%s] %ld seconds\n", pname, idletim); idle_player (pname, idletim); } return (1); } /*---------------- Ignore some messages ----------------*/ if (stlmatch (msg, "I don't see that player here.")) { ignore_msg (msg); return (1); } /*---------------- Ignore other modes output ----------------*/ if (mode != NORMAL) { ignore_msg (msg); return (1); } /* Message not matched by this rule set */ return (0); } /**************************************************************** * check_time: Check time varying modes ****************************************************************/ check_time () { long pl; /* Check the WHO list once every two minutes */ if ((now = time (0)) - lastwsynch > 120) { wsynch (); /* usynch (); */ do_msgs (); } /* Clear the code word after 10 minutes */ if ((now - codeset) > 10 * MINUTES && *code) *code = '\0'; /* Alone tracks the number of other players in the room */ alone = 0; player[me].active = player[me].present = 0; for (pl = 0; pl<players; pl++) { if (player[pl].active && player[pl].present) alone++; } /* Print out current location */ if (!terse && !printedloc) print_locn (); /* Actions if we are not really, really busy */ if (!*pagedby || *pagedby == '<') { /* Look at everyone (sleepers twice a day, others every 45 minutes) */ for (pl = 0; pl<players; pl++) { if (player[pl].present && (randint (100) > 95 || (now - player[pl].lastlook) > (player[pl].active ? (45 * MINUTES) : (12 * HOURS)))) { look_at_thing (player[pl].name); } } /* Do we need to checkpoint our map and players files? */ if (alone < 2 && ((now > (lastcheck + checkfreq)) || (newrooms > 10) || (newexits > 500)) || ((now > (lastcheck + checkfreq + 20 * MINUTES)) || (newrooms > 20) || (newexits > 1000))) { if (*speaker && speaktime + 120 > now && (pl = find_player (speaker)) >= 0 && player[pl].present) { reply ("\"Excuse me a minute, I have to save my map, %s.", speaker); } else { strcpy (speaker, ""); unlogged ("\"Excuse me a minute, I have to save my map."); } command ("@descri me = %s is busy saving %s map.", myname, male ? "his" : "her"); checkpoint (); command ("@descri me = %s.", mydesc); unlogged ("\"Okay, I saved my map."); } } return (1); } /**************************************************************** * print_locn: ****************************************************************/ print_locn () { long printed; long pl; /* Print location */ if (*typecmd) { fprintf (stderr, "\nLocn: [%8.8s] %s(%ld), typecmd '%s'\n", ctime (&now)+11, *here ? here : "(nowhere)", hererm, typecmd); } else { fprintf (stderr, "\nLocn: %8.8s %s(%ld)\n", ctime (&now)+11, *here ? here : "(nowhere)", hererm); } if (*desc && !terse) { fprintf (stderr, "Desc: %-72.72s\n", desc); } if (*contents && !terse) { fprintf (stderr, "Cont: %-72.72s\n", contents); } player[me].active = player[me].present = 0; for (pl = 0, printed=0; pl<players; pl++) { if (player[pl].active && player[pl].present) { if (!printed++) fprintf (stderr, "Pres: (%ld) ", alone); fprintf (stderr, " %s", player[pl].name); } } if (printed) fprintf (stderr, "\n"); if (!terse) { for (pl = 0, printed=0; pl<players; pl++) { if (!player[pl].active && player[pl].present) { if (!printed++) fprintf (stderr, "Inac:"); fprintf (stderr, " %s", player[pl].name); } } } if (printed) fprintf (stderr, "\n"); fprintf (stderr, "\n"); printedloc++; } /**************************************************************** * reset_robot: Reset by longjumping to the robot initialize. * leaves the map and player info in the current state. ****************************************************************/ reset_robot (msg) char *msg; { char buf[4]; long len; fprintf (stderr, "Rset: resetting at %15.15s, message: %s\n", ctime (&now)+4, msg); /* Drain input */ while (charsavail (fmud)) { while ((len = read (fmud, buf, 1)) > 0) { if (*buf == '\n') break; } } /* Reset reachable map */ reach_changed++; /* Jump to the top of the main loop */ longjmp (start_state, 0); } /**************************************************************** * fatal: Fatal error message ****************************************************************/ fatal (fmt, a1, a2, a3, a4, a5, a6, a7, a8) char *fmt, *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8; { close (tmud); fprintf (stderr, fmt, a1, a2, a3, a4, a5, a6, a7, a8); exit (1); } /**************************************************************** * is_me: True if string matches my name ****************************************************************/ is_me (name) char *name; { return (strfoldeq (name, myname)); } /**************************************************************** * is_tell: True if msg is a 'JuliaGram' message to be sent to * another player ****************************************************************/ char *is_tell (lcmsg) char *lcmsg; { register char *s; if (tty_interface) return (NULL); if (( MATCH (lcmsg, "julia tell *") || MATCH (lcmsg, "tell *") || MATCH (lcmsg, "would you tell *") || MATCH (lcmsg, "could you tell *") || MATCH (lcmsg, "would you please tell *") || MATCH (lcmsg, "could you please tell *") || MATCH (lcmsg, "ask *") || MATCH (lcmsg, "julia ask *") || MATCH (lcmsg, "also tell *") || MATCH (lcmsg, "also ask *") || MATCH (lcmsg, "and tell *") || MATCH (lcmsg, "and ask *") || MATCH (lcmsg, "please, tell *") || MATCH (lcmsg, "please, ask *") || MATCH (lcmsg, "please tell *")|| MATCH (lcmsg, "please ask *")) && (s = car (res1)) || (MATCH (lcmsg, "*: please tell *") || MATCH (lcmsg, "*: please ask *") || MATCH (lcmsg, "*, please tell *") || MATCH (lcmsg, "*, please ask *") || MATCH (lcmsg, "*: please, tell *") || MATCH (lcmsg, "*: please, ask *") || MATCH (lcmsg, "*, please, tell *") || MATCH (lcmsg, "*, please, ask *") || MATCH (lcmsg, "*: tell *") || MATCH (lcmsg, "*: ask *") || MATCH (lcmsg, "*, tell *") || MATCH (lcmsg, "*, also tell *") || MATCH (lcmsg, "*, ask *")) && strfoldeq (res1, myname) && (s = car (res2)) || (MATCH (lcmsg, "*: *, tell *") || MATCH (lcmsg, "*: *, ask *") || MATCH (lcmsg, "*, *, tell *") || MATCH (lcmsg, "*, *, please tell *") || MATCH (lcmsg, "*, *, also tell *") || MATCH (lcmsg, "*, *, ask *")) && strfoldeq (res1, myname) && (s = car (res3))) { if (stlmatch (res2, "your owner") || stlmatch (res2, "your programmer") || stlmatch (res2, "your master") || stlmatch (res2, "your amway representative")) { return (owner); } else if (streq (s, "me") || streq (s, "all") || streq (s, "everybody") || streq (s, "everyone") || streq (s, "every") || streq (s, "us") || streq (s, "your") || streq (s, "you") || streq (s, "yourself") || reserved (s)) { return (NULL); } else { return (s); } } else { return (NULL); } } /**************************************************************** * send_page: ****************************************************************/ send_page (name, msg) char *name, *msg; { char cmd[BIGBUF]; if (tty_interface) { strcpy (cmd, msg); } else if (ismuck && pagecmd) { if (msg && *msg) { sprintf (cmd, "%s\n%s\n#%d\n%s\n%s %s\n%s %s\npages: \"%s\"", opre, osuf, pagecmd, name, opre, outpre, osuf, outsuf, msg); } else { sprintf (cmd, "%s\n%s\n#%d\n%s\n%s %s\n%s %s\n.", opre, osuf, pagecmd, name, opre, outpre, osuf, outsuf); } } else { if (msg && *msg) { sprintf (cmd, "page %s = %s", name, msg); } else { sprintf (cmd, "page %s", name); } } command ("%s", cmd); } /**************************************************************** * send_whisper: ****************************************************************/ send_whisper (name, msg) char *name, *msg; { char cmd[BIGBUF]; if (tty_interface) { strcpy (cmd, msg); } else if (ismuck && pagecmd) { sprintf (cmd, "%s\n%s\n#%d\n%s\n%s %s\n%s %s\nwhispers, \"%s\"", opre, osuf, pagecmd, name, opre, outpre, osuf, outsuf, msg); } else { sprintf (cmd, "whisper %s = %s", name, msg); } command ("%s", cmd); } /**************************************************************** * send_say ****************************************************************/ send_say (msg) char *msg; { char cmd[BIGBUF]; if (tty_interface) { strcpy (cmd, msg); } else if (ismuck && posecmd) { sprintf (cmd, "%s\n%s\n#%d\n%s %s\n%s %s\nsays, \"%s\"", opre, osuf, posecmd, opre, outpre, osuf, outsuf, msg); } else { sprintf (cmd, "\"%s", msg);} command ("%s", cmd); } /**************************************************************** * send_pose ****************************************************************/ send_pose (msg) char *msg; { char cmd[BIGBUF]; if (tty_interface) { sprintf (cmd, "Julia %s", msg); } else if (ismuck && posecmd) { sprintf (cmd, "%s\n%s\n#%d\n%s %s\n%s %s\n%s", opre, osuf, posecmd, opre, outpre, osuf, outsuf, msg); } else { sprintf (cmd, ":%s", msg);} command ("%s", cmd); } /**************************************************************** * is_newbie: Return true is player is 'new' (someone we've known * less than 3 days). Also a 30 percent chance of treating an * old player like a newbie ****************************************************************/ is_newbie (name) { long pl; if (isowner (name)) return (randint (100) < 50); if ((pl = find_player (name)) < 0) return (1); if ((now - player[pl].firstsaw) < 3 * DAYS) return (1); if (randint (100) < 30) return (1); return (0); } # ifndef cmu # define TRUE 1 # define FALSE 0 /**************************************************************** * Routines from CMU's libcs.a, for compatibility ****************************************************************/ /* stlmatch -- match leftmost part of string * * Usage: i = stlmatch (big,small) * int i; * char *small, *big; * * Returns 1 iff initial characters of big match small exactly; * else 0. * * HISTORY * 20-Nov-79 Steven Shafer (sas) at Carnegie-Mellon University * Rewritten for VAX from Ken Greer's routine. * * Originally from klg (Ken Greer) on IUS/SUS UNIX */ int stlmatch (big,small) char *small, *big; { register char *s, *b; s = small; b = big; do { if (*s == '\0') return (TRUE); } while (*s++ == *b++); return (FALSE); } /* sindex -- find index of one string within another * * Usage: p = sindex (big,small) * char *p,*big,*small; * * Sindex searches for a substring of big which matches small, * and returns a pointer to this substring. If no matching * substring is found, 0 is returned. * * HISTORY * 26-Jun-81 David Smith (drs) at Carnegie-Mellon University * Rewritten to avoid call on strlen(), and generally speed up things. * * 20-Nov-79 Steven Shafer (sas) at Carnegie-Mellon University * Adapted for VAX from indexs() on the PDP-11 (thanx to Ralph * Guggenheim). The name has changed to be more like the index() * and rindex() functions from Bell Labs; the return value (pointer * rather than integer) has changed partly for the same reason, * and partly due to popular usage of this function. * * Originally from rjg (Ralph Guggenheim) on IUS/SUS UNIX. */ char *sindex (big,small) char *big,*small; { register char *bp, *bp1, *sp; register char c = *small++; if (c==0) return(0); for (bp=big; *bp; bp++) if (*bp == c) { for (sp=small,bp1=bp+1; *sp && *sp == *bp1++; sp++) ; if (*sp==0) return(bp); } return 0; } # endif