Implemented: An NPC programming language

Skip to first unread message

Phil Goetz

Oct 24, 1996, 3:00:00 AM10/24/96

I was working some more on the planner. I added a set of
programming constructs to the set of plan primitives,
so that you can write programs for NPCs.

Here are the primitives I have.
In Prolog, brackets enclose lists of variable size,
while parentheses are used for lists of constant size.

achieve(List, ProtectedList): This isn't really a primitive;
it always gets expanded into a sequence of the real
primitives, below. It tries to achieve all the things
on List (which can include conjunctions and disjunctions)
without making any of the things on ProtectedList false.
This forms a plan to either open or break the desk.

do(move(jim,west)) If this is on Jim's plan queue, Jim
moves west when he comes to it.

if(Cond, Plan)
if(closed(desk), [try(open(jim,desk), [])] )
If this is on Jim's plan queue, then if the desk is
opened, Jim tries to close it.

try(Action, ProtectedList)
This is like do, but it forms a plan to achieve all the
preconditions for an action, making sure that the things
in the protected list do not become false, and tacks a
"do" onto the end of that plan.
If the desk is locked, Jim will try to find a key
and unlock it without breaking it.

sleep(3): Wait 3 turns.

wait(closed(desk)): Blocks on this action until the desk
is closed.

while(Cond, Plan)
When this act is called, it tests the condition Cond.
If Cond is false, the act is pulled off the action queue.
If Cond is true, it creates a subqueue with all the
actions on Plan in it. It calls that subqueue.
When that subqueue terminates, it returns to the calling
queue and starts over, checking Cond.
while(true, [if(in(wilbur,barn), [try(kick(ed,wilbur))])])
is a plan for Ed to endlessly kick Wilbur whenever he
comes into the barn.

You can put these all together in a plan like the following:

plans([me],[fred, 1]). % Fred is executing from queue 1

% The first item on a queue is its number.
% The second item is the goal it serves.
% The third and onward are the plan steps, in order.
[1, % queue number
opened(desk), % goal of this plan
if(closed(desk), [achieve([opened(desk)], [])]),
[wait(closed(desk)), achieve([opened(desk)], [])])

which produces the following annoying behavior:

>close desk.
You close Fred's desk.
Fred opens Fred's desk.

>close desk.
You close Fred's desk.
Fred opens Fred's desk.

Deepak Kumar wrote a dissertation here on the primitive actions
you want to have for a sophisticated planning system:

Deepak Kumar (1993). _From Beliefs and Goals to Intentions
and Actions: An Amalgamated Model of Inference and Acting._
Ph.D. dissertation.
Technical Report 94-04, Dept. of Computer Science,
State University of New York at Buffalo.

<a href=""
>From Beliefs and Goals to Intentions and Actions:
An Amalgamated Model of Inference and Acting.</a>

Shorter paper:

<LI>Deepak Kumar and Stuart C. Shapiro, <A
Architecture</A>. <CITE>International Journal of Artificial
Intelligence Tools 3,</CITE> 3 (March, 1994), 349--366.

This contains more primitives to combine reasoning and action.
Among other things, he provided a list of "transformers" to
mediate between thought and action. Each one transforms from
belief to belief, belief to act, act to belief, or act to act.
For example:

belief -> belief:
If X is true, then Y is true.
belief -> act:
if-do: If X is true, do Y.
for-do: To find out whether X is true, do Y.
(He calls this an act->belief transformer, but I disagree.)
act -> belief:
After X happens, believe Y.
act -> act: This isn't a very useful category.

His primitives combined with my planning system would let your
do pretty much whatever they need to. This is something some
enterprising soul really ought to take up in Inform/TADS/Hugo.


Phil Goetz

Oct 31, 1996, 3:00:00 AM10/31/96

Today I extended the NPC programming language so you can insert
arbitrary Prolog predicates inside a plan. Presumably they
are to be called for their side-effects, not for logical functions.
For example, the following plan:

queue(1, [1, fail,
if(not(opened(desk)), [achieve([opened(desk)], [])]),
print('Jim says, "Who keeps shutting my desk?"'), nl,

achieve([opened(desk)], [])])]).

produces the following behavior:

>close desk.
You close Jim's desk.
Jim says, "Who keeps shutting my desk?"
Jim opens Jim's desk.

>shut desk.
You close Jim's desk.
Jim says, "Who keeps shutting my desk?"
Jim opens Jim's desk.

Are there any other features people really want in an
NPC programming language?

The Usenet Oracle has pondered your question deeply.
Your question was:

> help i'm a bug

And in response, thus spake the Oracle:

} <poof> you're a feature!

Reply all
Reply to author
0 new messages