So I'm fiddling around with Twine for the first time, mocking up a simple RPG.
I have next to no experience with this kind of thing, so apologies if this is an obvious question, but is there some way to make an "array of arrays?"
Consider for example an party of 3 characters, each with health, mana and level. Past forum answers suggest to me that I ought to use an array for each (in this example, a 3-variable array, health, mana and level). With multiple arrays being created and destroyed through character creation and death, how do I manage this? My first inclination was to hard-code 10 or so character arrays, but that would require constant checks to see if each array is populated by a character or not. I've got one array working just fine, but I can't find guidance on going farther.
Basically, the question is this: how should I manage several sets of similar variables that apply to different characters, objects, etc? I hesitated to use the term "array of arrays," since it sounds wretched, but that's what comes to mind. Where an array is a list (one dimension), I'm looking for a grid (two dimensions).
Comments
I'm not really an expert on arrays and array-type things, but in some of my projects I've found the (datamap:) type to be pretty handy. It's a specialized array that you set up with pairs of string variables and their values, which can be either numbers or strings. You can access the sub-variables with commands like (set: $datamapA's propertyInQuestion to NewValue) or (print: $datamapB's yetAnotherProperty).
So, for instance, you can do something like this:
and it will produce output like this:
The downside of using a map that contains other maps is you'll have to re-insert each slot variable if you change a character value. So, say Hiro gets attacked by a monster. You can set his health down easily using the 's method, but in order to get $party to realize it, need to do something like
All that said, there are other options as well, especially if you try the Sugarcane format that has more javascript functionality. Maybe someone who knows more about it can help you there, or correct any mistakes I made above, since I'm still relatively new to the coding side of things myself.
Edit: had a dumb bug in my examples up there. You should set the initial values in a different passage than the one you're using for testing, because if you come back to the one that sets them to begin with, they'll just be reset... whoops.
I am. Beg pardon, should have included that.
I feel like I am right on the cusp of figuring this out. I'll use your example. Say I want to swap characters in and out of slots in the party lineup, e.g. swap character datamaps in and out of a party datamap. So we put Hiro in slot 1 of the party datamap, the leader slot.
If I read this code correctly, it's hardcoded that the monster's attack hits Hiro. How do we get the attack to hit the guy in slot 1, regardless of whether that's Hiro or not? How can we get a subtraction from "slot 1 guy's health," have the code recognize that "slot 1 guy" is Hiro, and assign the subtraction to his datamap?
Thank you for your help.
That's probably more convenient if you want to keep $party as your main container object. However, keep in mind that when it's set up like this, the individual $character arrays are separate from their representations in the $party one; in essence, the $party datamap contains copies of the original characters, not the originals. I'm not entirely sure if there is any way to tell the $party datamap to reference or contain the character maps themselves or a pointer to their contents or anything. It might be possible, but I'm not that well versed in this stuff.
If you prefer to keep the $party as the primary object you're going to interact with, you'll probably want to do something like this when/if someone changes their party slot:
This will copy $party's version of Heela into her base object ($Heela) for reference purposes and put the (currently undefined) contents of $Sparkie in the $party's Support slot.
(you can also use (put:) instead of (set:) - it's essentially the reverse process, which translates into words easier. (put: $party's Support into $Heela) is putting the contents of the support slot into Heela's reference variable. (put: $Sparkie into $party's Support) does basically what it says on the tin. Saying (set: $x to 2) is readily understandable enough, but copying variable contents around can get tricky to remember.)
Of course, since Sparkie is a dog who can't heal at all, you can just invert it like so:
You can also extend this as far as you want, as far as I know, though it does get sort of cumbersome eventually.
(This also illustrates the need to remember if you're referencing the $party copy (aka $party's Leader) or the reference $Hiro. I've made a lot of those mistakes in the past. You'll note that the first link, which is the way I would usually intuitively write the code, doesn't work for the copy of Hiro currently in the party, and might actually make unwanted changes to his reference variable.)
I'll try to come at this from another example. Let's say we're back at camp sitting around the campfire that all RPG heroes apparently have to sit around. The player character can talk to each character, interact with them, swap equipment etc.
So for example, let's say there's a series of "talk to" passages that call a character's morality and attitude variables. Naturally, that code should exist once rather than individually for each character. Therefore, it has to somehow call the variables of the character being talked to. Going by your patient explanation, I have gotten to taking a character's variables from his datamap and putting them into a "character currently being interacted with" datamap. What I cannot figure out how to do is denote which character this is, so that the code can put the data back in the right datamap when the conversation is complete.
In terms of your original example, I get mapping Hiro's data and I get using a party map. What I do not get is how to tell the code that it's Hiro in slot 1 when the player tells the game to bench Hiro, thus taking him out of the party. There's data in slot 1; it needs to go back into Hiro's datamap; how does one specify that?
Put another way, how do I use datamaps to write code that can change variables in any of a set of datamaps, depending on which datamap the player specifies?
Thanks again.
(Describing this with my level of competence is like trying to explain what Spanish word you'd like to know, while being mute. Sorry.)
Here's the function I want. Where $char1 is the datamap of the character in slot 1, Hiro; and $Hiro is the datamap of his stats elsewhere:
(link: Send $leader's name back to camp.)[(put: $leader into [WHICHEVER DATAMAP's 1st = HIRO])(goto: "datatest")]
The [ALLCAPS] bit is what I'm missing. Search a set of datamaps for the one whose 1st variable matches the datamap in $leader, copy $leader datamap over that datamap.
Array's use index positions (numbers): Datamap's use keys (names):
This is why I'm trying to use datamaps, because for something like a character with 10+ variables its much easier to call $map's age than it is to call $array's 12th.
Another way to come at this: is there a way to call a datamap based on that datamap's name, or in other words, to call not $map's age but $x's age, where x is a string defined as "map"?
Only if I can get data back into a datamap this way, as well as getting it out.
Is there some way to (set:) variables in $bob based on something in $people so that if $sally were also present, we could (set:) the health of whichever of $bob or $sally were in $people? That's what I'm after.
Personally I don't think Twine is the right tool for creating a RPG, especially one featuring a complex object based npc sub-system.
But if I had to do something like that then I would use SugarCube instead of Harlowe purely because it allows Author to add custom features to the story format and allows direct access of $variable system from Jacascript code.
...the idea being that if $talkTarget's name key returns 'Hiro', it evaluates to $ + Hiro, concatenates it together and copies $talkTarget over $Hiro
...but that doesn't seem to work. It might just be that I can't figure out the syntax, or that you can't get the system to recognize a variable by concatenating a $ to it, or that this is just not possible in Harlowe (or perhaps Twine in general).
You could try using a bunch of conditionals to determine whether a given character is present, but basically if you really want to do complex variable structures, you might be better off trying SugarCube or maybe a more robust engine that will let you use a full object-based code language.
If you do decide to try SugarCube, this thread might be helpful: http://twinery.org/forum/discussion/3079/retrieving-values-from-javascript-objects-sugarcube