Showing posts with label init. Show all posts
Showing posts with label init. Show all posts

Tuesday, July 3, 2012

init simplification / compression

The init routine in the "new shell" listed on Hugo by Example currently is as follows (actually, I took some comments out of it to make it even more readable here):
!:: Game Initialization routine
routine init
{

#ifset BETA
        if word[1] = "script"
                transcript_is_on = true
#endif
        word[1] = ""    ! clear word[1] in case of game restart
        MAX_SCORE = 0   ! ready to change for a scored game
        STATUSTYPE = 0  ! 0 = none :: 1 = score/turns :: 2 = time
        counter = -1    ! 1 step before first turn

        TEXTCOLOR = DEF_FOREGROUND
        BGCOLOR = DEF_BACKGROUND
        SL_TEXTCOLOR = DEF_SL_FOREGROUND
        SL_BGCOLOR = DEF_SL_BACKGROUND
        color TEXTCOLOR, BGCOLOR

        verbosity = 2

        display.title_caption = "<game title>"
! display.title_caption - used for GUI clients for title bar text.
        prompt = ">"
        window 0 ! resets the windows in case the player is restarting a game  
        cls      ! clear the screen, too

#ifset GLK
        glkcheck
#endif

        DEFAULT_FONT = PROP_ON
        Font(DEFAULT_FONT)

!:: Opening Text
        "Intro to game"
        print ""    ! For a blank line between the intro and the game title

        Font(BOLD_ON)
        "Game Title"
        Font(BOLD_OFF)
        "Game Blurb"
        print BANNER;

#if defined IFID  ! print the IFID, if there is one
        print IFID
#endif

        player = you
        location = STARTLOCATION
 
        move player to location
        old_location = location
        FindLight(location)
        DescribePlace(location)
        location is visited
        CalculateHolding(player)

#ifset USE_PLURAL_OBJECTS
        InitPluralObjects
#endif
}
 I've mentioned on here that I would also like to make init simpler, so authors new to Hugo can get to writing their games quicker (and are less likely to do something out of order, like trying to start a daemon before the location and player globals have been set). In one of my more recent test games, I got init down to this:
routine init
{
!: First Things First
SetGlobalsAndFillArrays
!: Screen clear section
SimpleIntro
InitScreen
!: Set up any special libraries
Init_Calls
!: Game opening
IntroText
MovePlayer(location)
}
 Of course, all of the same routines and lines of code are being run; they're just moved around into their respective routines. This is how I break it down:
  1. SetGlobalsAndFillArrays - This routine would reside nearby in the shell, as it requires game-specific information to be set.

    Example:
    routine SetGlobalsAndFillArrays
    {
    !\ Uncomment and modify this section if your game has scoring and ranking.
        MAX_SCORE = 50
        ranking[0] = "Amateur Adventurer"
        ranking[1] = "Competent Door-Unlocker"
        ranking[2] = "Bomb-Meddling Adventurer"
        ranking[3] = "Master Magic Wand Finder"
        ranking[4] = "The Genuine Article Sample Game Solver"
        MAX_RANK = 4  \!

        counter = -1                    ! 1 turn before turn 0

        STATUSTYPE = 1   ! 1 = score/turns, 2 = time, 3 = moves: score:
        TEXTCOLOR = DEF_FOREGROUND
        BGCOLOR = DEF_BACKGROUND
        SL_TEXTCOLOR = DEF_SL_FOREGROUND
        SL_BGCOLOR = DEF_SL_BACKGROUND
        prompt = ">"
        DEFAULT_FONT = PROP_ON
        player = you
        location = STARTLOCATION
    }
     
  2. SimpleIntro - A roodylib routine that prints some blank lines before a simple, non-glk game starts (sort of faking a clearscreen). This could be replaced if you wanted to do a cool logo like mentioned in another post.
  3. InitScreen - This is a screen clearing routine. The roodylib version has different behavior for simple, regular, and glk interpreters. It also sets the font and colors.
  4. Init_Calls - This automatically calls all library routines that need to be executed in init. I gave each library an object that goes into an init_instructions object. Init_Calls just checks for children of init_instructions and runs all applicable code.
  5. If any of the library routines print anything (like beta.h asking if the player would like to start a transcript), it returns a value telling Init_Calls to run InitScreen again so the screen is cleared before the "game proper" begins.
  6. Then, Intro_Text would be another "shell-side" routine. This is where the opening text of the game would go.
  7. MovePlayer automatically prints the location name and description.
All in all, I'm pretty happy with this system. I'm not sure if I'll recommend it for the "official shell", but I think I might distribute a "roodylib shell" with roodylib. The one other thing I'd possibly do is just add a dummy routine after Init_Calls so authors can just fill it with whatever other calls they want (even though they could conceivably add such routines to the end of SetGlobalsAndFillArrays).

Anyhow, I'm sort of conflicted about how I should handle this. On one hand, of course, I'm designing init so the author really has to change it as little as possible, but since that goes against init's traditional handling, I hope the new way isn't even more confusing. Ah well, time will tell, I guess.

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.

Monday, June 25, 2012

More glk.h talk and some init

I've been continuing going over my "glk.h"-using library contributions, as I consider "destroying" it. For some of them, changing glk-checks to a simple-port-check makes absolutely no difference, like for boxdraw (the quote-box drawing extension), as both glk and regular simple interpreters can't use the command "locate" in the main window. The automap extension will require a bit more attention, though, as "locate" does work in the status window (which allows me to redirect the map up there), but it won't work at all in regular simple ports (like the simple DOS port), where I'll have to disallow it completely.

Another thing on my mind is how we can improve handling of the "init" routine. Despite how relatively straightforward it is, I worry that it looks like a bunch of noise to a newcomer, so if possible, I'd like to figure out a good way to compress and modularize it. Ideally, I'd like to come up with a way where including a library contribution automatically adds relevant routine calls to init so adding extensions isn't always an exercise in editing init.

Actually, just this instant, I thought of a possible answer to that. I could make a init_routines object. Each library contribution, when included, will place an object (with a property pointing to the relevant setting-up routine) inside that init_routines object. Then init could just have a routine that checks for children of the init_routines object and executes all relevant properties. I could probably also add an order priority system if it turns out that order of execution really matters (of course, order will already be set by order of inclusion, too).

Well, at some point, I'll probably throw the above together as a proof-of-concept. Hopefully, it doesn't come across as needless obfuscation to everyone else!