Adding stuff to the Status Bar

Another weird request: I want to add a timer to a portion of my game (if anyone thinks this is a horrible idea, obviously say so - I figured I’d give it to a few play-testers and see how they responded to it). So I can do this with a Fuse/Daemon without too much trouble. But in terms of keeping the player aware of the time they have left, the perfect place to put this countdown would be in the status bar.

Is this possible? I can’t find anything in the docs about it.

I’ve never tried it, but … there’s an article on the Banner Window in the System Manual, and the Library Reference Manual has pages for the classes BannerOutputStream, BannerUIWindow, and BannerWindow. That would be the place to start, I guess.

The top status bar is known as the status line (in the Tads documentation). The ADV3 source code for the base methods is in status.t.

The statusLine object can be used to set it’s text.

There are some methods to set the status line in TadsIO (if you’re not using ADV3).

Okay, here’s a bit of code that adds a dummy message to the status line. I copied showStatusRight() from status.t and added “… Not bad.” to the output. It works. You could edit this by inserting a call to whatever object is keeping track of the state of your fuse.

[code]modify statusLine
showStatusRight()
{
local s;

    /* if there's a score object, show the score */
    if ((s = libGlobal.scoreObj) != nil)
    {
        /* show the score and the number of turns so far */
        "<.statusscore><<s.totalScore>>/<<
        libGlobal.totalTurns>> ... Not bad.<./statusscore>";
    }
}

;[/code]
Adding text in this manner appears to work identically whether you’re using the standard T3 interpreter or the WebUI. (The other functionality, such as changing colors and adding more banner windows, doesn’t work in the WebUI.)

Dang - I just spent a while successfully working on this functionality using the banner API (which is perfect for purpose) without twigging that it’s not supported under WebUI. Pity, really, I don’t see that there’s any obvious reason not to support it. I presume it’s simply not been added to the WebUI interface “yet”.

deletes code and starts again

Thanks for the sample code, Jim. Status line, here we come…

Yep, that worked a charm. I ended up modifying showStatusHtml() too, of course, because otherwise my status-right countdown ended up being hyperlinked to the score. Thanks again!

Spoke too soon: the challenge now is updating the status bar, in real-time, for a countdown. I’ve got everything correctly set and it counts down, but the status bar only updates on user input, which makes the countdown a little less than impressive.

It occurred to me that you might want a real-time display, but since you mentioned Fuses and Daemons (which are once-per-turn devices) I assumed I was guessing wrong.

If you’re running a real-time process, I’m pretty sure there’s a method that will flush the status line and force it to display new text immediately. Search for “flush.”

You could use RealTimeFuse or RealTimeDaemon for timed updates instead of per turn updates. It will work both in interpreter and on the web. But if your target is web and you want the timer to be updated every second (as opposed to every minute), I will strongly discourage to use this method because it will generate too much traffic on the network. Better way in this case would be programming of timer in javascript for continuous update of visible timer and RealTimeFuse only to fire at the end of interval to trigger something that should happen.

Yes I’m using a RealTimeFuse and a RealTimeDaemon right now (code below including testing verbs to start the countdown and stop it etc). I’ve tried several attempts to flush, restore, update the banner etc., without any results. The only thing which did anything was statuslineBanner.clearWindow(); which, of course, zapped all the content including the left-side status bar text.

Here’s what I tried:

statuslineBanner.showStatusRight(); statuslineBanner.showStatusHtml(); statusRightOutputStream.flushStream(); statuslineBanner.flushBanner(); statuslineBanner.flushWin(); statuslineBanner.updateForRestore(); bannerTracker.restoreDisplayState(true);

Here’s my full code. Should be easy to drop into a vanilla project.

[spoiler][code]#include <adv3.h>
#include <en_us.h>

gameCountdown:InitObject
active = nil
timeRemaining = 0
text = “”
fuse = nil
daemon = nil
create(seconds) {
timeRemaining = seconds;
active = true;
onTimeChanged();
}
remove() {
fuse.removeEvent();
daemon.removeEvent();
active = nil;
}
changeTime(secondsChange) {
timeRemaining += secondsChange;
onTimeChanged();
}
onTimeChanged() {
if (fuse) fuse.removeEvent();
if (daemon) daemon.removeEvent();
fuse = new RealTimeFuse(self, &timeout, timeRemaining * 1000);
daemon = new RealTimeDaemon(self, &tick, 1000);
tick();
}
tick() {
text = 'Time Remaining: ’ + timeRemaining;
statuslineBanner.flushBanner();
timeRemaining -= 1;
}
timeout() {
"YOUR TIME HAS RUN OUT. ";
fuse.removeEvent();
daemon.removeEvent();
active = nil;
}
;

// Show the countdown in the top-right of the status line, if it’s active.
modify statusLine
showStatusRight()
{
if (gameCountdown.active != nil) {
“<span class=“countdown”><<gameCountdown.text>>”;
}
else {
// “”;
}
}
;

// Debug verbs for testing it
DefineIAction(Showtimer)
execAction() { gameCountdown.create(5); }
;
VerbRule(Showtimer) ‘showtimer’ : ShowtimerAction;
DefineIAction(Hidetimer)
execAction() { gameCountdown.remove(); }
;
VerbRule(Hidetimer) ‘hidetimer’ : HidetimerAction;
DefineIAction(Addtime)
execAction() { gameCountdown.changeTime(15); }
;
VerbRule(Addtime) ‘addtime’ : AddtimeAction;[/code][/spoiler]

Regarding a JS timer, tomasb, I agree this would be a much better method indeed. I actually started another thread about how I should go about invoking JS from the game: https://intfiction.org/t/invoking-js-directly-from-webui/4955/1

bcressey chimed in with an extension for doing so but I’ve not managed to get it to work yet, because the script frame he includes gets served by the frob webserver as text/plain instead of text/html, which prevents the browser from doing anything with that. After assembling a vanilla test-case of the same issue I actually filed it as a bug (bugdb.tads.org/view.php?id=187). I’m waiting to see if it qualifies as one, or whether it will be thrown back at me…

FWIW, after some thought (and more failed testing to update the status bar in realtime, and still being unable to call JS from TADS) the following approach seems the best one to me:

[]For text play, show the countdown in the status bar. It won’t update itself unless the user types something, so on specific intervals (every 30 seconds etc), show the time remaining in the command window. [/]
[]For HTML play, create JS which runs on window load. It polls for the presence of the countdown 50 times a second or so. If it finds it, it starts updating it every second, thus the countdown will work fine in HTML mode and I won’t need to echo time updates to the command window.[/]

It’s not ideal really but it avoids constant server polling in HTML mode, which was tomasb’s problem.