Saturday, July 19, 2014

Roodylib 3.9

This was actually released a couple days ago, but I didn't get around to writing this post about it until now.  Here are the new changes!


  • updated ObjectIs and TestObjectIs
  • small fix to CheapTitle
  • updated CenterTitle to work with the NO_MENUS flag
  • changed "skip" local variable in DoGo to "skip_ahead" since newcango.h already uses a SKIP constant
  • added AUTOMATIC_EXAMINE and LIST_CLOTHES_FIRST switches
  • updated code so characters have holding properties automatically and a substitute global is used for containers without them so authors aren't punished for not remembering to supply them
  • added extra supercontainer code to CheckReach, FindObject, DoExit, and DescribePlace
  • fixed mistake in CurrentCommandWords
  • moved ListObject's constant printing (IS_WORD, etc) to RLibMessage for easy replacing
  • better character name listing if there are multiple characters in the room
  • changed HugoFix's object tree listing (now skips replaced objects by default)
  • added "HugoFixInit" menu for setting debugging flags before the game has begun
  • added screen-size-change code to EndGame
  • various changes to grammar, ExcludeFromAll, verbheldmode, ParseError, and DoGet for better handling with clothes
  • added AnythingTokenCheck to FindObject for more control when using anything token grammar
  • changed "rank" local variable in PrintScore to "temp_rank"
  • defined settings objects as type "settings"
  • moved some PrintStatusLine printed text to RLibMessage for easier changing
  • HugoFix, when on, tries to organize the object tree at the start of the game for easier reading
  • lowered the time it takes to redraw the screen in ReDrawScreen and now uses InitScreen for consistancy
  • Changed some of the supercontainer object code itself
  • updated PrepWord to accept multiple words
  • gave names to replaced class objects
  • isolated DoEmptyGround from DoEmpty so authors can write before routines specific to it
  • changed order of checks in DoGet, more parent(object) code and clothing stuff
  • created an AssignPronounsToRoom (defaults to returning true) that allows you to disallow pronouns being set to that room (when it returns false). also created an exit_type global that keeps track of the type of exit used to get to the room (direction, door, non_door_portal). I think my thinking was that if the player types >GO RED DOOR, it'd be jarring when they see the pronoun set to something else. maybe this idea sucks. I don't know!
  • cleaned up children listing for certain instances in DoLook
  • added "object = -1" to things like DoLookIn, DoLook, and DoOpen so pronouns get set nicely
  • added an Infocom-esque "Continuing on." message to canceled DoQuits, DoRestarts, and such.
  • added a default response for trying to remove clothes from other characters. "so-and-so doesn't let you."
  • CoolPause now defaults to bottom-oriented text. put a value in the second routine argument to put it in the statuse line.
  • changed "PauseForKey" to "GetKeyPress". basically just prints and optional prompt and uses HiddenPause to get a keypress value.
  • created a SpeakerCheck routine so you don't have to put too much speaker-checking code in your main routine. if your game needs to do speaker-checking beyond "speaker in location", you can replace SpeakerCheck to fit your needs.
  • Added Kent Tessman's Future Boy! "time.hug" routines to Roodylib. set #USE_TIME_SYSTEM to use.
  • added #FORCE_DEFAULT_MESSAGES flag to keep old DoLook behavior
  • added a default auto-generated DoVersion routine for quick set-up. set #NO_VERSION to turn off.

As always, the latest version can be downloaded at http://roody.gerynarsabode.org/notdead/roodylib_suite.zip

why so much code?

So, when I posted that handful of posts the other day, someone said, "That's a lot of code. Why are you sharing so much code?"  They might have been joking, but it made me instantly self-conscious of how ugly the code looked (I made some changes to the page layout, but there's only so much that can be done).

Admittedly, the last bunch of posts aren't the best advertisement for Hugo.  On the positive side, the vast majority of it is something a new author has no need to be aware of.  I mainly show it now and here just as a snapshot of Roodylib's current development and also to give clues to future authors looking into any of these things.  Still, maybe it couldn't hurt to try to share more game code (you know, stuff that is fun to look at).  We'll see.

Some of these things I've been writing about are difficult in any language.  Some of the code in the last few days handled spacing, and new Inform 7 authors, at least, are often getting spacing wrong.  Still, I know Inform (and probably TADS, too) are a bit more powerful when it comes to grammar, and they probably have code to make some of the other things I've mentioned a lot easier, too.

This all got me thinking about the things I'm proudest about concerning Hugo's current state.  Here are some of them:

  • I really like my PrintStatusLine code.  I'm glad I've set up a system for really-configurable status lines that look great in all sorts of environments.
  • I'm also proud of the work that's gone into "newmenu.h."  Menus look great in the regular terp, glk terps- even simple DOS/Linux terps.
  • There's also my "configlib" extension, which takes various configuration-file-writing extensions and lets them piggyback into one saved file (you can easily add your game-specific configuration thingies to be saved, too), saving the author the headache of figuring out how things be saved when only one part of it changes.
Of course, there's not much I can do to make the actual writing of Hugo rooms and objects easier or more appealing.  It still just comes down to people who want their game code to be code-y but not too code-y (at least, that's one of its appeals for me).

