Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Remember and Rewind

Hmmm. Seems the rewind function undoes a remember macro.

Any way to get the remembering to be preserved? I'd been assuming rewind worked like a restart with fast forward... I'm trying to remember the various endings of the story that they had reached - but it they use rewind to resume play from an earlier bookmark it seems to be resetting the remembered variables as well.

Twine 1.4.2 and the default sugarcane.

Comments

  • I believe the point of the rewind option is to go backwards though the history of the players actions, undoing whatever they have done between where they are now and the historical bookmark they selected.
  • edited May 2015
    Yes, but it appears to undo remember actions as well, which I wasn't expecting it to. Rewind the current pool, but not the long term memory/meta data.

    Leaves me with a playability issue:

    Keep rewind and loose the tracking of which of the 10+ different endings you've reached.

    Keep the ending tracking and disable rewind, meaning you have to start over if you die (maybe 20+ decisions in). And I really dislike games that make me go through the same intro section over and over just to explore different options in the mid and end game.

    Thoughts?
  • edited May 2015
    Seems like the best feature to address the issue would be a save game option like in SugarCube. You can make it autosave at specific passages so you could autosave it directly before the major ending branch.

    Even having to "rewind" passage by passage to get to a conversation branch would end up annoying in a large game with 10+ endings.
  • Rewind works exactly like using the back button, it simply goes backward within the story history.

    The <<remember>> macro only stores the current value of the $variable passed into it to the remember store. The remembered $variable is still a normal story $variable in every way, meaning it still exists within the story history and rewinding to a particular point in said history will still yield whatever the value of the $variable was at that point. The only time remembered $variables are copied from the remember store is at story/game startup.

    An illustrative example:
    → Forward To → A
    /% Sets $bob to: Bob the Unlucky %/
    <<set $bob to "Bob the Unlucky">>
    /% Prints: Bob the Unlucky %/
    $bob
    
    → Forward To → B [bookmark]
    /% Prints: Bob the Unlucky %/
    $bob
    
    → Forward To → C
    /% Sets $bob to: Bob the Extremely Unfortunate %/
    <<set $bob to "Bob the Extremely Unfortunate">>
    /% Prints: Bob the Extremely Unfortunate %/
    $bob
    
    → Forward To → D
    /% Store the current value of $bob (Bob the Extremely Unfortunate) to the remember store %/
    <<remember $bob>>
    /% Prints: Bob the Extremely Unfortunate %/
    $bob
    
    ← Rewind To ← B
    /% Prints: Bob the Unlucky %/
    $bob
    /% However, the value of $bob in the remember store is: Bob the Extremely Unfortunate %/
    
    The <<remember>> macro is only really useful for remembering things between story/game sessions, not within the same session.

    Situations like this are why SugarCube's documentation for <<remember>> discourages its use:
    Note: Generally, you do not need, or want, to use <<remember>>, as it is only useful in very specific circumstances and problematic in most others. Unless you know that you need to use it, you very likely do not.

    If you need a variable which will absolutely not be affected by navigation of the story history, then don't use story $variables. That said, currently, your options for doing so are somewhat slim. For now, you could put the following in a script tagged passage (only for SugarCube v1):
    window.TwineStore = (function () {
    	var	_prefix  = "author.TwineStore.",
    		_fullKey = function (key) {
    			if (key == null || key === "") {
    				throw new Error("key parameter is missing or has a bad value: " + key);
    			}
    			return _prefix + key;
    		},
    		clear = function () { storage.removeMatchingItems(_prefix); },
    		has   = function (key) { return storage.hasItem(_fullKey(key)); },
    		get   = function (key) { return storage.getItem(_fullKey(key)); },
    		set   = function (key, value) { storage.setItem(_fullKey(key), value); },
    		del   = function (key) { if (has(key)) { storage.removeItem(_fullKey(key)); } };
    	return Object.freeze({ clear : clear, has : has, get : get, set : set, delete : del });
    }());
    
    Usage:
    /% Setting a value (using a boolean here, but values may be any value type or simple objects) %/
    <<run TwineStore.set("ending1", true)>>
    
    /% Checking a value %/
    <<if TwineStore.get("ending1")>>
    You've seen the first ending!
    <</if>>
    
  • @TheMadExile That looks like it might do it. Thanks.

    @Claretta Rewind works with bookmarks placed via passage tags. You don't bookmark very passage, just the ones before key decisions (the start of scenes or acts), so your stack of rewind points might only hold 8 or 9 passages (although it does seem to repeat them if you revisit a passage).
  • Well, perhaps not exactly what I needed, but with some work I was able to bludgeon it into:
    macros["metastore"] = {
    	version: { major: 1, minor: 0, revision: 0 },
    	handler: function (place, macroName, params) 
    	{
    		if (params.length < 3) {
    			var errors = [];
    			if (params.length < 1) { errors.push("get|put"); }
    			if (params.length < 2) { errors.push("key"); }
    			if (params.length < 3) { errors.push("value|varname"); }
    			return this.error("no " + errors.join(" or ") + " specified");
    		};
    
    		var action = params[0].trim();
    		var key = params[1].trim();
    		var value = params[2].trim();
    
    		var prefix = state.history[0].variables['metacache'];
    
    		if (key.charAt(0) == '$') {
    			key = key.slice(1);
    			key = state.history[0].variables[key];
    		}
    
    		if (value.charAt(0) == '$') {
    			value = value.slice(1);
    			value = state.history[0].variables[value];
    		}
    
    		if (action == 'get') {
    			var val = localStorage.getItem(prefix + key);
    			state.history[0].variables[value] = val;
    		};
    
    		if (action == 'put') {
    			localStorage.setItem(prefix + key, value);
    		};
    
    	}
    };
    

    You need to set a variable called metacache to a unique prefix for the game, and then you call it as:
    <<metastore 'put' 'key' value>>
    <<metastore 'get' 'key' 'varname'>>
    

    Should support variables for the key and value fields, so you can:
    <<set $ename to "ending_" + $ending>><<metastore 'put' $ename $score>>
    
  • Oh, fudge. Sorry about the SugarCube example code, I thought I read that, but now I see you said Sugarcane.
  • No worries, got it working - and now we got code for SugarCane as well ;-)
Sign In or Register to comment.