Thursday, November 21, 2013

I'm no good at versioning

I recently ran into some annoyances with my WIP where I realized that Hugo's default message for GO-ing at a non-enterable object is "You can't enter that."  I think, more often than not, GO TO <object> will be typed by an IF newbie unfamiliar with IF's world model.  I have updated DoGo to reflect this.  It now results in a "<the object> is right here." message.

Anyhow, I had forgotten that I had already uploaded a version 3.5 of Roodylib (in my memory, I was still sitting on some changes for the next version), so I have uploaded another version 3.5.  Don't care enough right now to change it.

Other things:

  • Been meaning to write a game design theory post with thoughts about designing routines for jumping around your game.  My WIP has several dream and flashback sequences that can be triggered almost whenever so debugging theory has been on my mind.
  • I asked Kent for some ideas for responses for the "You can't enter <the object>." replacement mentioned above.  Besides giving several responses, he jokingly suggested randomizes between them.  It didn't sound like a terrible idea, though.  While I wouldn't provide multiple, random responses to something like verbstub verbs, I could almost imagine randomized responses for some hugolib-centric messages, like ParseError or something.  Ideally, it could give the illusion that the parser/library is more robust than it is.  Still, at the moment, it's probably not worthwhile to go through hugolib and decide which responses could be multiplied.  More important things to do.

Tuesday, November 5, 2013

Roodylib update

After months of neglect, I've uploaded a new Roodylib.

One is the DoExit bug mentioned in the last post.  Additionally, there are some verb things suggested by Mike Snyder.

Not sure if I ever properly uploaded the previous release (3.4), so here's the changelog from that, too:

v 3.4 - * Updated DescribePlace so it can be called without arguments
* Found another USE_PLURAL_OBJECTS DescribePlace bug in the NEW_DESC stuff
* Updated SpecialDesc, WhatsIn, DoTakeOff
* Checkheld versions of DoWear and DoTakeOff
* Updated FindObject, ExcludeFromAll, VerbHeldMode, SpeakTo, CheckReach
* DoLookIn no longer requires container grammar (now works with non-container, transparent objects)

As always, Roodylib can be downloaded here:
http://hugo.gerynarsabode.org/index.php?title=Roodylib

Wednesday, October 16, 2013

new old bug! (DoExit)

We've had some new eyes looking at Hugo code lately, and sometimes that's all it takes to discover a long-existing bug.  Don't really know how it didn't turn up before, but this person noticed that when the player is in a closed, openable, and enterable container, typing "OUT" would result in "Nothing is closed."

Initially, I was worried that this was due to the SetUpDirectionObjects routine not properly setting the object global to the out_obj object (since I still don't entirely trust how Perform uses that routine), but the problem turned out to be in DoExit itsellf (in fact, the out_obj doesn't really matter when DoExit is called since almost all applicable error messages will mention the parent of the player, if anything).

The problem turned out to be that the "so-and-so is closed" VMessage text was expecting the object global to exist, and DoExit wasn't properly defining it in that instance.  So, here's a version of DoExit where that is fixed:

replace DoExit
{
local p

#ifclear NO_OBJLIB
! >GO OUT winds up calling DoExit with object = out_obj, thanks to
! the direction-parsing code in Perform().  English ambiguities being
! what they are, we correct that interpretation of "out" here, and
! treat the command as a generic instruction to exit whatever
! container context we may be in.
if object = out_obj
object = nothing

if object = nothing or object = location
{
if player in location and out_obj in direction
{
word[1] = out_obj.noun
word[2] = ""
return Perform(&DoGo)
}
}
elseif object = d_obj and player in location
{
return Perform(&DoGo, object)
}
#endif

p = parent(player)

#ifclear NO_OBJLIB
if object and player not in object
#else
if object and player not in object
#endif
VMessage(&DoExit, 1)             ! "You aren't in that."
elseif p is openable, not open
{
object = p
VMessage(&DoLookIn, 1)           ! "X is closed."
}
else
{
if object = nothing
object = p
move player to location
if not object.after
VMessage(&DoExit, 2)     ! "You get out.."
}
return true
}

Of course, this will be added to future versions of Roodylib.

Friday, July 12, 2013

Dead Laptop

So, a couple nights ago, my laptop died.  Now, as far as my Hugo stuff goes, that isn't extremely dire.  First off, I was pretty good about uploading Roodylib and other extension stuff to my bitbucket account as I worked on it, so, at most, the bitbucket version might be missing a day or two's amount of work.  Also, I backed up all of my game work in progress code before a trip some months ago, and both fortunately and unfortunately, I've been so bad about working on my games in progress the last several months that there isn't probably a whole lot changed between what-I-most-recently-had and what-I-have-backed-up (I did recently have my games open and did a whole lot of code-cleaning and optimizing, but no real new content was added).

Beyond that, I'm pretty sure the hard drive in my defunct laptop is ok, so I should be able to retrieve all of my old data once I get an external dock or something.  Between that and the fact that I was in a midsummer coding slump anyhow, I'm not in any real hurry to work on anything in the near future.

Mainly, I'm just kicking myself for not making better use of today's free cloudspace so I had more of my data still at my fingerprints.

As far as music goes, while I don't have my ~100 GB mp3 collection uploaded anywhere, all of my purchased-from-Amazon mp3s are always available in the Amazon Cloud Player (plus the extra 240 songs I could fit into my remaining free space).  My Amazon music might make up for a fraction of my overall collection, but it's still 4000 some songs so it's not shabby, either.  Plus, some of my music is on last.fm, too, so I can just sign into that and do the playlist where it only plays songs it has already played previously in my music library. Lastly, spotify can be good for individual album listening.

My bought games can all be re-downloaded, but I have to say that I'm especially glad that Steam has added cloud saving.  It is really nice that I don't have to restart on the few Steam games I really cared about.

My coding projects are mostly in various states of "backed-up".  The most backed up projects I have are the ones that I share with Robb Sherwin and are repo'd.  It's a really nice thing that with a repository, you always know you have the working copy of something.  On the other hand, I'm currently borrowing time on somebody else's laptop, so I'm not sure if I'm actually going to install repo software on it.

