Friday, August 24, 2012

finishing touches

Ok, I did those things I mentioned in the previous post, as far as newmenu.h goes. I'm pretty much happy with everything. I did notice that there is some odd behavior in Hugor where the following code:
                    print "[N]ext item"; to 24; "[Q]uit menu"
                    print "[P]revious item"; to 24; "[Enter] to select"
 Occasionally results in:
[N]ext item             [Q]uit menu
[P]revious item          [Enter] to select
(Where [Q]uit is not aligned with [Enter])

Now, the font is PROP_OFF at the point in question. The only way I've found to fix it is to print a blank line beforehand (""). Somehow, I guess, Hugor is getting confused about cursor position or something. Maybe it's a result of the newly-supported realtime transcripting; I haven't checked it in older versions yet. Anyhow, it seems like it might be a tricky bug to track down so I'm going to see how simply I can replicate it before I send it on to Nikos.

Anyhow, my point is, other than that, I'm pretty happy with the current state of newmenu.h. I think all I really need to do now is perfect all of the default messages. I'm still not sure what the best "press a key to continue" text should be, and my "what is IF?"/"how to play IF" stuff in the default menu could use some polishing.

Again, the latest version is at http://roody.gerynarsabode.org/hbe/newmenu.zip. Everybody is invited to weigh in!

updates

A lot has changed since I uploaded "newmenu.h" to the IF archive, and I'd like to make sure it's in a good place before I upload it again. After working on the transcript stuff, I doublechecked that it worked ok with and without roodylib.h. This brought me to the auto-generating help menu thing that I set up some months ago. I was reminded that there should be a way for game-specific menu options to take precedent over the generic ones; in fact, the author should have complete control over the order of all of the options, right?

So yeah, I made a "priority" property for menu options- the higher the number, the earlier an option is listed. Coming up with a solution was trickier than I had predicted as I originally wanted to do it with regular arrays (and even modified my SortArray routine to allow for starting at an element other than 0), but since newmenu currently keeps track of its menu choices using two arrays, it was easier to just write the choices to a property array and use SortProp to re-order them.

As far as newmenu goes, I seem to be running out of hugolib-defined properties to alias to. Not aliasing is no big deal, but I try to do it when possible. Still, you don't want to accidentally alias something with a property that might be interpreted another way or otherwise interfere. I found one such overlap today, when checking to make sure that the roodylib-enhanced version of newmenu didn't run the MenuInit routine after UNDOs and RESTOREs.

So, the main thing is, the latest versions of newmenu and roodylib can be found at http://roody.gerynarsabode.org/hbe/newmenu.zip and roody.gerynarsabode.org/notdead/roodylib_suite.zip, respectively.

I've got some things to do with newmenu before I upload it to IF archive, yet. I have to make sure that the different-color-scheme-per-menu-page code still works and that the "cheap"-mode codes still works. Plus, just now, it occurs to me that maybe I should cut it down to use one array, so yeah, maybe I'll do that.

Thursday, August 23, 2012

simpler yet

I decided that my menu output could also ignore choices and just give titles to selected pages. The latest version looks like this:
>thoughts
[OPENING MENU]

[”Fatty Arbuckle”]
Blah blah hooray!

[”Whoa, a Helicopter!”]
Blah blah blah

[LEAVING MENU]
Returning to the story...
I think I'm on the right path.

EDIT: I didn't like how titles looked in the simple interpreter especially, so I switched it to something that looks more "title-like":
Transcription on.

>thoughts
[OPENING MENU]
                                                           Fatty Arbuckle
Blah blah hooray!

                                                         Whoa, a Helicopter!
Blah blah blah

[LEAVING MENU]
Returning to the story...
I'm keeping the menu "bookend" texts since I feel it's important to distinguish the menu from the rest of the game.

tales from the script

I've been fixing up "newmenu.h" again. I've got the screen-clearing mentioned in another post all sorted out; lately, I've just been touching up transcript behavior again.

In Hugo's original menu code, menus are kind of funky in game transcripts since most of the options are printed in the status window, which means that they don't show up in the transcript, so you get clumps of unlabeled text. In my menu update, I've been trying to make it so transcripts are easier to read by printing "invisible text" that only shows up in the transcript.

Here is how menu currently looks in a transcript:
Transcription on.

>thoughts
[MENU CHOICE: “BB Studios”]

