Hello everyone !
I've started playing around with Twine 2.0 / Harlowe this week to create what is essentially an RPG with a focus on social interactions with NPCs.
I'm stumbling on an issue that I haven't found answered elsewhere (maybe I missed it), regarding the creation of variables with computed names. I'm sure it's just a syntax that I haven't yet found, but it may be simply something one can't do with Harlowe, which I'd found rather odd, but, well
Context
My NPC roaster (
$npcroaster) is an array of datamaps, each datamap being a single NPC.
Each NPC has a "currentloc" key with a string value (like "tavern", "house", etc.).
When the player's character is in a location, I test that location (
$charloc) against the "currentloc" value of every NPC to find out who the NPCs present in that same location are.
The player can talk to anyone in his current location: for that, I'm setting-up an interface element allowing the selection of what NPC(s) he wants to be addressing. He can talk to one NPC, or several NPCs at the same time (if there are enough in that location of course), by toggling "on and off" their names in a list that is rendered when the player clicks on the option "I want to have a chat" :

The list of present NPCs is displayed for the player to choose from.

By clicking on a name, the player selects it as shown above.

Once submitted, the game shows the NPCs in the conversation and offers the option to select them again.
Actual code
I've written the logic and systems for retrieving the present NPCs correctly (then store their names in an separate array called
$presentnpcs):
(if: $npcroaster.length > 0)[
(if: $loopcount > 0)[
(if: $npcroaster's $loopcount's currentloc is $loctest)[
(set: $presentnpcs to it + (array: $npcroaster's $loopcount's name))]
(set: $loopcount to it -1)
(display: "Determine present NPCs")]
(else:)[
(print: $presentnpcs)
(display: "Talk to menu")]
]
(else:)[
There are no NPCs in this world!]
... and the mechanic of the selection menu, which uses two passages. One is for displaying the menu:
(set: $cycle1 to 0)(set: $cycle2 to 0)(set: $cycle3 to 0)
|ui>[
Select who you want to talk with and click OK:
||name1>[Anton]| |name2>[Gert]| |name3>[Julie]| ]
|ok>[(text: "[")OK(text: "]")]
(click-replace: ?name1)[(set: $click to 1)(display: "logic")]
(click-replace: ?name2)[(set: $click to 2)(display: "logic")]
(click-replace: ?name3)[(set: $click to 3)(display: "logic")]
(click-replace: ?ok)[
(replace: ?ui)[]You are now talking to:
|(if: $cycle1 is 1)[Anton|](if: $cycle2 is 1)[Gert|](if: $cycle3 is 1)[Julie|](if: $cycle1 is 0 and $cycle2 is 0 and $cycle3 is 0)[no one|]
(hook: "talk")[
(click to reselect)]
]
(click: ?talk)[
(replace: ?ok)[]
(replace: ?ui)[(display: "Talk to menu")]
]
... and one for its toggling logic:
(if: $click is 1)[
(set: $cycle1 to (it +1) % 2)
(if: $cycle1 is 0)[Anton]
(else-if: $cycle1 is 1)[(text: "*")Anton(text: "*")]
(click-replace: ?name1)[
(set: $click to 1)(display: "logic")]]
(else-if: $click is 2)[
(set: $cycle2 to (it +1) % 2)
(if: $cycle2 is 0)[Gert]
(else-if: $cycle2 is 1)[(text: "*")Gert(text: "*")]
(click-replace: ?name2)[
(set: $click to 2)(display: "logic")]]
(else-if: $click is 3)[
(set: $cycle3 to (it +1) % 2)
(if: $cycle3 is 0)[Julie]
(else-if: $cycle3 is 1)[(text: "*")Julie(text: "*")]
(click-replace: ?name3)[
(set: $click to 3)(display: "logic")]]
The tricky part for me comes from the fact that the number of NPCs in a location at any given time can be different, of course.
As you can see from above, the mechanic of the selection menu uses (click-replace:) macros that need a different hook for each name (
?name1,
?name2, etc for ex.), as well as a different variable for storing identifying the clicks (
$click1,
click2, etc.).
The above code works very well in my "test" write-up of the menu logic and mechanic, where I have fixed the number of NPCs to 3 for testing purposes, and fixed variables'/hooks' names. However, for this to work in the context of an unknown number of NPCs in a location, I need to write-up a new loop in which each ?name# and $click# will be incremented for each loop iteration, the number of iterations depending on the number of NPCs present (in other words,
$presentnpcs.length).
Doing this with hooks is easy enough, but I haven't been able to find how to do it for the creation of new variables based on others - essentially, the system correctly constructs $click1, $click2 etc. but I can't seem to find a way to escape the fact that the result of this construction is considered a string and that, evidently, gives the error:
I can't put a new value into the string "$cycle1".
I've tried a whole lot of options to write it up correctly, but to no avail.
So here's my question: does anyone know how to create a new variable with a name that's composed of a string ("click") and a number ?
Comments
This would allow you to have as many cycle 'variables' as you need.
Thanks a lot for this alternative
But does that mean that one can't create new variables in such a way in Harlowe ?
Here is what I've written so far, starting with the passage to determine what NPCs are there:
Then the Talk to menu built up dynamically:
And the logic I'm struggling with:
Clearly, I know it doesn't work at least in part because of that $loopclick variable always ending up being 0, but I'm at a lost as to how I should proceed to solve this...
any ideas?
Your example is using Passage Content Nesting (not looping) to dynamically create your desired output, and as found out by @noahmarshall recently in this thread Harlowe will return an error message if the depth of the HTML generated from your nested passages become to deep.
If you need looping then I would suggest using SugarCube because it has a <<for>> macro.
I will look into SugarCube, then - but I believe there's not much Harlowe could need for me to achieve what I want with it (and the puzzle aspect of doing it with Harlowe is part of the fun I'm having with this attempt
Anyway, thanks a ton for your time and help, greyelf !
based on the issues you are having this does not seem to be the case. *smile*
Well, if only you could create variables dynamically, like I was originally looking to do... let's say it would have taken me much longer to see Harlowe limits with respects to what I want to do :P
For someone like me, you have to start somewhere, and Harlowe is the default language for Twine, so I would guess that's what a lot of people who know nothing will be starting with, not really having the background/training/experience as a basis for choosing something other than Harlowe.