Jump to content

Recommended Posts

I am currently running this program on repeat to bruteforce the code.

Spoiler
On 1/10/2026 at 8:05 AM, Instant-Noodles said:

I wrote a quick script to more easily test potential solutions in the musical rotary machine.  The script will translate the musical notes you enter into the proper dial inputs on the rotary machine.

To use, copy and paste the following into your browser's console (F12) while on the night side of the comic and with the musical rotary machine panel open.

const coords={
  "1": {"x": 31.14, "y": 42},
  "2": {"x": 38.71, "y": 35.86},
  "3": {"x": 48.29, "y": 33.57},
  "4": {"x": 58.14, "y": 34.29},
  "5": {"x": 66.29, "y": 40.86},
  "6": {"x": 68.86, "y": 51.29},
  "7": {"x": 69, "y": 60.86},
  "8": {"x": 62.43, "y": 69.85},
  "9": {"x": 54, "y": 73},
  "10": {"x": 44, "y": 74.29},
  "11": {"x": 34.43, "y": 69.86},
  "12": {"x": 30.43, "y": 60.71},
  "redbutton": {"x": 67.71, "y": 90.43},
  "levertop": {"x": 92, "y": 19},
  "leverbottom": {"x": 93, "y": 47.71},
  "notchup": {"x": 89.86, "y": 56.57},
  "notchdown": {"x": 90.43, "y": 70.71},
};

const prettyLookup={
  "1": "Stored Button 1 - Note C",
  "2": "Stored Button 2 - Note C# / Db",
  "3": "Stored Button 3 - Note D",
  "4": "Stored Button 4 - Note D# / Eb",
  "5": "Stored Button 5 - Note E",
  "6": "Stored Button 6 - Note F",
  "7": "Stored Button 7 - Note F# / Gb",
  "8": "Stored Button 8 - Note G",
  "9": "Stored Button 9 - Note G# / Ab",
  "10": "Stored Button 10 - Note A",
  "11": "Stored Button 11 - Note A# / Bb",
  "12": "Stored Button 12 - Note B",
  "redbutton": "Finished storing note(s) for this Notch",
  "levertop": "Moved to Lower Octave",
  "leverbottom": "Moved to Higher Octave",
  "notchup": "Increased Music Length by 1",
  "notchdown": "Decreased Music Length by 1",
}

const noteLookup={
  "C": 1, "c": 1,
  "C#": 2, "c#": 2, "Db": 2, "db": 2,
  "D": 3, "d": 3,
  "D#": 4, "d#": 4, "Eb": 4, "eb": 4,
  "E": 5, "e": 5,
  "F": 6, "f": 6,
  "F#": 7, "f#": 7, "Gb": 7, "gb": 7,
  "G": 8, "g": 8,
  "G#": 9, "g#": 9, "Ab": 9, "ab": 9,
  "A": 10, "a": 10,
  "A#": 11, "a#": 11, "Bb": 11, "bb": 11,
  "B": 12, "b": 12,
};

const notchLookup={
  "53.2%": 20,
  "54.02%": 19,
  "54.83%": 18,
  "55.65%": 17,
  "56.46%": 16,
  "57.28%": 15,
  "58.09%": 14,
  "58.91%": 13,
  "59.73%": 12,
  "60.54%": 11,
  "61.36%": 10,
  "62.17%": 9,
  "62.99%": 8,
  "63.81%": 7,
  "64.62%": 6,
  "65.44%": 5,
  "66.25%": 4,
  "67.07%": 3,
  "67.88%": 2,
  "68.7%": 1,
};

function sleep(delay){
  return new Promise(function(resolve, reject){setTimeout(resolve, delay)});
}

async function click(target, handle="skip"){
  if (!(target in coords)){
    console.log("Skipped invalid input", target);
    return;
  }

  const panel=document.querySelector("#page1panel17>.panel-background");
  const bbox=panel.getBoundingClientRect();
  const handleDown=document.querySelector("#page1panel17handle").classList.contains("down");

  if (handle=="up" && handleDown){
    click("leverbottom");
    await sleep(1500);
  }
  else if (handle=="down" && !handleDown){
    click("levertop");
    await sleep(1500);
  }

  panel.dispatchEvent(new MouseEvent("click", {bubbles: true, cancelable: true, view: window, clientX: bbox.left+bbox.width*coords[target].x/100, clientY: bbox.top+bbox.height*coords[target].y/100}));
  console.log(" -", prettyLookup[target]);
  await sleep(1000);
}

async function clickSequence(seq=[[]]){
  for (let clickTarget in seq){
    await click(seq[clickTarget][0], seq[clickTarget][1]);
    await sleep(1500);
  }
}