As far as where my code needs the most work, I'd still like to polish "newconverse.h" up.  That's the extension that allows for several types of conversation menus.  When it works, I think it looks great and really has a lot of possibility.  Still, whenever I apply it to a new game, I always have a hard time getting it started so, yeah, that needs to be more user-friendly.

Thursday, July 17, 2014

AnythingTokenCheck (new to Roodylib 3.9)

One of the things I was most excited to take a swing at in Robb Sherwin's CZK was a certain gun.  I had noticed when betatesting the game that >UNLOAD GUN dropped the ammo to the location.  This was the impetus for me to code my "new empty" system for Roodylib, which uses grammar sorcery and object classes to support objects with different emptying behavior- held items that empty to the ground, held items that empty to the player, unheld items that empty to the ground, etc.

So I was really happy to apply this code to CZK and see how it worked.  Unfortunately, it didn't work great!  See, my "grammar helper" stuff uses the "anything" grammar token, so any object is fair game.  Since CZK has several guns, >EMPTY GUN got a "Which gun do you mean, this gun or that gun or... ?"

Nothing else could be done about this at the grammar level so I had to look other places.  Luckily, FindObject determines what objects are available at any point, so it just took some digging and examination to find a good place to test against an AnythingTokenCheck routine.


            if not AnythingTokenCheck(obj)
            {
#ifset DEBUG
                if debug_flags & D_FINDOBJECT
                {
                    print "[FindObject("; obj.name; " ["; number obj; "], "; \
                    objloc.name; " ["; number objloc; "]):  "; \
                    "false (AnythingTokenCheck returned false)]"
                }
#endif
                return false
            }


Now let's look at the AnythingTokenCheck routine:

I check for a parent of obj just so we can dismiss any objects not currently in any room or container straight away, and then it can check against the location.  This way, >EMPTY will only be used against objects within scope.

Now, it doesn't seem like people generally use the anything grammar token for much other than ASK/TELL, but I still think AnythingTokenCheck will be useful whenever people do use them for other means, and now it's there to be replaced when people need it.

Tuesday, July 15, 2014

More Roodylib updates

First off, you may have noticed that I've been using pastebin lately for larger pieces of code.  I'm in the process of looking at gist (github's source code sharing thingy) and may switch over to that soon (it seems it does a better job of preserving tabs, although you can still keep pastebin's tabs if you click through to the raw format).  Ideally, eventually I'll have some kind of syntax highlighting on here, too.

Anyhow, let's talk about the things I've added to Roodylib!

New DoOpen Behavior

While taking a look at another look at Cryptozookeeper, that mailbox in the first room reminded me how much I don't like Hugo's default opening behavior.  Funny how my perfect example goes so far back, but I've always liked Zork's "Opening the <blank> reveals a..." text.

So I added this code to do it:


See, it even properly sets the pronoun now

Initially, I wanted the contents to be listed even if there was an object.after, so you could have something like:

"The mailbox squeaks open.

Inside the mailbox is..."

