Npcmove.h(comes with its own findbot!)

This is a discussion / support forum for the Hugo programming language by Kent Tessman. Hugo is a powerful programming language for making text games / interactive fiction with multimedia support.

Hugo download links: https://www.generalcoffee.com/hugo
Roody Yogurt's Hugo Blog: https://notdeadhugo.blogspot.com
The Hugor interpreter by RealNC: http://ifwiki.org/index.php/Hugor

Moderators: Ice Cream Jonsey, joltcountry

loafingcoyote
Posts: 89
Joined: Wed Jan 04, 2012 2:57 pm
Location: Texas

Npcmove.h(comes with its own findbot!)

Post by loafingcoyote »

Npcmove.h is another character movement routine for Hugo. With it you can easily implement fairly complex character movement that is either random or goal driven. Here is the link:

http://dl.dropbox.com/u/11102009/ice.zip

It includes "npcmove.h", the sample game "ice.hex" and the game's source code "ice.hug".

The random movement routine supports the ability to restrict certain rooms from wandering characters and allow characters to prefer certain locations, even those that are restricted to other npc's. This would be most helpful in situations where you have a private space like an office or apartment that you don't want characters to wander into randomly.

The goal driven routine allows a character, no matter where they are, to find and move to any object, scenery, component or room, as long as both are in a predefined set of rooms where npc movement is allowed. The routine cannot yet deal intelligently with doors or scenery items that have the found_in property. In both cases the character will move to the first defined object in the found_in or between property.

In order to use it you have to include npcmove.h before any room objects and give any room that you want characters to be able to move through the "npc_move" property. Here is an example:

room throne_room "Throne Room"
{
npc_move n_obj, e_obj
}

Each direction that you want the npc to be able to move to must have its own direction object defined in the npc_move
property. This may seem like extra work but, trust me, it works much better that using a room's n_to, s_to, ect...property for this purpose.

This comes with a sample game, "Ice Station Hippo". This extension was mostly ready a few days ago, with a very crude sample game. However, as often happens, it took on a life of its own and before I knew it, the sample game began to resemble an actual work of IF. I was compelled to get it to a playable state.

This extension is still a work in progress, so I would appreciate any input on how I could trim out any inefficiency or what attributes and properties can be safely aliased with existing attributes and properties, etc...

Roody_Yogurt
Posts: 2179
Joined: Mon Apr 29, 2002 6:23 pm
Location: Milwaukee

Post by Roody_Yogurt »

Congratulations! I'm not much of a tinkerer, so I haven't tried that hard to break anything, but I think it's especially neat that you bundled it with a game. It was fun to play through.

I know it's not the point, but as far as the game itself goes, I'd maybe help the player out with motivation at a couple places. Like, looking at the radio (and its battery panel) prompts the thought, didn't I see a battery around her somewhere? And trying the dead battery prompts the thought, wasn't there another battery in the shed?

Also, it'd be kind to the player if he couldn't even play with the breaker settings until the radio had power, so they don't end up playing with it prematurely like I did.

The one question I had about npcmove.h is, in "array path_exits[20]", what exactly does 20 represent? If it's a value that should be increased in a larger-sized game, I'm thinking you should use a constant there like I did with mine so the player can easily change it without modifying the file itself.

Also, personally, I'd probably change the "#ifset BETA" to "#ifset DEBUG" since that's almost more of a HugoFix monitoring kind of deal, but that's really not important, of course.

In the game code itself, the only thing that really called out to me (in a distressing way) was:

Code: Select all

	e_to
	{
		"You prepare yourself to face the cold and step outside.\n"
		return outer_door
	}
That works fine with your game designed as it is, but in general, I think it's safer to have circumstance-checks on strings printed in direction code. These alternatives should work better with exit-checking code:

Code: Select all

room desertroom1 "In The Desert"
{
    s_to  {
          if verbroutine = &DoGo ! the next line will only run if the player
                                   ! actually typed >GO SOUTH
              "Blinking your eyes against the whirling sandstorm, you trudge southward until you reach the..."
          return desertoasis
          }
}
Or:

Code: Select all