async function setNotch(target=1){
  target=Math.min(Math.max(target, 1), 20);
  let notchPos=notchLookup[document.querySelector("#page1panel17tick").style.top];
  let diff=notchPos-target;

  console.log("Target Music Length is", target, "Notch(es)");

  while (diff!=0){
    if (diff>0){
      await click("notchdown");
    }
    else if (diff<0){
      await click("notchup");
    }

    notchPos=notchLookup[document.querySelector("#page1panel17tick").style.top];
    diff=notchPos-target;
    await sleep(1000);
  }

  await sleep(1000);
  console.log("Set Music Length to", notchPos, "Notch(es)");
}

async function resetState(){
  let markerPos=document.querySelector("#page1panel17marker").style.top;
  let counter=0;

  if (markerPos!="69.52%"){
    console.log("Notes were previously stored - Clearing by playing pre-existing sequence");
  }

  while (markerPos!="69.52%"){
    await click("redbutton");
    markerPos=document.querySelector("#page1panel17marker").style.top;
    counter+=1;
    await sleep(1500);
  }

  await sleep(counter*1500);
}

async function playMusic(music=[[]]){
  await resetState();
  await setNotch(music.length);

  for (let input in music){
    console.log("Storing note(s) for Notch", parseInt(input)+1);
    var sequence=[];

    for (let note in music[input]){
      const octaveup=music[input][note].endsWith("^");
      const item=octaveup?noteLookup[music[input][note].slice(0, -1)]:noteLookup[music[input][note]];
      const octave=octaveup?"up":"down";
      sequence.push([item, octave]);
    }

    sequence.push(["redbutton"]);
    await clickSequence(sequence);
    await sleep(1000);
  }

  console.log("Pausing for", music.length*0.75, "seconds to let music play");
  await sleep(music.length*750);
}

This code assumes the following correlation between the rotary buttons and notes:

image.png

