/****************************************************************
* 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