[SugarCube] Auto-loading the autosaved game

293 views
Skip to first unread message

Erik Temple

unread,
Nov 28, 2013, 3:11:11 PM11/28/13
to twee...@googlegroups.com
Now that SugarCube has an autosave slot (yay!), I'd like to have the autosave load automatically/semi-automatically when the reader opens up the story. The problem is, I don't think I know exactly how to do it.

First issue: It seems that the Start passage is auto-saved by default, so that if you try to call a macro from the Start passage to auto-load the autosaved game, you will be too late--the game will have autosaved on the Start passage and the old saved state will be gone. This can be got around by configuring autosave system to save automatically only for passages with a given tag: If we leave the Start passage untagged and tag every other passage with the autosave tage, we are able to access the old save from the newly begun story's Start. 

Second issue: Unfortunately, I can't quite seem to get an autoload macro working. The following almost works: It properly detects whether there is an existing game stored in the autosave slot, but while it seems to attempt to load the autosaved game in the same way that the SugarCube source does, nothing happens when it gets to the moment of truth:

macros.add("loadAutosave", {
    version: { major: 1, minor: 0, revision: 0 },
    handler: function () {
    var saves = storage.getItem("saves");
if (saves !== null && saves.autosave !== null) {
var retVal = confirm("Do you want to continue ?");
    if( retVal == true ){
      SaveSystem.loadAuto;
      }
      }
    }
});

Any ideas what I'm doing wrong? Also, would it make sense to always exempt the Start passage from autosaving?

Thomas Michael EDWARDS

unread,
Nov 28, 2013, 11:02:31 PM11/28/13
to twee...@googlegroups.com

--- Erik Temple on 11/28/2013 2:11 PM, wrote:

> First issue: It seems that the Start passage is auto-saved by
> default, so that if you try to call a macro from the Start passage
> to auto-load the autosaved game, you will be too late--the game will
> have autosaved on the Start passage and the old saved state will be
> gone.

That's the problem (one of the problems?) with wanting to save on
every single passage. Still, there are solutions.


> This can be got around by configuring autosave system to save
> automatically only for passages with a given tag: If we leave the
> Start passage untagged and tag every other passage with the autosave
> tage, we are able to access the old save from the newly begun story's
> Start.

You could do that, but there's a much better and easier way. Use the
config.saves.isAllowed property, which is checked by all saves, even
the autosave.

Set config.saves.isAllowed to something like this:

config.saves.isAllowed = function () {
if (tale.get(state.active.title).tags.indexOf("nosave") === -1) {
return false;
}
return true;
};

And then tag any passage (e.g. Start) where you don't want saving to
be allowed with "nosave". For normal saves, in addition to the save
being disallowed, the user will get a message about it. For the auto-
save, the save will simply be disallowed, no message will be given.


> Second issue: Unfortunately, I can't *quite* seem to get an autoload
> macro working. ...
>
> SaveSystem.loadAuto;

That bit right there. You're referencing the function definition,
not calling the function. Try this instead:

SaveSystem.loadAuto();

Tangentially, I wouldn't use the non-strict equality operators unless
you actually need to (there are a few instances that require them).
So, instead of this:

