/**************************************************************** * zog: 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 # include # include # include # include # include # include # include # include # include # include # include #include #include #include # include "robot.h" # include "vars.h" #include "rand.h" #include "words.h" #include "reply1.h" #include "players.h" #include "explore.h" #include "codeword.h" #include "zog.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 Zog */ long tty_interface = 0; char PI_500[512] = "3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196442881097566593344612847564823378678316527120190914564856692346034861045432664821339360726024914127372458700660631558817488152092096282925409171536436789259036001133053054882046652138414695194151160943305727036575959195309218611738193261179310511854807446237996274956735188575272489122793818301194912"; // Forward static void onintr(int); static void start_up(void); static void do_special_check(void); static int do_warn(void); static void do_twiddle(void); static int do_wander(void); static int spoof_msg(const char *, const char *); static int says_msg(char *, const char *); static int action_msg(const char *, const char *, const char *); static int hi_priority(const char *, const char *, const char *); static int small_talk(const char *, const char *); static int lo_priority(const char *, const char *); static int sorry_msg(const char *, const char *, const char *); static void give_tour(const char *, const char *); /**************************************************************** * setconfig: These values are defined in zog.h ****************************************************************/ void setconfig(void) { male = MALE; owner = OWNER; creation = CREATION; if (myname == NULL) myname = MYNAME; if (mudhost == NULL) mudhost = MUDHOST; if (mudport == 0) mudport = MUDPORT; } /**************************************************************** * robot main loop ****************************************************************/ void robot(void) { waitfor (" -----=> If you see"); 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, &onintr); signal (SIGINT, &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) { /* 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); { time_t tt; tt = now; fprintf (stderr, "\nExited main play loop at %15.15s.\n", ctime (&tt) + 4); } quit_robot (); } /**************************************************************** * start_up: Initial commands ****************************************************************/ static void start_up(void) { 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); 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 = 1; lastcheck = now = time (0); } /**************************************************************** * do_special_check: ****************************************************************/ static void do_special_check(void) { now = time (0); strcpy (postcmd, ""); } /**************************************************************** * do_warn: Warn the terminators target, if present ****************************************************************/ static int do_warn(void) { /* 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 ****************************************************************/ static void do_twiddle(void) { /* 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); } } /**************************************************************** * do_wander: Wander around ****************************************************************/ static int do_wander(void) { /* 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"); } else if (dice < 80) { dest = close_room ("library"); } if (dest < 0) { do { dest = randint (rooms); } while (!room[dest].name); } } while (dest < 0 || (dest == hererm || randint (100) < 90)); now = time (0); { time_t tt; tt = now; fprintf (stderr, "Wndr: [%15.15s] %s(%ld)\n", ctime (&tt) + 4, room_name (dest), dest); } disengage (room_name (dest)); pagedto = dest; pagedfrom = hererm; pagedat = time (0); if (dest == homerm) { strcpy (pagedby, ""); } else { strcpy (pagedby, ""); } return (1); } return (0); } /**************************************************************** * readmsg: Handle messages ****************************************************************/ void readmsg(const char *msg) { char lcmsg[TOKSIZ], name[MSGSIZ]; const char *s; char *t; long oldmsgtype; /* 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(msg,lcmsg)) { msgtype = oldmsgtype; return; } /* Ignore most messages until we are really awake */ if (!awake) { msgtype = oldmsgtype; return; } if (spoof_msg (name, msg) || says_msg (name, msg) || action_msg (name, msg, lcmsg)) { msgtype = oldmsgtype; return; } /* Ignore message altogether, then */ msgtype = oldmsgtype; return; } /**************************************************************** * spoof_msg: Check for messages from robots own name ****************************************************************/ static int spoof_msg(const char *name, const char *msg) { 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."'). ****************************************************************/ static int says_msg(char *name, const char *msg) { char buf[TOKSIZ], lcbuf[TOKSIZ]; char sname[TOKSIZ]; const char *cs; char *ws; /* skip over first word (should be the name) */ for (cs=msg; *cs && !isspace (*cs); cs++); while (isspace (*cs)) cs++; /* 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 (cs, "says")) { cs += 4; msgtype = M_SPOKEN; } else if (ismuck && index (cs, '"')) { while (*cs && *cs != '"') cs++; msgtype = M_PAGE; pagedmsgs++; } else if (stlmatch (cs, "whispers")) { cs += 8; msgtype = M_WHISPER; } else if (stlmatch (cs, "pages:")) { cs += 5; msgtype = M_PAGE; pagedmsgs++; } else if (stlmatch (cs, "shouts")) { cs += 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 (cs[0]) || index ("`'\".,:;!?", cs[0])) cs++; strcpy (buf, cs); ws = buf + strlen (buf); while (isspace (ws[-1]) || index ("`'\".,:;!?", ws[-1])) ws--; *ws = '\0'; strcpy (lcbuf, lcstr (buf)); /*-------- Log the message --------*/ if (!printedloc) print_locn (); if ((cs = is_tell (lcbuf)) && !isowner (cs) && !isowner (name)) { fprintf (stderr, "Says: %s[%s] \n", msgtype == M_SPOKEN ? "" : msgtype == M_WHISPER ? "whisp" : msgtype == M_PAGE ? "pages" : msgtype == M_SHOUT ? "shout" : "poses", name, cs); } 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, lcbuf)) { check_stay (); /* Now try various speech rule sets */ if (hi_priority (name, buf, lcbuf) || small_talk (name, lcbuf) || standard_msg (name, buf, lcbuf) || lo_priority (name, lcbuf) || polite_msg (name, 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. ****************************************************************/ static int hi_priority(const char *name, const char *msg, const char *lcmsg) { long dur, pl; const char *s; /*---- Zog won't 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 Zog 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*zog")))) { 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 long int 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*zog*")) { 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, "") || streq (pagedby, "") || streq (pagedby, ""))) { 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 Zog, the Maas-Neotek Robot, %s", name); return(1); } /*---- 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(1); } /*---- 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. ****************************************************************/ static int small_talk(const char *name, const char *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." static int lo_priority(const char *name, const char *lcmsg) { /*---- 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(1); } /*---- 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(1); } /*---- 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,"*zog 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" ****************************************************************/ static int sorry_msg(const char *name, const char *msg, const char *lcmsg) { /*---- Log the non-understood msg ----*/ sorry_log (name, msg); /*---- Else ----*/ if (randint (100) < 50 || MATCH (lcmsg, "*, zog*") || MATCH (lcmsg, "*zog: *") || MATCH (lcmsg, "*zog, *")) { 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) ****************************************************************/ static int action_msg(const char *name, const char *msg, const char *lcmsg) { long pl, dur; const char *action; int pokes=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.")) { const 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 Zog!"))) { 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*")) { time_t tt; now = time (0); tt = now; fprintf (stderr, "\nGoing down message: %15.15s.\n", ctime (&tt) + 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(%ld)", 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 Zog --------*/ /*---- Zog won't 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 zog*") && !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 zog*") && (action = "waves to")) || (MATCH(lcmsg,"* smiles at zog*") && (action = "smiles at")) || (MATCH(lcmsg,"* smiles to zog*") && (action = "smiles at")) || (MATCH(lcmsg,"* hugs zog*") && (action = "hugs")) || (MATCH(lcmsg,"* nods to zog*") && (action = "nods to")) || (MATCH(lcmsg,"* blinks at zog*") && (action = "blinks at")) || (MATCH(lcmsg,"* kisses zog*") && (action = "kisses") && (randint(100) < 50)) || (MATCH(lcmsg,"* greets zog*") && (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 zog*") && (action = "assault")) || (MATCH(lcmsg,"* baps zog*") && (action = "bap")) || (MATCH(lcmsg,"* bashes zog*") && (action = "bash")) || (MATCH(lcmsg,"* bonks zog*") && (action = "BONK")) || (MATCH(lcmsg,"* bops zog*") && (action = "bop")) || (MATCH(lcmsg,"* hits zog*") && (action = "hit")) || (MATCH(lcmsg,"* kicks zog*") && (action = "kick")) || (MATCH(lcmsg,"* prods zog*") && (action = "prod")) || (MATCH(lcmsg,"* pushes zog*") && (action = "push")) || (MATCH(lcmsg,"* reprogrames zog*") && (action = "reprogram")) ) { pokes++; } else if ( (MATCH(lcmsg,"* slaps zog*") && (action = "slap")) || (MATCH(lcmsg,"* slashes zog*") && (action = "slash")) || (MATCH(lcmsg,"* spanks zog*") && (action = "spank")) || (MATCH(lcmsg,"* stabs zog*") && (action = "stab")) || (MATCH(lcmsg,"* thumps zog*") && (action = "thump")) || (MATCH(lcmsg,"* thwacks zog*") && (action = "thwack")) || (MATCH(lcmsg,"* whacks zog*") && (action = "whack")) || (MATCH(lcmsg,"* whaps zog*") && (action = "whap")) || (MATCH(lcmsg,"* whips zog*") && (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. ****************************************************************/ int page_okay(const char *caller, const char *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" ****************************************************************/ void home_hook(void) { havebook = 0; } /**************************************************************** * before_move_hook: things to do before moving out of current room ****************************************************************/ void before_move_hook(void) { 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, ""))) { msgtype = M_UNKNOWN; if (streq (pagedby, "")) { unlogged (":strolls by on %s way home.", MALE ? "his" : "her"); } else if (streq (pagedby, "")) { unlogged (":goes by on %s way to %s.", MALE ? "his" : "her", room_name (pagedto)); } else if (streq (pagedby, "")) { unlogged (":wanders by on %s way to %s.", MALE ? "his" : "her", room_name (pagedto)); } else if (streq (pagedby, "")) { 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 ****************************************************************/ void after_move_hook(void) { } /**************************************************************** * new_room_hook: things to do after moving into a new room ****************************************************************/ void new_room_hook(void) { 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 ****************************************************************/ void checkpoint(void) { time_t tt; now = time (0); tt = now; fprintf (stderr, "Save: %15.15s, %ld of %ld rooms new, %ld of %ld exits new\n", ctime (&tt) + 4, newrooms, rooms, newexits, exits); write_players (plyfile); if (newrooms || newexits) { write_map (mapfile, 0); now = time (0); tt = now; if (!terse) fprintf (stderr, "Save: done at %15.15s\n", ctime (&tt) + 4); } lastcheck = time (0); newrooms = newexits = 0; } /**************************************************************** * onintr: Got an interrupt, checkpoint and quit ****************************************************************/ static void onintr(int sig __attribute__((__unused__))) { 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 ****************************************************************/ int isowner(const char *name) { return (streq (lcstr (name), OWNER)); } /**************************************************************** * amount_hook: Check amount given to player ****************************************************************/ long int amount_hook(long int amount, const char *name, int polite) { (void)name; (void)polite; return(amount); } /**************************************************************** * who_is_hook: ****************************************************************/ int who_is_hook(const char *pers, const char *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 Zog ****************************************************************/ void do_number(void) { } /**************************************************************** * lost_connect: Watchdog: send mail if Islandia goes down ****************************************************************/ void lost_connect(const char *pat, int tim) { (void)pat; (void)tim; } /**************************************************************** * give_tour ****************************************************************/ static void give_tour(const char *query, const char *name) { long from, to, town; const char *answer = 0; long i; 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; } if (!( ( (msgtype >= M_PAGE) && ((town = close_room("town")) >= 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; } 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); } /**************************************************************** * answer_what: ****************************************************************/ int answer_what(const char *name, const char *det, const char *thing) { /* No public rules yet */ (void)name; (void)det; (void)thing; return(0); } long fasttype = 0; void fakeprint(void) { fprintf (stderr, "fakeprint not avail in zog, exiting\n"); exit (1); } void hearts_msg(void) { } void reset_cnet(void) { }