[CONCEPT] Saving states of multiple questlines in teaseStorage

All about the past, current and future webteases and the art of webteasing in general.
---
Post Reply
Thamrill
Explorer At Heart
Explorer At Heart
Posts: 265
Joined: Thu Jan 03, 2013 4:55 pm
Gender: Male
Sexual Orientation: Straight
I am a: Submissive

Re: [CONCEPT] Saving states of multiple questlines in teaseStorage

Post by Thamrill »

Quality_Control wrote: Wed Oct 26, 2022 5:38 pm I'm currently thinking about an EOS project featuring multiple questlines. I plan to keep track of all of them with a single variable in teaseStorage to minimize the used space. Before I dive into it, I was wondering however, if anyone can confirm (or deny) that this actually works. I'll try to outline my ideas to some extend in pseudo-code. If anyone has the correct code at hand, I'll gladly take it :)

My idea is to have one variable per questline in the "working memory" that tracks it's state with a single letter. If a questline is not started, it's variable would have the value "z". All of the questline-variables would be set as "z" in the ini script.

If the tease is saved, I want to condense all questline-variables into one string, ordered by the number of their questline. So for example:

Code: Select all

questline1 = "b"
questline2 = "k"
questline3 = "z"
questline4 = "g"
teaseStorage.setItem("qstate", questline1 + questline2 + questline3 + questline4)
This would yield a saved variable "qstate" in teaseStorage:

Code: Select all

qstate == "bkzg" is true
I intend progress not saved to be lost (e.g. if a player fails to reach a checkpoint).

If the tease is loaded, I want to re-establish it's state be deciphering qstate:

Code: Select all

qstate = teaseStorage.getItem("qstate")
questline1 = qstate[1]
questline2 = qstate[2]
questline3 = qstate[3]
This would yield the initial variables with values "b", "k", "z", and "g" back in the "working memory".