[MENU CHOICE: “Fatty Arbuckle”]
Blah blah hooray!

[MENU CHOICE: “The Chase”]

[MENU CHOICE: “Whoa, a Helicopter!”]
Blah blah blah

[LEAVING MENU]

Returning to the story...

BB Studios
  According to local signage, one of the giant buildings that holds several of the lot’s stages is to the north. A fancy building for the top brass is to the west.
The "blah blah" parts are where there would be a page of menu text. All lines enclosed in brackets only show up in the transcript.

I'm happy with how it's shaping up. At one point, I had it print the name of the current page, too, but that made the transcript really ugly fast so I cut it down to just writing something when you make a choice.

I like how it is now, but if people have suggestions on how menus in transcripts could look better, I am open to suggestions. Let me know.

Huh, I just learned something as I was writing this post. I was going to post a transcript of how the menu looks in a simple interpreter where things like colors aren't supported. Throwing a transcript together just now, I was kind of surprised to find out that despite the environment's hacky way of showing the status window, it follows the default behavior of not-printing-status-window-text-to-the-transcript-file. Since "invisible text" (where I print text with the same foreground and background color) is not a possibility in a simple interpreter, I'll have simple interpreters automatically get the "cheap mode" treatment.

Anyhow, that is good to know, as I had been wondering whether I should do that anyway. This thing might actually be finished one day!

Saturday, August 18, 2012

>GO TO Hugo

Turns out my newmenu extension still has some annoying deficiencies. In the thought-I-fixed-that-but-if-so-I-lost-the-updated-code department, it turns out that my latest version wasn't clearing the screen enough when menus are initially opened or when options are selected. Fixing it ended up being a bit more complicated than I figured- and I'm not yet sure I've found my optimal solution- because, depending on the interpreter and the speed of the computer, clearing the screen (or "window 0") can cause text flicker which just annoys me for whatever reason. I'm trying to optimize it so only necessary text is cleared, allowing for as little flicker as possible.

Two of my WIPs are either entirely or partially driven by a >GO TO [room] mobility system. The second one, which I just recently started working on, got me thinking that I should turn the idea into an extension (or at least a page on Hugo by Example). I haven't really perfected anything, but I'll share what I've got so far.

First off, before "hugolib.g" is included, I declare some new >GO grammar:

 verb "go", "walk"
    *                            DoGo
    * "to"/"in"/"into"/"inside"/"through" anything            DoGoTo
    * "out" object                                            DoGo
    * "out"/"outside"                                         DoExit
    * anything                                                DoGoTo

Now, since we're going to be giving rooms noun and adjective properties, making them refer-able, we'll replace the room class with something that redirects a lot of actions:

replace room
{
    type room
    is static, light, open, known
    before
        {
        object
            {
            if verbroutine = &DoGo, &MovePlayer,&DoLook, &DoGoTo
                {
                return false
                }
            object = 0
            Perform(verbroutine)
            return true
            }
        object DoLook
            {
            Perform(&DoLookAround)
            }
        }
}
EDIT: It turns out the above is really bad code, as lots of verb routines (like DoGet) expect to have an object value, so Perform-ing them with no object actually makes you pick up the nothing object (and so on). Here is some better code (although it's kind of "blunt force"; maybe there's a more elegant solution):
replace room
{
    type room
    is static, light, open, known
    before
        {
        object
            {
                if verbroutine = &DoMove,&DoGet, &DoDrop, &DoPutIn,
                &DoEmptyOrGet, &DoGive, &DoShow, &DoWear, &DoTakeOff,
                &DoEat, &DoDrink, &DoHit, &DoLookThrough, &DoLookUnder, &DoExit
                    {
                    "I didn't understand you. Try being more specific."
                    return true
                    }
                elseif verbroutine = &MovePlayer,&DoLook, &DoGoTo
                {
                    return false
                    }
                elseif verbroutine = &DoGo, &DoEnter
                    {
                    Perform(&DoGoto, self)
                    return true
                    }
            object = 0
            Perform(verbroutine)
            return true
            }
        object DoLook
            {
            Perform(&DoLookAround)
            }
        }
}
We'll also make an "exits" property that keeps track of which rooms are available from other rooms (in this game, >GO TO just works room-to-room; this is not intended to be a Magnetic Scrolls type >GO TO scenario).

