/**************************************************************** * 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); }