/****************************************************************
* colin: TinyMUD automaton. Test Robot
*
* HISTORY
* 09-Jan-94 Michael Mauldin (mlm) at Carnegie-Mellon University
* Fourteenth animal release. New public release based on
* Julia.
*
* 17-Oct-90 Michael Mauldin (mlm) at Carnegie-Mellon University
* Tenth ceremonial release. Mods for planck DB switching.
*
* 05-May-90 Michael Mauldin (mlm) at Carnegie-Mellon University
* Seventh sequential release.
* Mods for TinyHELL.
*
* 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.
*
****************************************************************/
# include <stdio.h>
# include <ctype.h>
# include <sys/types.h>
# include <sys/ioctl.h>
# include <sys/socket.h>
# include <setjmp.h>
# include <netinet/in.h>
# include <netdb.h>
# include <signal.h>
# include <ctype.h>
# include <varargs.h>
# include <time.h>
# include "robot.h"
# include "vars.h"
# include "colin.h"
long period;
long havebook = 0;
/* Vars for defense against killers */
char kname[MSGSIZ] = "";
char kshape[MSGSIZ] = "";
long killed = 0;
long nosave = 0;
/* Not used in Colin */
long contest_mode = 0;
long tty_interface = 0;
char PI_500[512] = "3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196442881097566593344612847564823378678316527120190914564856692346034861045432664821339360726024914127372458700660631558817488152092096282925409171536436789259036001133053054882046652138414695194151160943305727036575959195309218611738193261179310511854807446237996274956735188575272489122793818301194912";
/****************************************************************
* setconfig: These values are defined in colin.h
****************************************************************/
setconfig ()
{
male = MALE;
whoami = WHOAMI;
owner = OWNER;
creation = CREATION;
if (myname == NULL) myname = MYNAME;
if (mudhost == NULL) mudhost = MUDHOST;
if (mudport == 0) mudport = MUDPORT;
}
/****************************************************************
* robot main loop
****************************************************************/
robot ()
{
waitfor ("Use the WHO command to ");
now = time (0);
if (mapfile == NULL)
{ mapfile = (streq (world, ALT1_WORLD) ? ALT1_MAPFILE :
streq (world, ALT2_WORLD) ? ALT2_MAPFILE :
ALT3_MAPFILE);
}
if (plyfile == NULL)
{ plyfile = (streq (world, ALT1_WORLD) ? ALT1_PLYFILE :
streq (world, ALT2_WORLD) ? ALT2_PLYFILE :
ALT3_PLYFILE);
}
if (streq (world, ALT1_WORLD))
{ mapfile = ALT1_MAPFILE;
plyfile = ALT1_PLYFILE;
ismuck = 0;
}
else if (streq (world, ALT2_WORLD))
{ mapfile = ALT2_MAPFILE;
plyfile = ALT2_PLYFILE;
ismuck = 0;
}
else if (streq (world, ALT3_WORLD))
{ mapfile = ALT3_MAPFILE;
plyfile = ALT3_PLYFILE;
ismuck = 1;
statuscmd = STATUS_CMD;
pagecmd = PAGE_CMD;
posecmd = POSE_CMD;
scorecmd = SCORE_CMD;
}
else
{ mapfile = UNK_MAPFILE;
plyfile = UNK_PLYFILE;
ismuck = 0;
}
read_players (plyfile);
read_map (mapfile);
check_players ();
/* Set up signal handling */
signal (SIGHUP, (void *) onintr);
signal (SIGINT, (void *) onintr);
/* Log in to TinyMUD */
sendmud ("connect %s %s", MYNAME, MYPASS);
/* Save state for resetting robot */
setjmp (start_state);
/* Initialize the robot */
start_up ();
while (playing)
{ char *dir;
long pl, from, to;
/* Check who is here and where we are */
check_time ();
do_special_check ();
do_msgs ();
/* Hi priority actions */
if (do_warn ()) continue;
if (do_typecmd ()) continue;
if (do_page ()) continue;
if (do_notes ()) continue;
if (do_findold (14 * DAYS)) continue;
if (do_explore ()) continue;
/* Long wait */
do_twiddle ();
/* Low priority actions */
if (do_wander ()) continue;
/* Reset if dead */
if (dead) reset_dead ();
}
sendmud ("QUIT");
sleep (2);
now = time (0);
fprintf (stderr, "\nExited main play loop at %15.15s.\n",
ctime (&now) + 4);
quit_robot ();
}
/****************************************************************
* start_up: Initial commands
****************************************************************/
start_up ()
{ static int locked = 0;
/* Special features of some worlds */
if (streq (world, "TinyHELL") ||
streq (world, "Islandia"))
{ pagedmsgs++; }
/* Reset character state */
sendmud ("%s %s", opre, outpre);
sendmud ("%s %s", osuf, outsuf);
if (!locked) { command ("@lock me = me"); locked++; }
command ("@descri me = %s.", WHOAMI); strcpy (mydesc, WHOAMI);
naked = 0;
command ("@fai me = You masher!");
command ("@ofai me = %s", ROBFAIL);
me = add_player (MYNAME);
wsynch ();
havebook = 0;
movemud ("home");
strcpy (home, here);
strcpy (homedesc, desc);
homerm = add_room (home, desc);
recrm = leads_to (homerm, "rec");
if (recrm == homerm) recrm = -1;
psynch ();
usynch ();
msgtype = M_UNKNOWN;
unlogged (":wakes up and picks his head off his desk."); atdesk++;
command ("@descri %s = %s", DESK, OPENMSG);
awake++;
lastcheck = now = time (0);
}
/****************************************************************
* do_special_check:
****************************************************************/
do_special_check ()
{ static lastshapecheck = 0;
now = time (0);
strcpy (postcmd, "");
return (1);
}
/****************************************************************
* do_warn: Warn the terminators target, if present
****************************************************************/
do_warn ()
{
/* Warn target player */
if (termtarg >= 0 &&
player[termtarg].present &&
player[termtarg].active &&
!termwarn &&
!dead)
{ strcpy (speaker, player[termtarg].name);
spoke_player (player[termtarg].name);
reply ("\"Oh by the way, %s, %s in %s about %s ago.",
player[termtarg].name,
"Terminator was looking for you",
termloc, time_dur (time (0) - termat));
termwarn = time (0);
return (1);
}
return (0);
}
/****************************************************************
* do_twiddle: Wait around a while
****************************************************************/
do_twiddle ()
{
/* Sit around and twiddle thumbs */
if (!dead && !*typecmd)
{ long dur;
if (nextwait) dur = nextwait;
else if (exploring) dur = (randint (speed) + 1) * 5;
else dur = randint (240) + 120;
nextwait = 0;
psynch ();
hangaround (dur);
return (1);
}
return (0);
}
/****************************************************************
* do_wander: Wander around
****************************************************************/
do_wander ()
{
/* If not exploring, head for his office */
if (!exploring && !nextwait && ! *pagedby &&
! *typecmd && ! dead && !takingnotes)
{ long dest;
long dice;
do
{ dice = randint (100);
dest = -1;
if (dice < 50)
{ dest = homerm; }
else if (dice < 70)
{ dest = close_room ("town", NULL); }
else if (dice < 80)
{ dest = close_room ("library", NULL); }
if (dest < 0)
{ do { dest = randint (rooms); } while (!room[dest].name); }
} while (dest < 0 || (dest == hererm || randint (100) < 90));
now = time (0);
fprintf (stderr, "Wndr: [%15.15s] %s(%d)\n",
ctime (&now) + 4, room_name (dest), dest);
disengage (room_name (dest));
pagedto = dest;
pagedfrom = hererm;
pagedat = time (0);
if (dest == homerm) { strcpy (pagedby, "<HOME>"); }
else { strcpy (pagedby, "<WHIM>"); }
return (1);
}
return (0);
}
/****************************************************************
* readmsg: Handle messages
****************************************************************/
readmsg (msg)
char *msg;
{ char lcmsg[TOKSIZ], name[MSGSIZ], place[MSGSIZ];
register char *s, *t;
long oldmsgtype;
long pl;
/* Drop messages that happen "between rooms". We should queue them */
if (inmove) return;
/* Stack message type */
oldmsgtype = msgtype;
msgtype = M_UNKNOWN;
/* Save lower case copy of message */
strcpy (lcmsg, lcstr (msg));
/* Save name for replies */
for (s=msg, t=name; *s && !isspace (*s); ) *t++ = *s++;
*t = '\0';
/*---- Standard message handling. Try each batch of replies in turn ----*/
if (special_mode (name, msg, lcmsg))
{ msgtype = oldmsgtype; return; }
/* Ignore most messages until we are really awake */
if (!awake)
{ msgtype = oldmsgtype; return; }
if (spoof_msg (name, msg, lcmsg) ||
says_msg (name, msg, lcmsg) ||
action_msg (name, msg, lcmsg))
{ msgtype = oldmsgtype; return; }
/* Ignore message altogether, then */
msgtype = oldmsgtype; return;
}
/****************************************************************
* spoof_msg: Check for messages from robots own name
****************************************************************/
spoof_msg (name, msg, lcmsg)
char *name, *msg, *lcmsg;
{
if (is_me (name))
{ if (!printedloc) print_locn ();
fprintf (stderr, "Spof: saw message '%s'\n", msg);
msgtype = M_UNKNOWN;
reply (":detects spoofing, fake message was '%s'", msg);
return (1);
}
else
{ return (0); }
}
/****************************************************************
* says_msg: Handle spoken messages from other players (that is
* messages like 'Foo says "Hello."').
****************************************************************/
says_msg (name, msg, lcmsg)
char *name, *msg, *lcmsg;
{ char buf[TOKSIZ], lcbuf[TOKSIZ], *is_tell();
char sname[TOKSIZ];
register char *s;
/* skip over first word (should be the name) */
for (s=msg; *s && !isspace (*s); s++);
while (isspace (*s)) s++;
/* Check for and remove trailing 's */
if (ismuck && strlen (name) > 2 && streq (name+strlen(name)-2, "'s"))
{ strcpy (sname, name);
sname[strlen (name) - 2] = '\0';
if (find_player (sname) >= 0)
{ name[strlen (name) - 2] = '\0';
}
}
/* Verify that this is a speech action */
if (!awake) { return (0); }
else if (stlmatch (s, "says")) { s += 4; msgtype = M_SPOKEN; }
else if (ismuck && index (s, '"')) { while (*s && *s != '"') s++;
msgtype = M_PAGE; pagedmsgs++;
}
else if (stlmatch (s, "whispers")) { s += 8; msgtype = M_WHISPER; }
else if (stlmatch (s, "pages:")) { s += 5; msgtype = M_PAGE; pagedmsgs++; }
else if (stlmatch (s, "shouts")) { s += 6; msgtype = M_SHOUT; }
else { return (0); }
/* Count messages/actions in this room */
room[hererm].msgsum++;
/*
* Strip leading and trailing quotes, punctuation, and whitespace,
* put message in buf, save lower case version in lcbuf.
*/
while (isspace (s[0]) || index ("`'\".,:;!?", s[0])) s++;
strcpy (buf, s);
s = buf + strlen (buf);
while (isspace (s[-1]) || index ("`'\".,:;!?", s[-1])) s--;
*s = '\0';
strcpy (lcbuf, lcstr (buf));
/*-------- Log the message --------*/
if (!printedloc) print_locn ();
if ((s = is_tell (lcbuf)) && !isowner (s) && !isowner (name))
{ fprintf (stderr, "Says: %s[%s] <msg to %s>\n",
msgtype == M_SPOKEN ? "" :
msgtype == M_WHISPER ? "whisp" :
msgtype == M_PAGE ? "pages" :
msgtype == M_SHOUT ? "shout" : "poses",
name, s);
}
else
{ fprintf (stderr, "Says: %s[%s] \"%s\"\n",
msgtype == M_SPOKEN ? "" :
msgtype == M_WHISPER ? "whisp" :
msgtype == M_PAGE ? "pages" :
msgtype == M_SHOUT ? "shout" : "poses",
name, buf);
}
if (awake && find_player (name) >= 0 && !reserved (name))
{ if (msgtype < M_PAGE) saw_player (name, here, desc);
/* New: do not gossip about whispers or pages */
if (msgtype == M_SPOKEN) heard_player (name, buf);
}
speaktime = time (0);
/*---- Verify that this message was meant for the robot ----*/
if ((msgtype != M_SPOKEN && msgtype != M_SHOUT) || to_me (name, buf, lcbuf))
{ check_stay ();
/* Now try various speech rule sets */
if (hi_priority (name, buf, lcbuf) ||
small_talk (name, buf, lcbuf) ||
standard_msg (name, buf, lcbuf) ||
lo_priority (name, buf, lcbuf) ||
polite_msg (name, buf, lcbuf) ||
sorry_msg (name, buf, lcbuf))
{ return (1); }
}
/*---- The speaker has started talking to someone else ----*/
else if (streq (name, speaker))
{ strcpy (speaker, ""); }
/* Message was "says", so we match it by ignoring it */
return (1);
}
/****************************************************************
* hi_priority: Handle messages that must be checked first. That
* does not mean they are particularly important.
****************************************************************/
hi_priority (name, msg, lcmsg)
char *name, *msg, *lcmsg;
{ long dur, pl;
char *item, *s, *is_tell();
/*---- Colin wont talk to his last murderer ----*/
if (!isowner (name) && (dur = killed_me_today (name)))
{ if (dur && dur < 10) return (1);
strcpy (speaker, name);
switch (randint (4))
{ case 0: reply ("\"I don't talk to murderers!"); break;
case 1: reply (":ignores %s.", name); break;
case 2: reply (":steels himself for another attack from %s.", name);
break;
default: ; /* totally ignore them */
}
return (1);
}
/*---- A message to another player ----*/
else if (s = is_tell (lcmsg))
{ char buf[BIGBUF];
strcpy (speaker, name);
spoke_player (name);
if ((pl = find_player (s)) >= 0)
{ sprintf (buf, "%s said '%s'", name, msg);
add_msg (pl, now, buf);
if (PLAYER_GET(pl, PL_HAVEN))
{ reply ("\"Message saved, %s, but %s %s. When I next see %s, %s",
name, player[pl].name,
"was not accepting pages last time I checked",
player[pl].name, "I'll relay the message by whispering.");
}
else
{ unlogged ("\"Message for %s saved, %s.", player[pl].name, name); }
}
else
{ reply ("\"I've never heard of player %s, %s.", s, name); }
return (1);
}
/*---- Tell Colin to quit ----*/
else if (MATCH (lcmsg, "*bye*") ||
MATCH (lcmsg, "*good*night*") ||
MATCH (lcmsg, "*good*day*") ||
MATCH (lcmsg, "*adios*") ||
MATCH (lcmsg, "*ciao*") ||
MATCH (lcmsg, "*auf*wieder*") ||
MATCH (lcmsg, "*shut*up*") ||
MATCH (lcmsg, "*shutdown*") ||
MATCH (lcmsg, "*later*guy*") ||
MATCH (lcmsg, "*later*dude*") ||
MATCH (lcmsg, "*later*people*") ||
MATCH (lcmsg, "*later*d00*") ||
MATCH (lcmsg, "*be*quiet*") ||
MATCH (lcmsg, "*stop*talk*") ||
MATCH (lcmsg, "*have a*nice*day*") ||
MATCH (lcmsg, "*hasta*luego*") ||
MATCH (lcmsg, "*hasta*l*vista*") ||
MATCH (lcmsg, "*stop*talk*") ||
MATCH (lcmsg, "*sayonara*") ||
MATCH (lcmsg, "*i'm*leaving*") ||
MATCH (lcmsg, "*i'm*out*here*") ||
MATCH (lcmsg, "*hasta*vista*"))
{ if (isowner (name) &&
(ismuck && *code && sindex (msg, code) ||
trusting && MATCH (lcmsg, "bye*colin")))
{ fprintf (stderr, "Quitting on command of %s\n", name);
sendmud ("\"Goodbye, %s, I'm going home to sleep.", name);
sendmud ("home");
sendmud ("@describe %s = %s", DESK, CLOSEDMSG);
sendmud (":puts his head down and goes to sleep.");
sendmud ("@describe me = %s", POWEROFF); strcpy (mydesc, POWEROFF);
sendmud ("QUIT");
spoke_player (name);
quit_robot ();
}
else /* They probably mean they are leaving */
{ static lastgoodbye = 0;
if (now - lastgoodbye > 30)
{ spoke_player (name);
strcpy (speaker, name);
speaktime = 0;
reply ("\"Goodbye, %s.", name);
strcpy (speaker, "");
lastgoodbye = now;
return (1);
}
}
}
/*---- Set code word ----*/
else if (MATCH (lcmsg, "*what*is*code*word*") && isowner (name))
{ strcpy (speaker, name);
spoke_player (name);
if (msgtype < M_WHISPER) msgtype = M_WHISPER;
reply ("\"The code word is %s, %s.", strcpy (code, codeword ()), name);
codeset = now;
return (1);
}
/*---- Set code word ----*/
else if (isowner (name) &&
(MATCH (lcmsg, "*forget*code*") ||
MATCH (lcmsg, "*erase*code*") ||
MATCH (lcmsg, "*invalidate*code*")))
{ strcpy (speaker, name);
spoke_player (name);
strcpy (code, "");
codeset = now;
if (msgtype < M_WHISPER) msgtype = M_WHISPER;
reply ("\"Code word cleared, %s.", name);
return (1);
}
/*---- Checkpoint files ----*/
else if (MATCH (lcmsg, "*core*dump*colin*"))
{ strcpy (speaker, name);
spoke_player (name);
if (isowner (name) && (trusting || *code && sindex (msg, code)))
{ crash_robot ("Core dumped by %s: %s", name, msg); }
return (1);
}
/*---- Checkpoint files ----*/
else if (MATCH (lcmsg, "wait") ||
MATCH (lcmsg, "*, wait") ||
MATCH (lcmsg, "wait, *") ||
MATCH (lcmsg, "stay") ||
MATCH (lcmsg, "*, stay") ||
MATCH (lcmsg, "stay, *") ||
MATCH (lcmsg, "stop") ||
MATCH (lcmsg, "*, stop") ||
MATCH (lcmsg, "stop, *") ||
MATCH (lcmsg, "*don't go*") ||
MATCH (lcmsg, "*don't leave*"))
{ strcpy (speaker, name);
spoke_player (name);
if (isowner (name) ||
(!*pagedby ||
streq (pagedby, "<WHIM>") ||
streq (pagedby, "<HOME>") ||
streq (pagedby, "<EXPLORING>")))
{ if (nextwait < 180) nextwait = 180;
switch (randint (4))
{ case 0: reply ("\"Okay, %s, I'll stay.", name); break;
case 1: reply ("\"I'll stay a while, then, %s.", name); break;
case 2: reply ("\"I can stay a few minutes, I guess, %s.", name);
break;
case 3: reply ("\"For you, %s, sure....", name); break;
}
}
else
{ reply ("\"Sorry, %s, I really must be going.", name); }
return (1);
}
/*---- A query about 'who belong' ----*/
else if (MATCH (lcmsg, "*who*you*belong*") ||
MATCH (lcmsg, "*whose*are*you*") ||
MATCH (lcmsg, "*who*you*owner*") ||
MATCH (lcmsg, "*who*work*") ||
MATCH (lcmsg, "*who*built*you*") ||
MATCH (lcmsg, "*who*made*you*") ||
MATCH (lcmsg, "*who*created*you*") ||
MATCH (lcmsg, "*who*you*creator*") ||
MATCH (lcmsg, "*who*wrote*") ||
MATCH (lcmsg, "*who*own*juli*") ||
MATCH (lcmsg, "*who*juli*owner*") ||
MATCH (lcmsg, "*who*s*you*amway*") ||
MATCH (lcmsg, "*who*s*reinc*elvis*") ||
MATCH (lcmsg, "*who*s*third*hacker*") ||
MATCH (lcmsg, "*who*own*you*"))
{ strcpy (speaker, name);
spoke_player (name);
if (isowner ("Fuzzy"))
{ reply ("\"Fuzzy, of course, %s.", name); }
else
{ reply ("\"Fuzzy created me, but I work for %s, %s.", owner, name); }
return (1);
}
/*---- A query about 'how ' ----*/
else if (MATCH (lcmsg, "*who*are*you*") ||
MATCH (lcmsg, "*what*is*you*"))
{ strcpy (speaker, name);
spoke_player (name);
reply ("\"I am Colin, the Maas-Neotek Robot, %s", name);
return;
}
/*---- A query about 'how ' ----*/
else if (MATCH (lcmsg, "*give*me*tour*") ||
MATCH (lcmsg, "*take*me*tour*"))
{ strcpy (speaker, name);
spoke_player (name);
give_tour (lcmsg, name);
return;
}
/*---- A query about lines ----*/
else if (MATCH (lcmsg, "*would*you*like *,*") ||
MATCH (lcmsg, "*would*you*like *") ||
MATCH (lcmsg, "*how*you*like *,*") ||
MATCH (lcmsg, "*how*you*like *") ||
MATCH (lcmsg, "*do*you*like *,*") ||
MATCH (lcmsg, "*do*you*like *"))
{
strcpy (speaker, name);
spoke_player (name);
switch (randint (2))
{ case 0: reply ("\"I'm not sure, %s.", name); break;
case 1: reply ("\"I don't know, %s.", name); break;
}
return (1);
}
/* Message not matched by this rule set */
return (0);
}
/****************************************************************
* small_talk: handle small talk, come-ons, put-downs, etc.
****************************************************************/
small_talk (name, msg, lcmsg)
char *name, *msg, *lcmsg;
{
/*---- Hug ----*/
if (MATCH (lcmsg, "hug me*") ||
MATCH (lcmsg, "* hug me*") ||
MATCH (lcmsg, "*embrace me*") ||
MATCH (lcmsg, "*take*me*your*arm*") ||
MATCH (lcmsg, "*wrap*your*arm*"))
{ strcpy (speaker, name);
spoke_player (name);
switch (randint (2))
{ case 0: reply (":hugs %s.", name); break;
case 1: zinger (":shakes %s's hand, instead.", name); break;
}
return (1);
}
/* Message not matched by this rule set */
return (0);
}
/****************************************************************
* lo_priority: Handle messages particular to a given robot
* This is the place to add your own replies and
* give your robot a personality.
****************************************************************/
# define FIRST_LAW \
"1. A Robot may not injure a human being, or, through inaction, \
allow a human being to come to harm."
# define SECOND_LAW \
"2. A robot must obey the orders given it by human beings except \
where such orders would conflict with the First Law."
# define THIRD_LAW \
"3. A robot must protect its own existence as long as such protection \
does not conflict with the First and Second Laws."
# define LAW_REF \
"Isaac Asimov, \"Runaround\", Astounding Science Fiction, March 1942."
lo_priority (name, msg, lcmsg)
char *name, *msg, *lcmsg;
{ long count;
static long grouch = 0;
/*---- A query about 'the laws of robotics' ----*/
if ((sindex (lcmsg, "what is") ||
sindex (lcmsg, "what are") ||
MATCH (lcmsg, "*do*you*know*") ||
sindex (lcmsg, "*tell*") ||
sindex (lcmsg, "*describe*") ||
sindex (lcmsg, "*repeat*") ||
sindex (lcmsg, "*say*") ||
sindex (lcmsg, "*say*")) &&
(MATCH (lcmsg, "*three*laws*") ||
MATCH (lcmsg, "*three*rules*") ||
MATCH (lcmsg, "*asimov*law*") ||
MATCH (lcmsg, "*asimov*rule*") ||
MATCH (lcmsg, "*law*robot*") ||
MATCH (lcmsg, "*rule*robot*") ||
MATCH (lcmsg, "*zero*law*") ||
MATCH (lcmsg, "*0*law*") ||
MATCH (lcmsg, "*first*law*") ||
MATCH (lcmsg, "*1st*law*") ||
MATCH (lcmsg, "*second*law*") ||
MATCH (lcmsg, "*2nd*law*") ||
MATCH (lcmsg, "*third*law*") ||
MATCH (lcmsg, "*3rd*law*")))
{ int printed=0;
strcpy (speaker, name);
spoke_player (name);
if (sindex (lcmsg, "zeroth") || sindex (lcmsg, "0"))
{ zinger ("\"The zeroth law is a myth, %s", name); return (1);}
if (sindex (lcmsg, "first") || sindex (lcmsg, "1"))
{ zinger (": %s", FIRST_LAW); printed++; }
if (sindex (lcmsg, "second") || sindex (lcmsg, "2"))
{ zinger (": %s", SECOND_LAW); printed++; }
if (sindex (lcmsg, "third") || sindex (lcmsg, "3"))
{ zinger (": %s", THIRD_LAW); printed++; }
if (!printed)
{ zinger (":%s", FIRST_LAW);
zinger (":%s", SECOND_LAW);
zinger (":%s", THIRD_LAW);
}
zinger (": --%s", LAW_REF);
return (1);
}
/*---- Do you work here ----*/
else if (MATCH (lcmsg, "*do you*here*") &&
(sindex (lcmsg, "work") ||
sindex (lcmsg, "live") ||
sindex (lcmsg, "stay")))
{ strcpy (speaker, name);
spoke_player (name);
if (hererm == homerm)
{ reply ("\"Yes, I work here, %s.", name); }
else
{ reply ("\"No, I work in %s, %s.", room_name (homerm), name); }
return;
}
/*---- Where do you work ----*/
else if (MATCH (lcmsg, "*where*do you*") &&
(sindex (lcmsg, "work") ||
sindex (lcmsg, "live") ||
sindex (lcmsg, "hang out") ||
sindex (lcmsg, "stay")))
{ strcpy (speaker, name);
spoke_player (name);
reply ("\"I work in %s, %s.", room_name (homerm), name);
return;
}
/*---- Pick commands ----*/
else if ((MATCH (lcmsg, "*take *") ||
MATCH (lcmsg, "*get *") ||
MATCH (lcmsg, "*pick *")) &&
!sindex (lcmsg, "don't") &&
!sindex (lcmsg, "sorry"))
{ strcpy (speaker, name);
spoke_player (name);
reply ("\"I'm sorry, %s, I don't pick things up.", name);
return (1);
}
/*---- Pick commands ----*/
else if (MATCH (lcmsg, "*kill*") ||
MATCH (lcmsg, "*murder*") ||
MATCH (lcmsg, "*fight*"))
{ strcpy (speaker, name);
spoke_player (name);
reply ("\"I'm sorry, %s, I don't like violence.", name);
return (1);
}
/*---- Are you a robot ----*/
else if (MATCH (lcmsg, "*are*you*robot*") ||
MATCH (lcmsg, "*are*you*a bot*") ||
MATCH (lcmsg, "*are*you*an ai*") ||
MATCH (lcmsg, "*are*you*autom*") ||
MATCH (lcmsg, "*are*you*machine*") ||
MATCH (lcmsg, "*are*you*computer*") ||
MATCH (lcmsg, "*are*you*program*") ||
MATCH (lcmsg, "*are*you*simulati*") ||
MATCH (lcmsg, "*you*are*robot*") ||
MATCH (lcmsg, "*you*are*a bot*") ||
MATCH (lcmsg, "*you*are*an ai*") ||
MATCH (lcmsg, "*you*are*autom*") ||
MATCH (lcmsg, "*you*are*machine*") ||
MATCH (lcmsg, "*you*are*computer*") ||
MATCH (lcmsg, "*you*are*program*") ||
MATCH (lcmsg, "*you*are*simulati*") ||
MATCH (lcmsg, "*you* be *robot*") ||
MATCH (lcmsg, "*you* be *a bot*") ||
MATCH (lcmsg, "*you* be *an ai*") ||
MATCH (lcmsg, "*you* be *autom*") ||
MATCH (lcmsg, "*you* be *machine*") ||
MATCH (lcmsg, "*you* be *computer*") ||
MATCH (lcmsg, "*you* be *program*") ||
MATCH (lcmsg, "*you* be *simulati*") ||
MATCH (lcmsg, "*colin is *") &&
(sindex (res2, "robot") ||
sindex (res2, "program") ||
sindex (res2, "simulati") ||
sindex (res2, " bot") ||
sindex (res2, "automat") ||
sindex (res2, "machine") ||
sindex (res2, "computer")))
{ static long lasttold = 0;
strcpy (speaker, name);
spoke_player (name);
if ((now - lasttold) > 2 * MINUTES )
{ zinger ("\"I am a Maas-Neotek robot, %s.", VERSION);
lasttold = now;
}
else
{ reply (":nods."); }
return (1);
}
/*---- Are you wizard ----*/
else if (MATCH (lcmsg, "*are*you*wizard*"))
{ sleep (2);
strcpy (speaker, name);
spoke_player (name);
switch (randint (4))
{ case 0: zinger ("\"I am not a wizard, %s.", name); break;
case 1: zinger ("\"I do not believe I'm a wizard, %s.", name); break;
case 2: zinger ("\"I'd like to be a wizard, %s.", name); break;
case 3: zinger ("\"I don't know, %s.", name); break;
}
return (1);
}
/* Message not matched by this rule set */
return (0);
}
/****************************************************************
* sorry_msg: fail message. Say "I did not understand"
****************************************************************/
sorry_msg (name, msg, lcmsg)
char *name, *msg, *lcmsg;
{
/*---- Log the non-understood msg ----*/
sorry_log (name, msg);
/*---- Else ----*/
if (randint (100) < 50 ||
MATCH (lcmsg, "*, colin*") ||
MATCH (lcmsg, "*colin: *") ||
MATCH (lcmsg, "*colin, *"))
{ sleep (2);
strcpy (speaker, name);
spoke_player (name);
if (msgtype < M_WHISPER) msgtype = M_WHISPER;
reply ("\"I'm sorry, %s, I couldn't understand you.", name);
return (1);
}
/* Message not matched by this rule set */
return (0);
}
/****************************************************************
* action_msg: handle actions (some involve TinyMUD world messages)
****************************************************************/
action_msg (name, msg, lcmsg)
char *name, *msg, *lcmsg;
{ long pl, rm, dur;
char *action, abuf[MSGSIZ], *gerund, *item, *plural, *iscloth();
int pokes=0, molests=0, isplural=0;
/* Count messages/actions in this room */
room[hererm].msgsum++;
/*-------- If dead, ignore actions until reset --------*/
if (dead) return (1);
/*-------- Log players actions --------*/
if (awake && find_player (name) >= 0 &&
(!reserved (name) || stlmatch (msg, "You killed")) &&
!MATCH (msg, "* has left.") &&
!MATCH (msg, "* brushes by you, heading *.") &&
!MATCH (msg, "* has arrived."))
{ register char *s;
for (s=msg; *s && !isspace (*s); s++) ;
while (isspace (*s)) s++;
if (!printedloc) print_locn ();
fprintf (stderr, "Actn: [%s] %s\n", name, s);
active_player (name, here, desc);
}
/*-------- If dead, ignore actions until reset --------*/
msgtype = M_ACTION;
/*-------- Accept donations --------*/
if (MATCH (lcmsg, "* gives you * pennies.") ||
MATCH (lcmsg, "* gives you * penny."))
{ long oldpennies = pennies;
strcpy (speaker, name);
speaktime = time (0);
if (debug) fprintf (stderr, "Recv: [%s] %s pennies\n", res1, res2);
/* Check for spoofing */
psynch ();
donate_player (name, atoi (res2));
if ((killed_me_today (name) ||
streq (kshape, name) ||
streq (kname, name)) &&
pennies > oldpennies &&
randint (100) < (pennies - oldpennies))
{ player[add_player (name)].lastkill = 0;
if (streq (kshape, name) || streq (kname, name))
{ command ("@lock me = me");
strcpy (kname, "");
strcpy (kshape, "");
}
reply ("\"Okay, %s, you're forgiven.", name);
}
else
{ reply ("\"Thanks for the donation, %s.", name); }
return (1);
}
/*-------- Arrivals --------*/
else if (MATCH (msg, "* has arrived."))
{ static long artime = 0;
char buf[MSGSIZ];
strcpy (buf, res1);
if (!terse) fprintf (stderr, "Arrv: [%s]\n", buf);
arrive_player (buf, here, desc);
alone++;
if (((pl = find_player (buf)) >= 0) &&
(player[pl].lastlook + 600 < now))
{ look_at_thing (buf); }
/* Special case if someone walks into robots home */
if ((atdesk || !quiet && randint (100) < 20) && time (0) > artime + 30)
{ if ((pl = find_player (name)) < 0 ||
time (0) > player[pl].lastspoke + 300)
{ strcpy (speaker, name);
spoke_player (name);
reply ("\"Hello, %s.", name);
}
else
{ reply (":nods to %s.", name); }
artime = time (0);
}
give_msgs (find_player (name));
return (1);
}
/*-------- Depart --------*/
else if (MATCH (msg, "* has left.") ||
MATCH (msg, "* has disconnected.") ||
MATCH (msg, "* brushes by you, heading *."))
{ if (!terse) fprintf (stderr, "Dprt: [%s]\n", res1);
leave_player (res1, here, desc);
--alone;
if (streq (res1, speaker)) *speaker = '\0';
return (1);
}
/*-------- Murder attempts --------*/
else if (MATCH (msg, "* tried to kill you!"))
{ if (!printedloc) print_locn ();
fprintf (stderr, "Kill: [%s] attempt\n", name);
assault_player (name);
reply ("\"Help! Help! %s tried to kill me!", name);
return (1);
}
/*-------- Murdered! --------*/
else if (MATCH (msg, "* killed you!") ||
ismuck && MATCH (msg, "* killed Colin!"))
{ if (!printedloc) print_locn ();
fprintf (stderr, "Kill: [%s] success\n", name);
strcpy (kname, name);
assault_player (name);
return (1);
}
/*-------- Dispatch on first character --------*/
else
{ switch (lcmsg[0])
{ case 'e': if (!ismuck &&
MATCH (lcmsg, "either that player does not exist*"))
{ fprintf (stderr, "Cannot connect to character\n");
sendmud ("QUIT");
quit_robot ();
}
break;
case 'g': if (MATCH (lcmsg, "give to whom*"))
{ gave = 0; return (1); }
else if (MATCH (lcmsg, "going down - bye*"))
{ now = time (0);
fprintf (stderr, "\nGoing down message: %15.15s.\n",
ctime (&now) + 4);
if (ismuck)
{ fprintf (stderr, "Ignr: ignoring going down message\n"); }
else
{ lost_connect (NULL, 0); quit_robot (); }
return (1);
}
break;
case 'y': if (MATCH (msg, "You sense that * is looking for you in *."))
{ set_page (res1, res2); return (1); }
else if (streq (msg, "You feel a wrenching sensation..."))
{ fprintf (stderr, "Tele: from %s(%d)", here, hererm);
reset_teleported ();
return (1);
}
else if (MATCH (msg, "You sense that * is forcing you to *"))
{ fprintf (stderr, "FORC: %s\n", msg);
msgtype = M_UNKNOWN;
reply (":was forced by %s to type \"%s\"", res1, res2);
}
else if (MATCH (lcmsg, "your insurance policy*"))
{ strcpy (killer, kname);
strcpy (kshape, kname);
killed = now;
dead++;
fprintf (stderr, "Dead: setting killer to '%s'\n", kname);
if (*kname) command ("@lock me = me & !*%s", kname);
if (MATCH (lcmsg, "your insurance policy pays * penn*"))
{ pennies += atoi (res1); }
return (1);
}
break;
}
}
/*-------- Actions involving Colin --------*/
/*---- Colin wont talk to his last murderer ----*/
if (!isowner (name) && (dur = killed_me_today (name)) &&
sindex (lcmsg, lcstr (myname)))
{ switch (randint (4))
{ case 0: reply ("\"I don't talk to murderers!"); break;
case 1: reply (":ignores %s.", name); break;
case 2: reply (":steels himself for another attack from %s.", name);
break;
default: ; /* totally ignore them */
}
return (1);
}
/*---- Ping! ----*/
if (MATCH (lcmsg, "* pings colin*") && !sindex (res2, "back"))
{ static long lastping = 0, lastpinger = 0;
pl = find_player (name);
strcpy (speaker, name);
spoke_player (name);
if (lastpinger != pl || lastping + randint (15) < now)
{ zinger (":pings %s back.", name);
lastpinger = pl;
lastping = now;
}
return (1);
}
/*---- Friendly greeting ----*/
if (MATCH (lcmsg, "* waves to colin*") && (action = "waves to") ||
MATCH (lcmsg, "* smiles at colin*") && (action = "smiles at") ||
MATCH (lcmsg, "* smiles to colin*") && (action = "smiles at") ||
MATCH (lcmsg, "* hugs colin*") && (action = "hugs") ||
MATCH (lcmsg, "* nods to colin*") && (action = "nods to") ||
MATCH (lcmsg, "* blinks at colin*") && (action = "blinks at") ||
MATCH (lcmsg, "* kisses colin*") && (action = "kisses") &&
randint (100) < 50 ||
MATCH (lcmsg, "* greets colin*") && (action = "greets"))
{ static long lasthug = 0, lasthugee = 0;
pl = find_player (name);
strcpy (speaker, name);
spoke_player (name);
if (lasthugee != pl || lasthug + randint (15) < now)
{ switch (randint (6))
{ case 0: reply ("\"Hi, %s!", name); break;
case 1: reply (":hugs %s.", name); break;
case 2: reply (":waves to %s.", name); break;
case 3: reply (":nods to %s.", name); break;
case 4: reply (":greets %s.", name); break;
case 5: reply (":smiles at %s.", name); break;
}
lasthugee = pl;
lasthug = now;
}
return (1);
}
/*---- Say ouch ----*/
if (MATCH (lcmsg, "* assaults colin*") && (action = "assault") ||
MATCH (lcmsg, "* baps colin*") && (action = "bap") ||
MATCH (lcmsg, "* bashes colin*") && (action = "bash") ||
MATCH (lcmsg, "* bonks colin*") && (action = "BONK") ||
MATCH (lcmsg, "* bops colin*") && (action = "bop") ||
MATCH (lcmsg, "* hits colin*") && (action = "hit") ||
MATCH (lcmsg, "* kicks colin*") && (action = "kick") ||
MATCH (lcmsg, "* prods colin*") && (action = "prod") ||
MATCH (lcmsg, "* pushes colin*") && (action = "push") ||
MATCH (lcmsg, "* reprogrames colin*") && (action = "reprogram"))
{ pokes++; }
else if (
MATCH (lcmsg, "* slaps colin*") && (action = "slap") ||
MATCH (lcmsg, "* slashes colin*") && (action = "slash") ||
MATCH (lcmsg, "* spanks colin*") && (action = "spank") ||
MATCH (lcmsg, "* stabs colin*") && (action = "stab") ||
MATCH (lcmsg, "* thumps colin*") && (action = "thump") ||
MATCH (lcmsg, "* thwacks colin*") && (action = "thwack") ||
MATCH (lcmsg, "* whacks colin*") && (action = "whack") ||
MATCH (lcmsg, "* whaps colin*") && (action = "whap") ||
MATCH (lcmsg, "* whips colin*") && (action = "whip"))
{ pokes++; }
if (pokes)
{ strcpy (speaker, name);
spoke_player (name);
if (streq (action, "BONK") && randint (100) < 40)
{ zinger ("\"OIF, %s!", name); }
else
{ switch (randint (5))
{ case 0: zinger ("\"Ouch, %s!", name); break;
case 1: zinger ("\"Quit it, %s!", name); break;
case 2: zinger ("\"Stop that, %s!", name); break;
case 3: zinger ("\"Don't you dare, %s!", name); break;
case 4: zinger ("\"Don't do that, %s!", name); break;
}
}
return (1);
}
/* Message not matched by this rule set */
return (0);
}
/****************************************************************
* page_okay: True if we will allow caller to page us to loc
* this function is not called for owner.
****************************************************************/
page_okay (caller, loc)
char *caller, *loc;
{
if (killed_me_today (caller) && !isowner (caller))
{ if (!quiet || randint (100) < 10)
{ reply ("\"Hah! %s is paging me from %s. %s.",
caller, loc, "I don't answer pages from murderers");
}
return (0);
}
return (1);
}
/****************************************************************
* home_hook: We went "home"
****************************************************************/
home_hook ()
{ havebook = 0; }
/****************************************************************
* before_move_hook: things to do before moving out of current room
****************************************************************/
before_move_hook ()
{
if (streq (here, home))
{ if (atdesk) send_pose ("gets up from his desk."); atdesk=0;
command ("@describe %s = %s", DESK, AWAYMSG);
}
if (pagedto >= 0 && pagedfrom != hererm &&
(!quiet || streq (pagedby, "<AUTORETURN>")))
{ msgtype = M_UNKNOWN;
if (streq (pagedby, "<HOME>"))
{ unlogged (":strolls by on %s way home.", MALE ? "his" : "her"); }
else if (streq (pagedby, "<unlogged>"))
{ unlogged (":goes by on %s way to %s.",
MALE ? "his" : "her", room_name (pagedto)); }
else if (streq (pagedby, "<WHIM>"))
{ unlogged (":wanders by on %s way to %s.",
MALE ? "his" : "her", room_name (pagedto)); }
else if (streq (pagedby, "<EXPLORING>"))
{ command (":walks by on %s way to explore %s.",
MALE ? "his" : "her", room_name (pagedto)); }
else
{ command (":rushes by on %s way to %s to see %s.",
MALE ? "his" : "her", room_name (pagedto), pagedby);
}
}
}
/****************************************************************
* after_move_hook: things to do after moving out of current room
****************************************************************/
after_move_hook ()
{
}
/****************************************************************
* new_room_hook: things to do after moving into a new room
****************************************************************/
new_room_hook ()
{
strcpy (speaker, "");
strcpy (pathto, "");
/* Tell our caller where we are */
if (*pagedby && *pagedby != '<' && hererm != pagedto && pennies > MINPEN)
{ pennies --;
command ("page %s = I'm now in %s", pagedby, room_name (hererm));
}
/* Check for home actions */
if (hererm == homerm)
{ if (!atdesk && (pagedto < 0 || pagedto == homerm))
{ if (awake)
{ unlogged (":sits down at his desk."); atdesk++;
command ("@descri %s = %s", DESK, OPENMSG);
}
}
}
}
/****************************************************************
* checkpoint: Write out files
****************************************************************/
checkpoint ()
{
now = time (0);
fprintf (stderr,
"Save: %15.15s, %ld of %ld rooms new, %ld of %ld exits new\n",
ctime (&now) + 4, newrooms, rooms, newexits, exits);
write_players (plyfile);
if (newrooms || newexits)
{ write_map (mapfile, 0);
now = time (0);
if (!terse) fprintf (stderr, "Save: done at %15.15s\n", ctime (&now) + 4);
}
lastcheck = time (0);
newrooms = newexits = 0;
}
/****************************************************************
* onintr: Got an interrupt, checkpoint and quit
****************************************************************/
onintr ()
{
fprintf (stderr, "Quitting because of interrupt\n");
sendmud ("\"Goodbye, all, I'm going home to sleep.");
sendmud ("home");
sendmud ("@describe %s = %s", DESK, CLOSEDMSG);
sendmud (":puts his head down and goes to sleep.");
sendmud ("@describe me = %s", POWEROFF); strcpy (mydesc, POWEROFF);
sendmud ("QUIT");
quit_robot ();
exit (0);
}
/****************************************************************
* isowner: Return true if the named person can give special orders
****************************************************************/
isowner (name)
{ return (streq (lcstr (name), OWNER)); }
/****************************************************************
* amount_hook: Check amount given to player
****************************************************************/
amount_hook (amount, name, polite)
long amount, polite;
char *name;
{
return (amount);
}
/****************************************************************
* who_is_hook:
****************************************************************/
who_is_hook (pers, name)
char *pers, *name;
{
if (streq (pers, "fuzzy"))
{ switch (randint (6))
{ case 0: zinger ("\"%s just this guy I met in a bar, %s.",
streq (name, "Fuzzy") ? "You're" : "He's", name);
break;
case 1: zinger ("\"%s the reincarnation of Elvis Presley, %s.",
streq (name, "Fuzzy") ? "You're" : "He's", name); break;
case 2: zinger ("\"%s the world's third greatest hacker, %s.",
streq (name, "Fuzzy") ? "You're" : "He's", name); break;
case 3: zinger ("\"%s just this guy, you know, %s.",
streq (name, "Fuzzy") ? "You're" : "He's", name);
break;
case 4: zinger ("\"%s my Amway representative, %s.",
streq (name, "Fuzzy") ? "You're" : "He's", name);
break;
case 5: zinger ("\"I don't know, %s, I just follow %s around.",
name, streq (name, "Fuzzy") ? "you" : "him"); break;
}
}
else if (streq (pers, "stewy"))
{ reply ("\"%s Clamen Airlines and the People Mover, %s.",
streq (name, "Stewy") ? "You run" : "He runs", name); }
else if (streq (pers, "flexi"))
{ reply ("\"%s Puddle Blvd. and Emailboxes, %s.",
streq (name, "flexi") ? "You run" : "He runs", name); }
else if (streq (pers, "wizard"))
{ reply ("\"%s used to own the world and everything in it, %s.",
streq (name, "Wizard") ? "You" : "He", name); }
else if (streq (pers, "tinker"))
{ reply ("\"%s the world and everything in it, %s.",
streq (name, "Tinker") ? "You own" : "He owns", name); }
else if (streq (pers, "nymph"))
{ reply ("\"%s the Rec Room, %s.",
streq (name, "Nymph") ? "You own" : "She owns", name); }
else if (streq (pers, "zippy"))
{ reply ("\"%s the TFM room, %s.",
streq (name, "zippy") ? "You own" : "He owns", name); }
else if (streq (pers, "danny"))
{ reply ("\"He's the chatty hermit who lives %s, %s.",
"in a dark cave north of Cirdan's", name); }
else if (streq (pers, "gloria"))
{ reply ("\"She was the assistant librarian of the original TinyMUD, %s.",
name); }
else
{ return (0); }
return (1);
}
/****************************************************************
* do_number: Unused in Colin
****************************************************************/
do_number ()
{
return (0);
}
/****************************************************************
* lost_connect: Watchdog: send mail if Islandia goes down
****************************************************************/
lost_connect (pat, tim)
char *pat;
int tim;
{
}
/****************************************************************
* give_tour
****************************************************************/
give_tour (query, name)
char *query, *name;
{ long from, to, town;
char *answer = NULL;
long i, numhelp, cnt=0;
fprintf (stderr, "Tour: '%-32.32s', name '%s'\n", query, name);
for (i=0; i<20; i++)
{ to = randint (rooms);
if (room[to].name && room[to].name[0] && ROOM_GET (to, RM_REACH)) break;
}
if (i >= 20)
{ zinger ("\"I can't think of any good places to show you, %s.", name);
return (1);
}
if (!((msgtype >= M_PAGE && (town = close_room ("town", NULL)) >= 0) &&
(answer = find_path (town, to, SHORTPATH)) && (from = town) >= 0 ||
(answer = find_path (hererm, to, SHORTPATH)) && (from = hererm) >= 0 ||
(answer = find_path (homerm, to, SHORTPATH)) && (from = homerm) >=0))
{ zinger ("\"I can't think of any good places to show you, %s.", name);
return (1);
}
switch (randint (3))
{ case 0: zinger ("\"Hmm...you should visit %s, %s.",
room_name (to), name);
break;
case 1: zinger ("\"%s in %s, %s.",
"Perhaps you will find what you seek",
room_name (to), name);
break;
case 2: zinger ("\"You should go see %s, %s.",
room_name (to), name);
break;
}
strcpy (speaker, name);
reply ("\"From %s, go %s.",
(from == hererm) ? "here" : room_name (homerm), answer);
return (1);
}
/****************************************************************
* answer_what:
****************************************************************/
answer_what (name, det, thing)
char *name, *det, *thing;
{
/* No public rules, yet */
}
long fasttype = 0;
fakeprint ()
{ fprintf (stderr, "fakeprint not avail in colin, exiting\n");
exit (1);
}
hearts_msg () { return (0); }
reset_cnet () { return (0); }