Thursday, June 28, 2012

init thoughts and updates

First off, I spent a good chunk of time working on the glk update of Cardinal Teulbach's "automap" extension yesterday. It no longer requires "glk.h" and now has proper message routines. As I have done with some other extensions, I changed most of the global variables to object properties, as there is a hard limit on global variables and there isn't one on properties (plus, most of the time, you can alias your new property to some pre-existing propert). I don't know if Robb Sherwin ever ran into the global variable limit on Cryptozookeeper, but judging by the game source, I'd guess it has more than a hundred global variables (and the limit is 150), so it could be a limit that nobody ever runs into but I avoid it just the same.

The coolest addition to the automap extension actually involves adding a global variable, though. If you are using the "windows.h" header file and create a window with it, you can set the map_window global variable to that window. Then, every turn, it'll draw the map to that window. The intent is to make it easy to make a game with a Cryptozookeeper/Fallacy of Dawn type screen layout and be able to use one of the windows for an automapper.

The nice thing about touching up "automap" and "boxdraw" is that I think they are getting to the point where I can demote the original files to "outdated" status on Hugo by Example. I still don't know how likely it is that anyone will use them, but it should be simpler to approach from now on.

So yeah, the other thing, init.

Considering I want it to get to a point where an author doesn't really need to think about where to throw an extra routine into init, I've been thinking that the traditional order of things in init should be shaken up a bit.

As it is right now, global variables like "player" and "location" aren't set to nearly the end of the routine, after the intro and game title have already been printed. This makes it harder to find that sweet spot to call certain routines or start fuses that rely on those globals being set properly.

I intend to tidy things up so the order is something like this:
  1. Screen-clearing code and the like so games look the same for new games or restarts.
  2. Set all global variables (including "player" and "location"
  3. Execute any routines-to-be-called by init (like those from library contributions)
  4. Print game intro and title
  5. execute MovePlayer(location)
I still haven't decided if I should break any of the sections into routines themselves or any other similar organizational endeavor. It's a fine line between making-things-simpler and obfuscation.

4 comments:

  1. I remember thinking that the Hugo shell's init routine look more complicated than I6's Initialise routines did. For instance, here's the Initialise routine from the Inform version of Adventure:

    [ Initialise;
    location = At_End_Of_Road;
    score = 36;
    StartDaemon(dwarf);
    StartDaemon(pirate);
    StartDaemon(cave_closer);
    "^^^^^Welcome to Adventure!^
    (Please type HELP for instructions and information.)^^";
    ];

    I think there might be a reason for the standard init template not using MovePlayer, because MovePlayer sometimes calls DescribePlace and maybe does other stuff that you might not want when you're playing with the location variable. In my soon-to-be-released game, when I was moving the player to an enterable object, using MovePlayer and then moving the player object again into the enterable object was not satisfactory. Instead, I copied the code from my init routine that you helped me with on Jolt Country, manually resetting location and old_location.

    ReplyDelete
    Replies
    1. Hmm, yeah, how quickly I forget. It's definitely a tricky issue. According to MovePlayer's code, doing MovePlayer(bleachers) should automatically set the parent of bleachers as location:

      move player to loc
      old_location = location
      if parent(loc) = 0 ! if it's likely a room object
      location = loc
      else ! if it's an enterable object
      location = parent(loc) ! (noting that the object must be

      The only downside is that Moveplayer will incorrectly set the bleachers as old_location, too, but I don't think old_location is used much for anything anyway so it might not matter that it's wrong for the first turn.

      As far as DescribePlace goes, yeah, by the time MovePlayer comes along, you should be done setting the location global. Other than that, MovePlayer does a good job of cutting down init code. In my hypothetical init-processing-order list above, having already set "location" to "bleachers" in the global-defining area,
      old_location = location
      move player to location ! initialize player location
      FindLight(location) ! whether the player can see
      DescribePlace(location) ! the appropriate description
      location is visited

      Can be replaced with:
      MovePlayer(location)

      But yeah, I still can understand your misgivings.

      Delete
  2. The new automap would be so very clutch. I take it you are still working on it?

    I didn't encounter the global variable limit in Cryptozookeeper, however, I used arrays with hundreds of items in many places in order to get around any sort of global limit.

    ReplyDelete
    Replies
    1. Yeah, it's basically done, other than final polishing of roodylib.h and proper documentation of both. You can check it out here, in the meantime: http://roody.gerynarsabode.com/notdead/newautomap.zip

      In the included sample file, the map_window global is pointed to a sample_window window object, but you could point it to whatever you wanted.

      Far down the road, I might want to touch it up so that a room is five characters instead of four, so the player character doesn't overlap with the "u"/"d"/"i"/"o" key. I might even try to touch up the whole thing so rooms are more cube-shaped, instead of rectangular, which I imagine would give it more of an Infocom feel. Still, those things would require enough time that I don't intend to do them anytime soon.

      Delete