Inform 7 Gems – Pathfinding – 1.1

My last post on pathfinding in Inform 7, showed a simple beginning to the power of pathfinding in Inform 7.   I thought I’d expand on this slightly to show a little NPC movement that is a bit smarter than simply following the player around, as I was playing with the code, I found a bug in the code, that I thought I’d like to share the fix first before moving into new territory.

Bug fix from last post

When I fixed the code to be able to move through only open doors, I actually broke it so that if there was not a door between rooms, that the NPC would fail to follow.  So building upon the code from the previous post, we change our every turn rule to be:

Every turn:
	let course be the best route from location of the kitten to the location of the player through kitten-friendly rooms, using doors;
	if course is a direction:
		let the target be the room-or-door course from the location of the kitten;
		if target is not a door:
			try kitten going course;
		otherwise:
			 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";
		else:
			say "The kitten tried to enter [the location], but thought better of it."

Here we simply add a check to see if the target of the direction the kitten is attempting to move, is a door or room.  If it’s not a door, then the kitten can simple head in that direction.  If the target is a door, then we drop into our normal code from last time where we check for the open / closed door.  The important section of code above is this:

		let the target be the room-or-door course from the location of the kitten;
		if target is not a door:
			try kitten going course;
		otherwise:

 

With that fixed, I do believe the code should work as described from last time.   Now I’ll move on to exploring pathfinding to try and make this all a bit smarter.

Extensions

I should also note that there are some extensions out there that will wrap a lot of this code up for you.  A few that I’ve looked at before include Patrollers and Planner.  And there is a newer one Problem-Solving Characters, that I want to look at a bit deeper.

So other than perhaps some simple situations we can use those instead.  I like to dig deeper into the code and know how things work, even if I use an extension….so I’ll continue to these subjects…well….because I think it’s fun!

Advertisements

Inform 7 Gems – Pathfinding

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.

Inform 7 Gems – Is Transcription On?

As I was poking around the forums the other day, I realized how much information is buried in the forums.  Things I might not even think to search on or are difficult to find even when looking.  And when you do find something, it’s often difficult to piece the useful information together from a long thread.

With that in mind, I’m going to start a series of posts, starting with this one, on things I’ve found in the forums or elsewhere that I find interesting or useful and try to put them in nice digestible bites.  I hope to educate myself through this process and hopefully they’ll be of use to others as well.

Are we transcripting?

My first gem was suggested to me by Andrew Schultz.  Back in 2012 he had started a thread entitled I7 – Check if transcripting is on when noting?  The basic premise behind the post was checking if transcripting is turned on.  As I talked about in my previous post on easy transcription notes, Andrew was doing something similar, but as an added bonus, wanted to check if the transcription was turned on and if so, at a minimum warn the user that it wasn’t turned on.  Very useful for beta-testing and I myself often forget to turn on transcription.

With some help from zarf and others, what we end up with is pretty useful.

Include (-
[ CheckTranscriptStatus;
#ifdef TARGET_ZCODE;
return ((0-->8) & 1);
#ifnot;
return (gg_scriptstr ~= 0);
#endif;
];
-).

To decide whether currently transcripting: (- CheckTranscriptStatus() -)

ignore-transcript-nag is a truth state that varies.

After reading a command:
	if the player's command matches the regular expression "^\*.+":
		if currently transcripting:
			say "Noted.";
		otherwise:
			if ignore-transcript-nag is false:
				say "You've made a comment-style command, but Transcript is off. Type TRANSCRIPT to turn it on, if you wish to make notes.[paragraph break]The long version of this nag will only appear once. You may press any key to continue.";
				wait for any key;
				now ignore-transcript-nag is true;
			else:
				say "(Comment not sent to transcript.)";
		reject the player's command.

What we have is some I6 code that is checking a flag (different depending on zcode vs glulx) that when the user enters a note command, it checks to see if transcription is on and warns the user if it is not.

We can even take it one step further and add this line of code if it is not on:

try switching the story transcript on;

This will prompt the user to turn on transcription and should work in either zcode or glulx.

I seeing more and more that I really need to dive into I6 more to see the possibilities that I may be missing.

Edit: changed the regular expression to work around the I7 bug mentioned in the comments.