"error" moving NPC randomly

I’ve made a NPC get impatient after the player takes an action and then the NPC leaves after a certain number of turns. They move to a room randomly selected from a table. Most of the time it works perfectly fine. Sometimes, I get an error message in the story of You'll have to say which compass direction to go in. I didn't understand that instruction.

I cannot figure out why, made worse by the fact that it doesn’t always happen, and since the game doesn’t halt, there’s no debug message saying what’s gone wrong. Any ideas on what I’ve done wrong?

A stripped-down version of the code:

The Library is north of the Kitchen. The Kitchen is north of the Living Room. The Living Room is north of the Foyer. The Foyer is north of the Lawn.

Kevin is a person in the Library. Kevin can be leaving or static. Kevin is static.

Table of Kevin Destinations
destination
Library
Kitchen
Living Room
Foyer
Lawn

Every turn when Kevin is leaving:
	if Kevin is leaving:
		choose a random row in the Table of Kevin Destinations;
		let the heading be the best route from the location of Kevin to the destination entry;
		try Kevin going the heading;
	if the location of Kevin is the destination entry:
		now Kevin is static.
		
Instead of examining Kevin:
	say "Good [']ole Kevin.";
	Kevin getsimpatient in one turn from now.

At the time when Kevin getsimpatient: 
	if the player is in the location:
		say "'BORING,' Kevin declares as he makes to leave the room.";
		now Kevin is leaving.

If there is no such route, heading will wind up as nothing. Then try Kevin going the heading will produce the failure messages you’re seeing.

All those rooms are connected?

If you’re getting an error message saying “You’ll have to say which compass direction to go in” when you’re having an NPC try going, it is very likely that you are accidentally having the NPC try going nothing. That is, “the heading” is getting set to nothing and so “try Kevin going the heading” is an instruction to try the action with Kevin as the actor, going as the action, and nothing as the noun–this gets interpreted as “going” with a missing noun and leads to that error message.

This can happen when you have something like “let the heading be the best route from the location of Kevin to the destination entry.” Sometimes there is no such route–for instance, if the location of Kevin is already the destination entry. Then the best route will get set to “nothing.” (Also, the route won’t use doors unless you add “, using doors” at the end of the “best route” phrase.)

The simplest way to avoid this, and something that’s a good idea whenever you’re using best routes, is to include the line if the heading is a direction: before you try Kevin going the heading.

(zarf said that more succinctly, naturally, so the tl;dr is that you can still get the error if the destination can be the original room. Anyway it’s always a good idea to check if the heading is a direction, even if you think it can’t go wrong.)

1 Like

Did you check for the case where the destination room and the starting room are the same? That would also leave heading as nothing.

I’m extra confused then, because the error happens after the NPC has already moved from the room like it’s heading toward a proper target. Not getting the error at the firing of the movement. I guess it’s moving away and then trying to come back again?

Matt, for the if the heading is a direction:, I’m struggling to see where that additional “if” statement squeezes into my code.

Every turn when Kevin is leaving:
	if Kevin is leaving:
		choose a random row in the Table of Kevin Destinations;
		let the heading be the best route from the location of Kevin to the destination entry;
		if the heading is a direction: [<------here]
			try Kevin going the heading;
	if the location of Kevin is the destination entry:
		now Kevin is static.
1 Like

Thanks, Matt. Still learning about where it’s cool to stack “if’s”.

For this one, I think what’s happening is that every turn when Kevin is leaving, it’s picking a new destination. So if the initial destination is two rooms away, Kevin won’t become static, and the next turn it will pick a new destination… and that could be the room Kevin’s already in, which will lead to the error. Check this sequence (I added a “say” statement to say what the destination and heading were):

lengthyish gameplay excerpt

Lawn
You can see Kevin here.

x kevin
Good 'ole Kevin.

z
Time passes.

“BORING,” Kevin declares as he makes to leave the room.

z
Time passes.

Kevin is heading to Kitchen and going north.

Kevin goes north.

n

Foyer
You can see Kevin here.

Kevin is heading to Kitchen and going north.

Kevin goes north.

n

Living Room
You can see Kevin here.

Kevin is heading to Lawn and going south.

Kevin goes south.

s

Foyer
You can see Kevin here.

Kevin is heading to Kitchen and going north.

Kevin goes north.

n

Living Room
You can see Kevin here.

Kevin is heading to Living Room and going nothing.

You’ll have to say which compass direction to go in.
I didn’t understand that instruction.

You can see that, on a few occasions when Kevin has not yet reached the original destination, a new destination gets chosen; and that the error happens when the new destination is the room where Kevin is already. I checked a few cases and that’s the problem every time the error message appears.

I haven’t tried actually compiling this, but a variation on this theme that you could do to avoid changing destinations constantly is to have Kevin remember what he was intending to do:

Kevin has an object called current destination.
Definition: Kevin is static rather than leaving if the current destination of it is nothing.

To make Kevin leave:
    while 1 is 1:
        choose a random row in the Table of Kevin Destinations;
        now the current destination of Kevin is the destination entry;
        if the current destination of Kevin is not the location of Kevin, break.

Every turn when Kevin is leaving:
    let the heading be the best route from the location of Kevin to the current destination of Kevin, using doors;
    if the heading is not nothing:
        try Kevin going the heading;
    if the location of Kevin is the current destination of Kevin:
        now the current destination of Kevin is nothing.

You can then use the phrase make Kevin leave whenever you want him to go somewhere else. The while loop in there also forces him to pick somewhere other than the location to go to, so that he actually does leave.

FYI, the above did compile. You can have a bit more fun with it, though – I’m not sure if this is better or worse for performance and memory (though I assume worse if there’s a large number of non-Kevin-capable rooms), but rather than defining a Table of Kevin Destinations and having that loop, you can do this:

Definition: a room is Kevin-free if it is not the location of Kevin.
Definition: a room is Kevin-capable if it is listed in { Lab, Kitchen, Bathroom }
            or it is in Gallery.
[Elsewhere: Gallery is a region.]

To make Kevin leave:
    now the current destination of Kevin is a random Kevin-free Kevin-capable room.
1 Like

Thanks, @matt_weiner and @mirality. I think I may opt to just have “Kevin” follow a predetermined route that’s mixed up enough for satisfactory faux-randomness. One of those moments when spending more time figuring it out isn’t worth the feature.

In reality my game has up to three NPCs wandering a large mansion at any given time so probably not a good idea to hit the memory too hard. And they need to avoid hanging out in or entering certain rooms so room-by-room random movement doesn’t work.