To input a music sequence (after entering the above code in the browser's console), use the playMusic() function in the browser's console (F12):

playMusic( [ [music notes for notch 1], [music notes for notch 2], ... , [up to music notes for notch 20] ] )

Music notes should be enclosed in quotes.  If more than one note is desired in a single notch, then the notes should be separated by commas also.  If you wish to have a higher octave for a particular note, then use "^" at the end of the note.  

For example, this input will play a sequence of: A (higher octave), F (higher octave), F# (lower octave), C# (higher octave), E (higher octave):

playMusic([ ["a^"], ["f^"], ["f#"], ["c#^"], ["e^"] ]);

If you want to play multiple music sequences consecutively, then also use await operator in front of the each playMusic() function. 

For example, to play two sequences one followed by the other... with the first sequence being the same as the first example above, followed by a second sequence of: A# (higher octave) + A# (lower octave), B (lower octave), blank, C(lower octave) + C# (lower octave), use this input:

await playMusic([ ["a^"], ["f^"], ["f#"], ["c#^"], ["e^"] ]); await playMusic([ ["a#^", "a#"], ["b"], [], ["c", "c#"] ]);

There is a pause of 0.75 seconds per occupied notch after each music sequence is fully inputted.  Hopefully, this is a sufficient enough buffer for a music sequence to be completely played out before the script tries entering the next sequence.

---

EDIT: Should note that both lowercase and uppercase letters work for the input.  For example:

playMusic([ ["E"], ["G"], ["C"], ["D"], ["E"] ])

---

EDIT 2: I had someone ask to see an example of how to use the script, so here's a clip of it playing the Wagstaff Whistle with:

playMusic( [ ["f#"], ["d#"], ["c#"], ["c#"] ] )

 

 

By making a chain-command, I am running through each high-octave/low-octave combo 12 attempts at a time.

Problem is, it takes about 1 minute for the program to input each attempt and play the resulting song. Add in the 3.75 second wait-time between each attempt, and the time it takes to re-paste the chain-command, and the time it takes to edit the next note into the chain command, it takes about 15 minutes per possible high-octave note. 3 hours total if we suppose the correct 5th input is ("B^","B").

I am currently going through "G" aka the 8th cycle.

  • Spooky 1
55 minutes ago, filipahped said:

I am currently running this program on repeat to bruteforce the code.

  Reveal hidden contents

 

By making a chain-command, I am running through each high-octave/low-octave combo 12 attempts at a time.

Problem is, it takes about 1 minute for the program to input each attempt and play the resulting song. Add in the 3.75 second wait-time between each attempt, and the time it takes to re-paste the chain-command, and the time it takes to edit the next note into the chain command, it takes about 15 minutes per possible high-octave note. 3 hours total if we suppose the correct 5th input is ("B^","B").

I am currently going through "G" aka the 8th cycle.

Well crap, this didn't work. Either the ARG requires the player to click the door or something after the correct input, or the ARG is clever enough to know the difference between human inputs, and console coding. Either way, I'm turning in for the night. Can't be bothered to keep trying for now.

Three is still more than two, so I'm still curious if the other person was trying only combinations of two notes. And also they may have been trying only pairs in opposite octaves, like, one low, one high.

And was it ever confirmed that the presence of three bells is a hint as to how many notes should be played simultaneously? The first four sets of notes are two notes each, not three.

Given that the first 4 inputs were all one low+one high, I figured input 5 would also be that. So that's what I did. Tell you what:

playMusic([ ["g#^","f#"], ["e","f#^"], ["d#^","c#"], ["c#","d#^"], [""] ]);

Here you go, the first 4 notes, ready to plug into the code. I even prepped an empty space for note 5, ready for you to fill in. If you wanna try every possible combination, you can use this for starters. If nothing else, it'll at least be faster than having to manually punch in the same 4 note sequence every time.

  • Like 2
2 hours ago, filipahped said:

I am currently running this program on repeat to bruteforce the code.

  Hide contents

 

By making a chain-command, I am running through each high-octave/low-octave combo 12 attempts at a time.

Problem is, it takes about 1 minute for the program to input each attempt and play the resulting song. Add in the 3.75 second wait-time between each attempt, and the time it takes to re-paste the chain-command, and the time it takes to edit the next note into the chain command, it takes about 15 minutes per possible high-octave note. 3 hours total if we suppose the correct 5th input is ("B^","B").

I am currently going through "G" aka the 8th cycle.

Hell yeah! Btw, can we just skip the first four beats and focus on the last beat since the second sticker would show too? Once we get the second sticker, then we put them together.

Edited by DST enjoyer
On 1/10/2026 at 9:05 AM, Instant-Noodles said:
 

I wrote a quick script to more easily test potential solutions in the musical rotary machine.  The script will translate the musical notes you enter into the proper dial inputs on the rotary machine.

To use, copy and paste the following into your browser's console (F12) while on the night side of the comic and with the musical rotary machine panel open.

const coords={
  "1": {"x": 31.14, "y": 42},
  "2": {"x": 38.71, "y": 35.86},
  "3": {"x": 48.29, "y": 33.57},
  "4": {"x": 58.14, "y": 34.29},
  "5": {"x": 66.29, "y": 40.86},
  "6": {"x": 68.86, "y": 51.29},
  "7": {"x": 69, "y": 60.86},
  "8": {"x": 62.43, "y": 69.85},
  "9": {"x": 54, "y": 73},
  "10": {"x": 44, "y": 74.29},
  "11": {"x": 34.43, "y": 69.86},
  "12": {"x": 30.43, "y": 60.71},
  "redbutton": {"x": 67.71, "y": 90.43},
  "levertop": {"x": 92, "y": 19},
  "leverbottom": {"x": 93, "y": 47.71},
  "notchup": {"x": 89.86, "y": 56.57},
  "notchdown": {"x": 90.43, "y": 70.71},
};

const prettyLookup={
  "1": "Stored Button 1 - Note C",
  "2": "Stored Button 2 - Note C# / Db",
  "3": "Stored Button 3 - Note D",
  "4": "Stored Button 4 - Note D# / Eb",
  "5": "Stored Button 5 - Note E",
  "6": "Stored Button 6 - Note F",
  "7": "Stored Button 7 - Note F# / Gb",
  "8": "Stored Button 8 - Note G",
  "9": "Stored Button 9 - Note G# / Ab",
  "10": "Stored Button 10 - Note A",
  "11": "Stored Button 11 - Note A# / Bb",
  "12": "Stored Button 12 - Note B",
  "redbutton": "Finished storing note(s) for this Notch",
  "levertop": "Moved to Lower Octave",
  "leverbottom": "Moved to Higher Octave",
  "notchup": "Increased Music Length by 1",
  "notchdown": "Decreased Music Length by 1",
}

const noteLookup={
  "C": 1, "c": 1,
  "C#": 2, "c#": 2, "Db": 2, "db": 2,
  "D": 3, "d": 3,
  "D#": 4, "d#": 4, "Eb": 4, "eb": 4,
  "E": 5, "e": 5,
  "F": 6, "f": 6,
  "F#": 7, "f#": 7, "Gb": 7, "gb": 7,
  "G": 8, "g": 8,
  "G#": 9, "g#": 9, "Ab": 9, "ab": 9,
  "A": 10, "a": 10,
  "A#": 11, "a#": 11, "Bb": 11, "bb": 11,
  "B": 12, "b": 12,
};

const notchLookup={
  "53.2%": 20,
  "54.02%": 19,
  "54.83%": 18,
  "55.65%": 17,
  "56.46%": 16,
  "57.28%": 15,
  "58.09%": 14,
  "58.91%": 13,
  "59.73%": 12,
  "60.54%": 11,
  "61.36%": 10,
  "62.17%": 9,
  "62.99%": 8,
  "63.81%": 7,
  "64.62%": 6,
  "65.44%": 5,
  "66.25%": 4,
  "67.07%": 3,
  "67.88%": 2,
  "68.7%": 1,
};

function sleep(delay){
  return new Promise(function(resolve, reject){setTimeout(resolve, delay)});
}

async function click(target, handle="skip"){
  if (!(target in coords)){
    console.log("Skipped invalid input", target);
    return;
  }

  const panel=document.querySelector("#page1panel17>.panel-background");
  const bbox=panel.getBoundingClientRect();
  const handleDown=document.querySelector("#page1panel17handle").classList.contains("down");

  if (handle=="up" && handleDown){
    click("leverbottom");
    await sleep(1500);
  }
  else if (handle=="down" && !handleDown){
    click("levertop");
    await sleep(1500);
  }

  panel.dispatchEvent(new MouseEvent("click", {bubbles: true, cancelable: true, view: window, clientX: bbox.left+bbox.width*coords[target].x/100, clientY: bbox.top+bbox.height*coords[target].y/100}));
  console.log(" -", prettyLookup[target]);
  await sleep(1000);
}

async function clickSequence(seq=[[]]){
  for (let clickTarget in seq){
    await click(seq[clickTarget][0], seq[clickTarget][1]);
    await sleep(1500);
  }
}

async function setNotch(target=1){
  target=Math.min(Math.max(target, 1), 20);
  let notchPos=notchLookup[document.querySelector("#page1panel17tick").style.top];
  let diff=notchPos-target;

  console.log("Target Music Length is", target, "Notch(es)");

  while (diff!=0){
    if (diff>0){
      await click("notchdown");
    }
    else if (diff<0){
      await click("notchup");
    }

    notchPos=notchLookup[document.querySelector("#page1panel17tick").style.top];
    diff=notchPos-target;
    await sleep(1000);
  }

  await sleep(1000);
  console.log("Set Music Length to", notchPos, "Notch(es)");
}

async function resetState(){
  let markerPos=document.querySelector("#page1panel17marker").style.top;
  let counter=0;

  if (markerPos!="69.52%"){
    console.log("Notes were previously stored - Clearing by playing pre-existing sequence");
  }

  while (markerPos!="69.52%"){
    await click("redbutton");
    markerPos=document.querySelector("#page1panel17marker").style.top;
    counter+=1;
    await sleep(1500);
  }

  await sleep(counter*1500);
}

async function playMusic(music=[[]]){
  await resetState();
  await setNotch(music.length);

  for (let input in music){
    console.log("Storing note(s) for Notch", parseInt(input)+1);
    var sequence=[];

    for (let note in music[input]){
      const octaveup=music[input][note].endsWith("^");
      const item=octaveup?noteLookup[music[input][note].slice(0, -1)]:noteLookup[music[input][note]];
      const octave=octaveup?"up":"down";
      sequence.push([item, octave]);
    }

    sequence.push(["redbutton"]);
    await clickSequence(sequence);
    await sleep(1000);
  }

  console.log("Pausing for", music.length*0.75, "seconds to let music play");
  await sleep(music.length*750);
}

This code assumes the following correlation between the rotary buttons and notes:

image.png

To input a music sequence (after entering the above code in the browser's console), use the playMusic() function in the browser's console (F12):

playMusic( [ [music notes for notch 1], [music notes for notch 2], ... , [up to music notes for notch 20] ] )

Music notes should be enclosed in quotes.  If more than one note is desired in a single notch, then the notes should be separated by commas also.  If you wish to have a higher octave for a particular note, then use "^" at the end of the note.  

For example, this input will play a sequence of: A (higher octave), F (higher octave), F# (lower octave), C# (higher octave), E (higher octave):

playMusic([ ["a^"], ["f^"], ["f#"], ["c#^"], ["e^"] ]);

If you want to play multiple music sequences consecutively, then also use await operator in front of the each playMusic() function. 

For example, to play two sequences one followed by the other... with the first sequence being the same as the first example above, followed by a second sequence of: A# (higher octave) + A# (lower octave), B (lower octave), blank, C(lower octave) + C# (lower octave), use this input:

await playMusic([ ["a^"], ["f^"], ["f#"], ["c#^"], ["e^"] ]); await playMusic([ ["a#^", "a#"], ["b"], [], ["c", "c#"] ]);

There is a pause of 0.75 seconds per occupied notch after each music sequence is fully inputted.  Hopefully, this is a sufficient enough buffer for a music sequence to be completely played out before the script tries entering the next sequence.

---

EDIT: Should note that both lowercase and uppercase letters work for the input.  For example:

playMusic([ ["E"], ["G"], ["C"], ["D"], ["E"] ])

---

EDIT 2: I had someone ask to see an example of how to use the script, so here's a clip of it playing the Wagstaff Whistle with:

playMusic( [ ["f#"], ["d#"], ["c#"], ["c#"] ] )

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


Thank you for your script, which speeds up and replaces manual data entry 🙌

I have a more convenient (in my opinion) and faster way to enter parameters for the playMusic function for the community.
I also tested the author's version and sped up the time it takes to enter values (this can be customized, but more details on that later).
The instructions for use are the same, and if necessary, you can use the input option, as in the author's case 🔥


––––––––––––––––––––––––––––––––––––––
Here is an example of an input option.
––––––––––––––––––––––––––––––––––––––


Author's version:

playMusic([ ["g#^","f#"], ["e","f#^"], ["d#^","c#"], ["d#^","c#"] ]);

My version in the form of notes:

playMusic("g#^ f# | e f#^ | d#^ c# | d#^ c#");

My version in the form of numbers:

playMusic("9^ 7 | 5 7^ | 4^ 2 | 4^ 2");


 

Quote

The symbol “ ” (space) is used to separate notes. The symbol “|” (pipe, the vertical bar) is used to separate chords. (this can be customized, but more details on that later).

 

Question: How do the numbers work?
Answer: It's pretty simple. It's like dialing a number on a phone.

 

I hope this will be more convenient and help us verify the theory for solving the puzzle faster 🙌
Let's solve this puzzle Together🎉

 

––––––––––––––––––––––––––––––––––––––
Script
––––––––––––––––––––––––––––––––––––––

Spoiler
const ACTIONS = {
  '1': "1",
  '2': "2",
  '3': "3",
  '4': "4",
  '5': "5",
  '6': "6",
  '7': "7",
  '8': "8",
  '9': "9",
  '10': "10",
  '11': "11",
  '12': "12",
  'redbutton': "redbutton",
  'levertop': "levertop",
  'leverbottom': "leverbottom",
  'notchup': "notchup",
  'notchdown': "notchdown",
}

const NOTCH_LIMITS = {
  "min": 1,
  "max": 20,
}

const OCTAVES_POSITIONS = {
  "up": "up",
  "down": "down",
  "skip": "skip",
}

const OCTAVE_RANGE = {
  "lower": {
    "min": 1,
    "max": 12,
  },
  "upper": {
    "min": 13,
    "max": 24,
  },
  "min": 1,
  "max": 24,
}

const UPPER_OCTAVE_SUFFIX = "^";

const SKIP_NOTE_SYMBOL = "_";

const CHORD_SPLIT_SYMBOL = "|";

const COORDS = {
  [ACTIONS[1]]: { "x": 31.14, "y": 42 },
  [ACTIONS[2]]: { "x": 38.71, "y": 35.86 },
  [ACTIONS[3]]: { "x": 48.29, "y": 33.57 },
  [ACTIONS[4]]: { "x": 58.14, "y": 34.29 },
  [ACTIONS[5]]: { "x": 66.29, "y": 40.86 },
  [ACTIONS[6]]: { "x": 68.86, "y": 51.29 },
  [ACTIONS[7]]: { "x": 69, "y": 60.86 },
  [ACTIONS[8]]: { "x": 62.43, "y": 69.85 },
  [ACTIONS[9]]: { "x": 54, "y": 73 },
  [ACTIONS[10]]: { "x": 44, "y": 74.29 },
  [ACTIONS[11]]: { "x": 34.43, "y": 69.86 },
  [ACTIONS[12]]: { "x": 30.43, "y": 60.71 },
  [ACTIONS['redbutton']]: { "x": 67.71, "y": 90.43 },
  [ACTIONS['levertop']]: { "x": 92, "y": 19 },
  [ACTIONS['leverbottom']]: { "x": 93, "y": 47.71 },
  [ACTIONS['notchup']]: { "x": 89.86, "y": 56.57 },
  [ACTIONS['notchdown']]: { "x": 90.43, "y": 70.71 },
};

const NOTES = {
  lookup: {
    "C": ACTIONS[1], "c": ACTIONS[1], "1": ACTIONS[1],
    "C#": ACTIONS[2], "c#": ACTIONS[2], "Db": ACTIONS[2], "db": ACTIONS[2], "2": ACTIONS[2],
    "D": ACTIONS[3], "d": ACTIONS[3], "3": ACTIONS[3],
    "D#": ACTIONS[4], "d#": ACTIONS[4], "Eb": ACTIONS[4], "eb": ACTIONS[4], "4": ACTIONS[4],
    "E": ACTIONS[5], "e": ACTIONS[5], "5": ACTIONS[5],
    "F": ACTIONS[6], "f": ACTIONS[6], "6": ACTIONS[6],
    "F#": ACTIONS[7], "f#": ACTIONS[7], "Gb": ACTIONS[7], "gb": ACTIONS[7], "7": ACTIONS[7],
    "G": ACTIONS[8], "g": ACTIONS[8], "8": ACTIONS[8],
    "G#": ACTIONS[9], "g#": ACTIONS[9], "Ab": ACTIONS[9], "ab": ACTIONS[9], "9": ACTIONS[9],
    "A": ACTIONS[10], "a": ACTIONS[10], "10": ACTIONS[10],
    "A#": ACTIONS[11], "a#": ACTIONS[11], "Bb": ACTIONS[11], "bb": ACTIONS[11], "11": ACTIONS[11],
    "B": ACTIONS[12], "b": ACTIONS[12], "12": ACTIONS[12],
  },
  pretty: {
    [ACTIONS[1]]: "Stored Button 1 - Note C",
    [ACTIONS[2]]: "Stored Button 2 - Note C# / Db",
    [ACTIONS[3]]: "Stored Button 3 - Note D",
    [ACTIONS[4]]: "Stored Button 4 - Note D# / Eb",
    [ACTIONS[5]]: "Stored Button 5 - Note E",
    [ACTIONS[6]]: "Stored Button 6 - Note F",
    [ACTIONS[7]]: "Stored Button 7 - Note F# / Gb",
    [ACTIONS[8]]: "Stored Button 8 - Note G",
    [ACTIONS[9]]: "Stored Button 9 - Note G# / Ab",
    [ACTIONS[10]]: "Stored Button 10 - Note A",
    [ACTIONS[11]]: "Stored Button 11 - Note A# / Bb",
    [ACTIONS[12]]: "Stored Button 12 - Note B",
    [ACTIONS['redbutton']]: "Finished storing note(s) for this Notch",
    [ACTIONS['levertop']]: "Moved to Lower Octave",
    [ACTIONS['leverbottom']]: "Moved to Higher Octave",
    [ACTIONS['notchup']]: "Increased Music Length by 1",
    [ACTIONS['notchdown']]: "Decreased Music Length by 1",
  }
}

const NOTCH_LOOKUP = {
  "53.2%": 20,
  "54.02%": 19,
  "54.83%": 18,
  "55.65%": 17,
  "56.46%": 16,
  "57.28%": 15,
  "58.09%": 14,
  "58.91%": 13,
  "59.73%": 12,
  "60.54%": 11,
  "61.36%": 10,
  "62.17%": 9,
  "62.99%": 8,
  "63.81%": 7,
  "64.62%": 6,
  "65.44%": 5,
  "66.25%": 4,
  "67.07%": 3,
  "67.88%": 2,
  "68.7%": 1,
};

const TIMEOUTS = {
  "click": 450,
  "pause": 600,
  "playMusic": 750,
};

const sleep = async (delay) => {
  return new Promise((resolve, reject) => { setTimeout(resolve, delay) });
}

const click = async (target, handle = OCTAVES_POSITIONS.skip) => {
  if (!(target in COORDS)) {
    console.warn("[⚠️] Skipped invalid input: ", target);
    return;
  }

  const panel = document.querySelector("#page1panel17>.panel-background");
  const bbox = panel.getBoundingClientRect();
  const handleDown = document.querySelector("#page1panel17handle").classList.contains("down");

  if (handle == OCTAVES_POSITIONS.up && handleDown) {
    click(ACTIONS['leverbottom']);
    await sleep(TIMEOUTS.click);
  }
  else if (handle == OCTAVES_POSITIONS.down && !handleDown) {
    click(ACTIONS['levertop']);
    await sleep(TIMEOUTS.click);
  }

  panel.dispatchEvent(new MouseEvent("click", { bubbles: true, cancelable: true, view: window, clientX: bbox.left + bbox.width * COORDS[target].x / 100, clientY: bbox.top + bbox.height * COORDS[target].y / 100 }));
  console.log("  ↳", NOTES.pretty[target]);
  await sleep(TIMEOUTS.pause);
}

const clickSequence = async (seq = [[]]) => {
  for (let clickTarget in seq) {
    const [target, handle] = seq[clickTarget];

    await click(target, handle);
    await sleep(TIMEOUTS.click);
  }
}

const setNotch = async (target = 1) => {
  target = Math.min(Math.max(target, NOTCH_LIMITS.min), NOTCH_LIMITS.max);
  let notchPos = NOTCH_LOOKUP[document.querySelector("#page1panel17tick").style.top];
  let diff = notchPos - target;

  console.log("Target Music Length is", target, "Notch(es)");

  while (diff != 0) {
    if (diff > 0) {
      await click(ACTIONS['notchdown']);
    }
    else if (diff < 0) {
      await click(ACTIONS['notchup']);
    }

    notchPos = NOTCH_LOOKUP[document.querySelector("#page1panel17tick").style.top];
    diff = notchPos - target;
    await sleep(TIMEOUTS.pause);
  }

  await sleep(TIMEOUTS.pause);
  console.log("Set Music Length to", notchPos, "Notch(es)");
}

const resetState = async () => {
  let markerPos = document.querySelector("#page1panel17marker").style.top;
  let counter = 0;

  if (markerPos != "69.52%") {
    console.log("Notes were previously stored - Clearing by playing pre-existing sequence");
  }

  while (markerPos != "69.52%") {
    await click(ACTIONS['redbutton']);
    markerPos = document.querySelector("#page1panel17marker").style.top;
    counter += 1;
    await sleep(TIMEOUTS.click);
  }

  await sleep(counter * TIMEOUTS.click);
}

const chordSplitter = (music = '') => {
  return music.split(CHORD_SPLIT_SYMBOL).map(note => note.trim());
}

const parseMusicLineToArray = (music = '') => {
  if (typeof music !== 'string') {
    console.error("[🚨] Invalid line music input: ", JSON.stringify(music));
    return [];
  }

  let chords = chordSplitter(music);

  if (chords.length === 0) {
    console.error("[🚨] No valid chords found in music input: ", JSON.stringify(music));
    return [];
  }

  if (chords.length > NOTCH_LIMITS.max) {
    console.warn(`[⚠️] Too many chords found in music input!\nI'll only use the first ${NOTCH_LIMITS.max} chords then ${chords.length} incoming chords from the input.`);
    chords = chords.slice(0, NOTCH_LIMITS.max);
  }

  return chords.map(chord => {
    return chord.trim()
    .split(/\s+/)
    .map(note => {
      const noteValue = note.trim();
      return noteValue === SKIP_NOTE_SYMBOL ? null : noteValue
    })
    .filter(note => {
      const [noteValue] = note;

      if (typeof noteValue === 'undefined') {
        return true;
      }

      const baseNote = noteValue.endsWith(UPPER_OCTAVE_SUFFIX)
        ? noteValue.slice(0, -1)
        : noteValue;
      return NOTES.lookup.hasOwnProperty(baseNote);
    });
  });
}

const playMusic = async (music = [[]]) => {
  if (!Array.isArray(music) && typeof music !== 'string') {
    console.error("[🚨] Invalid music params: ", JSON.stringify(music));
    return;
  }

  if (typeof music === 'string') {
    music = parseMusicLineToArray(music);
  }

  await resetState();
  await setNotch(music.length);

  console.group(`🎼 Music playback: ${JSON.stringify(music)}`);

  for (let input in music) {
    console.log("Storing note(s) for Notch", parseInt(input) + 1);
    var sequence = [];

    for (let note in music[input]) {
      const octaveup = music[input][note].endsWith(UPPER_OCTAVE_SUFFIX);

      const item = octaveup ? NOTES.lookup[music[input][note].slice(0, -1)] : NOTES.lookup[music[input][note]];
      const octave = octaveup ? OCTAVES_POSITIONS.up : OCTAVES_POSITIONS.down;

      sequence.push([item, octave]);
    }

    sequence.push([ACTIONS['redbutton']]);
    await clickSequence(sequence);
    await sleep(TIMEOUTS.pause);
  }

  console.groupEnd();

  console.log("Pausing for", music.length * (TIMEOUTS.playMusic / 1000), "seconds to let music play");
  await sleep(music.length * TIMEOUTS.playMusic);
}

 

 

––––––––––––––––––––––––––––––––––––––
Customization
––––––––––––––––––––––––––––––––––––––

You can change the wait time in the code for calling events. For example, you have a weak internet connection and need to increase the wait time.
[WARNING]: Do not set the value too low, as Klei's servers may not be able to process your events in time. Thank you!

Timeouts:

const TIMEOUTS = {
  "click": 450,
  "pause": 600,
  "playMusic": 750,
};
  • Each number is written in milliseconds. 1 second = 1000 milliseconds.
  • “click” event – delay time for clicking on the puzzle.
  • “pause” event – delay time between events.

Specific symbols:

const UPPER_OCTAVE_SUFFIX = "^";

const SKIP_NOTE_SYMBOL = "_";

const CHORD_SPLIT_SYMBOL = "|";

Here you can configure specific characters for entering parameters for the playMusic function.
[WARNING]: This will break the input logic if:

  • Set special characters that are reserved musical notes or numbers from 1 to 12.

  • Symbols of different states (UPPER_OCTAVE_SUFFIX, SKIP_NOTE_SYMBOL, CHORD_SPLIT_SYMBOL) will have the same symbol.

  • Like 6
5 hours ago, DST enjoyer said:

Hell yeah! Btw, can we just skip the first four beats and focus on the last beat since the second sticker would show too? Once we get the second sticker, then we put them together.

I doubt it'd be that easy. If anyone just so happened to input the correct 5th note in a completely unrelated melody, it would still count as "solved" then. Besides, Nome responded, as an answer to a much similar question:

10 hours ago, Popian said:

Will it accept the final chord as 1 entry or do we have to enter the rest for every attempt?

10 hours ago, nome said:

Every attempt, sorry. It's a hack on a preexisting puzzle, I didn't want to rip out the guts of it too badly.

 

11 minutes ago, Harthur90 said:

Anyone understand where we got those numbers from? also there is something to assume that they all have a difference of 2? is this something the other elements would have?

9 7 4 4
7 5 2 2

these numbers are from wagstaff's whistling, i guess

Trying to rule out the simple interpretations. Don't bother to manually input the combinations below, which consist of 3 notes:

experiment.png.60837ede86681ad3869ff247d6c64db9.png

"643" note might not be the correct clue for the second part, and the inputs could be more or fewer than 3 notes. Although they said the fifth beat is a complex chord. Could someone figure out how many possibilities there are for the fifth beat? For the sake of knowing the maximum time needed to run a program or to copy-paste generated code#1 up to code#xxxxxx. :wilson_tranquil:

Edited by DST enjoyer
20 minutes ago, DST enjoyer said:

Trying to rule out the simple interpretations. Don't bother to manually input the combinations below, which consist of 3 notes:

experiment.png.60837ede86681ad3869ff247d6c64db9.png

"643" note might not be the correct clue for the second part, and the inputs could be more or fewer than 3 notes. Although they said the fifth beat is a complex chord. Could someone figure out how many possibilities there are for the fifth beat? For the sake of knowing the maximum time needed to run a program or to copy-paste generated code#1 to code#xxxxxx. :wilson_tranquil:

It dependes on the number of inputs 

n! / k! - (n-k)!

if we agree on 3 inputs that would be 12,144 / 6 that is equal to 2,024 combinations, but if its 4 this jumps to more than 10k



 

Another way we can interpret the 6-4-3 note is as saying we are playing 6 notes, 4 of them are with the lever up, and 3 of them are with the lever down-- currently we play 5 notes (9, 7, 5, 4, and 2) and 3 of them are in each octave (7 is played in both octaves and the rest are either in up or down). This would mean we're missing one note, which would play with the lever up.
Or maybe I'm wrong and it's something completely different

Another thing I've been considering is that the last input is 1-2-7-5 in some orientation-- look at this part of the note. It says With - For - Tu on the left, which could be interpreted as saying 1-2-7-5 comes after Four-Two (which happens to be the second-to-last note)

image.png

Edited by LavenderLillie
26 minutes ago, Harthur90 said:

It dependes on the number of inputs 

n! / k! - (n-k)!

if we agree on 3 inputs that would be 12,144 / 6 that is equal to 2,024 combinations, but if its 4 this jumps to more than 10k



 

The number of inputs is 24 different notes.

 

Meanwhile, I'll be trying the whistle with every combination from the 1-input scenario (24), the 2-input scenario (276), and the 24-input scenario (1) - Just in case.

Edited by DST enjoyer
33 minutes ago, LavenderLillie said:

Another way we can interpret the 6-4-3 note is as saying we are playing 6 notes, 4 of them are with the lever up, and 3 of them are with the lever down-- currently we play 5 notes (9, 7, 5, 4, and 2) and 3 of them are in each octave (7 is played in both octaves and the rest are either in up or down). This would mean we're missing one note, which would play with the lever up.
Or maybe I'm wrong and it's something completely different

Another thing I've been considering is that the last input is 1-2-7-5 in some orientation-- look at this part of the note. It says With - For - Tu on the left, which could be interpreted as saying 1-2-7-5 comes after Four-Two (which happens to be the second-to-last note)

image.png

NOTES (5 total): 9, 7, 5, 4, 2, [ 6th = ? ]

(4) ^  (9) (7) (4) (?)
(3) v  (7) (5) (2)

 i - U D
1 - 9  7
2 - 7  5
3 - 4  2
4 - 4  2 
5 - X  Y

By my friend logic Y must be 7, 5 or 2?
and X could be 1, 3, 6 or 8 ?

Edited by jgog8
7 minutes ago, Grifffffffff said:

how do i input this?

Lever up then 9th button on the dial, then pull the lever down and press 7. Then press red button and take the lever up and press 7 then lower the lever and press 5 then red button and so on.

I can try to make a recording if u want if you don't understand what I mean.

Edited by MrKoopa
Forgot to add something
2 minutes ago, MrKoopa said:

Lever up then 9th button on the dial, then pull the lever down and press 7. Then press red button and take the lever up and press 7 then lower the lever and press 5 then red button and so on.

I can try to make a recording if u want if you don't understand what I mean.

ya a recording would be really helpful

1 minute ago, Baark0 said:

why on earth would you use a gif to showcase this?

What's the problem? It shows what you need to do. I was going to make a youtube video, but then I remember I had a tool that can record the screen and make a gif so I decided to use that instead.

 

  • Health 2

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
  • Create New...