room desertroom1 "In The Desert"
{
    s_to desertoasis
    before
       {
       location DoGo
          {
          if object = s_obj
             "Blinking your eyes against the whirling sandstorm, you trudge southward until you reach the..."
          return false ! go on with DoGo like normal
          }
       }
}
Of course, since this kind of code is unnecessary in this case, it's just a personal preference thing.

All in all, good work! The fact that you were willing to put together this fun little gem for a library extension bodes well for our seeing-more-games-from-you prospects for the rest of the year!

User avatar
Ice Cream Jonsey
Posts: 28881
Joined: Sat Apr 27, 2002 2:44 pm
Location: Colorado
Contact:

Post by Ice Cream Jonsey »

I just became aware of this thread, this extension, and that game. This is terrific news - congrats, loafingcoyote!
the dark and gritty...Ice Cream Jonsey!

loafingcoyote
Posts: 89
Joined: Wed Jan 04, 2012 2:57 pm
Location: Texas

Post by loafingcoyote »

Roody_Yogurt wrote:Congratulations! I'm not much of a tinkerer, so I haven't tried that hard to break anything, but I think it's especially neat that you bundled it with a game. It was fun to play through.
Thanks! I understand about not wanting to break something. The extra week making the game allowed me to field test the contribution in a way that has made it much better than it would have been otherwise.

Roody_Yogurt wrote:I know it's not the point, but as far as the game itself goes, I'd maybe help the player out with motivation at a couple places. Like, looking at the radio (and its battery panel) prompts the thought, didn't I see a battery around her somewhere? And trying the dead battery prompts the thought, wasn't there another battery in the shed?

Also, it'd be kind to the player if he couldn't even play with the breaker settings until the radio had power, so they don't end up playing with it prematurely like I did.
There are some in-game hints, but they were a last minute addition. I'll tweak those and also provide the player with a little more motivation to visit the shed.

I put the breaker in to mix things up a little. Hopefully it's not too frustrating. I tested it out last night on my wife and she said that if she had been the one at the station they would have found her, months later, frozen to death with a shattered circuit breaker nearby.

Roody_Yogurt wrote:The one question I had about npcmove.h is, in "array path_exits[20]", what exactly does 20 represent? If it's a value that should be increased in a larger-sized game, I'm thinking you should use a constant there like I did with mine so the player can easily change it without modifying the file itself.

This is something that I should have made clear from the beginning. In the array's path[20] and path_exits[20], twenty is the maximum number of steps that can exist between an npc and his goal. If the npc is further than that the FindGoal routine will return false. Twenty was an arbitrary number picked at random. I'm sure it could be much higher.

Using a constant in this situation is brilliant. I've now added the constant PATHSTEPS, in which the default setting is 20, but can be set to whatever is needed.

I should also mention that, as of now, the maximum number of exits that can be tested by npcmove.h is 8. I've been meaning to change it to at least 10, but haven't gotten around to it yet.
Roody_Yogurt wrote:Also, personally, I'd probably change the "#ifset BETA" to "#ifset DEBUG" since that's almost more of a HugoFix monitoring kind of deal, but that's really not important, of course.

You know, I was wondering about this and chose #ifset BETA simply because I understand the concept better that Hugo's debugging abilities. I think you're right though, so now all instances of #ifset BETA are changed to #ifset DEBUG

Roody_Yogurt wrote: In the game code itself, the only thing that really called out to me (in a distressing way) was:

Code: Select all

	e_to
	{
		"You prepare yourself to face the cold and step outside.\n"
		return outer_door
	}
That works fine with your game designed as it is, but in general, I think it's safer to have circumstance-checks on strings printed in direction code. These alternatives should work better with exit-checking code:

If anyone should appreciate smooth running exit checking code, it's me. Thank you for the tip. I think I prefer the first instance:

Code: Select all

room desertroom1 "In The Desert"
{
    s_to  {
          if verbroutine = &DoGo ! the next line will only run if the player
                                   ! actually typed >GO SOUTH
              "Blinking your eyes against the whirling sandstorm, you trudge southward until you reach the..."
          return desertoasis
          }
}
It feels more natural to put it in the s_to property as opposed to the before property.

loafingcoyote
Posts: 89
Joined: Wed Jan 04, 2012 2:57 pm
Location: Texas