Robb Sherwin also set me up with a linode server account, so maybe I should have kept all of my stuff on there.  Also, maybe I could just bitbucket all of my game code, besides just library stuff.

There's also just being better about backing up to USB devices and stuff, but that's such an easy thing to fall out of habit with.  Just the same, I wish I had been better about stocking a USB stick with as many of my favorite apps that support running from portable drives.

I'll also say that I was happily surprised that since I had used the multiple-user feature in Chrome on my dead laptop, when I added accounts to this temporary one, all of my bookmarks and passwords were instantly accessible.  Besides that, of course, all of my Google Docs stuff is already all save in the cloud.  On my old laptop, I pretty much used Chrome for just e-mail and productivity stuff (Google Docs, Google Tasks, etc.), but with how easy it is to have your stuff follow you everywhere, maybe I'll get in the habit of using it for more things.

I can understand why some people are distrustful of the cloud and warn people to not put all of their eggs in that basket. I agree with that, too, but there are still plenty of ways of using it to your advantage.  I'll try to be smarter about it in the future.

Tuesday, July 2, 2013

recent updates

So, first off, updating Roodylib to support non-container, transparent objects did take quite as many changes as I thought it would.  I just need to replace DoLookIn and add some more code to CheckReach and DoLook but that's basically it.  Now it's just a waiting game to see if I made more problems for myself.

Anyhow, let's get back to that situation the other day, where I was helping code a wearable coat with a pocket.  The problem was that its contents weren't showing up in inventory listings.  First, this required a change to WhatsIn to fix some spacing issues.  After that, I realized that SpecialDesc was only listing children-of-children if the object had more than one child, so I added some code to check for that when there is one child.

You can see the evolution of my code over at this thread: http://www.joltcountry.com/phpBB2/viewtopic.php?t=8938

While testing all of these compiled coats with their various pockets, I would often take the keychain from the coat pocket just to make sure inventory was still printing correctly even when the coat has no children.  At one point, I noticed that while >REMOVE KEYCHAIN FROM POCKET worked, >REMOVE KEYCHAIN alone did not.  I thought, huh, well, it really should be smart enough that if the object has a parent other than the player, it should be directed to DoGet.

So, I added some code to fix that, but in doing so, I noticed that DoTakeOff and DoWear both had multi grammar tokens, so out of curiosity (and since my test game had both a coat and the player wearing some shoes), I started testing the commands >WEAR ALL and >REMOVE ALL.

Oddly, I found that the multi grammar token defaulted to not-held items, so both of these commands often would respond with things like "Nothing to wear." I thought, huh, I'll fix that!

So, besides playing around with grammar, I tracked down the problem to hugolib's VerbHeldMode routine, which redirects the parser to held or not-held behavior based on the verb being used.  I also turned on the checkheld system and added some code to FindObject.

By this point, >WEAR ALL and >REMOVE ALL were working correctly, but the results had the player trying to wear or remove everything in his inventory, so I added some code to ExcludeFromAll so non-clothing items would be ignored.

Long story short, Hugo is now "AIF"-ready!


Welcome, AIF Authors!


So yeah, Hugo can now accept >WEAR ALL and >REMOVE ALL.  Still, I wasn't excited about the prospect of default Roodylib behavior making it too easy to disrobe, so I thought, huh, maybe I could do something about that, too.

In the end, I changed ExcludeFromAll so that in the default behavior, it excludes all clothes, too, and in the case of DoTakeOff and DoWear, I changed the ParseError message to "Be specific about what you'd like to <blank>."

So, that means something like >WEAR PANTS AND FUNNY HAT will still work, but >WEAR ALL will get the "Be specific..." message.

Of course, if you want >WEAR ALL to work, all you have to do is set the new "AIF" flag.

My one point of conflict right now is that >REMOVE <object>  gets directed to DoGet even when the object is in your location (and not a child of something).  On one hand, I feel like I should give that instance a "you can't do that." message, but on the other hand, I wonder if there are room descriptions where "remove" will feel like an applicable verb (and I imagine that most players wouldn't notice that it works there otherwise).  Feel free to weigh in!

So yeah, I'll try to get the latest Roodylib uploaded to HbE soon enough so anyone who wants to play around with this stuff can do so.
 

Sunday, June 30, 2013

Container Theory Part II

Ok, so not long after writing that last post, I remembered one of the main reasons I have long associated "transparent" with "container".

In the example of a snowglobe, if we define it as a non-container, transparent object, it'll work fine with DoPutIn. A container, transparent object would need additional before routines to disallow it. This is part of the reason why yesterday's view of containers sounded appealing to me.

Still, that doesn't change the fact that DoLookIn demands that objects be containers. What's the point of a snowglobe that you can't look into? Anyhow, instead of trying to fix what is and isn't a container, I think I'm just going to fix DoLookIn's grammar.

I could try to do it on the grammar level, using Roodylib's "grammar helper" stuff to only allow containers and transparent items to work on the grammar pass, but I don't like forcing Roodylib users to use extensions like that so I'm probably just going to change DoLookIn's container check to an object token and add all necessary additional code to DoLookIn itself.

On the plus side, this should make coding windows (the glass kind) more intuitive to future authors. On the down side, maybe this change will have some ramifications down the road.

I mean, I could go back to my old container assumptions, but since I've already learned that others find other definitions more intuitive, I don't think that's the right path. I mean, the holy grail of an IF language is to make everything as intuitive as possible.

Container Theory -or- How Do You Code a Bucket?

So recently, I've been helping with a contents-listing problem during the >INVENTORY command involving coat pockets. Fixing that involved a change to WhatsIn and SpecialDesc- which I had intended to write up here, if it weren't for the issue that I want to talk about today (in fact, after WhatsIn and SpecialDesc, I have another thing I want to write about, so hey, the next entry will be a nice, multi-part post).

It turns out that my updated code still isn't working for that other person, and my hunch is that it has to do with the fact that my code has been slowly changing how containers are dealt with. Today, I figured I should finally run my designs past Kent. Eventually, we unearthed the point of contention where we disagreed on default behavior.

In Kent's view, a bucket coded in Hugo should have the following attribute definition:

    is container

While in my mind, it should be defined as such:

    is container, open

I think this might also be the difference in the coat objects as defined by me and the fellow I'm trying to help (since my new SpecialDesc code relies on the open attribute being used). To those who prefer the first definition, adding "open" must seem like overkill. As far as whether-contents-can-be-seen, I agree, as far as unopenable containers are concerned, it can be assumed that they are either open or transparent (otherwise, it's useless for them to be a container).

