Hard to believe, the core part of this Twine experience is almost done. Granted, it looks like cat vomit, but you’ll address the look and feel down the road. For now, you still have work to do.
All the game objects are now placed in easy mode. Now comes the time to place all the game objects in hard mode. In hard mode, all the objects are placed in random locations.
To get started, open your project in progress or download the starter project for this tutorial. If you don’t have it handy, you can download the project in progress here:
Open it up into Twine and then load your project. It’s time to get started.
Creating a Random Seed
Random numbers are pretty critical in dynamic stories. They allow for different outcomes. You can use random numbers to determine a die roll or whether a player’s attack hit the target. You can use them to determine the amount of gold in chest. Or the amount of bullets already loaded into a gun.
In short, it’s time to get serious with randomness.
Harlowe makes random numbers accessible by way of the (random :) macro. This macro takes two numbers: a minimum value and a maximum value. If you want to simulate a twenty sided die roll, you run the following code:
(random: 1, 20)
This produces a random number between one and twenty. You can combine it with a (set :) to save the value.
(set $randomNumber to (random: 1, 20))
And that’s it takes to get random! Well – there is a caveat. When working with computers, there is no such as random numbers. Computers use an algorhtm to create a random number, but it’s not random. The computer uses a “seed” value as the basis of its calculations. If you use that the same seed, you’ll receive the same “random” numbers.
This is why you can replicates worlds in Minecraft by simply sharing the seed value. Most of the time, the seed is based off the date and time. That way, it’s always guaranteed to be unique. You may want to add your own seed.
Hawlowe allows you do do that. Open the Startup passage. At the top of the code, add the following:
(seed: "bernie's revenge")
It should look as follows:
Now your random values will be in sync with the tutorial’s random values. To try this out, open the Introduction passage. Add the following:
(set: $random to (random: 1, 10))
(print: $random)
Now run the story. You should see the following:
Back in the Introduction passage, add the following to generate another random number:
(set: $anotherRandom to (random: 1, 10))
(print: $anotherRandom)
When you start your story, will see 5 and 6. So much for random!
But the good news is that you can test the “randomness” parts of your story since you can replicate the randomness. Should you need a new set of random numbers, just change the seed. Just don’t forget to delete the seed at the end of development.
Delete all that code in the Introduction passage. It’s time to get random!
Determining Random Locations
Now comes the time to put the (random :) macro to use. Remember, the random numbers you are generating is the actual room id. You defined them in the Startup passage using the following code:
(set: $rooms to
(a:
(dm: "name", "Camp Entrance", "id", 1),
(dm: "name", "Side Road", "id", 2),
(dm: "name", "Waterfront", "id", 3),
(dm: "name", "Lakeside Road", "id", 4),
(dm: "name", "Crafts Station", "id", 5),
(dm: "name", "Intersection", "id", 6),
(dm: "name", "Store", "id", 7),
(dm: "name", "Parade Ground", "id", 8),
(dm: "name", "Mess Hall", "id", 9),
(dm: "name", "Soccer Field", "id", 10),
(dm: "name", "Back Road", "id", 11),
(dm: "name", "Hopi Campground", "id", 12),
(dm: "name", "Dusty Road", "id", 13),
(dm: "name", "Tombstone Campground", "id", 14),
(dm: "name", "Camp Path", "id", 15)
)
)
You could generate a random number from 1 to 15, but there may be locations that you don’t want to use. For instance, in this story, you do not want random items to appear on the Camp Path. This path is a shortcut that requires that the player is holding a flashlight. If the flashlight appears in that location, it is effectively unreachable.
For this story, you are going to keep all items out of the Tombstone Campground, the Camp Path, and the Camp Entrance. Open the Hard passage. Delete the code there so it is blank.
There are multiple ways for us to generate a random location. You could loop through all the available items and then generate a random number from 1 to 13 for the location. You could do that, but you aren’t going to. The reason: each item should be placed in a unique location. That way, the player is forced to explore the game world.
Add the following:
(set: $randomLocations to (a: 2,3,4,5,6,7,9,10,11,12,13))
Here you’ve designated all the possible locations for random locations in an array. Now, let’s randomize them:
(set: $randomizedLocations to (shuffled: ...$randomLocations))
The (shuffled :) macro takes an array and simply shuffles the contents. This guarantees that you’ll be using a unique location. Print out the location:
(print: $randomizedLocations)
Run the story and make sure to select Hard mode. You’ll see your list of “random” locations.
Now to assign them to the room locations.
Setting Random Locations
At this point, you have everything you need to set the random locations. You have each item created in code and you have a list of random location ids. Take a moment to think how you will associate the new location with each item.
There are many ways to do this, but in this example, you are going to use your old friend, the loop. If you don’t remember loops, you can review them back here. Loops are great tools for dealing with repetitive tasks such adding items to locations.
In the Hard passage, first delete the (print :) macro that printed out all the randomized location. Next, create a new array.
(set: $randomizedItems to (a:))
This is a temporary array you are using to store the items. Now for the loop:
(for: each _item, ...$items) [
]
This loop goes through each of the items that you defined in the (startup :) passage. Now set the location inside of the brackets:
(for: each _item, ...$items) [
(set: _item's location to 1st of $randomizedLocations)
]
Unfortunately, with this code, every item is going to be placed at the same location. You need to alter the $randomizedLocations array. Add the following:
(set: $randomizedLocations to $randomizedLocations - (a: 1st of $randomizedLocations))
This bit of code may seem confusing. Start at the right part of the code. You can see it is creating an array using the first element of the $randomizedLocations. After which, it subtracts it from the $randomizedLocations array.
In another story format like SugarCube, this would be quite easy to do without all the code gymnastics. Unfortunately, this is just a pain point working with Harlowe. That is, ugly code.
Now add the following right after that last line:
(set: $randomizedItems to $randomizedItems + (a: _item))
This sets all the altered items into another array. This allows you to make changes to objects in arrays without creating new objects. Again, this is another Harlowe pain point. Your loop should look the following:
(for: each _item, ...$items) [
(set: _item's location to 1st of $randomizedLocations)
(set: $randomizedLocations to $randomizedLocations - (a: 1st of $randomizedLocations))
(set: $randomizedItems to $randomizedItems + (a: _item))
]
After the loop, add the following under the last (set :) macro:
(set: $items to $randomizedItems)
This sets all the changes you made back to the main $items array. Last but not least, add the following to redirect the user to the start of the story.
(go-to: "Camp Entrance")
Finally wrap all your code in braces { } so that you remove any whitespace. Your finalcode should look like the following:
Congratulations! You now have random item locations added to the story.
Playing the Story
Now it’s time to test the item locations. Start up the game and this time select hard mode. When you printed out the shuffled location array, you learned where everything was going to be placed. You can find items at the following locations: Intersection, Lakeside Road, Side Road, Mess Hall, and Back Road.
When you start the game, you can immediately head to the Back Road and low and behold, you’ll find a set of keys.
Proceed through the camp and collect all the items. Now to truly experience the randomness, you can alter the seed or delete the seed in the Startup passage. Don’t forget to put it back as there are still lots of random things to do!
Where to go from here
At this point, your story is looking good. You have lots of objects in play and on hard mode, those objects are placed at random locations throughout your story world. Well done! If you did get stuck, feel free to down the final project and compare the code.
In the next article, you’ll put those objects to use. You’ll make the player able to traverse the dark path with the flashlight and you’ll add Bernie’s truck to the mix.