Post by loafingcoyote »

Ice Cream Jonsey wrote:I just became aware of this thread, this extension, and that game. This is terrific news - congrats, loafingcoyote!
Thanks! I'm beginning to feel like an actual IF author now!

Roody_Yogurt
Posts: 2179
Joined: Mon Apr 29, 2002 6:23 pm
Location: Milwaukee

Post by Roody_Yogurt »

loafingcoyote wrote:Thanks! I understand about not wanting to break something. The extra week making the game allowed me to field test the contribution in a way that has made it much better than it would have been otherwise.
Of course, it wasn't my implication that the code isn't durable enough to resist some poking and prodding. I just meant, some people have that ok-let-me-see-how-this-thing-works-(and-breaks) nature that makes for great betatesting. I'm just the sort that, once I find out how to make something work, I'm not naturally curious about ways to break it.

loafingcoyote
Posts: 89
Joined: Wed Jan 04, 2012 2:57 pm
Location: Texas

Post by loafingcoyote »

Roody_Yogurt wrote:Of course, it wasn't my implication that the code isn't durable enough to resist some poking and prodding. I just meant, some people have that ok-let-me-see-how-this-thing-works-(and-breaks) nature that makes for great betatesting. I'm just the sort that, once I find out how to make something work, I'm not naturally curious about ways to break it.
That's funny. No, I didn't take it that way at all. What I was saying was, given the number of bugs that I found in the last week, I'm sure there are plenty more to find. I honestly want it to be put to the test.

Since we're on the subject; I have a dual approach to IF. I'm absolutely ruthless when testing something, covering all reasonable(and unreasonable)actions. I try to put as much stress on an untested work as possible, although I have noticed that it's a lot harder to torture your own creation than someone else's. Another good reason for beta testing.

When it comes to playing IF, however, I take a much gentler approach. My goal is to experience the work as the author intended it. I play nice and become immersed in their created world for awhile. It just seems right, given how much work an IF author does; with the full knowledge that he'll receive no money for it at all(or almost none).

Roody_Yogurt
Posts: 2179
Joined: Mon Apr 29, 2002 6:23 pm
Location: Milwaukee

Post by Roody_Yogurt »

I feel like, in my own games, I'm good at predicting less-obvious game-breaking things, but at the same time, I'm also the kind of guy that if I make a food object, I'll forget that I should give it a non-standard response to >EAT.

So yeah, betatesting!

loafingcoyote
Posts: 89
Joined: Wed Jan 04, 2012 2:57 pm
Location: Texas

Post by loafingcoyote »

I've updated npcmove.h so that npc's are not allowed to move through locked doors unless they have a key. The extension supports doors having more than one key object, so multiple npc's and the player could have a key to the same door. The current version is 1.03.

Now to start polishing Ice Station Hippo. I was considering making a "players version" of the game and uploading it to the archive. It would differ mostly in that some commands would be removed and the player would not be able to order Findbot around unless he was in the same room. I'll probably spend a week or two whipping this into shape!

Roody_Yogurt
Posts: 2179
Joined: Mon Apr 29, 2002 6:23 pm
Location: Milwaukee

Post by Roody_Yogurt »

loafingcoyote wrote:Now to start polishing Ice Station Hippo. I was considering making a "players version" of the game and uploading it to the archive. It would differ mostly in that some commands would be removed and the player would not be able to order Findbot around unless he was in the same room. I'll probably spend a week or two whipping this into shape!
That is cool. At least among people I talk to, it seems that a lot of people with no real vested interested in Hugo have been happy to see new Hugo games from non-Sherwin authors (I mean, I think ICJ is rightfully accepted into the pantheon of "respected IF authors", so his IF system choice is somewhat taken for granted). My point is, everyone loves an underdog, and seeing a new game added to the Hugo directory at the IF archive will be more appreciated than you might realize.

Be sure to announce it at the IF Database, too, when you are done.

loafingcoyote
Posts: 89
Joined: Wed Jan 04, 2012 2:57 pm
Location: Texas

Post by loafingcoyote »

Okay, this took far longer than it should have but, the archive version of "Ice Station Hippo" can be found here.