I was going to say that as far as other container behaviors go, I was worried about things like not-open, unopenable, transparent objects, but I had a Hugo-understanding breakthrough just now as I write this. I glanced over at the character class definition and was reminded that characters are transparent without being containers. I think part of my container-understanding problem is that I have so strictly associated "open" and "transparent" with containers (since thinking of transparent examples often make you think of something like a glass jar), when it's better to pretend that "transparent" has nothing to do with containers and remember that "open" only exists to work with "openable".

Anyhow, I feel pretty dumb that I have been so unclear on the concept for this long, but I'll try to update HbE so future coders don't fall into the same traps I did. Also, I still think that some of the hugolib contents-checking conditionals could be more concise, so I'm going to try to do something about that.

While I'll quickly admit being wrong on this issue, it's interesting that something as simple as containers can so easily catch people (maybe most people won't make the same assumptions I did, but I'm sure some do). I imagine the container code I wrote in ZIL recently is just as flawed. Ah, well.

Thursday, June 27, 2013

New newmenu stuff

So, some days ago- I've taken my time getting around to write this blog post about it- I was working on porting John Menichelli's HugoZork to Roodylib. One of the last additions I plan to do involved transferring his menu code over to my newmenu format. This, in turn, got me thinking about newmenu for the first time in a while.

alt_title property


First off, his menu pages often have a different title from the link name that led to them. In the past, with newmenu, I've just kept an extra CenterTitle call in the page text. This has the downside of possibly getting double-titled in a simple terminal interpreter. Converting HugoZork was the straw that made me go, eh, I might as well add another property to menu option objects. Behold, the alt_title property (I actually gave it an alt_name alias in case I forget what I called it along the way)!

(Also, hey, look, I found a better way to share code)

option amusement_option "For Your Amusement/Words To Try"
{
    in main_menu
    alt_title "For Your Amusement"
    menu_text
    {
        "Have you ever:\n"

        "\_  ...opened the grating from beneath while the leaves were still
        on it?"
        "\_  ...tried swearing at ZORK I?"
        "\_  ...waved the sceptre while standing on the rainbow?"
        "\_  ...tried anything nasty with the bodies in Hades?"
        "\_  ...burned the black book?"
        "\_  ...damaged the painting?"
        "\_  ...lit the candles with the torch?"
        "\_  ...read the matchbook?"
        "\_  ...tried to take yourself (or the Thief, Troll, or Cyclops)?"
        "\_  ...tried cutting things with the knife or sword?"
        "\_  ...poured water on something burning?"
        "\_  ...said WAIT or SCORE while dead (as a spirit)?\n"

       ! "\nPress any key for more..."

       ! pause
            CoolPause(1)
        CenterTitle("Words To Try")

        "Words you may not have tried:\n"

        "\_  HELLO (to Troll, Thief, Cyclops)"
        "\_  ZORK"
        "\_  OIL (lubricate)"
        "\_  XYZZY"
        "\_  WALK AROUND (in forest or outside house)"
        "\_  PLUGH"
        "\_  FIND (especially with house, hands, teeth, me)"
        "\_  CHOMP (or BARF)"
        "\_  COUNT (candles, leaves, matches, blessings)"
        "\_  WIN"
        "\_  MUMBLE (or SIGH)"
        "\_  LISTEN (especially to the Troll, Thief, or Cyclops)"
        "\_  REPENT"
        "\_  WHAT IS (grue, zorkmid, ...)"
        "\_  YELL (or SCREAM)"
        "\_  SMELL\n"

        CoolPause(1)
    }
}

So, the name of the object represents how the choice will be listed in the menu itself, and the alt_title property is how the page is titled when you are reading it (if you don't provide an alt_title property, it just uses the link name).

TopPageMargin routine


I also added a routine called TopPageMargin. It is to newmenu what LinesFromTop is to Roodylib. I give it its own routine for two reasons- 1) newmenu does not require Roodylib and 2) I find that I sometimes like menu pages to have a slightly different margin than the game itself.

Right now, TopPageMargin defaults to returning 2 so page text automatically starts 2 lines down from the top. If your menu page text already does its own carriage returns for proper spacing, you can always replace TopPageMargin to return 0.

Glk menus


I also tweaked the glk behavior for better detecting when there are too many options and the menu has to be drawn by the "cheap" non-windowed method. Right now, it only draws the cheap menus as needed, so it's entirely possible that mid-menu, it'll jump from one kind to the other. I'm considering having it decide before it even gets started if it'd ever possibly use the cheap menu (and then just use that throughout), but that leaves the window open for game crashes if the player resizes the window mid-menu.

Other thoughts


Looking at the code again, I was reminded how newmenu is currently a mix of array and object hierarchy design. Given that I've done much more object-hierarchy organized design since I initially wrote newmenu, I started wondering, hmm, maybe I should just switch newmenu to doing everything by object hierarchy.

After thinking about it, my initial conclusion was that all of the necessary object-organization routines would complicate things more than necessary, and the end result would probably be more memory-intensive than the existing system so I've given up on that idea for now. Still, it seems like it might be possible to design something that only rearranges itself as necessary and largely works without writing values to anything.

I'll probably get back to this as some point when I have something else I really should be doing instead.

Thursday, June 20, 2013

SpeakTo stuff

So, yesterday, I was adapting John Menichelli's Hugozork to Roodylib, just because I'm always curious to see how well Roodylib plays with already-written games. Initially, there was some ParseError replacement code for the Loud Room that I was able to move to Roodylib's PreParseError routine, but I noticed that some of it didn't do the Loud Room's echo behavior quite right so I spent some time fixing that.

While testing that code, I realized that the engine-called SpeakTo was skipping all of my glorious code completely (SpeakTo is called directly both when you give characters commands, like: >CLOWN, HELLO or just when you type an object with no verb, like >ROCK).

