Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Error: cannot execute macro : Cannot read property 'length' of undefined

edited April 2017 in Help! with 1.x
I need some help with a script i'm attempting to use from this site : http://strugglingwithtwine.blogspot.co.uk/2014/03/strategy-games.html

It gives me the error message: Error: cannot execute macro <<summary>>: Cannot read property 'length' of undefined

I've played around with it and can't seem to work out whats wrong, help? Using Twine 1 and sugarcube.

Full script:

var turn, knights, peasants, gold, banditRisk;

window.init = function() {
turn = 0;
knights = 0;
gold = 100;
peasants = 50;
banditRisk = 50;
}

var banditRisks = [
"-",
"Some concern among the peasants about bandits in the hills",
"Some peasants are claiming there are bandits in the hills",
"Bandits have been seen in the area",
"The bandits are becoming bolder",
"The bandits have killed a couple of peasants; your people are demanding action",
"The bandits have killed a large number of peasants, and are threatening the castle",
"The bandits have overrun the castle",
];


window.nextTurn = function() {
turn++;
gold += (state.active.variables.peasants * 2);
gold -= (state.active.variables.knights * 20);
// Knights quit if there is no gold for them
if (gold < 0) {
knights += (gold / 20);
if (knights < 0) {
knights = 0;
}
}
// handle bandits
banditRisk += (peasants * 2);
banditRisk -= (knights * 5);
if (banditRisk < 0) banditRisk = 0;
}

window.banditFail = function() {
return (Math.round(banditRisk / 60) >= (banditRisks.length - 1));
}


window.recruitKnight = function() {
knights++;
gold -= 50;
}


macros.summary = {
handler: function(place, macroName, params, parser) {
var s = '';
s += "Turn: " + turn;
s += "\nKnights: " + knights;
s += "\nPeasants: " + peasants;
s += "\nGold: " + gold;
new Wikifier(place, s);
if (banditFail()) {
new Wikifier(place, banditRisks[banditRisks.length - 1]);
} else {
new Wikifier(place, banditRisks[Math.round(state.active.variables.banditRisk / 60)]);
}
},
};

Comments

  • edited April 2017
    First. You should always state the story format you're using and its full version, because advice will tend to vary based on that information. Also, please use the code tag when posting code or markup—it's C on the editor bar.

    For the moment, I'm going to assume you're using some version of SugarCube v2—because, frankly, you should be.


    Aside from being shoddily written—no offense to the author, but it is what it is—they make a fundamental mistake right at the beginning.
    We are going to be doing a lot of coding, and I would really rather not have to type "state.active.variables." every time, so for this game we will be using variables that are local to the script passage.
    In general, you should never do that with non-static data. Any values that you plan to modify from turn to turn and want to a) be available within normal markup and TwineScript and b) be recorded by saves must be stored within story variables. That said, static data—i.e. values that will never change over the course of the story/game—are better kept outside of story variables, however, that's not what we're dealing with here for the most part—only the banditRisks array really fits the criteria.

    There are various other bad practices and outright errors within—e.g. attempting to use story variables they haven't defined, rather than the local variables they did; though, again, never do that for non-static data.


    As to the actual error you're receiving. The error is coming from the <<summary>> macro, specifically from an access to banditRisks.length. There are two such accesses within the macro, from the following lines:
    if (banditFail()) {
    new Wikifier(place, banditRisks[banditRisks.length - 1]);
    
    Assuming the code you posted is the actual code you're using, I see no reason for the error. The local banditRisks variable has been declared, and assigned an array, by that point and both the banditFail() function and <<summary>> macro's handler() method should capture it as they're within the same scope—thus it should not be undefined.

    Either you've left something out of your description or something very odd is going on. What browser—include its version—are you using?


    Regardless. Here's a version of the script, written specifically for SugarCube v2, which addresses all of the big ticket issues:
    (function () {
    	'use strict';
    
    	/*
    		Set up static data.
    	*/
    	var banditRisks = [
    		'-',
    		'Some concern among the peasants about bandits in the hills.',
    		'Some peasants are claiming there are bandits in the hills.',
    		'Bandits have been seen in the area.',
    		'The bandits are becoming bolder.',
    		'The bandits have killed a couple of peasants; your people are demanding action.',
    		'The bandits have killed a large number of peasants, and are threatening the castle.',
    		'The bandits have overrun the castle.'
    	];
    
    
    	/*
    		Set up global utility functions.
    	*/
    	window.init = function () {
    		var sv = State.variables;
    
    		sv.turn = 0;
    		sv.knights = 0;
    		sv.gold = 100;
    		sv.peasants = 50;
    		sv.banditRisk = 50;
    	};
    
    	window.nextTurn = function () {
    		var sv = State.variables;
    
    		sv.turn++;
    		sv.gold += sv.peasants * 2;
    		sv.gold -= sv.knights * 20;
    
    		// Knights quit if there is no gold for them
    		if (sv.gold < 0) {
    			sv.knights += Math.round(sv.gold / 20);
    
    			if (sv.knights < 0) {
    				sv.knights = 0;
    			}
    		}
    
    		// Handle bandits
    		sv.banditRisk += sv.peasants * 2;
    		sv.banditRisk -= sv.knights * 5;
    
    		if (sv.banditRisk < 0) {
    			sv.banditRisk = 0;
    		}
    	};
    
    	window.recruitKnight = function () {
    		var sv = State.variables;
    
    		sv.knights++;
    		sv.gold -= 50;
    	};
    
    	window.banditFail = function () {
    		return Math.round(State.variables.banditRisk / 60) >= banditRisks.length - 1;
    	};
    
    
    	/*
    		Set up macros.
    	*/
    	Macro.add('summary', {
    		handler : function () {
    			var sv = State.variables;
    
    			$(this.output).wiki(
    				'Turn: $turn\n' +
    				'Knights: $knights\n' +
    				'Peasants: $peasants\n' +
    				'Gold: $gold\n\n'
    			);
    
    			if (banditFail()) {
    				$(this.output).wiki(banditRisks[banditRisks.length - 1]);
    			}
    			else {
    				$(this.output).wiki(banditRisks[Math.round(sv.banditRisk / 60)]);
    			}
    		}
    	});
    })();
    
Sign In or Register to comment.