From: cg@ami-cg.UUCP (Chris Gray)
Newsgroups: rec.games.programmer
Subject: Re:  Computer-Controlled Players (New, More Appropriate Thread)
Distribution: world
Date: 13 Aug 92 23:20:25 MST
Organization: Not an Organization

In article <1992Aug13.144305.11297@news.uit.no> roarf@stud.cs.uit.no
(Roar Foshaug) writes:

[pseudo-code in a pseudo-language for running a 'robot' omitted]

Here is some real code in a real language for the Caretaker machine (robot)
in my standard AmigaMUD scenario. Similar, but different ( :-) ) code runs
the Packrat and Postman machines. As you can see it is very similar to the
type of thing that Roar Foshaug was suggesting, but is probably much more
detail than you wanted! I to use fixed intervals between steps, rather than
random ones for these robots. I'm not sure why, since the "monster" machines
use random intervals.


define tp_machines Caretaker CreateThing(nil).

/* caretakerGreet - let the caretaker greet everyone in a room he enters. */

define tp_machines proc caretakerGreet(thing who)void:
    string name;

    name := who@p_pName;
    if name ~= "Caretaker" then
	DoSay("Good day " + FormatName(name) + "!");
    fi;
corp;

/* caretakerStep - the central action routine for the caretaker */

define tp_machines proc caretakerStep()void:
    thing here, me, object, home;
    list thing lt;
    int dir, firstNum, count, n;
    bool found, lost;

    if not ClientsActive() then
	/* no clients (humans) are playing - do little */
	After(60, caretakerStep);
    else
	me := Me();
	if me@p_mArrived then
	    /* this phase - greet everyone */
	    me@p_mArrived := false;
	    ForEachAgent(Here(), caretakerGreet);
	    After(20, caretakerStep);
	else
	    /* this phase - move */
	    me@p_mArrived := true;
	    firstNum := me@p_mLastDir;
	    if Random(3) ~= 0 then
		dir := firstNum;
	    else
		firstNum := DirBack(firstNum);
		while
		    dir := Random(12);
		    dir = firstNum
		do
		od;
		firstNum := dir;
	    fi;
	    found := false;
	    lost := false;
	    while not found do
		if TryToMove(dir) then
		    found := true;
		else
		    dir := (dir + 1) % 12;
		    if dir = firstNum then
			lost := true;
			found := true;
		    fi;
		fi;
	    od;

	    if lost then
		Log("Caretaker stuck, " + Here()@p_rName + "\n");
		Say("I'm stuck! Heeeeelp!!");
		After(600, caretakerStep);
	    else
		me@p_mLastDir := dir;
		MachineMove(dir);
		here := Here();

		/* Go through the objects in the room we just entered. Pick
		   each normal object up. If the object is not where it
		   "belongs", then keep it, otherwise drop it right away. */
		lt := here@p_rContents;
		count := Count(lt);
		n := 0;
		while n < count do
		    object := lt[n];
		    if not object@p_oInvisible then
			/* DoGet removes an object from the list */
			count := count - 1;
			if not DoGet(here, me, object) then
			    /* something happened - abort out */
			    n := count;
			else
			    home := object@p_oHome;
			    if home = here or home = nil then
				/* object belongs here - drop it right away */
				if not DoDrop(here, me, object) then
				    /* something happened - abort out */
				    n := count;
				fi;
				/* otherwise, object is put on the end of the
				   contents list, and we do not need to look at
				   it again. */
			    fi;
			    /* otherwise, he just keeps it for now */
			fi;
		    else
			n := n + 1;
		    fi;
		od;

		/* Go through the list of stuff he is carrying. If anything
		   in that list "belongs" here, then drop it. */
		lt := me@p_pCarrying;
		count := Count(lt);
		n := 0;
		while n < count do
		    object := lt[n];
		    if object@p_oHome = here then
			count := count - 1;
			if not DoDrop(here, me, object) then
			    n := count;
			fi;
		    else
			n := n + 1;
		    fi;
		od;

		After(20, caretakerStep);
	    fi;
	fi;
    fi;
corp;

/* have the caretaker do the command we want him to do */

define tp_machines proc caretakerCommand()void:
    thing me;
    string command;

    me := Me();
    command := me@p_mCommand;
    me -- p_mCommand;
    ignore Parse(G, command);
corp;

/* the caretaker's "understanding" of things told to him */