I decided that SpeakTo should have to do location and player before checks, to better allow response configurations for situations just like the Loud Room. Here is my current SpeakTo:
replace SpeakTo(char)
{
local a, v, TryOrder, IgnoreResponse, retval, stay, same, different
#ifset USE_CHECKHELD
if verbroutine = &DoDrop_CheckHeld
verbroutine = &DoDrop
elseif verbroutine = &DoPutIn_CheckHeld
verbroutine = &DoPutIn
#endif

#ifset VERBSTUBS
if verbroutine = &DoHelpChar and object = player
{
verbroutine = &DoHelp
object = nothing
}
#endif

#ifset USE_CHECKHELD
ResetCheckHeld
#endif

#ifset DEBUG
if debug_flags & D_PARSE
{
print "\B[Speakto("; char.name;
if (debug_flags & D_OBJNUM)
print " ["; number char; "]";
print ") verbroutine="; number verbroutine;
print ", object="; object.name;
if (debug_flags & D_OBJNUM)
print " ["; number object; "]";
print ", xobject="; xobject.name;
if (debug_flags & D_OBJNUM)
print " ["; number xobject; "]";
print "]\b"
}
#endif

v = verbroutine
a = actor
actor = player
verbroutine = &SpeakTo
retval = player.before
actor = a

if retval
{
#ifset DEBUG
if debug_flags & D_PARSE
{
print "\B["; player.name;
if debug_flags & D_OBJNUM
print " ["; number player; "]";
print ".before returned "; number retval; "]\b"
}
#endif
return retval
}

retval = location.before
if retval
{
#ifset DEBUG
if debug_flags & D_PARSE
{
print "\B["; location.name;
if debug_flags & D_OBJNUM
print " ["; number location; "]";
print "before returned "; number retval; "]\b"
}
#endif
return retval
}

verbroutine = v

if char is not living
{
ParseError(6)  ! "That doesn't make any sense."
return
}

AssignPronoun(char)

! Handle player/typist-related ParseError messages:
if char = player
Message(&Speakto, 1)    ! "Stop talking to yourself..."
elseif not ObjectisKnown(object) and not FindObject(object, location)
ParseError(10, object)
else
   stay = true

if not stay
  {
  speaking = 0
  return
  }

if char is unfriendly
IgnoreResponse = true
else
{
! In the event of:  >CHARACTER, GO NORTH.  GET THE THING.  GO WEST., etc.
if not FindObject(char, location)
{
speaking = char
run char.order_response
return true
}

same = (char = speaking)

select verbroutine
case 0                  ! Just the character name is given,
! so just "X is listening."
{
if not char.order_response
Message(&Speakto, 2, char)
retval = true
}

#ifclear NO_VERBS
case &DoHello           ! Note the ampersands ('&')--or else
{                       ! the routines themselves would run
if not char.order_response
{
if char is not unfriendly
{
! "X nods hello."
Message(&Speakto, 3, char)
retval = true
}
else
{
IgnoreResponse = true
}
}
else
retval = true
}

case &DoAskQuestion
return Perform(&DoAsk, char, object)

case &DoTalk
{
if xobject
ParseError(6)
else
return Perform(&DoAsk, char, object)
}

case &DoTell
{
if object = player
return Perform(&DoAsk, char, xobject)
else
TryOrder = true
}
#endif  ! ifclear NO_VERBS

case else
{

! If the character can respond to a request, this should be dealt with by
! an order_response property routine; order_response--if it exists--should
! return false if there is no response for the given verbroutine

TryOrder = true
}
}

if TryOrder
{
if (not char.order_response)
IgnoreResponse = true
else
retval = true
}

different = (speaking ~= char)

! This same/different local variable stuff allows for certain
! orders to end conversations. If your order_response code clears
! the speaking global, this code prevents it being reset.

if retval and not (same and different)
speaking = char

if IgnoreResponse
{
if not char.ignore_response
Message(&Speakto, 4, char)      ! "X ignores you."
speaking = 0  ! clear the speaking global
}
return retval
}
Now, there are a couple problems. One, currently, both the location and player code have no idea what command the player is trying to order done, as I had to change the verbroutine to &SpeakTo for easy catching. Further complicating things, is that for the player object, I had to change the SpeakTo-determined actor global, too.

Ideally, I'll be able to figure out a way to organize all of these values so authors can have as clear an idea as possible about what was typed, and hopefully I'll be able to do it without the creation of new globals (although that isn't a big deal and I'll probably end up doing it anyway).

Also, let it be said that this new code is very lightly tested so there might be a gaping bug I haven't found yet.

Tuesday, May 28, 2013

listing discontent

So, a couple things to talk about today, but one of them is more useful to Hugo users everywhere so I'll cover that one first.

As mentioned in another post, Roodylib now automatically lists the contents of the room's (non-quiet) platforms in a room's description. This might give some pre-existing games some unexpected behavior, but logically, I don't know why platforms should be treated any differently than containers.