property exits
Now, our DoGoTo routine:
routine DoGoTo
{
    if object = location
        {
        "You're already there!"
        return false
        }
    if not FindObject(object, location)
        {
        if object.type = room
            {
            if InList(location,exits,object)
                {
                return MovePlayer(object)
                }
            else
                {
                if not location.cant_go
                    {
                    "You can't go that way."
                    }
                return false
                }
            }
        }
        return Perform(&DoGo,object)
}
A "here" object to redirect things like >GO TO HERE to the current location:
object here_object "here"
{
    noun "here"
    before
        {
        object
            {
            Perform(verbroutine, location)
            }
        xobject
            {
            Perform(verbroutine, object, location)
            }
        }
    in_scope you
    is known
}
An example room:
room STARTLOCATION "Start Location"
{
    adjective "start"
    noun "location"
    exits pond, barn
}

 So, that's basically it. An issue: one of the things my code does is make every room known so that MovePlayer works. If you still want a sense of discovery in your games, you could have DoGoTo automatically make rooms listed in the exits property known (so that rooms 2 connections away might still be a mystery).

Anyhow, I don't think the code is ready for HbE yet, but I thought people might find it interesting just the same. Plus, hey, this blog needs all of the posts it can get.

Wednesday, August 1, 2012

turn theory

(This post actually has some cross-system theory- almost making it worthwhile to post to the JC blog- but most of it will be Hugo-specific enough that I'm just going to keep it here.)

In getting newconverse working, I had to make some small changes to both the roodylib and newconverse versions of SpeakTo. One thing I noticed was that in the regular library, variations of the command >HELLO (CHARACTER) do not take up a turn (I changed this for roodylib).

Whether or not a verb routine returns true determines whether a turn passes (if a turn passes, the turn counter increases, PrintStatusLine is run again, and event code is executed). It seems like the philosophy behind turns is that ineffectual commands shouldn't take up any game time, but important commands should. Like, the entirety of verbstub, I believe, returns false, as Hugo makes the assumption that >YELL-ing or >SLEEP-ing will just provide some snide answer and that is that. >HELLO (CHARACTER) does have a pretty meaningless default response, but the command does still set the speaking global, which seems pretty important.

This system presents several points of confusion, including:
  • Any time you have to stop an action with a before rule, the "can't do" message will take up a turn while the regular action doesn't. Consistency cries! (maybe these are instances where verb routines should be replaced completely with something that always returns true)
  • What's the best way to distinguish between an ineffectual command and a useful one? From the player's perspective, it can be pretty unclear.
Some people contend that verbs like >LOOK and >EXAMINE shouldn't take up a turn, either. It's an interesting idea but might be more trouble than it's worth.

Still, what is turn-worthy is one of those things I imagine Hugo inherited from Inform. Now that I'm much more comfortable with the idea of suggesting improvements for the library, it's worth nothing that, hey, if we think we can design a more consistent system, there's nothing stopping us. In the meantime, we can continue to tune the responses one verb routine at a time.

I'll make this one quick

I spent 10-15 minutes working on my WIP today. That gave me some motivation to play around with newconverse a bit more. The good news is:
  1. Got all types of "[ undoing (last command)]" working to my satisfaction.
  2. Moved whatever I could from npc.parse_rank (npc being newconverse's character class object) to ConversePreparse, just because PreParse is only called once per turn while parse_rank is called a lot. In parse_rank, I kept some code that sets a verbroutine value if there isn't one, as that doesn't work in PreParse since the engine clears verbroutine after Parse is finished.
  3. Successfully made newconverse both roodylib and non-roodylib compatible. As much as I'd love everyone to always use roodylib, I'm making an effort for all of my extensions to standalone, if possible. That was too much work for cheaplib and colorlib (which now comprise part of the "roodylib suite"), but when I can, I will. Anyhow, it was very satisfying to get it working for both, as I originally thought I had to use some of roodylib's special features for optimal performance.
I think I'm done with newconverse and roodylib for a bit. The latest versions can be downloaded at http://roody.gerynarsabode.org/JC/newconverse.zip and http://roody.gerynarsabode.org/notdead/roodylib_suite.zip, respectively.

Newconverse could use a lot of documentation, and now that I think about it, I probably broke the peaceful coexistence of ASK/TELL characters and menu-driven-conversation characters (which I had purposefully supported with earlier versions of newconverse). I'll probably patch that up down the road, even if I might be the only person who thinks having both kinds of conversations in one game might be kind of cool.