JavaScript Function not being recognized

Twine Version: 2.7.1
SugarCube Version: 2.36.1

I am having an issue getting Twine to recognize my JavaScript Function. I have looked at similar posts on the board and I’ve tried using the “setup” built into SugarCube. It’s stillnot working. I get reference errors stating that “setup is not defined”.

I’m trying to create an escape room type game where the player has to answer math questions to escape “Math Mansion”. (I’m a Math teacher btw.)

I want a reusable function in javascript that checks the answers to systems of equations but I keep getting the *** function not defined error. I’m currently using Twine 2.7.1 and SugarCube 2.36.1. (I have attempted several iterations and several builds including Harlowe and SnowMan with varying function names)

The passage where I attempt to call the javascript is:

::Solution1

X-coordinate: <input type="text" id="userAnswerX" placeholder="Enter x">
Y-coordinate: <input type="text" id="userAnswerY" placeholder="Enter y">

<button onclick="setup.checkAnswer(setup.correctX1, setup.correctY1, 1)">Submit</button>

And the “Story JavaScript” is as follows:

//Declare and initialize user input variables for x and y
setup.correctX1 = 2;
setup.correctY1 = 0.6;
setup.score = 0;
setup.penalty = 0;
setup.attempts = 0;

// Functions defined below
setup.checkAnswer = function checkAnswer(correctX, correctY, qID) {
  do {
    // Get the user's input for x and y and convert to floats
    var userInputX = parseFloat(document.getElementById("userAnswerX").value);
    var userInputY = parseFloat(document.getElementById("userAnswerY").value);

    // Define a tolerance for comparison to handle decimal precision
    var tolerance = 0.01; // You can adjust this value as needed

    // Check if both x and y are within an acceptable range
    if (Math.abs(userInputX - correctX) < tolerance && Math.abs(userInputY - correctY) < tolerance) {
      setup.attempts = 0; // Reset attempts on correct solution
      setup.score++; // Add a point to questions answered correctly
      // If correct, guide to the next passage
      State.history.go("Jbox");
    } 
    else {
      setup.attempts++; // Add one to the number of failed attempts
      setup.penalty++; // Add one to the total number of incorrect solutions
      // If incorrect, display a message
      alert("Sorry, that's not correct. Please try again.");
      // Clear the input fields (optional)
		document.getElementById("userAnswerX").value = "";
		document.getElementById("userAnswerY").value = "";
     }
    }while (attempts < 5);

  // If the player exceeds the allowed attempts, you can handle it accordingly
  switch (qID) {
    case 1:
      alert("You've exceeded the allowed attempts. A trap door has dropped you into a dungeon.");
      State.history.go("Dungeon");
      break;
    case 2:
      alert("You've exceeded the allowed attempts. Sadly, your fate has been sealed.");
      State.history.go("Death");
      break;
  }
}

I have some programming experience but I’m very out of practice.

Thanks for any help.

The problem here is your onclick handler, which does not see setup.

The idiomatic way to write your passage would be:

:: Solution1

X-coordinate: <input type="text" id="userAnswerX" placeholder="Enter x">
Y-coordinate: <input type="text" id="userAnswerY" placeholder="Enter y">

<<button "Submit">>
    <<run setup.checkAnswer(setup.correctX1, setup.correctY1, 1)>>
<</button>>

Even then, I think you’d find it easier to use SugarCube’s built in <<textbox>> macro, which would save you needing to trying to look up the elements directly.

1 Like

I like your solution and will explore it. I have found a few workarounds since my original post. I don’t like the solution I came up with but I do like that it appears to be working. Here is my latest update:

//Declare and initialize solution and tracking variables
window.correctX1 = 2;
window.correctY1 = 0.6;
window.score = 0;
window.penalty = 0;
window.attempts = 0;

// Variable to track the next passage
var nextPassage = "Jbox";

// Functions defined below
window.checkAnswer = function checkAnswer (correctX, correctY, qID) {
  do {
    // Get the user's input for x and y and convert to floats
    var userInputX = parseFloat(document.getElementById("userAnswerX").value);
    var userInputY = parseFloat(document.getElementById("userAnswerY").value);

    // Define a tolerance for comparison to handle decimal precision
    var tolerance = 0.01; // You can adjust this value as needed

    // Check if both x and y are within an acceptable range
    if (Math.abs(userInputX - correctX) < tolerance && Math.abs(userInputY - correctY) < tolerance) {
      window.attempts = 0; // Reset attempts on correct solution
      window.score++; // Add a point to questions answered correctly
      // If correct, guide to the next passage
      qID = 0; //allow for alternate redirects for correct answers
      nextPassage = "Jbox";
    } 
    else {
      window.attempts++; // Add one to the number of failed attempts
      window.penalty++; // Add one to the total number of incorrect solutions
      // If incorrect, display a message
      alert("Sorry, that's not correct. Please try again.");
      // Clear the input fields
		document.getElementById("userAnswerX").value = "";
		document.getElementById("userAnswerY").value = "";
      nextPassage = "Solution1";
     }
    }while (window.attempts < 5 && window.attempts>0);

  // If the player exceeds the allowed attempts, you can handle it accordingly
  switch (qID) {
    case 1:
      alert("You've exceeded the allowed attempts. A trap door has dropped you into a dungeon.");
      nextPassage = "Dungeon";
      break;
    case 2:
      alert("You've exceeded the allowed attempts. Sadly, your fate has been sealed.");
      nextPassage = "Death";
      break;
    default:
      break;/*exit the switch without doing anything.  redirects should have happened elsewhere in the script.  Remain in current passage if not redirected elsewhere.*/
  }
  Engine.play(nextPassage);
}

I don’t love reverting to the window.* construct but it appears to be functioning.

Thank you for explaining why setup wasn’t recognized in the event handler.

I’m new to Twine so I will have to explore the <<textbox>> macro.