HiEv's system to import JS scripts error

I tried using the system HiEv created to import some scripts from the game folder, but that doesn’t seem to work.

setup.Path = "scripts/";
setup.JSLoaded = false;
importStyles(setup.Path + "default.css");
importScripts(setup.Path + "macros.js")
	.then(function() {
		setup.JSLoaded = true;
	}).catch(function(error) {
		alert("Error: Could not find file 'macros.js'.");

As current written, the example you provided will only work if you have:

  1. generated and saved a story HTML file. (via the “Publish to File” option of the Twine 2.x application if you are using it)
  2. your default.css & macros.js files are stored within a “scripts” folder that a child folder of whichever location you saved the story HTML to.

eg. A folder/file structure something like the following, assuming the project was named “adventure” and that you saved the generated story HTML file within a folder of the same name…
(Windows example)


How do you know it didn’t work? What exactly does or doesn’t happen?

warning: As explained within the SugarCube documentation, those functions load the referenced external files asynchronously, which means that the contents of the StoryInit special passage and of your project’s main passage may be processed before the contents of those external files have finished loading. You may need to use the LoadScreen API to delay the processing of those passages.

In addition to what Greyelf mentioned, I’ve seen three other problems happen when doing things that way.

  1. Having scripts in a folder other than the one the HTML file is in may cause a CORS (Cross-Origin Resource Sharing) security error in some browsers when working with local files. If it does then you’ll be able to see that error in your browser’s console window. Because of this, if the game is going to be played locally (files on the user’s computer, as opposed to on the Internet), I recommend having all scripts in the same folder as the HTML file.
  2. I note that your file is named “macros.js”, so if there are any references to SugarCube functions in it, then, for example, instead of “Macro.add(...” you’ll likely need to use code like “SugarCube.Macro.add(...” instead, since that code isn’t in the same scope anymore, which means that you’ll have to directly reference SugarCube like that.
  3. If you’re using Internet Explorer, it may not like the files anyways, unless the correct permissions are set for the files. To fix this, create a text file called “IESecurityFix.bat” and put the following inside of it:
cd %~dp0
icacls *.* /setintegritylevel L
  1. (continued) Copy that .BAT file to any directory your game is loading files from (including images, etc.), right-click on it, and choose “Run as Administrator” in each of those directories, and it will fix the file permissions so that Internet Explorer will allow access to those files.

If you want your code to work when launched from Twine, as well as the published HTML file, I’d recommend modifying it like this:

if (window.hasOwnProperty("storyFormat") || document.location.href.toLowerCase().includes("/temp/")) {
	// Change this to the path where the HTML file is
	// located if you want to run this from inside Twine.
	setup.Path = "C:/Games/MyGame/";  // Running inside Twine application
} else {
	setup.Path = "";  // Running in a browser
setup.SoundPath = setup.Path + "sounds/";
setup.ImagePath = setup.Path + "images/";

setup.JSLoaded = 0;  // setup.JSLoaded == 0 means the JavaScript isn't loaded yet
var lockID = LoadScreen.lock();  // Lock loading screen
importStyles(setup.Path + "default.css");
importScripts(setup.Path + "macros.js")
	.then(function() {
		var tmp = setup.JSLoaded;  // setup.JSLoaded == 1 means reload the passage after the JavaScript has loaded
		setup.JSLoaded = 2;  // setup.JSLoaded == 2 means the JavaScript has loaded
		if (tmp == 1) {
			Engine.show(passage());  // Reloads current passage to trigger code
		/* Put any code here which needs to be triggered initially after macro.js is loaded. */
		LoadScreen.unlock(lockID);  // Unlock loading screen
	}).catch(function(error) {
		alert("Error: Could not find file 'macros.js'.");

You’ll need to change “C:/Games/MyGame/” to the path to your game’s HTML file (note that using “\” may break things, you should use “/” instead). Also, if you aren’t working on Windows, then you’ll likely need to change “/temp/” to something else in the default URL path you get when launching from Twine.

If you have any code in your JavaScript section which needs to call code from the “macros.js” file, but is triggered by a passage being displayed, you’ll need to set it up like this:

$(document).on(":passagerender", function (event) {
	if (setup.JSLoaded < 2) {  // External JavaScript files haven't loaded yet.
		setup.JSLoaded = 1;  // Waits for external JavaScript to load, which will trigger a reload of the current passage to activate this section again.
	} else {
		/* Your ":passagerender" code here. */

And that should do the trick!

Hope that helps! :slight_smile: