ARG:What's in a name

This page contains spoilers about the Heartbound ARG. If you want to solve the puzzle yourself, avoid reading this article.

What's in a name was found by solving Truncated, this brought us to the page https://gopiratesoftware.com/games/Heartbound/CORE_DUMP/MEMORY_ALPHA/CRASH_LOG/BOOT_RECORD/. This puzzle was released on February 24th 2021.

The page is called "Core Dump", like all the previous pages of Phase 6. But unlike the other pages, it has no images and it is completely black. However, its source code has the following comments:

<!-- What's in a name? -->
<!-- Rule of Three -->
<!-- Power of Three -->

What is in the name

"What's in a name?" is a quote from William Shakespeare's Romeo and Juliet. But in our context, it refers to the name of the game window, that is, the title at the top of the Heartbound window. The window title changes on a few occasions during the playthrough, all of which happen on Animus.

Animus is divided into a few storylines, each one has different outcomes based on you actions, and the title that the window changes to depend on which outcome you got. The window title change happens during the stories of Emelio, Fern / Rhode, and Avocado, as shown on these pictures:

Avocado is the only case where the window title changes twice, in the other cases the change happen only once. These are all the window titles you can get:

  • Emelio
    • If you chose to help him: 342O2C312P2L2F2O2I2F2B3133
    • If you choose to not help him: 2C312P2L2F2O2I2F2B3133
  • Fern and Rhode
    • If they end up together: 2N2B312L2F2E362J332I2H312F2F2O
    • If they do not end up together: 2N2B312L2F2E362J332I312F2E
  • Avocado
    • If you chose to chill out with her: 362J332I2B322N2J2M2F
      2Q2P2C2P371M1M1M1P2023332B2D2P2N2B362B23221P1M1M
    • If you refused to chill out with her: 362J332I2B2G312P362O
      2Q2P2C2P371M1M1M1P2023332B2D2P2N2B362B23221P1M1M

What we got is some ciphertext. The other two hints we have ("Rule of three" and "Power of three") will help us to decipher it.

Decoding the "names"

When we look at the ciphertext we can begin to notice some patterns, like pairs of letters that appear multiple times. This suggests that we should break our ciphertext into letter pairs:

34 2O 2C 31 2P 2L 2F 2O 2I 2F 2B 31 33
2C 31 2P 2L 2F 2O 2I 2F 2B 31 33
                       
2N 2B 31 2L 2F 2E 36 2J 33 2I 2H 31 2F 2F 2O
2N 2B 31 2L 2F 2E 36 2J 33 2I 31 2F 2E
                       
36 2J 33 2I 2B 32 2N 2J 2M 2F
2Q 2P 2C 2P 37 1M 1M 1M 1P 20 23 33 2B 2D 2P 2N 2B 36 2B 23 22 1P 1M 1M
36 2J 33 2I 2B 2G 31 2P 36 2O
2Q 2P 2C 2P 37 1M 1M 1M 1P 20 23 33 2B 2D 2P 2N 2B 36 2B 23 22 1P 1M 1M

In order to figure out what to do with those sequences, we need to remember the other two clues we have: "Rule of three" and "Power of three". The former is a storytelling concept that suggests that events or concepts might be more satisfying when they happen in groups of three. Like in Heartbound where we have three worlds to choose from, and the tree storylines we went through to get our ciphertext.

In our context, it has some further meaning. Those two hints combined are telling us to raise "three to the power of three", which is multiplying three by itself three times: 33 = 27.

This result of 27 is important, it hints that ciphertext we have is actually numbers on base-27. The base of a number is the amount of unique digits to represent a value. The numbering system we are more used to is the decimal system, also known as base-10 because it has ten unique digits (01234567890). But other bases are possible to represent numbers, like binary (base-2) or hexadecimal (base-16).

On bases greater than 10, when we get beyond the 10 usual numeric digits (0-9), then we start using letters (A-Z, until we have enough digits). We have numbers on base-27, so the digits we will use are 0123456789ABCEFGHIJKLMNOPQR.

Our ciphertext corroborates with that idea since no digits other than those 27 show up. Each letter pair seems to be an individual base-27 number. Now let's convert each base-27 number to base-16 (hexadecimal), which is commonly used on computer science. We get the following result:

55 4E 42 52 4F 4B 45 4E 48 45 41 52 54
42 52 4F 4B 45 4E 48 45 41 52 54