Still, this puts some in an awkward position, because they are not familiar with the ways to avoid listing contents. Of course, the quiet attribute will prevent content listing until the player explicitly looks into the object (at which point it'll list the contents at every opportunity).

To have full control over when contents are listed, you have to use the list_contents property.

To only allow content-listing when the player explicitly LOOKS IN/ON:

list_contents
{
if verbroutine ~= &DoLookIn
return false
else
return true
}

To allow content-listing only for EXAMINE or LOOK IN:

list_contents
{
if verbroutine ~= &DoLookAround
return false
else
return true
}

So yeah, the three times that contents are listed are room descriptions ( &DoLookAround), object descriptions (&DoLook), and when looking in objects (&DoLookIn). Knowing that, you can write your own list_contents rules. Of course, you can still use list_contents to print your own content listings before you return true.

The other thing is that, while applying Roodylib to another game, it became apparent that there was a problem with my new DescribePlace system when the USE_PLURAL_OBJECTS flag is set. I had copied over some code from the old one that checked for identical objects without finessing it into the new code. When this error made me take a look at the code again, I had to calculate exactly how useful the code was.

In the old DescribePlace, the lines in question prevent identical objects from being listed among objects-with-short_desc's. I started thinking, well, hey, why can't we have it both ways? I then altered my code to allow identical objects with short_descs and found that, ok, ListObjects (the routine that tallies the identical objects) lists the same total regardless of which objects have already been described. So, long story short, there's now some code in there preventing that from happening.

There's still some work to do with the new DescribePlace. Right now, I think objects and characters with descriptions always have to be listed before their description-less counterparts. Eventually, I should see if I can make the order truly interchangeable. I'm not sure how often that situation comes up, but it'd be good to support it just the same.

Tuesday, May 7, 2013

goods news, bad news

So, after some more playing, it turns out that the game I was testing the 16-bit interpreter with, the Vault of Hugo, won't restart even if you only use the standard library (also, a small Roodylib game will still restart in the 16-bit interpreter). If I drop the HugoFix debugging suite and identical and plural object support from Vault of Hugo, the game will work, but add either one of those and it's back to shenanigans. I take this to mean that the issue is deeper than anything I can do to fix.

For the most part, not being able to provide games for the 16-bit interpreters isn't a big loss. It'd really only be useful for things like the @ party thing mentioned in the last post (although it's still very possible that IF doesn't even need to meet the 1992 requirement) or targeting other real die-hard retro fans.

When I do the @ party thing, I'd like to go somewhat hardcore. I think that means that I'll probably have to use ZIL for that, which is cool, but my only regret is that it's probably too late this year for me to write a ZIL game in time for @ party. Still, next year, the @ party might be a great thing for a ZIL competition to piggyback on to.

Monday, May 6, 2013

not surprising, but disappointing

A recent post on the int-fiction forums informed me that @ party demoscene gathering has continued to invite interactive fiction into its yearly competition. I had considered submitting something a couple years ago when I first heard about it (although at the time, it had one of those wordings where Inform games were preferred). Anyhow, not having heard about it at all since then, I had assumed that they had dropped the IF invitation.

I don't exactly have a game idea ready as much as a malnourished concept. We'll see if I turn it into something worthwhile.

While the Interactive Fiction section of the @ party rules doesn't request any particular requirements, one of the other ones requests that submissions be run on computers available in 1992 so I'm approaching it from the same angle. Out of curiosity, I tried compiling a couple games to see how the current Roodylib works with the 16 bit and simple Hugo interpreters.

Disappointingly, there were two problems that popped out at me right away. For one thing, the status line wasn't being drawn properly in the 16 bit interpreter. For another thing, both interpreters would hang when I tried to restart the game. That problem wasn't just Roodylib's DoRestart's fault, as replacing it with the original did not help. I think the interpreters were just out of memory.

As far as PrintStatusLine stuff goes, it seems that the 16 bit interpreter also miscalculates the screenwidth, just as the simple interpreter does. The actual screenwidth is one character shorter than the detected screenwidth (in the simple interpreter, it is two characters short). Possibly, this is DOSbox's fault, or possibly, print to works differently in each of these interpreters. Also, Roodylib's latest PrintStatusLine also doesn't work in the DOS 32-bit interpreter, either, but I, admittedly, do some strange window-drawing stuff in that. It works fine with the previous PrintStatusLine.

Anyhow, making Roodylib compile a game that works with all of these interpreters is probably impossible, especially since the 16 bit interpreter considers itself a non-MINIMAL_INTERFACE interpreter. Still, I put some stuff in Roodylib that specifically helps out interpreters like the simple interpreter, so it'd be a shame to stop supporting it altogether. I'm going to try to go through Roodylib and provide a switch for turning off unnecessary features, and hopefully the resulting games will still work with older interpreters. Authors will unfortunately have to compile multiple versions of their games (if they wish to support old DOS interpreters), but I don't really see a way around it.

That said, games compiled with the minimum-feature Roodylib probably won't work with extensions like newconverse.h, which is another shame. Oh well.

Update: Ok, it's not so much that the DOS 'terps are detecting the wrong width (although the simple interpreter still is short by one character), it's just that when they write the last character to the line, it automatically goes to the next line, whereas in the Windows 'terp, you can stop right there. Right now, I'm thinking that I'm going to make the Infocom-style status line (two spaces on the left and right sides) the default, regardless of whether you set the DESCFORM_F flag. Again, not optimal, but better than trying to code for every possible interpreter.

Wednesday, May 1, 2013

more character stuff

So, the character DoGet stuff mentioned two posts ago allows >GET ALL FROM <character>. I was thinking about how this will not always be optimal behavior and what to do about that.

There's probably a grammar-based solution (especially if you use Roodylib's GRAMMAR_HELPER stuff), and actually, that is probably the easiest way to deal with it.

Still, if you want to avoid grammar-tampering, another way to do it is to replace the ExcludeFromAll routine:
replace ExcludeFromAll(obj)
{
if obj is hidden
return true

! Exclude things NPCs are carrying unless the NPC is explicitly
! given as the parent
if parent(obj) is living
{
! if IsPossibleXobject(parent(obj)) or parent(obj) = player
! return false
return true
}

return false
}
Making sure it always returns true when the parent is living gets the player a "Nothing to get." message when he tries >GET ALL FROM <character>. To change this, we'll need to add a case to NewParseErrror:

replace NewParseError(errornumber,obj)
{
     select errornumber
case 9
{
if xobject is living and children(xobject)
{
"You will have to specify one object at a time."
return true
}
else
return false
}
         case else : return false
     return true
}
So yeah, that's that. To do more complicated behavior, like allowing the first item but not allowing the rest, I'd probably incorporate the use of a global or, more likely, the word array (with SaveWordSetting and CheckWordSetting), but that  scenario is unlikely enough that I won't put it together unless I need it myself or someone asks for it.

Roodylib 3.2 has been released

Just since practically everyone who uses Roodylib follows this blog, yes, I uploaded the latest version of Roodylib and it is available at the usual spot:
http://hugo.gerynarsabode.org/index.php?title=Roodylib

always more to do

I have to admit that recently, I've been yet again not working on my own games but have found a distraction. I've been applying Roodylib and my extensions to somebody else's already-released game-with-available-source-code. Mainly, I've been curious how well my code can integrate with other games and whether it helps the overall playing experience. So far, I'd say the results have been fairly promising, although the experience has brought some more issues to my attention

