0 votes
by (680 points)

Hello everyone,

Rundown: I'm making a twine rpg and a core feature of my the game is being able to transfer gold and items between characters.  I implemented a simple custom saving system that autosaves into a specific save slot using the following code (the save slot is chosen by the player at the start of the game): 

<<if $saveslot is 1>>
	<<remember $S1_playername to $playername>>
	<<remember $S1_playerLVL to $playerLVL>>
	<<remember $S1_playerclass to $playerclass>>
	<<remember $S1_player_race to $player_race>> 
	<<script>>Save.slots.delete(0); Save.slots.save(0)<</script>>
<</if>>

 

I then implemented a common "stash" that enables the player to transfer gold between saved characters using a simple <<remember>> macro, and forcefully saving the game immediately after executing a gold transfer (to prevent unlimited gold duping).  

<<remember $stash_gold to $stash_gold + $deposit_gold>> // $deposit_gold is a value inputted by the player//
<<set $gold to $gold - $deposit_gold>>
<<autosave>> // This runs the above macro //

The following code works beautifully.  I was able to both deposit and withdraw gold using the common variable $stash_gold.

Now my primary problem is making the same thing happen with an array of objects.  Simply put, my RPG has a lot of equipment: Swords, Shields, Armor, etc... and each is an object with its own properties. All these items are stored in an $equipment array.  When I try to replicate the stash_gold method above, i.e. using the following code:

<<set _temporary to $equipment.pluck(0,0)>>
<<remember $stash_equipment.push(_temporary)>>

I successfully transfer said Object into the $stash_equipment array.  Upon restarting my browser and using the "Debug" feature to view the variable library, I still see the object and all its properties in the $stash_equipment array.  HOWEVER, when I load another saved character, the array simply VANISHES.  

I checked my entire game's code thoroughly and I did not find any code snippet which modifies the $stash_equipment array in any way except the following code at the top of the "Stash" passage:

<<if ndef $stash_equipment>><<set $stash_equipment to []>><</if>>

Sorry for being long winded and very newbie-ish, but I've been wrecking my brain trying to figure out a solution to this problem.  Am I doing it the wrong way?  Can the <<remember>> macro remember Objects within arrays? 

Edit: Here's a snippet of my "Load Game" code:

<<click "Load Slot 1">>
    <<stopallaudio>>
    <<script>>Save.slots.load(0)<</script>>
<</click>>\
\
<<if $saveslot1 is 1>>   | <<print $S1_playername>>, Level <<print $S1_playerLVL>> <<print $S1_player_race>> <<print $S1_playerclass>>, <<print $S1_difficulty>> <<print $S1_gamemode>> |   <<link "Delete">><<script>>Save.slots.delete(0)<</script>><<remember $saveslot1 to 0>><<goto "Load Game">><</link>><<else>>   | Empty |<</if>>

 

1 Answer

+1 vote
by (68.6k points)
selected by
 
Best answer

Questions:

  • When do you run the code to store items in the equipment stash?
  • Have you written code to remove items from the equipment stash yet?

Also, a couple of other things—though they likely have nothing to do with your primary issue.

1. You don't need the slot metadata variables.  Since you're manually saving, you may specify both a title and metadata for the save, which you may access later.  For example, to store the metadata as-is:

<<if $saveslot is 1>>
	<<script>>
	var sv = State.variables;
	Save.slots.save(0, null, {
		'name'  : sv.playername,
		'level' : sv.playerLVL,
		'class' : sv.playerclass,
		'race'  : sv.player_race
	});
	<</script>>
<</if>>

And to reference it later:

<<if Save.slots.has(0)>><<set _metadata to Save.slots.get(0).metadata>>   | _metadata.name, Level _metadata.level _metadata.race _metadata.class, <<print $S1_difficulty>> <<print $S1_gamemode>> |   <<link "Delete">><<script>>Save.slots.delete(0)<</script>><<goto "Load Game">><</link>>\
<<else>>   | Empty |<</if>>

I didn't modify the difficulty and game mode variables, since your example didn't show them as part of your save code.

 

2. The lower and upper bounds parameters of <Array>.pluck() are deprecated.  I'd suggest using <Array>.deleteAt() instead.  For example:

<<set _temporary to $equipment.deleteAt(0)>>
<<remember $stash_equipment to $stash_equipment.concat(_temporary)>>

/*
	You really don't need the temporary variable here,
	so the following also works.
*/
<<remember $stash_equipment to $stash_equipment.concat($equipment.deleteAt(0))>>

 

by (680 points)
edited by

Sorry for the late reply, TME.  Was busy with work.  Noted on using the .deleteAt().  Will use that instead. 

  • When do you run the code to store items in the equipment stash?

When I click on an arrow in a passage called "The Stash".  It has some complicated code so i'll just explain with a picture.  I used some basic "onclick" javascript to determine which object they want to transfer (it sets the $equipmentslot variable to a specific number representing the object's position in the array, then clicking on the arrow runs the following code (note that I will modify it later according to your recommendation with the deleteAt() instead): 

<<if $transfer_target is "Bag">>
  <<set _temporary to $equipment.pluck($equipmentslot,$equipmentslot)>>
  <<remember $stash_equipment.push(_temporary)>>
  <<autosave>>
  <<goto "The Stash">>
<<else>>
  <<set _temporary to $equipment.pluck($equipmentslot,$equipmentslot)>>
  <<remember $stash_equipment.push(_temporary)>>
  <<autosave>>
  <<goto "The Stash">>
<</if>>
  • Have you written code to remove items from the equipment stash yet?

I basically use the .pluck method to remove the selected object from the desired array as shown in the code above.

 

I'm just trying to figure out WHY the $equipment_stash array just doesn't seem to <<remember>> its properties after loading a game.  The objects persist on browser resets and restarts, but it does not persist when i manually "load" another character.  

Edit: Okay... i figured out that loading a Saved Game also loads the current state of the variables at the time of the save (Well, duh...) and thus overwrites the $stash_equipment variable even though it was "remembered".   Is there a better approach to trying to get variables and arrays to persist through saves?  Like perhaps storing a variable's data in an external place and then loading it upon Loading a game?

by (68.6k points)
edited by

Since you were attempting to use <<remember>> (generally a bad idea), I'm assuming you want the stashes to be persistent (i.e. closing the browser shouldn't cause the data to be lost).  Warning: Browsing modes like Private/Incognito always cause session data to be discarded at the end of a session!

For the purposes of multiple characters in separate playthroughs (in the same browser), you could store your various stashes using SugarCube's (undocumented) storage subsystem.  It's undocumented mostly because it's possible to clobber SugarCube's own data, which would be bad for your game.  That said, as long as you keep your stashes named things like stash_equipment and stash_gold you should be safe.

Move equipment to stash example:

<<script>>
// Get the existing stash or initialize it to an empty array.
var stash = storage.get('stash_equipment') || [];

// Cache the story variables store.
var sv = State.variables;

// Remove the equipment at the selected index from its array and
// append it to the stash array.
stash.concat(sv.equipment.deleteAt(sv.equipmentslot));

// Set the stash.
storage.set('stash_equipment', stash);
<</script>>
<<autosave>>

Move gold to stash example:

<<script>>
// Get the existing stash or initialize it to 0.
var stash = storage.get('stash_gold') || 0;

// Cache the story variables store.
var sv = State.variables;

// Remove the gold and add it to the stash.
stash += sv.deposit_gold;
sv.gold -= sv.deposit_gold;

// Set the stash.
storage.set('stash_gold', stash);
<</script>>
<<autosave>>

 

...