But since the original Hugo library didn't do that, I don't want to break all of the existing games out there more than I have to (of course, you can put the content-listing code in your object.after property routine, which is what those old games already do... it's just uglier).

As of right now, I'm thinking this will be a default behavior, but if people hate it, I'll put in some way to turn it off.

Anchorhead-style Auto-Examination of Picked Up Items

The other day, I was looking at the tips section of Hugo By Example, and I was reminded of this neat little thing that Anchorhead does that I wouldn't mind seeing in more games.  In the game, for certain items, if you hadn't examined them before picking them up, picking them up automatically examines them.  I think it's a cute time-saving device, and I figured there's no reason it can't be thrown into Roodylib for convenience.  To use it, all you have to do is set the AUTOMATIC_EXAMINE flag.

Here is the code that makes it work:


Actually, more Zork-style stuff

I also haven't liked how it's always on the author's shoulders to specify whether a container is open. Even though, in this day and age, all objects should have a long_desc anyway, I've updated DoLook so that if an object doesn't have one, openable containers automatically tell you if they are open or closed.


mailbox with object.after property routine and the above DoLook code
Pretty sure that's all I wanted to talk about for now! New Roodylib update coming soon!

more parent(player) shenanigans!

So, notice in that last post how, when the player is in an enterable container, DescribePlace doesn't do a good job of specifying which objects are outside the container, what with all of those "this-and-that is here" messages?  Doesn't that bother you?  It bothered me!

So, the next thing I worked on was making that stuff get listed better when the player is in a container.  Here's what the final product looks like:



Currently, my code doesn't do anything with platforms, because while "So-and-so is here on the couch." sounds nice, what do you say for the the things NOT on the couch?  The best I could come up with is "is also in the room." or something, but it'd have to be easily changeable for all of the instances where the room is not a "room" (say, an open space or what have you).

Anyhow, as much as I like the idea of games sounding smarter, this isn't going to go into Roodylib at this point, either.  In the meantime, you can look at the code that I wrote to do it (important stuff is highlighted):



Maybe not the easiest stuff in the world to read, but if any of you want any help getting something like this working in your game, just let me know!

Monday, July 14, 2014

Some non-Roodylib parent(player) code

It seems like I've been spending a lot of time this year making sure Roodylib handles parent objects as well as possible, and every so often, I find something to tweak.

The other day, I found myself thinking about the old player-in-a-closed-container situation.  For my purposes, I was coding a coffin in a room.  Once the player is in the coffin and closes it, I wanted only objects within the coffin to be within reach (and seen).

Of course, it doesn't work out of the box, and I went on this epic quest, updating DoOpen, DoClose, FindLight, ObjectIsLight, and FindObject.  I was attempting to code an elaborate system that tried to figure out if the player can be seen from the location and act accordingly.  Working against me was the fact that FindObject likes to take for granted that the player object can always be seen, no matter what room is being used with it.  I tried so hard to tweak it to work for all occasions, but some instance was always breaking.

It's probably for the best that it never worked because who wants to add all of that code, anyway?  Eventually, it occurred to me that the easiest thing an author could do was just to set the coffin as the location when it was closed (and the room to the location when it was opened again).  Here is some example code:


It's possible that I didn't think of every verbroutine instance to be covered when the player is in the container, but that should be a good start!


Closing the coffin without a light source
More coffin antics coming in the next post!!

Clothing Update Part II

So, all of this work with clothing made me go, huh, wonder if my old "AIF" code still works. That's the flag that allows you to take off all of your clothes easily.  I mean, I have no intention of writing any clothes-heavy (or clothes-light har har) games anytime soon, AIF or not, but the world model fetishist in me likes to know these things work.  Anyhow, I found that, no, my old code did not work (I don't think it ever worked perfectly; I just hadn't completely tested it correctly).

See, the big problem is that >REMOVE ALL should default to held items, but you can't give it a multiheld token because you still want REMOVE to work with things like platforms or containers, and if you give it just the multi token, it ignores held items completely (only working for held items when they are used specifically).

Initially, the only way I could get it to work was to use the USE_CHECKHELD flag.  The checkheld system moves everything the player is holding to a hidden container in the room, so everything is considered not held (but it marks them with the checkheld workflag so the library knows it WAS held), allowing all verbs to work as you'd like.

Still, I put in all of this work so that in the instances where REMOVE failed, I made WEAR and TAKE OFF also fail in the same way just so there'd be consistency. I also made some instances of DoGet get directed to DoTakeOff.  Anyhow, I'm sort of embarrassed by how much work went into it, but if you want to check it out for yourself, check out the routines ExcludeFromAll, ParseError (cases 3 and 9), and VerbHeldMode in the next official release of Roodylib (version 3.9).  It is really ugly code; I should probably clean it up, but I just don't want to even look at it for a while.

As it often goes, I figured out a nice, non-checkheld-system workaround the next day. It occurred to me that the following PreParse code would do the trick:


        if word[1] = "remove" and word[2] = "~all"
        {
            word[1] = "take"
            InsertWord(2,1)
            word[2] = "off"
            return true
        }
        return false

So, basically, >REMOVE ALL gets turned into >TAKE OFF ALL (since >TAKE OFF doesn't have the same grammar issues).  Of course, ParseError messages will say TAKE OFF instead of REMOVE, but I don't think most players would even notice it isn't intentional.

Right now, if the AIF flag is not set, all variations of TAKE OFF, REMOVE, or WEAR ALL get a "Please specify which item to <blank>."-type message.  If it's set, those commands work, although they work in slightly different ways, depending on whether USE_CHECKHELD is set.

(Of course, I jokingly call it the "AIF" flag, but an author could easily want such a flag in a roleplaying-flavored game where the PC changes his or her armor a lot.)

Clothing Update Part I

So, it feels like I've been working on Roodylib a lot over the last few weeks.  It'll be interesting when I put up the next official release and go over all of the updates one last time for the changelog.

Robb Sherwin has been looking to get his game Cryptozookeeper sold online at places such as Steam and Desura, so I've been looking over the code to suggest tweaks to make this or that more user-friendly to those not familiar with IF.  Anyhow, looking at some of the things that game does made me go, "oh yeah, that probably should be an option in Roodylib!" on several occasions.

One thing CZK does is list worn clothing items before listing the rest of the inventory.  I actually wrote that code in the first place, but I didn't like how it replaced SpecialDesc in such an awkward way.  I felt, this time around that, hey, Roodylib can do it better!

So, first off, Roodylib has a new LIST_CLOTHES_FIRST flag that you should set if you want to run the new code. Then, for any character you want clothing to be automatically listed for, you add this:


    list_contents
        return ListClothesFirst(self)

Interestingly, ListClothesFirst only returns true if the character is wearing all of their belongings (this keeps an extra space from being printed after the worn-clothing list).  If you have an NPC where you only want clothing and held items to be listed when you examined them (and not in room descriptions), you could do this:


    list_contents
    {
        if verbroutine = &DoLookAround
            return true
        else
            return ListClothesFirst(self)
    }


Here is a screenshots of this system in action:




So, let's take a look at how this works. First off, of course, there's that ListClothesFirst routine:


routine ListClothesFirst(char)
{
    local x,w,c, list_save, v
    v = verbroutine
    verbroutine = &ListClothesFirst
    list_save = list_count
    list_count = 0
    for x in char
    {
        if x is worn and x is clothing
        {
            w++
            list_count++
        }
        elseif x is not hidden
        {
            x is already_listed
            c++
        }
    }
    if w and c
        list_nest = 1
    if list_count
    {
        if v ~= &DoInventory
            Indent
        if v = &DoLook
            FORMAT = FORMAT | USECHARNAMES_F
        RLibMessage(&ListClothesFirst,1,char) ! "You are wearing"
        ListObjects(char)
        if FORMAT & USECHARNAMES_F
            FORMAT = FORMAT & ~USECHARNAMES_F
        else
            FORMAT = FORMAT & ~USECHARNAMES_F
        list_nest = 0
    }
    for x in char
    {
        if x is not worn or (x is not clothing and x is worn)
            x is not already_listed
        else
        {
            AddSpecialDesc(x) ! tags worn items as already_listed
        }
    }
    verbroutine = v
    list_count = list_save - w
    return (not c and w)
}

It checks to see if any objects are worn, lists them, and marks them as already_listed.  I also needed to add this bit to ListObjects:


The ClothingCheck routine makes sure that children of worn clothing items aren't listed a second time (as they were listed by the ListClothesFirst routine).  There's also some code to make sure character names are used when it might be confusing.

Anyhow, here is the ClothingCheck routine:


routine ClothingCheck(a)
{
#ifset LIST_CLOTHES_FIRST
    if (a is worn and a is clothing and verbroutine ~= &ListClothesFirst) or
        (a is not worn and verbroutine = &ListClothesFirst)
        return true
    else
#endif
        return false
}


As you see, it has to check the verbroutine (which ListClothesFirst temporarily sets).

Anyhow, part of the reason I break this all down is because it's very possible you'll want to split up your player's or characters' inventories in other ways, and hopefully this is enough of a blueprint to get you on your way.

(All of this will be in the next official Roodylib release... coming soon!)