Simple pathfinding is really pretty easy in Inform 7. A very simple example of having a NPC following the player around can be coded up pretty simply.
Kitchen is a room. The description of kitchen is "Smells of last night's dinner still linger in the air."
Family-room is a room. The printed name of family-room is "Family Room". The description of family-room is "A sole rocking chair sits facing the large screen television in the corner." Family-room is south of kitchen.
Dining-room is a room. The printed name of dining-room is "Dining room". The description of dining-room is "A table sits in the middle of the room with just two chairs on either side." The dining-room is north of the kitchen.
The den is a room. The description of den is "The den contains a student desk with a simple wooden chair." The den is west of the dining-room.
The kitten is an animal. The kitten is in the kitchen. The description of kitten is "The small fluffy kitten sits and looks expectantly at you."
Every turn:
let course be the best route from location of the kitten to the location of the player;
if course is a direction, try kitten going course.
Pretty simple, yet useful in a lot of situations. The manual has a decent set of examples with character movements.
What about doors?
As it stands doors will present an issue for the pathfinding routines. To handle doors, just change the best route line to something more like the following:
let course be the best route from location of the kitten to the location of the player, using doors;
What about closed doors?
This might be ok for a human NPC that can open doors, but for the kitten, how do we stop them from entering through closed doors?
The kitchen is a room. The description of kitchen is "Smells of last night's dinner still linger in the air."
The family-room is a room. The printed name of family-room is "Family Room". The description of family-room is "A sole rocking chair sits facing the large screen television in the corner."
The dining-room is a room. The printed name of dining-room is "Dining room". The description of dining-room is "A table sits in the middle of the room with just two chairs on either side." The dining-room is north of the kitchen.
The den is a room. The description of den is "The den contains a student desk with a simple wooden chair." The den is west of the dining-room.
The kitten is an animal. The kitten is in the family-room. The description of kitten is "The small fluffy kitten sits and looks expectantly at you."
The kitchen-door is a door. the kitchen-door is north of family-room and south of the kitchen. The kitchen-door is closed. Understand "door" as kitchen-door. The printed name of kitchen-door is "kitchen door".
Every turn:
let course be the best route from location of the kitten to the location of the player, using doors;
if course is a direction:
repeat with doorway running through visible doors:
if the other side of doorway from the location of the kitten is room course from the location of the kitten:
if doorway is open:
try kitten going course;
otherwise:
say "You hear a scratching from the other side of the door.";
Let’s add one more tidbit to this little example. What happens if there isn’t a best course for the kitten to get from it’s location to the player’s location? In this case, the pathfinding returns the value nothing for the variable course. When does this happen? It will occur when the kitten is already in the location of the player, it can occur when there is no direct route between the player and the kitten, and it can occur when there is some criteria we put on the pathfinding that doesn’t match up (there may be other reasons as well, but I’m just going to expand on these few).
Let’s look at the first situation, when the kitten is already in the location of the player. In our path-finding routine in our Every Turn rule, we are already checking to make sure that course is a direction, which if it’s nothing, it won’t be. So let’s add a quick otherwise on that if.
if course is a direction:
repeat with doorway running through visible doors:
if the other side of doorway from the location of the kitten is room course from the location of the kitten:
if doorway is open:
try kitten going course;
otherwise:
say "You hear a scratching from the other side of the door.";
otherwise:
if location of kitten is the location of the player:
say "The kitten sits and looks up at you expectantly";
There we are simply checking locations and if they match, print a quick little message.
Now we’ll expand on that a bit with some criteria to keep the kitten out of certain rooms. Let’s say we have some kitten repellent that we’ve put in the Den. Add the following line somewhere in your code.
A room can be kitten-friendly. A room is usually kitten-friendly.
This way we can make all rooms kitten friendly be default.
Then on the code defining the Den, let’s change it to the following to make it unfriendly to kittens.
The den is a room. The den is not kitten-friendly. The description of den is "The den contains a student desk with a simple wooden chair." The den is west of the dining-room.
Then we will simply make that final otherwise in our every turn rule to read;
otherwise:
if location of kitten is the location of the player:
say "The kitten sits and looks up at you expectantly";
else:
say "The kitten tried to enter [the location], but thought better of it."
Now we have this basis for pathfinding for an NPC, that can be expanded on greatly. There are also a few extensions you can get that encapsulates some of the more complex stuff for you, but for simple situations this is really pretty easy to put together.
Pathfinding can be used in many other situations, not just with directional relations between rooms. For example, it could be used in conversational models. I believe Glass by Emily Short is a good example of someone doing this. I’ll be exploring some other usages that perhaps I’ll write about in the future.
I’d be interested in hearing about or seeing code for any creative usages of the built-in pathfinding functionality.
EDIT (12/22/2013): Found a small bug in the above code that I detail out in another post.