This version is called "Escape from Ice Station Hippo". Hopefully this will keep the two versions from being confused with one another. The core of the game is mostly unchanged. I added some atmosphere and made some of the changes Roody suggested to make the game more player-friendly.

If you haven't gotten around to the original then this is definitely the one to play. I'll wait a few days(probably Saturday) and then load it onto the archive(I'll make a page on the IFDB too). If anyone has finds any bugs or has any suggestions between now and then I would appreciate the feedback.

Roody_Yogurt
Posts: 2179
Joined: Mon Apr 29, 2002 6:23 pm
Location: Milwaukee

Post by Roody_Yogurt »

I'll send you an e-mail about some typos I saw, but I thought I'd mention some personal preferences. No harm if you don't agree with them, but I figured I'd say them here in case anybody else is interested.
  • 1.Version/Banner stuff
    Personally, I like this look: "Version # / Hugo 3.1 / Library 31031"

    Code: Select all

    print "Version 1 / ";BANNER
    2.PrintStatusLine
    I don't like the existing PrintStatusLine routine. I think it's tacky to always have the score/move counter in the same place regardless of screen size. I also think it's tacky to automatically go to a two-line status window when the width is anything less than 80 characters (like the default Gargoyle setting). Ideally, you should only have to go to two lines when the screen is not wide enough to print both the location name and the score/turns stuff. Here's a replacement that at least handles the first thing:

    Code: Select all

    replace PrintStatusline
    {
    	if display.linelength < 40
    		display.statusline_height = 2
    	else
    		display.statusline_height = 1
     
    	Font&#40;BOLD_OFF | ITALIC_OFF | UNDERLINE_OFF | PROP_OFF&#41;
    	window display.statusline_height
    	&#123;
    		color SL_TEXTCOLOR, SL_BGCOLOR
    		cls
    		locate 1, 1
    		if not location
    			print "\_";
    		elseif not light_source
    			print "In the dark";
    		else
    		&#123;
    			if FORMAT & DESCFORM_F&#58;  print "\_";
    			print capital location.name;
    		&#125;
     
    ! &#40;The part we're changing&#41;
    !	        print to 65; ! is 65 characters good for every window size? No!
     
    ! Instead, let's begin by writing the entire 'SCORE / MOVES' to array _temp_string
    ! &#40;_temp_string is an array declared by the library&#41;
     
                    text to _temp_string
    		if STATUSTYPE = 1
    			print number score; " / "; number counter;
    		elseif STATUSTYPE = 2
    			print HoursMinutes&#40;counter&#41;;
    	        text to 0
    ! Ok, we've closed off the string array
     
    ! Now, if the screen is wide enough, let's move to the end of the screen MINUS the length of the _temp_string array
    ! plus two extra spaces for good measure &#40;so there's a little space to the right on the status bar&#41;
    		if display.statusline_height = 1
    			print to &#40;display.screenwidth - &#40;StringLength&#40;_temp_string&#41; + 2&#41;&#41;;
    		else
    		&#123;
    			locate 1, 2
    			if FORMAT & DESCFORM_F&#58;  print "\_";
    		&#125;
     
     ! Now let's print it!
    		if STATUSTYPE = 1,2
                         StringPrint&#40;_temp_string&#41;
    	&#125;
    	color TEXTCOLOR, BGCOLOR
    	Font&#40;DEFAULT_FONT&#41;
    &#125;
    
    3. Using "locate" in init
    When you open up a Hugo game in the official interpreter, it bugs me when it starts drawing the text from the bottom of the screen. Because of this, I use locate to move the cursor up to near the top of the screen. Since locate acts wonky in the main window under glk, in a glk-detecting game, I usually have some code like "if not glk: locate 1, 3". As long as nothing has been printed in the game already, you probably don't even need the glk check.
So yeah, those are things I like to do. Anyhow, I'm going to try to get in a proper playthrough soon enough and get that e-mail to you.

loafingcoyote
Posts: 89
Joined: Wed Jan 04, 2012 2:57 pm
Location: Texas

Post by loafingcoyote »

Hey, thanks! Formatting issues are not my strong point so I'll definitely take your advice on this. Your way of printing the "version/banner" does look better and I like the way the replacement of PrintStatusLine handles resizing the interpreter window.

Roody_Yogurt wrote:3. Using "locate" in init
When you open up a Hugo game in the official interpreter, it bugs me when it starts drawing the text from the bottom of the screen. Because of this, I use locate to move the cursor up to near the top of the screen.
I actually noticed this a couple of weeks ago when I played "Baby Uncle New Year". I meant to look up how you did it but got distracted and forgot about it. It's a nice effect and easy too!

Also, I looked up the HbE page on "locate" and noticed in the "example code" section what is probably a small typo. It says to add "locate 1, 3" in the main routine as opposed to init.

Roody_Yogurt wrote:Since locate acts wonky in the main window under glk, in a glk-detecting game, I usually have some code like "if not glk: locate 1, 3". As long as nothing has been printed in the game already, you probably don't even need the glk check.
You mention glk and I have to admit, I only just now played it all the way through on Gargoyle(which I like now, buy the way). It was on my to-do list but somehow was skipped. I don't think a work of IF is ever finished.

Roody_Yogurt wrote:So yeah, those are things I like to do. Anyhow, I'm going to try to get in a proper playthrough soon enough and get that e-mail to you.
Thank you for the help, I really needed a fresh set of eyes. I hadn't realized how stale this project had become. I wrote probably 90%-95% in about five days. It was fun and easy; I was in the flow. The last 5%-10%, which includes refitting the game for general release and polishing, has been agonizing. Everything that was added had to be made compatible with what was already there. And I had to be sure that anything that was striped out wouldn't make it unplayable.

Roody_Yogurt
Posts: 2179
Joined: Mon Apr 29, 2002 6:23 pm
Location: Milwaukee

Post by Roody_Yogurt »

loafingcoyote wrote:Also, I looked up the HbE page on "locate" and noticed in the "example code" section what is probably a small typo. It says to add "locate 1, 3" in the main routine as opposed to init.
Thanks, fixed now!
loafingcoyote wrote:Thank you for the help, I really needed a fresh set of eyes. I hadn't realized how stale this project had become. I wrote probably 90%-95% in about five days. It was fun and easy; I was in the flow. The last 5%-10%, which includes refitting the game for general release and polishing, has been agonizing. Everything that was added had to be made compatible with what was already there. And I had to be sure that anything that was striped out wouldn't make it unplayable.
I am also polishing up a tiny game for an official release (what was previously known as "The Ecto Horror"). It was really fun fixing some of the biggest flaws of the original material, but yeah, doing the polishing stuff like writing nice ABOUT menu entries is just not that fun.

Roody_Yogurt
Posts: 2179
Joined: Mon Apr 29, 2002 6:23 pm
Location: Milwaukee

Post by Roody_Yogurt »

In fact, people can take a look at mine now at: http://roody.gerynarsabode.org/games/Halloween.zip

The middle section (and to some extent, the whole game) is kind of purposefully crappy, but it's probably true that I need to polish several parts of it.

Anyhow, I invite people to weigh in before I release it for reals.

Roody_Yogurt
Posts: 2179
Joined: Mon Apr 29, 2002 6:23 pm
Location: Milwaukee

Post by Roody_Yogurt »

Er, turns out I zipped and uploaded old versions yesterday. The link now has the right files.

loafingcoyote
Posts: 89
Joined: Wed Jan 04, 2012 2:57 pm
Location: Texas

Post by loafingcoyote »

Okay, the belated update to "Escape from Ice Station Hippo v1.2" is here. It should fix all the issues raised by Roody and a few other things as well.

Too much of my time was spent trying to get identical class objects to behave. Some objects in the game share adjectives or nouns with the identical objects. Problems would arise when those similar identical and non identical objects were in the same room. Often I was completely unable to interact with an identical class object that was listed as being present. I've never studied the code closely(this is now on my endless IF project list)but plural class objects seem to function far better than identical ones.

I ended up converting all the identical objects to plural class objects(Thanks for the tip Roody!) and this fixed most of my problems. The effect isn't quite the same, but at least the player will be able to interact with objects properly.

I'll wait a couple of days, then go back over it with a fine toothed comb. If no more issues are found then this will finally go to the IF archive and IFDB!

Post Reply