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.

Tuesday, July 31, 2012

more stuff

Ha, I had already forgotten what my last post was about, but having read it, I can say, my latest problem was a continuation of the old one.

So, newconverse has this feature where >UNDO can remind the player what is being undone:

> talk to man
The man's eyes catch the torchlight for a moment as he looks up at
you.

> undo
[ undoing >talk to man ]

Gloomy Hall

>
It exists for a couple different reasons. I think, originally, the point was so that in a game where >UNDO skips over whole conversations, I wanted a mechanism to allow for a "[undoing to before conversation]" (which it does, under the right circumstances). It's also useful because it clarifies what really is being undone. Sometimes, as Hugo game authors, we might accidentally put important game text or code in something that returns false or, just as likely, a player might perceive a turn as counting (when it did not). This feature always keeps the player in the loop as to what's being done. Take, for instance:
 > talk to man
The man's eyes catch the torchlight for a moment as he looks up at
you.

> sleep
Not now--there's work to be done.

> undo
[ undoing >talk to man ]

Gloomy Hall

>

 ANYWAY...

So I noticed that the above feature was having a conflict with the issue from the last post. If you type only an object, the engine runs FindObject. After that, it jumps straight to SpeakTo. Oddly enough, it clears the word array before calling SpeakTo so my undo-command-saving code (which I stuck in an event, as that runs after every successful turn) wasn't saving the command properly (as concise as it was).

Anyhow, lots of futzing later, I got it working, but I also found out that a major culprit to it not working had been that while roodylib uses the word array to save states during UNDOs, RESTOREs, and RESTARTs, I was saving too low on the word array so some of it was actually being written over after a successful UNDO, screwing over the word-array-checking after-UNDO code.

I don't know how well I described all that, but that's what I did today!

Sunday, July 29, 2012

SpeakTo me

Today, I was trying to add some polish to newconverse. At one point, I started trying to modify its SpeakTo replacement so it was more like the one I put in roodylib, as I have become rather fond of most of my roodylib replacements. Eventually, I decided it might be altogether better to just drop the SpeakTo replacement in newconverse and alter newconverse to work with regular old SpeakTo.

This presented some interesting problems. If a player only types <character name> at the prompt, the engine calls SpeakTo directly so there wasn't an obvious way to redirect things with a before property. I ended up putting some code in the parse_rank property (since FindObject is called a couple times before SpeakTo) to change the verbroutine global if need be. Knowing what verbroutines to expect helped me write an order_response for the character class that could interpret things properly.

As if that wasn't all a big enough pain, I wanted to give the player a "You are already speaking." line if you do >TALK TO CHARACTER repeatedly (instead of an endless barrage of "<character> is listening."). While this was easy enough to trap for a regular TALK TO command, this turned out to be a pain for things like CHARACTER, HELLO what with the way that SpeakTo is always clearing or setting the speaking global. I had to change it yet again (hopefully for the last time) so it only clears and sets the speaking global when absolutely necessary (like, it only sets the global after order_response has been run, so your order_response code can correctly gauge whether or not the character was given his first command of the conversation).

Newconverse still has a ways to go before perfection; some of the messages could be tailored for multiple player persons (right now, it's all written in second player person) and just some general polishing, but hey, we're getting there.