Inform 7 – GL02 bug with First time / Only construct

I’ve been upgrading my WIPs to the new version of Inform and for the most part things have been going smoothly.  Once a few extensions were updated and I changed the way I was doing a few things (which were deprecated anyways), they worked pretty well.  After almost two weeks, I noticed somethings wasn’t correct with one description I had in some code like below.

The description of myObject is "[first time]Say this the first time only.[only] Rest of text that will print every time."

When examining the object, it never printed the text within the first time first time construct. After some digging and talking to a few people, I find that this has been reported.

0001291: “first time / only” is not shielded by say__comp

The work around for now is to use something like the following:

The description of myObject is "[one of]Say this the first time only.[or][stopping] Rest of text that will print every time."

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!

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.

 

Inform 7 – Paragraph Breaks in Text Substitutions

I’m a bit of a stickler when it comes to formatting of my text.  Not that I get it correct all the time…but it does bother me when I see something out of whack.  As I am continuing to practice my Inform 7 skills and increase my knowledge of the language constructs, I found myself being tripped up with one aspect of paragraph breaks repeatedly….hence this post to try and help me remember this.

One thing I run into enough is just the simple paragraph breaks that follow after hard stops at the end of some text.  (http://inform7.com/learn/man/doc79.html).   This seems easy enough and works the way I expected it too most of the time.

The clock tower is scenery in the town-square.  
The description of the clock tower is "You look up at the clock tower and see the time is [time of day]."

This produces the following results as expected.

>x tower
You look up at the clock tower and see the time is 11:10 pm.

>

Where I tend to run into trouble is when my description becomes a bit more complicated, where I may have nested logic in there so I’ll have to break it out into a new phrase. BTW: examples are really nonsensical for illustration purposes only…better ways to do things like this I’m sure.

The description of the clock tower is "[clock-tower-description]".

To say clock-tower-description:
	if turn count is 2:
		say "You look up at the clock tower and see the time is [time of day].";
	otherwise:
		if turn count is 3:
			say "You really want to see the time again?";
		otherwise:
			say "You've looked at this  before."

That produces the following output

>l
town square
You can see a clock tower here.

>x clock tower
You look up at the clock tower and see the time is 9:01 am.


>x clock tower
You really want to see the time again?


>x clock tower
You've looked at this  before.


>

You’ll notice the extra spacing. between the printed text and the next prompt. To fix that problem is a really easy fix, but wasn’t obvious to me at first.

The description of the clock tower is "[clock-tower-description][run paragraph on]"

Adding the [run paragraph on] phrase is letting the substituted text handle all line and paragraph breaks without the printing of the description adding it’s own.

I’m guessing that even this isn’t the best way to do things, but it is working for me for now.

Creating Interactive Fiction with Inform 7 by Aaron Reed – A Review.

When I got back into the IF world and wanted to start authoring my ownnote-1 I voraciously scoured the internet in search of all the information I could find….and there is quite a bit between the forums, some of the leaders in the field and having many games released with source code. Having spent a few days reading all I could, I stumbled upon Aaron Reed and his blog. Not only did I see he was an accomplished IF authornote-2, but also was one of the leaders in educating others in developing with Inform 7, but also in using interactive fiction as a tool to educate on other subjects. So of course when I noticed he wrote a book, Creating Interactive Fiction with Inform 7, I had to order it right away.

514a8837j6L._SL160_This book is a great introduction to creating interactive fiction in Inform 7. Aaron does a fine job of easing you into creating things by introducing us to interactive fiction, familiarizing ourselves with the Inform 7 application, and begin development of a sample game that we build upon throughout the entire book.

Aaron covers most of the important areas of Inform 7 that you will use in almost every game. From the basic creation of rooms, creating things and placing them in locations and creating custom kinds and properties to making things happen with rules and actions. He also covers some more advanced logic, scenes, conversation models and character interaction. He covers things in just enough detail to understand, often presents areas where we could improve or expand on what he has shown, and gives exercises to show off what we’ve learned by customizing his central game. Again, not everything is covered, or some topics aren’t covered in great detail, but the technical side of the book gives us more than enough to get started and often leads us to learn more.

In addition to the technical side of the book, Aaron often covers aspects of story design and authoring. Everything from creating good descriptions and creating atmospheric text, to story pacing and good conversation and character interaction. Often a book or article will cover either the technical side well or the artistic side well, but rarely both. Aaron does a fine job on both and blends them together nicely.

Regardless your level of expertise with Inform 7 or with interactive fiction creation, I believe Aaron’s book gives great insights for both novices and experts alike. I still refer to it at times when I’m looking for some specific aspect I recall being covered that I’m not remembering or for inspiration on a story element. Price is reasonable and there is a Kindle version available. Well worth the cost. I hope to see more works like this from Aaron or others.

1 – Back around 2002, I played with Inform 6 and created the stereotypical first game, a layout of my house, but real life got in the way and I never went much further. Jump to 2013 and I look to see what has been going on over the last few years and I discover Inform 7. It was a natural choice for me as I was already somewhat familiar and the natural language syntax intrigued me as a programmer.
2 – See Blue Lacuna, billed as the largest work of IF ever written…but the source code is available as well. Great learning available here.

Large interactive objects that act like a backdrop (sort of) – Inform 7

I ran across an interesting problem in my WIP that to solve I went through a couple different solutions before getting something simple to work.

Note:  This may not be the best way to handle the problem and I’m always open to suggestions for improvements.

In my current WIP (one of them anyway), I have a situation where I had a large object that was visible from many rooms.  Let’s say a large tree in my front yard and the rooms are areas around the yard.  There is also one room inside my house that I can see the tree out a window.  My first inclination was to make it a backdrop so it could be seen from those rooms.  Let’s assume that the entire map of the game is those outside locations and that one room in the house.

The shade tree is a backdrop. The shade tree is everywhere.
The description of shade tree is "A great big tree."

Worked great, until i wanted to the tree to be a supporter.  I tried adding the supporter tag to the tree “The shade tree is a backdrop and a supporter.”  This gave me the error: “… as a backdrop and a supporter are incompatible…”  I really needed the tree to be a supporter as it was critical to be able to put something on the tree.  So out came the backdrop and making the tree a supporter worked great.

However, it wasn’t very realistic.  It made no sense that I could go to a different part of the yard and if I tried to look at the tree I would get the message: “You can’t see any such thing.”  Well what’s the best way to be able to interact with an object that is not in the current location?  Put it in scope.

after deciding the scope of the player:
    place the tree in scope;

This worked fine, now I could examine the tree from anywhere.  And if I tried to do anything to the tree away from the actual location where the tree is, I get a message saying “I can’t reach into Under-the-tree” (which is where the tree is located).  Well that’s not a very good message so I need to change the rule for reaching inside a room (which is what you’re doing if you are trying to interact with an object, in scope, that is located in another room.)

Rule for reaching inside a room:
    if the location is up-the-tree:
        if the noun is the shade tree:
            allow access;
        otherwise:
            say "You can only look at [the noun] from a distance.";
            deny access;
    otherwise:
        say "You can only look at [the noun] from a distance.";
        deny access.

Let’s look at a few things with this last section of code.

  1. We are replacing the rule for reaching inside a room from the standard library so we can run some of our own checks.
  2. We first check to be in the location up-the-tree.  I hadn’t mentioned this before, but I let the player climb the tree and it puts you in a location up-the-tree.  Since the tree is not in that room, but is in-scope (because of our scope rule) without this rule we would have gotten the “Can’t reach into” message.  Which is silly since of course I can “touch the tree” since I’m in it.
  3. So if we are in the tree and the noun is the tree (meaning we are trying to do something to the tree while up the tree) then we allow access, which lets the appropriate rules and actions trigger.
  4. The otherwise’s tell us we are either not up the tree (say in the house) or we are trying to interact with something other than the tree.  In those cases, just display a generic (but more friendly) message.

So now if we try touching the tree for example and we are either under the tree or in the tree, both locations we should be able to touch the tree from we can do this.

instead of touching the tree:
    say "You affectionately touch the tree."

Like I mentioned, I went a couple different directions with this, trying to do more with overriding some standard library rules and going down the path of trying to find a way to create some sort of backdrop / supporter.  (Something I didn’t try that seems kind of obvious now that I’ve typed all this up is making a separate supporter part of a backdrop and then working with it that way, I suspect that may work, but haven’t tried it)

I haven’t tested this code completely, so there may be some flaws or unintended consequences that I’ve not run across yet.  But perhaps this will be useful to someone.

Please feel free to tell me why this is wrong or show me a better way

Edited (9/29/13) to format code a little better