Objects Can Be Grabbed From the Possession of Friendly Characters Without Comment

I was kind of surprised to find out that a character has to be unfriendly to refuse you from taking its possessions, and when you do take possessions from a friendly character, you just get the default "Taken." message.

Now, without modifying Roodylib, there is this solution:
replace character
{
   type character
   pronouns "he", "him", "his", "himself"
   capacity 50
   holding 0
   is living, transparent, static
   exclude_from_all true
   before
   {
      parent(object) DoGet
      {
         local l
         l = string(_temp_string, self.name)
         l--
         print "Nah, that is "; The(self);
         if _temp_string[l] = 's'
         {
            "'."
         }
         else
            "'s."
      }
   }
}
The above disallows taking things from friendly characters. To allow it, you'd have to replace the before routine with something that calls Acquire and prints its own "so-and-so lets you have the <blank>" message.

Just in thinking about the issue while I write this post, I think I will update Roodylib so that DoGet calls a character's after property to allow for different messages when you take objects from friendly characters.

EDIT: Actually, looking at DoGet closer, it already has a parent(object).after check, so I think I'll just give a default after routine to the character class.

Platforms Get No DescribePlace Love

While testing my code, I also noticed that contents of scenery platforms were not being listed by DescribePlace. The game (and others) have gotten around this by having code like this in a room's long_desc:
if child(self)
Perform(&DoLookIn, self)
else
"There's nothing on it."
Really, though, I can't think of a reason why you wouldn't want DescribePlace to handle platforms automatically. You can always deny content listing for &DoLookAround in list_contents, if you want.