4D 41 52 4B 45 44 57 49 54 48 47 52 45 45 4E
4D 41 52 4B 45 44 57 49 54 48 52 45 44

57 49 54 48 41 53 4D 49 4C 45
50 4F 42 4F 58 31 31 31 34 36 39 54 41 43 4F 4D 41 57 41 39 4A 3D 3A 3A
57 49 54 48 41 46 52 4F 57 4E
50 4F 42 4F 58 31 31 31 34 36 39 54 41 43 4F 4D 41 57 41 39 4A 3D 3A 3A

Notice that most of the hexadecimal numbers are on the 41-50 range, which is the range of uppercase letters on ASCII, which is an usual text encoding method. This suggests that we have ASCII encoded text. So if we convert our values to characters by using the [ASCII table], we get:

UNBROKENHEART
BROKENHEART
MARKEDWITHGREEN
MARKEDWITHRED
WITHASMILE
WITHAFROWN
POBOX111469TACOMAWA98411
POBOX111469TACOMAWA98411

That successfully decoded into plain text, which means that our assumptions were correct. Now we add spaces and punctuation to make the text lines more legible, and then we put them in the context where we found each:

Story outcome
Good Bad
Emelio Unbroken heart Broken heart
Fern and Rhode Marked with green Marked with red
Avocado With a smile
P.O. BOX 111469 TACOMA WA 98411
With a frown
P.O. BOX 111469 TACOMA WA 98411

What we got was a series of instructions, based on the route we followed in-game, followed by a P.O. Box where we can send physical mail to. That P.O. Box belongs to Pirate Software, the company that makes Heartbound. So it is assumed that now we need to follow the instructions and mail the result to that P.O. Box, which as the time of this writing a couple of people have done. We should see the results in the following weeks.

It is assumed that those instructions are for some art project, and which ones you follow depend on which outcome you got for each storyline. There are three stories with two outcomes each. So, for example, if you got the good outcome on all three storylines on your playthrough: you would need to draw or craft a "broken heart", that is "marked with green", and "with a smile". And then mail your drawing or craft to P.O. BOX 111469 TACOMA WA 98411.

Mailbox

At March 15th 2021, the first artwork has been confirmed to have arrived to the aforementioned P.O. Box. The art has been posted on Twitter by Thor himself[1]. According to the tweet were the art was posted, that was the first of a total of eight, which might mean that another seven art projects need to be received. Presumably it is one art for each one of the eight possible combinations of story outcomes.

These are the known artworks that were sent:

In the beginning of June 2021 we got the confirmation that the artworks of all 8 possible paths have been received, which made the current step to be declared as solved [2][3][4]. All those who mailed stuff to the PO Box are going to receive a mail with the next step of the puzzle.

Due to some personal difficulties, it took until December for the mail to be sent for the participants. The first mail has been corfirmed to be received at December 29 2021 [5][6]. The other seven letters have gradually been received afterwards, with the last one arriving at January 27 2021. The contents of the letters are as follow:

The letter reads:

Glorious Puzzler,

As you slashed open this letter I hope it came with a great feeling of accomplishment. You've done amazing things to get where you are today. Enclosed you will find one of every sticker from the store, a challenge coin and this letter. Hopefully nothing disappeared in transit. Nothing important anyway.

With that being said... you have quite the journey ahead of you. All of you do. All eight and the rest of the community will be needed. Make sure to share your notes and your findings with one another. You cannot do this alone.

Good luck out there Puzzle warriors. We're all counting on you.

-Thor

The capitalization of some words change from mail to mail. The words that differ are: Puzzle, You, Transit, Eight, Great, Being, Store, Needed.

We need all eight different mails in order to get solve the puzzle. All of them have been received, and the community has used Discord to keep track of what have been received. You are welcome to join the community at the Heartbound ARG Discord to participate of the next steps or just spectate!

Decoding the mail

Each mail had one different capitalized word. If we take the first letter of each of the seven received mail, we get: P, Y, T, E, G, B, S, N.

From those letters, we can form the word BYTES, leaving out the letters P, G, and N. Those 3 letters can form PNG, which is an image file format. Thus the letters spell the file name BYTES.PNG .

If we add that to the end of the URL, we get to this page, which has this image:   (this is the actual size, 21 x 21 pixels)

If we scale up the image:

 

