Howdy, Stranger!

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

Using the loop to assign variables in an array to another specific variable

edited November 2016 in Help! with 2.0
I want to be able to assign one person to a room. I have these 3 rooms with clickable links:
Room 01 - AssignRooms
Room02 - AssignRooms
Room03 - AssignRooms

where $room01, $room02, and $room03 will be the names of the people assigned to that room once selected (default is initialized to "none" when you begin). AssignRooms is the passage where you get to select the people.

I have the following people variables in an array (note: as the player progresses and meets new people, more names will be added here so it's not static):
<<set $temprooms = ["Lydia", "Desi", "Jereck", "Rawn", "Teleri"]>>


Here's what I have for the AssignRooms passage for room01:

Room #1: $room01

<<for $i to 0; $i lt $temprooms.length; $i++>>
<<link $temprooms[$i]>>
<<set $room01 to $temprooms[$i]>>
<<goto "Rooms">>
<</link>>

<</for>>

The problem is that $room01 literally returns "$room01" as a result and not a name when you go back to the Rooms passage. But all the << link $temprooms[$i] >> links do give the right name while still in the AssignRooms passage.

I tried changing up the code to this:
Room #1: $room01

<<for $i to 0; $i lt $temprooms.length; $i++>>
<<set $room01 to $temprooms[$i]>>
<<link $room01>>
<<goto "Rooms">>
<</link>>
<</for>>

and now no matter who I select, $room01 will always return "Teleri" as the result - always the last name in the array. But the << link >> macro still returns the right name. Is there a way to fix this?

Second question: Once a person is assigned to Room01 for example, I would like their name removed from the array so that they don't get selected for $Room02 or $Room03 anymore. Is that possible?

Thank you! This is for Twine 2 and Sugarcube 2

Comments

  • The quote tag for quotes. Please use the code tag for code—C on the editor bar.

    Also, in the future, please specify the full versions of the software involved—e.g. Twine v2.0.11 & SugarCube v2.11.0. Yes, it can make a difference.

    Coraline wrote: »
    I have the following people variables in an array (note: as the player progresses and meets new people, more names will be added here so it's not static):
    <<set $temprooms = ["Lydia", "Desi", "Jereck", "Rawn", "Teleri"]>>


    Here's what I have for the AssignRooms passage for room01:
    Room #1: $room01

    <<for $i to 0; $i lt $temprooms.length; $i++>>
    <<link $temprooms[$i]>>
    <<set $room01 to $temprooms[$i]>>
    <<goto "Rooms">>
    <</link>>

    <</for>>

    The problem is that $room01 literally returns "$room01" as a result and not a name when you go back to the Rooms passage. But all the << link $temprooms[$i] >> links do give the right name while still in the AssignRooms passage.
    That is not what is happening. The naked variable markup only replaces something which looks like a variable if a) such a variable actually exists and b) has a defined value. In your code above, the contents/interior of any of the <<link>> macros aren't evaluated until the player clicks upon them. By that point, your loop index variable $i is out-of-bounds, so $temprooms[$i] yields the undefined value. Since $room01 gets assigned undefined, it fails the second requirement of the naked variable markup and is not replaced.

    What you need to do is to force the contents of the <<link>> macros to be evaluated as they're created within the loop. You currently have to do that using the Stupid Print Trick™.

    Additionally, two other issues. You should be using temporary variables where you can, so that you do not bloat your story history unnecessarily—e.g. _i vs $i. You do not need the <<goto>> there, <<link>> is sufficient.

    (example below)

    Coraline wrote: »
    Second question: Once a person is assigned to Room01 for example, I would like their name removed from the array so that they don't get selected for $Room02 or $Room03 anymore. Is that possible?
    Yes. You'll probably want to use the <Array>.deleteAt() method for that.


    EXAMPLE:
    Untested, but should work.
    <<for _i to 0; _i lt $temprooms.length; _i++>>
    	<<='<<link $temprooms[_i] "Rooms">><<set $room01 to $temprooms.deleteAt(' + _i + ')[0]>><</link>>'>>
    
    <</for>>
    
    NOTES:
    • I did not force early evaluation of _i within the arguments to <<link>> as a macro's arguments are evaluated during its invocation—i.e. they're already evaluated early. We only need to worry about the _i within the contents/interior of the macro.
    • Since <Array>.deleteAt() returns an array, we have to index that to get the value we pulled from the array.
  • edited November 2016
    Thank you! I used your code this way:
    <<if $rooms eq "room01">>
    
    <<for _i to 0; _i lt $temprooms.length; _i++>>
    	<<print '<<link $temprooms[_i] "Rooms">><<set $room01 to $temprooms.deleteAt(' + _i + ')[0]>><</link>>'>>
    <</for>>
    
    <<elseif $rooms eq "room02">>
    
    <<for _i to 0; _i lt $temprooms.length; _i++>>
    	<<print '<<link $temprooms[_i] "Rooms">><<set $room02 to $temprooms.deleteAt(' + _i + ')[0]>><</link>>'>>
    <</for>>
    
    <</if>>
    

    It works for my first question, but not the second. When I choose for Room#2 though, it looks like I can still choose the same name that had already been selected for Room#1? It doesn't look like the name is removed from the list once selected, because I can get this result --
    Room 01: Rawn
    Room 02: Rawn
    

    Should I need to add something else?
  • Where are you setting $temprooms? If you're setting it in within one of the associated passages, then that would be why—i.e. you're resetting it every time.

    Beyond that, there are other issues, now that I'm thinking about it. If the player attempts to reassign a room, the original assignee won't be in the list and it's currently possible to exhaust the list thereby blocking the assignment of new rooms.

    I'd suggest something like the following instead.

    StoryInit special passage
    <<set $temprooms to [
    	"Lydia", "Desi", "Jereck", "Rawn", "Teleri"
    ]>>
    <<set $room01 to "(unoccupied)">>
    <<set $room02 to "(unoccupied)">>
    <<set $room03 to "(unoccupied)">>
    


    Rooms passage
    Room 01: <<link [[$room01|AssignRooms]]>><<set $room to "room01">><</link>>
    Room 02: <<link [[$room02|AssignRooms]]>><<set $room to "room02">><</link>>
    Room 03: <<link [[$room03|AssignRooms]]>><<set $room to "room03">><</link>>
    
    NOTE: The $room story variable should be set to the name of the room variable you want to set, minus the $-sigil. This will allow AssignRooms to be simplified.

    AssignRooms passage
    <<silently>>
    	/* Unassign the current room. */
    	<<set State.variables[$room] to "">>
    
    	/* Copy the list of available people. */
    	<<set _available to clone($temprooms)>>
    
    	/* Remove all people currently assigned to a room (must include all room story variables). */
    	<<set _available.delete($room01, $room02, $room03)>>
    <</silently>>
    \<<for _i to 0; _i lt _available.length; _i++>>
    	<<='<<link _available[_i] "Rooms">><<set $' + $room + ' to _available[' + _i + ']>><</link>>'>>
    <</for>>
    
    NOTE: The $room story variable is used to unassign the current room story variable and is printed so that it becomes the appropriate room story variable within the generated <<link>> macros.
  • This works perfectly. Thank you again!
Sign In or Register to comment.