The original scenery-contents check looks like this:
         if obj.type = scenery
         {
            obj is known
            if player not in obj and
               (obj is open or obj is not openable)
My check now looks like:
if obj.type = scenery
{
if player not in obj and
! (obj is open or obj is not openable)
((obj is container and (obj is open or obj is transparent))  or
obj is platform) and obj is not quiet
There's probably some overkill in there, and hopefully I didn't introduce new problems.

Platform Problems Part 2

Another problem cropped up, where even looking at scenery platforms or containers like above didn't prompt a listing of their contents. Since I've run into a problem like this before, I quickly guessed that my DescribePlace had left those items with the already_listed attribute, which DoLook looks for before listing contents. At first, I tried updating DescribePlace to always remove that attribute from them, but the thing is, in my modular version of DescribePlace, I really want the author to be able to list objects in any order they want, and I didn't want to restrict them to always having to list scenery contents last.

In the end, I thought, huh, why does DoLook even care about already_listed, anyway? Those attributes will just be reset the next time DescribePlace is run. The only thing instance where I think the already_listed-check might be important is in the case of identical plurals, but in my cursory testing, removing the check has had no effect on identical-plural behavior. Guess I'll just keep the check off the next version of Roodylib and see what problems pop up.

Speaking of Roodylib, I should probably upload a new official release soon. I guess I've been putting it off. I think I'll probably do something about that DoGet issue mentioned above, and here is some other stuff that'll show up in the new version:
 * added a missing printed bracket in parser monitoring code
* added NEW_EMPTY system for more container/platform-emptying options
* added AMERICAN_ENGLISH flag to switch between quotation punctuation styles
* added NEW_DESCRIBEPLACE to give more DescribePlace options
* added WhatsIn replacement and ListObjects RLibMessage-call for more printing options
* updated CenterTitle to not draw extra window in simple, non-Glk terps
* Fixed some places in the supercontainer class that didn't work right with transparent supercontainers.
* Fixed a problem where non-door items with door_to properties weren't being accepted by DoGo. Probably still some perfecting to do on this one.
* Attachables DescribePlace code was missing some parentheses.

Thursday, April 25, 2013

"You can go"? We can do!

So, Robb Sherwin's game, Necrotic Drift, was recently available in a games bundle. One of the perks of buying the "deluxe" version that was included was the original game source. I picked up a copy myself, and lately, I've been updating ND to use Roodylib and attempting personal challenges like tweaking the window sizes to work better with multiple displays.

Necrotic Drift uses Cardinal Teulbach's can_go.h extension. I've already forgotten if I had specific gripes, but I've long thought that we could improve on its design. A couple days ago, I decided to finally do something about it.

I had some ideas for things that'd improve can_go, but my plan quickly morphed into something I'd have to write myself. I never liked how YouCanGo (the routine that prints the "You can go" message) does all of the exit-figuring calculations every time it is called, and I liked it less now that I have personally run into problems from writing to too many array slots between turns.

I decided to implement a system where, on the entrance to a room, I'd move around some objects to save the configuration of available exits, so then, every time I want to print the exits, the printing routine can just go look at the relevant objects.

Here is the new can_go.

I also did a version that is an update to Teulbach's can_go. While I changed the behavior of how the preposition property is handled, the new version should be mostly compatible with games written for the old system. Besides adding some feature, I optimized the code a bit here and there to cut down on unnecessary loops.

Here is the update to the old can_go.

I originally forgot to put door support into my new design. In adding it, I discovered an existing problem in Roodylib's DoGo's handling of non-door items with door_to properties. See, &object.door_to refers to door_to property routines while object.door_to refers to simple properties. It is important to check for both in your code.

Anyhow, Roodylib on bitbucket has already been updated, and the fix will show up in the next official upload to HbE (it'll be version 3.2).

Thursday, April 4, 2013

using what I've learned

First off, hey, this is the 70th post of this blog. Not bad for something less than a year old, I think. Just goes to show how geeky I can be about taking apart an IF language!

Anyhow, I had been thinking that of all of my extensions, my NPC  pathfinding extension "findpath.h" probably had the most bad code, memory-wise, as it assigns every room two additional properties, which it clears between uses. That is not unlike my array-clearing code that caused that huge headache in Roodylib.

It's always interesting to look at code you wrote a year ago, as I found several parts of "findpath.h" useless. Among the changes:
  • Previously, before writing the directions to be taken to the applicable character's script, I stored it in a property for that character (something that I was replacing the whole character class to give each character enough open slots). Since the code only sets up one path at a time, I figured I could just store the steps in a regular array that all characters would use. I think I wrote the original code at a time that I was especially fond of property arrays.
  • The code used an included routine called PropertyCount that went through the given property array and counted how many elements had values. Now, this might still be useful somewhere, but the way my code used it, I found I could easily replace it with better usage of local variables. I also clipped some of my determining-which-exit-is-best code by using local variables better.
  • Instead of clearing the room properties, I now determine whether or not a room has been counted yet by using the already_listed attribute. I can't say for certain, but I thought there was a chance that using an attribute might leave a smaller memory footprint.
  • I replaced this finding-the-other-side-of-this-door-object code:
            if InList(a.d, between, a ) = 1
                a = (a.d).between #2
            else
                a = (a.d).between
    With this code:
            a = ((a.d).between #((a = a.d.between # 1) + 1))  
     Anyhow, that second thing, which I got off of CharMove or somewhere, might take a bit longer to read, but it does the same thing without having to call InList. Now, I don't know if calling InList really uses that much more processing power or memory or anything, but at least, when you are using the debugger, you won't have to step through those extra lines.

    So, all in all, findpath.h is a leaner, meaner machine now. It still has some of the same hang-ups. Like, it doesn't have awesome code for dealing with locked doors or anything, but even with that, I think I put it in a much more stable place (now, if there is no available path to the "prize", the code should shut down without printing anything embarrassing).

    So yeah, there's that. If you are curious about the two versions, the old version is http://roody.gerynarsabode.org/hbe/findpathold.h and the new version is http://roody.gerynarsabode.org/hbe/findpath.zip.

    Happy pathfinding!

Tuesday, April 2, 2013

new_desc

In one of my WIPs, I did some hacky things to my code so that in any given room, objects with short_descs are grouped together into one paragraph. Since I've been adding DescribePlace-related stuff to Roodylib lately, I thought, hey, let's see if I can make this an official option in there!

In my WIP, I defined my short_descs like this:
    short_desc
    {
        "A giant spoon lies on the ground, as if discarded by some humongous
        spoon musician.";
    }

With Roodylib, I didn't want to task the author to add the semi-colon each time, and DescribePlace and ShortDescribe really expect short_desc to be a property routine (and not just a regular property). I found that it's pretty much impossible to get the code to play nicely with both.

In the end, I had to create an optional new property and new DescribePlace helper routines to  Roodylib (luckily, I had already designed a DescribePlace that'd allow easy inclusion of such). A game compiled with NEW_DESC set would allow the following and give it proper spacing:

    new_desc "A giant spoon lies on the ground, as if discarded by some
    humongous spoon musician."

Anyhow, this is a feature that will probably only be used by me, but I thought I'd announce it just the same.

Monday, April 1, 2013

more roodylib updates

I added a lot to Roodylib today. The biggest chunk of code was probably my new (optional)  DescribePlace system. All in all, Roodylib went from 160 KB to 181 KB.

I also "released" my port of Cardinal Teulbach's SceptreQuest, which I uploaded to http://roody.gerynarsabode.org/games/squest.hex (I use quotes because I don't intend to announce the game any where besides here and my twitter account, as the copyright on the game doesn't technically allow re-release like this). Writing that inspired several Roodylib updates today. We'll get to that in a bit.

First off, I added an AMERICAN_ENGLISH flag to Roodylib. It really doesn't change as much as you'd think. All it really does is move quotation mark placement for statements such as "I don't understand the word 'blah.'"

As mentioned I also added that DescribePlace stuff. When I ported SceptreQuest, I also coded its odd color handling. I found that this involved changing color at places that forced me to replace whole hugolib routines, so among other things, I added calls to RLibMessages to handle different printed tasks for DescribePlace (such as the printing of the room name), WhatsIn, and ListObjects. As far as ListObjects goes, there are probably more bits of text that I could sent to a message routine, but I'll add those as needed.

 I also finally added that DESCFORM_I constant to act as a FORMAT mask. When enabled, DescribePlace does not print the blank line before printing the room name. It now does this check (in RLibMessage):
                    if not (FORMAT & DESCFORM_I) or (verbroutine ~= &MovePlayer and
                    verbroutine ~= &DoLookAround and a = location)
                        print "\n";
The location check allows one to use DescribePlace to fake movement to rooms (where it should not print a new line) but still prints a new line for when things like newmenu.h call DescribePlace after having printed "returning to the story...".

The next thing I'm considering working on is a combination of Future Boy's time object class and improved resource.h  routines where things like audio.current_music is automatically cleared after the song is over. Going over it in my head, though, has me thinking it might be too bulky for Roodylib-inclusion so I may just improve my already-existing-but-separate jukebox system to do that. We shall see!

Thursday, March 28, 2013

Empty Progress

So, I got a working prototype of my solution. It uses a mix of Roodylib's grammar routine helper stuff and object classes.

First, let's look at our new grammar definition:
verb "empty", "unload"
    *                                                       DoVague
#ifset NEW_EMPTY
    * (CheckEmpty) "on"/"onto" "ground"/"floor"             DoEmptyGround
#else
    * object "on"/"onto" "ground"/"floor"                   DoEmptyGround
#endif
    * multi "from"/"off"/"on"/"in" parent                    DoGet
    * multi "offof"/"outof" parent                         DoGet
    * multi "from" "offof"/"outof"/"on"/"in" parent         DoGet
! Send >UNLOAD OBJECT to DoEmptyoOrGet, which dispatches to DoEmpty or DoGet
!    * object                                                DoEmpty
#ifset NEW_EMPTY
    * (CheckEmpty)                        DoEmpty ! DoEmptyOrGet
#else
    * object                DoEmpty
#endif

In no cases does it run DoEmptyOrGet anymore as I think it's so general that it just leads to trouble. Next, let's take a look at our object classes:
#ifset NEW_EMPTY
property empty_type

class unheld_to_player
{
    empty_type NOTHELD_T
    before
    {
        object DoEmpty
        {
            local a, b, obj, xobj
            local thisobj, nextobj

            CalculateHolding(object)

            if object is container, openable, not open
            {
                VMessage(&DoEmpty, 1)           ! "It's closed."
                return true
            }

            if object is not container, platform
            {
                ParseError(12, object)
                return false
            }

            if not children(object)
            {
                VMessage(&DoEmpty, 2)           ! "It's already empty."
                return true
            }

            thisobj = child(object)
            while thisobj
            {
                nextobj = sibling(thisobj)

                print thisobj.name; ":  ";

                if thisobj is static
                    VMessage(&DoEmpty, 3)    ! "You can't move that."
                else
                {
                    a = player.holding
                    b = thisobj
                    obj = object
                    xobj = xobject

                    if Perform(&DoGet, b)
                        player.holding = a + b.size
                    else
                        player.holding = a
                    object = obj
                    xobject = xobj

                    if b not in object
                        object.holding = object.holding - b.size
                }

                thisobj = nextobj
            }

            run object.after
            return true
        }
    }
}

class held_to_player
{
    empty_type HELD_T
    inherits unheld_to_player
}

class held_to_ground
{
    empty_type HELD_T
}

constant NO_EMPTY_T 16

class no_empty
{
    empty_type NO_EMPTY_T
}
If it's not self-explanatory, that consists of a class that represents objects that must be held and empty out to player (like unloading bullets from a gun), objects that must be not held and empty out to player (like unloading a laundry machine), objects that must be held and empty out to ground (like a bottle of liquid), and objects that can't be emptied (for containers and platforms that deserve a "You can't empty that." message).

Here is the grammar helper routine:
routine CheckEmpty(obj)
{
    if obj.empty_type
    {
        TOKEN = obj.empty_type
        if not CheckObject(obj)
        {
            return false
        }
        elseif obj.empty_type = NO_EMPTY_T
        {
            ParseError(12, obj)
            return false
        }
        return true
    }
    elseif not CheckObject(obj)
        return false
    return true
}
#endif NEW_EMPTY

Lastly, whether or not players use this new system, I think Roodylib will replace DoEmpty to switch around the platform/container check before the children check:
 replace DoEmpty
{
    local a, b, obj, xobj
    local thisobj, nextobj

    CalculateHolding(object)

    if object is container, openable, not open
    {
        VMessage(&DoEmpty, 1)           ! "It's closed."
        return true
    }
    if object is not container, platform
    {
        ParseError(12, object)
        return false
    }
    if not children(object)
    {
        VMessage(&DoEmpty, 2)           ! "It's already empty."
        return true
    }

    thisobj = child(object)
    while thisobj
    {
        nextobj = sibling(thisobj)

        print thisobj.name; ":  ";

        if thisobj is static
            VMessage(&DoEmpty, 3)    ! "You can't move that."
        else
        {
            a = player.holding
            b = thisobj
            obj = object
            xobj = xobject

            if player not in location and
                (parent(player) is platform or
                    parent(player) is container) and
                not xobject:

                Perform(&DoPutIn, b, parent(player))
            else
                Perform(&DoDrop, b)

            object = obj
            xobject = xobj
            player.holding = a
            if b not in object
                object.holding = object.holding - b.size
        }

        thisobj = nextobj
    }

    run object.after
    return true
}
 EDIT: Just throwing in that, yeah, I know my code does nothing about the "multi from/outof/etc xobject" grammar that points to DoGet, but I think that would go to DoGet in most cases anyway and I'm comfortable with people having to write their own before routines to catch the rest.

full of "empty" problems

First things first, even with the next Hugo Open House months away, I've been thinking a bit about the next one's theme. I think all involved with last year agree that it was even more of a hassle to get things done, even with the extra time. I like to devote the rest of the year to real projects, though, so I don't really want to move the Open House earlier.

My recent thought was that this year's theme should be ports. Part of the inspiration for this was that Johnny Rivera and I have had our eye on Cardinal Teulbach's Hugo 1.2 games. I know Robb Sherwin has had his eye on some BASIC games, and in general, there are just a vast number of outdated game systems out there with games that could use new life.

So, yesterday, instead of actually waiting for the Hugo Open House to come around, I thought I'd dip my toe in the porting waters to see what it feels like. I started with Cardinal Teulbach's SceptreQuest which in itself is a port. Originally, I was looking at the original BASIC source and thought I'd be writing a new version of DescribePlace (which could be conceivably be used other similar BASIC ports), but when I opened up Teulbach's version, I was reminded that they are two very different games. His game is more of a re-imagining.

Anyhow, I'm mostly done with the reimplementation of it all, but I've been tidying up a couple things before I release it (even to what degree I release it is uncertain since Teulbachs was kind of hardcore about his usage license).

Long story short, in testing some of the various containers and platforms I have in the game, I have paid more attention than usual to the DoEmpty and DoEmptyOrGet routines. It is my current conclusion that they are in dire need of being fixed.

Right now, typing >EMPTY <non-held, non-container-or-platform object> results in that object being picked up.

There's also this bit in DoEmpty:
    if not children(object)
    {
        VMessage(&DoEmpty, 2)           ! "It's already empty."
        return true
    }
       
    if object is not container, platform
    {
        ParseError(12, object)
        return false
    }
I have a feeling that in earlier versions, this code may have been switched, as that ParseError message is successfully called in games like Spur and Guilty Bastards. I imagine that DoEmptyOrGet was added and DoEmpty was mixed around in the creation of Future Boy! to solve some problem, but it unwittingly opened some other problems.

Of course, sometimes game design  relies on player's not doing nonsensical things (like trying to empty or unload average non-container items), but when possible, these kind of holes should be patched.

It'd be nice if I had a better time envisioning the scenario that brought about the code change, but whatever the case, a verb routine such as DoEmpty could possibly be even more robust. For instance, I can imagine some objects that should unload or empty out onto the ground and other objects that should empty out into the player's inventory. Also, possibly there should be a way to quickly disallow emptying of a container or platform without having to write up a before routine to catch it.

This all presents the question, how do we handle all of these scenarios? Right now, I'm leaning towards a global variable used with format masks or possibly just attributes. I am going to think on this. Anyone have any suggestions?

EDIT: Ok, I was just playing with this for a bit. I was trying to do some complicated grammar token stuff, but my routine grammar doesn't play nicely with the "multi" grammar token used by much of the "empty" definitions. I have come to the conclusion that probably the best route to take would be to create object classes with various DoEmpty behaviors from which other objects can inherit from.