define tp_machines proc caretakerTold()void:
    thing me;
    string w, np;

    me := Me();
    w := GetTail();
    /* skip a , or : in the message, e.g. "say caretaker: get rock" */
    if SubString(w, 0, 1) = "," or SubString(w, 0, 1) = ":" then
	w := SubString(w, 1, Length(w) - 1);
    fi;
    SetTail(w);
    w := GetWord();
    if w == "drop" or w == "put" or w == "p" then
	/* someone is telling the caretaker to drop something */
	w := GetTail();
	np := GetNounPhrase(G, w, 0);
	if np = "" or FindName(me@p_pCarrying, p_oName, np) ~= succeed then
	    /* he is not carrying anything matching what they want him to
	       drop */
	    if MatchName("flashlight.light;flash", np) >= 0 then
		/* there really isn't any such thing */
		DoSay("No way! It's mine!");
	    else
		OPrint("Caretaker shakes his head in confusion.\n");
	    fi;
	else
	    /* He is carrying something that matches. Say 'Certainly' and
	       try to drop it after 1 second. */
	    me@p_mCommand := "drop " + w;
	    DoSay("Certainly.");
	    After(1, caretakerCommand);
	fi;
    else
	/* Dropping things is the only thing he will do */
	DoSay("Sorry, I've got my work to see to.");
    fi;
corp;

define tp_machines proc caretakerHear(string what)void:
    string word;

    word := SetSay(what);
    if word ~= "" and word ~= "Packrat" and word ~= "Caretaker" then
	/* ignore things said by the packrat or by himself */
	word := GetWord();
	if word == "Caretaker" then
	    /* only act if the speech started with his name */
	    caretakerTold();
	elif word == "hello" or word == "hi" then
	    /* minimal conversationalist! */
	    OPrint("Caretaker grunts an acknowledgement.\n");
	fi;
    fi;
corp;

/* called by the system when someone whispers to him */

define tp_machines proc caretakerWhispered(string what)void:

    if SetWhisperMe(what) ~= "" then
	caretakerTold();
    fi;
corp;

/* called as the first step of someone giving something to him */

define tp_machines proc caretakerPre()status:

    SPrint(TrueMe(), "Caretaker accepts the gift.\n");
    continue
corp;

/* used for several other possible actions */

define tp_machines proc caretakerNoNo()status:

    DoSay("Watch it!");
    fail
corp;

/* actually create the caretaker */

define tp_machines proc caretakerCreate()void:

    Caretaker@p_pStandard := true;
    Caretaker@p_mLastDir := D_SOUTH;
    Caretaker@p_mArrived := true;
    SetupMachine(Caretaker);
    Caretaker@p_pDesc :=
"The caretaker is a simple soul. He wears faded overalls, a green check "
"shirt, heavy work boots and a grimy cap, on backwards. His goal in life is "
"to put things back where they belong. One of his most prized possessions is "
"a small handheld flashlight, which he keeps securely hidden in an inside "
"pocket until he needs it.";
    Caretaker@p_oLight := true; 	/* he makes light in dark places */
    CreateMachine("Caretaker", Caretaker, r_crossSW, caretakerStep);
    ignore SetMachineActive(Caretaker, caretakerStep);
    ignore SetMachineSay(Caretaker, caretakerHear);
    ignore SetMachineWhisperMe(Caretaker, caretakerWhispered);
    GNewIcon(Caretaker, makeCaretakerIcon());
    Caretaker@p_pGivePre := caretakerPre;
    Caretaker@p_oTouchAction := caretakerNoNo;
    Caretaker@p_oSmellAction := caretakerNoNo;
    Caretaker@p_oPushAction := caretakerNoNo;
    Caretaker@p_oPullAction := caretakerNoNo;
    Caretaker@p_oTurnAction := caretakerNoNo;
    Caretaker@p_oLiftAction := caretakerNoNo;
    Caretaker@p_oLowerAction := caretakerNoNo;
    Caretaker@p_oEatAction := caretakerNoNo;
corp;

caretakerCreate().


Sorry about the long post - I just thought some folks might like to see the
details of a robot done in something other than lpc! And no, AmigaMUD still
isn't done. And yes, I'm still working on it.

--
Chris Gray   ualberta!ami-cg!cg   or   cg%ami-cg@kakwa.UCS.UAlberta.CA
Newsgroups: rec.games.programmer