Some parts of the image looks like a QR Code. Also 21 x 21 is the smallest possible size for a QR Code. All of this suggests that the image we got is a QR Code, however it seems to be corrupted.

If we use an image editor (like GIMP) in order to look at the image's metadata, we get this:

 

One value stand out, the user's comment (on the tag <Exif.Photo.UserComment>): 100100. This is a clue on what we need to do with the image, which is to XOR it by 100100.

XOR stands for "exclusive or". It is a logical operation between two true/false values that returns "true" only if one value is "false" and the other is "true". If both are "true" or both are "false", then XOR returns "false":

XOR truth table
Input Output
A B
false false false
false true true
true false true
true true false

XOR-ing some data is one of techniques in computing for encoding some data. It is commonly found as one of the steps for encrypting or obfuscating information.

The "100100" comment we got from the clue is the key for XOR-ing the image. In our case, each white pixel on the image is a "true" value, while each black pixel is a "false" value. Similarly, the "1" on the key means "true", while the 0 means "false". The key is just 6 values long, which of course is smaller than the amount of pixels on the image. In this case, the key just keeps repeating itself until the end of the image. So the key goes as "100100100100100100..." (note that here each third value is 1).

XOR-ing some data by 1 in practice means flipping its value: if it is "true" it will become "false", and if it is "false" it becomes "true". XOR-ing something by 0 keeps it unchanged. So what this tells us is that each third pixel on the image will be flipped (from black to white, or white to black). This could be done by hand, but it would be incredibly tedious and error prone. So we are going to write a small computer program to do that.

Here we are going to use Python. We will also need the Python modules Pillow and NumPy. What our program is going to do is to read the image into a 21 x 21 array of zeroes and ones, XOR each third value by 1, recreate the image from the result, then upscale and save the image.

The code goes as follows:

from PIL import Image
import numpy as np

# Read the image file
bytes_png = Image.open("BYTES.png")

# Store the pixel values in an array
image_array = np.array(bytes_png)
"""NOTE
The array has 3 dimensions:
image_array[height, width, RGBa]

The first two dimensions are the coordinates of the pixel,
and the last dimenstion is its color value.

In a PNG image, a color is described as 4 values:
Red, Green, Blue, Alpha (transparency).
Each of those values is an integer from 0 to 255.
"""

# Convert the image array to monochrome (only black and
#                                        white pixels)
barcode_array = (image_array[..., 0] // 255).astype("bool")
"""NOTE
Since each pixel on the image can only be either pure white
RGBa(255, 255, 255, 255), or pure black RGBa(0, 0, 0, 255),
then we only need one of the first three values (the other
two will be the same). This is why the code only took the
first value on each coordinate: image_array[..., 0]

Then each value was divided by 255, which turned each 255
into an 1 and kept the zeroes unchanged. Finally, the values
were changed to the boolean data type, which can be only
True (1) or False (0). This allows the program to interpret
the array as a monochrome image.
"""

# Flip every third value on the array
# (each third pixel change its color from black to white,
#  or white to black)
barcode_array[..., ::3] ^= True

# Add a padding of white pixels around the array
# (because QR codes require an white space around then to be scanned)
barcode_array = np.pad(
    barcode_array,
    # Add one value to all corners of the array
    pad_width = 1,
    # The value is always the same
    mode = "constant",
    # The value is 'True' (which here means an white pixel)
    constant_values = True
)

# Create an image object
barcode_image = Image.fromarray(barcode_array)

# Get the image dimensions in pixels
height, width = barcode_array.shape

# Upscale the image so it is not too small to be scanned
# Use no pixel interpolation, so the image do not get blurred
barcode_image = barcode_image.resize(
    size = (height * 10, width * 10),
    resample = Image.NEAREST
)

# Save the image to disk
barcode_image.save("QR code.png")

The "BYTES.png" image needs to be on the same folder as the Python script, and the output image will be saved on that folder. The image we get after XOR-ing our input is:

 

Now it looks like an actual QR code! Now lets scan it using a cellphone:

 

When scanning the QR code we get the text DEEP_THOUGHT. And if we add that to the URL, we get to the page https://gopiratesoftware.com/games/Heartbound/CORE_DUMP/MEMORY_ALPHA/CRASH_LOG/BOOT_RECORD/DEEP_THOUGHT/

This concludes the current puzzle, and brings us to the next puzzle of the ARG: Painful Memory.