If anyone can comment on whether this works or not or even give advice on how to turn my pseudo-code into actual code (as said above, I'm still in the concept-phase), I would appreciate the input.
Yes, that works (or should work, according to JS)
Image

Image

Image
kerkersklave
Explorer At Heart
Explorer At Heart
Posts: 559
Joined: Sun Jul 06, 2014 2:11 pm
Gender: Male
Sexual Orientation: Open to new ideas!
I am a: Slave

Re: [CONCEPT] Saving states of multiple questlines in teaseStorage

Post by kerkersklave »

Should work as a concept.

You could use an array of letters for the questlines instead of numbered variables so it would look something like this:

Code: Select all

var questlines = ["a", "b", "c"];
You can access single elements by questlines[0] to questline[2] and also assign values by questline[1] = "x".

You can turn the array into a string and store it:

Code: Select all

teaseStorage.setItem("qstate", questlines.join(""))
and read it:

Code: Select all

questlines = teaseStorage.getItem("qstate").split("")
fapnip
Explorer At Heart
Explorer At Heart
Posts: 430
Joined: Mon Apr 06, 2020 1:54 pm

Re: [CONCEPT] Saving states of multiple questlines in teaseStorage

Post by fapnip »

This is the kind of thing SaveState, and to some extent BitN, were written for.

With SaveState, as long as you instantiate your SaveState object(s) right, you can just use variables how you would normally, it will deal with compressing/encoding/saving/restoring them. You can also add a static dictionary to help with compression if needed.
fapnip
Explorer At Heart
Explorer At Heart
Posts: 430
Joined: Mon Apr 06, 2020 1:54 pm

Re: [CONCEPT] Saving states of multiple questlines in teaseStorage

Post by fapnip »

Without understanding more about what your "questline" variables are doing, when, where, why, how many, etc., I can't offer a great amount of specific advice.

If your "questlines" are simply a bunch of state variables crunched together, don't. SaveState does that for you. Just use discrete variables, use arrays, or, if you have a ton of Boolean values, use BitN.

If you have an existing tease showing use of these values, it would help me understand more what you're after. If there's not really an existing tease yet, think about using arrays for storing your values, and then abstracting getting/setting them with functions:

Code: Select all

// In init script
// Create a SaveState to track our variables
var gameState = new window.SaveState({
  store: window, // Our state will be stored in the global (window) object
  autoLoad: true, // We'll auto-load the variables below as state variables
  // Alternativly, state variables can be defined here via:
  // state: {varName: varValue, ..., ...}
})

// Define global game state variables that need to be saved, and only game state vars, here
//  Don't prefix with "var", else they will be ignored by the SaveState variable auto loader 
//  Don't set/use/define any of the variables below before their initialization  here
// *** WARNING:  Removing/renaming/inserting/re-ordering these variables will invalidate any current saved game state!
//               (you can _append_ new ones)
questlines = Array.apply(null, Array(4)).map(String.prototype.valueOf,"b") // Init array of 4 with default value of "b"
// ...  surely there will be more state variables here ...

// ^^ You CAN append new variables just above here without invalidating previous save states!

// *** No more game state vars that need to be saved by gameState.save() and restored by gameState.load() after here ***
gameState.loadStates() // Record all the variables from above as part of our save state

// support functions
function setQL(i,v) {
  questlines[i] = v
  // We could do a gameState.save() here, if you always wanted to save it on every change
}
function getQL(i) {
  return questlines[i]
}

// Elsewhere, use via:
setQL(0, 'k') // set questline 1 (0) to 'k', whatever that means.
setQL(1, 'z') // set questline 2 (1) to 'z', whatever that means.


if (getQL(0) === 'k') {
 // do something
}

// Then you can save/restore questlines using gameState.save() and gameState.hasSave() && gameState.load()

If you have an existing tease and are already using variables like "questline1", "questline2", etc., then:

Code: Select all

// In init script
// Create a SaveState to track our variables
var gameState = new window.SaveState({
  store: window, // Our state will be stored in the global (window) object
  autoLoad: true, // We'll auto-load the variables below as state variables
  // Alternativly, state variables can be defined here via:
  // state: {varName: varValue, ..., ...}
})

// Define global game state variables that need to be saved, and only game state vars, here
//  Don't prefix with "var", else they will be ignored by the SaveState variable auto loader 
//  Don't set/use/define any of the variables below before their initialization  here
// *** WARNING:  Removing/renaming/inserting/re-ordering these variables will invalidate any current saved game state!
//               (you can _append_ new ones)
questline1 = "b"
questline2 = "k"
questline3 = "z"
questline4 = "g"
// ...  surely there will be more state variables here ...

// ^^ You CAN append new variables just above here without invalidating previous save states!

// *** No more game state vars that need to be saved by gameState.save() and restored by gameState.load() after here ***
gameState.loadStates() // Record all the variables from above as part of our save state

// Then you can save/restore questline1-4 using gameState.save() and gameState.hasSave() && gameState.load()

If by "questline" you're alluding to multiple save slots, (doesn't look like this is what you're after, but just in case) you can have multiple save states storing/loading from the same global variables, if you wanted to save/restore different positions, like:

Code: Select all


// Define object for global variables we're saving/loading
var myStateVars = {
  myTeaseVariable1: 'Default value for this variable',
  anotherTeaseVariable: 2.3,  // another default value
  andAnotherTeaseVar: true, // and another default value for it
  // and so on
}

// Helper function we'll use to shallow copy objects
function mergeObjects() {
    var resObj = {}
    for(var i=0; i < arguments.length; i += 1) {
         var obj = arguments[i], keys = Object.keys(obj)
         for(var j=0; j < keys.length; j += 1) {
             resObj[keys[j]] = obj[keys[j]]
         }
    }
    return resObj
}

// Instantiate save state #1
var myGameState1 = new SaveState({
  stateKey: "1", // Store under the key "1"
  store: window, // Save/load values to/from the global object 
  state: mergeObjects({}, myStateVars), // We'll store/load the same state vars, so dupe myStateVars
})

// Instantiate save state #2
var myGameState2 = new SaveState({
  stateKey: "2", // Store under the key "1"
  store: window, // Save/load values to/from the global object 
  state: mergeObjects({}, myStateVars), // We'll store/load the same state vars, so dupe myStateVars
})

// and so on for 3, 4, etc.

//Now you can save/restore all your state variables to different states separately.

myGameState1.save()  // save values in myTeaseVariable1, etc., vars to tease storage under key "1"
// and
myGameState1.load() // restore values to myTeaseVariable1, etc., vars from tease storage's key "1"
// and/or
myGameState2.save()  // save values in myTeaseVariable1, etc., vars to tease storage under key "2"
// and
myGameState2.load() // restore values to myTeaseVariable1, etc., vars from tease storage's key "2"

// you can also load for inspection into different objects, like:
var myTestState = myGameState1.load({})
if (myTestState.myTeaseVariable1 === 'something') {
  // do something
}
Anyway, if you explain in more detail about what your end goal is, I may be able to offer better advice on how to get there.

How many variables you can store this way depends on the value size of the variables, how compressible the values are, and, if your values are larger strings with groups of 3 or more characters that are predictable, how you define your static dictionary. We get a total of 1024 bytes, including all key names and characters for encoding. If using my first example above, storing in an array, or second example, storing discretely, you'd probably be able to store around 400+ different single character "questlines".
fapnip
Explorer At Heart
Explorer At Heart
Posts: 430
Joined: Mon Apr 06, 2020 1:54 pm

Re: [CONCEPT] Saving states of multiple questlines in teaseStorage

Post by fapnip »

Quality_Control wrote: Fri Oct 28, 2022 7:13 am To put this idea into variables I plan on having four sets of them, that keep track of different things:
1. few general variables that track time, points, etc.
Using my first or second example above, place the default definitions of these in the save state area, between "// Define global game state variables that need to be saved" and "// ^^ You CAN append new variables just above here". Don't prefix these with "var", make sure this is the first place these global variables are set.
Quality_Control wrote: Fri Oct 28, 2022 7:13 am 2. a set of maybe 20 string-variables, each of which tracks the progress of exactly one questlines. If a questline has not been started, they have the value "z", if the first stage of the questline is reached, they have the value "a", if the second stage is reached, they have the value "b", and so on. Alternatively, if space allows, the values good also be more semantic, like "not started", "got thing", "delivered thing", etc.
Here you could use the first or second example, storing them in an array, or in discrete variables. Best to keep the values short, single characters. I'd use null for not yet started instead of 'z', since SaveState will encode null, false and true down to 1 character, but whatever floats your boat.
Quality_Control wrote: Fri Oct 28, 2022 7:13 am 3. a set of maybe 100 boolean-variables, each of which tracks whether one specific encounter has been done.
Here I'd probably store these booleans in a BitN bit map, referencing them from 0 to n, again defining the default bit map in the SaveState area with the other variables above:

Code: Select all

encounterMap = BitN.empty(99) // Create empty encounter map with 100 (0 to 99) bits
Then later use via:

Code: Select all

// Set an encounter bit
encounterMap = BitN.put(encounterMap, 9, true) // Set bit 9 (encounter 10) to true

// Test an encounter bit
if (BitN.test(encounterMap, 9)){
  // Encounter 10 (bit 9) is true... do something
}
This single encounter bit map of 100 bits will take up around 17 bytes plus a couple more for encoding vs over 100 bytes if you did it via a list of discrete variables or an array of Booleans.

Almost always best to abstract setting/getting common things like that through a function, so if you do add an encounter bitmap, I'd also add functions for setting/testing them like:

Code: Select all

// function to set an encounter bit
function setEnc(n, v) {
	encounterMap = BitN.put(encounterMap, n, v)
}

// function to get encounter bit
function getEnc(n) {
	return BitN.test(encounterMap, n)
}

Quality_Control wrote: Fri Oct 28, 2022 7:13 am 4. an indefinite set of "working-variables" such as whether someone knocked before entering a room, or the number of edges in an encounter. this set does not need to be saved and is reset in the init scrip.
These you would want to define outside of the SaveState area, and/or prefix the variable definitions with "var ", keeping them out of the SaveState instance.
Quality_Control wrote: Fri Oct 28, 2022 7:13 am I would like SaveState to save the sets 1, 2 and 3 only on checkpoints but never set 4. I would not like to use the auto-load feature for that but to explicitly define within the myGameState variable which variables to keep track of.
At whatever checkpoints, just do a gameState.save() (replacing gameState with whatever you called your SaveState instance.)

To restore a save, do an IF: gameState.hasSave() action to go to a restore selection page. If they choose yes, you can do a gameState.load() to restore variables to what they were at last save, then go to the appropriate page to continue. If they choose no, do a gameState.clear() and gameState.clearLoad(), then return to an appropriate page to start a new game.
Post Reply

Who is online

Users browsing this forum: No registered users and 20 guests