if (retVal == true) {

I'd suggest:

if (retVal === true) {


> Also, would it make sense to always exempt the Start passage from
> autosaving?

For most stories/games, where the Start passage is used as landing
passage/opening screen of sorts, yes. In that case, I'm honestly
not sure what anyone would gain from saving there.

However, it's not inconceivable for a story to use the Start passage
as a real, functional part of the story/game and to allowing passing
through it multiple times. Disallowing saves there by default would
be bad.

So, I'm inclined to leave things as they are. This issue only affects
the all-saves-all-the-time setting of config.saves.autosave and, as
noted, config.saves.isAllowed can be used to alleviate any problems
with that.

I probably should point out that pitfall in the docs, however.

--
Thomas Michael EDWARDS
Email: tmed...@motoslave.net Website: http://www.motoslave.net/thom/
"That a word like unnatural exists at all indicates a serious deficiency
in common sense...." -- Anna Puma, Dominion: Conflict 1 (No More Noise)

Erik Temple

unread,
Nov 28, 2013, 11:54:38 PM11/28/13
to twee...@googlegroups.com, tmed...@motoslave.net


On Thursday, November 28, 2013 10:02:31 PM UTC-6, Thomas Michael EDWARDS wrote:

> If we leave the
> Start passage untagged and tag every other passage with the autosave
> tage, we are able to access the old save from the newly begun story's
> Start.

You could do that, but there's a much better and easier way.  Use the
config.saves.isAllowed property, which is checked by all saves, even
the autosave.

Very nice, thanks for the tip!
 
> Second issue: Unfortunately, I can't *quite* seem to get an autoload
> macro working. ...
>
> SaveSystem.loadAuto;

That bit right there.  You're referencing the function definition,
not calling the function.  Try this instead:

SaveSystem.loadAuto();

I actually tried it both as a reference and a call--the reference form was the one I happened to paste in, but neither seems to have any effect :( Clicking the load button from the saves menu does work, of course, so I'm puzzled, since all clicking that button does is call the same function ($(tdLoadBtn).click(SaveSystem.loadAuto)). 



> Also, would it make sense to always exempt the Start passage from
> autosaving?

However, it's not inconceivable for a story to use the Start passage
as a real, functional part of the story/game and to allowing passing
through it multiple times.  Disallowing saves there by default would
be bad.

So, I'm inclined to leave things as they are.  This issue only affects
the all-saves-all-the-time setting of config.saves.autosave and, as
noted, config.saves.isAllowed can be used to alleviate any problems
with that.

I hadn't thought of that use-case, so I agree: if someone wants to do what I'm trying to do, they can use the config.save.isAllowed. Hopefully lots of folks will! It's almost 2014 and I think that players should not need to worry about keeping track of saved games unless they really want to! 

Thomas Michael EDWARDS

unread,
Nov 29, 2013, 12:29:31 AM11/29/13
to twee...@googlegroups.com

--- Erik Temple on 11/28/2013 10:54 PM, wrote:

> I actually tried it both as a reference and a call--the reference
> form was the one I happened to paste in, but neither seems to have
> any effect :(

That particular bit of reply was fairly off-the-cuff, so I may have
overlooked something important. I'll take a better look at it on the
morrow. Wait, I know, you're trying to load in the middle of an
actively rendering passage, which won't work.

Assuming you want this for the Start page, it might be better to show
a highlighted message ("Autosave available, load now?") which provides
a link or button that initiates the load of the autosave, or maybe just
directs them to the Saves menu.

Erik Temple

unread,
Dec 1, 2013, 5:06:27 PM12/1/13
to twee...@googlegroups.com, tmed...@motoslave.net
On Thursday, November 28, 2013 11:29:31 PM UTC-6, Thomas Michael EDWARDS wrote:
Wait, I know, you're trying to load in the middle of an
actively rendering passage, which won't work.

Assuming you want this for the Start page, it might be better to show
a highlighted message ("Autosave available, load now?") which provides
a link or button that initiates the load of the autosave...
 
Cool, thanks. I take it this means that I should be able to do a jquery dialog box (rather than the standard javascript dialog I was testing with), which is what I had planned anyway. However, I'm testing this out in the simplest form and am running into a different problem. Given the following code, the jquery seems to fail to attach any event to the input elements:

:: Start [nosave]
You have a session already in progress. Would you like to continue where you left off?
<button class='ui-autostart-button' id='resume-button'>Resume where I left off</button>
<button class='ui-autostart-button' id='restart-button'>Start over</
button>

<<if (storage.getItem("saves") === null || storage.getItem("saves").autosave === null)>>
 
<<display "Begin">>
<<else>>
   
<<script>>
        $
("#resume-button").click(function() {console.log('Resuming...')});
        $
("#restart-button").click(function() {console.log('Restarting...')});
   
<</script>>
<</
if>>

 I wonder if this could somehow be related to the apparent bug affecting <<replace>>? That macro seems to work only when the <<replace>> instruction is wrapped in a <<click>>, but not on its own or in, say, an <<if>> (it gives the message Error: <<replace>>: no elements matched the selector "#test").


Thomas Michael EDWARDS

unread,
Dec 1, 2013, 11:55:45 PM12/1/13
to twee...@googlegroups.com

--- Erik Temple on 12/1/2013 4:06 PM, wrote:

> Cool, thanks. I take it this means that I should be able to do a
> jquery dialog box (rather than the standard javascript dialog I was
> testing with), which is what I had planned anyway. However, I'm
> testing this out in the simplest form and am running into a different
> problem. Given the following code, the jquery seems to fail to attach
> any event to the input elements:
> [..snip..]

That's because you're trying to attach an event handler to elements
which don't exist in the DOM yet, because the passage isn't finished
rendering.

You'll either need to:
A. With something similar to your current code, defer the attempt
to attach the event handlers until after Start has rendered, by
using the PassageDone special passage.
B. Create the buttons programmatically, which will allow you to
attach the event handlers at the same time.

Option A might look something like this:
----
:: Start [nosave]
<<if
SaveSystem.autosaveOK
&& storage.getItem("saves").autosave !== null
>>
You have a session already in progress. Continue where you left off?
<button id="resume-button" class="ui-autostart-button">
Resume where I left off
</button>
<button id="restart-button" class="ui-autostart-button">
Start over
</button>
<<else>>
<<display "Begin">>
<</if>>

:: PassageDone
<<if state.active.title === "Start">>
<<script>>
$("#resume-button").click(function() {
console.log("Resuming...");
});
$("#restart-button").click(function() {
console.log("Restarting...");
});
<</script>>
<</if>>
----

Option B might look something like this:
----
:: Start [nosave]
<<if
SaveSystem.autosaveOK
&& storage.getItem("saves").autosave !== null
>>
You have a session already in progress. Continue where you left off?
<<script>>
var resumeBtn = insertElement(
output,
"button",
"resume-button",
"ui-autostart-button",
"Resume where I left off"
);
var restartBtn = insertElement(
output,
"button",
"restart-button",
"ui-autostart-button",
"Start over"
);
$(resumeBtn).click(function() {
console.log('Resuming...');
});
$(restartBtn).click(function() {
console.log('Restarting...');
});
<</script>>
<<else>>
<<display "Begin">>
<</if>>
----


> I wonder if this could somehow be related to the apparent bug
> affecting <<replace>>?

No bug, same issue. With how you're trying to do it, <<replace>>
works in <<click>> because the contents of the <<click>> aren't live
(i.e. they're deferred) until you click on its link, which is after
the passage has rendered and the elements exist in the DOM.

Erik Temple

unread,
Dec 2, 2013, 10:15:23 AM12/2/13
to twee...@googlegroups.com, tmed...@motoslave.net
I wasn't aware of PassageDone, thanks for that! And I see where I was going wrong when I was trying to insert the buttons programmatically (e.g., similar to your second example): I didn't know about the "output" target.

One thing regarding SugarCube's documentation of <<replace>> and similar macros: The explanation of this macro seems to imply pretty strongly that it will work in all cases, because the main limiting factor mentioned is that it is "probably most useful when paired with some method of control (e.g. <<click>> or <<if>>)." It might be useful to link from these to a section explaining the issues involved with creating and acting on DOM elements from within the same passage, and a discussion of PassageDone and, since it is unique to SugarCube, why one might need to use it.

Thanks as always for the help!

Thomas Michael EDWARDS

unread,
Dec 2, 2013, 8:24:33 PM12/2/13
to twee...@googlegroups.com

--- Erik Temple on 12/2/2013 9:15 AM, wrote:

> I wasn't aware of PassageDone, thanks for that!

PassageDone is in the documentation, listed within Reserved & Special
Names ( http://www.motoslave.net/sugarcube/docs/#reserved-names ),
under the Passage Names sub-heading.
Reply all
Reply to author
Forward
0 new messages