Introduction: Links From Variables in Twine With Sugarcube

About: I build robots out of boxes! I love teaching what I've learned and seeing people add their own ideas to what they've learned. Nothing excites me more than seeing a student really take an idea and run with it!

I'm so glad you've joined me again! This means the Wumpus hasn't eaten you yet. Good!

For those of you who aren't familiar, this is a set of tutorials I'm making to help my adorable oochy-skootchy widdle cousin with her senior project. These tutorials are meant to be a reference for what you can do with some of the programming features of Twine and Sugarcube. If you want to follow along, you can find the first tutorial here.

In the last tutorial, I built a small set of rooms that the player can explore. I added a Wumpus object, and made some generic room code to change what was displayed in each room depending on where the Wumpus is.

Step 1: Create Your Player

This step is very simple. Essentially I'm just using the same code as my $wumpus, but with a $player variable instead.

Step 2: New Room Code

Changed your generic room code so the value of $player is the current room. Then compare $wumpus to $player instead of the current room.

This is a minor change, and not totally necessary, but I like to keep my code organized.

Step 3: Creating a Link From a Variable

Finally, want to replace the link in my starting room to one that changes based off the value of $player. This can be done with the "<<link>>" function in Sugarcube. You can read more about that in Sugarcube's documentation page.

The first string after our command is the phrase that will appear in our passage. The second is the name of the passage we want to link to. I'm using "Hunt the Wumpus!" as my phrase, but we could use our variable there instead if we want the player to know where they're going beforehand, like this:

<<link $player $player>><</link>>

Step 4: Test

When you test your code, you should find that your link has been replaced with whatever phrase you wrote before. Clicking it takes you to a random room in your game.

Unfortunately, this can also take you straight to the Wumpus room! That doesn't matter much right now, but in a real game that would be an instant game over. We need to fix that.

Step 5: Add a Room List

First, we're going to create a room list, to make managing rooms easier. By declaring this array, we can use it to set our $player and $wumpus values without repeating code. It also has another advantage that we'll explore next.

Testing with this code should behave just like it had before.

Step 6: Eliminating Rooms

I've added a single line of code to the code from before (highlighted).

Arrays in Sugarcube have a built-in function that lets you delete elements from them by name. In this case, once we assign $wumpus a room, we can delete that room from our $roomlist. This function is finicky, however. It will not work unless the output of the function is assigned or used in some way. To take care of that, I've created the temporary variable _temp.

In Sugarcube, temporary variables start with an underscore (_) instead of a dollar ($). They're useful because they get deleted once the passage is run, so you don't have to worry about overlapping variable names.

I'm deleting the $player room from $roomlist as well, just as a matter of course.

Step 7: Testing

While we could run the code as it is now, that wouldn't be a very thorough test. If we run the code and find that $player and $wumpus are assigned to different rooms, we don't know if that's because the code works, or if it's just chance. Sure, we could run the code many times, and assume that if it never assigns them both the same room that it never will, but that will take forever and it's still not a 100% assurance that it can never happen.

Instead, we need a way to check.

I've added three lines to the top of our intro passage that will let us see the values of our $wumpus, $player, and $roomlist variables. Because of the way we set up our code, we know that the $wumpus room and $player room should be eliminated from the $roomlist.

When we run this code, we can check to make certain that's the case.

Step 8: Oddities With Sugarcube and Objects

Sugarcube objects are a little odd. Let me demonstrate this.

While I was building this project originally, I wanted to save my $roomlist to a $saveroom variable before I started deleting rooms from it. I figured it would come in handy later.

When I got some strange behavior from this code, I added another line to my intro page to let me look at my $saveroom variable (second picture).

I was shocked to find that the elements I had deleted from $roomlist had also been deleted from my saved list! You can see this in action in the third picture.

This is because when you copy an array like this, you're not actually telling Twine to copy the array, you're telling Twine that these two variables are the same array. When you do something to the array using one variable, it changes the same array that the other variable is looking at!

We can fix this with the clone() function.

Step 9: The Clone() Function

You can read about the clone() function on the Sugarcube documentation page.

A "shallow" copy is what we were doing before. Instead of making a complete copy of the whole array, it just assumes that your variable is working with the same array. Instead of a shallow copy, clone() does a "deep" copy, which behaves like you would expect. Each element of the array is copied over into a new array, and is totally separate from the original.

If we test this new code, we find it works as expected.

Of course, it doesn't matter whether you keep $roomlist or not. For the purposes of my project, I'm not going to. This was all just to demonstrate deep vs. shallow copies.

Step 10: That's It for Now!

We've added code that lets our player start in a random room. In addition to that, we've eliminated a bug where the player would start in the same room as the Wumpus.

We learned about how to create links from variables, and how array copying is treated by Sugarcube.

Things are ramping up, but we're just getting started!

Happy hunting!