Revision of Twine: visited(), a function to find how often a passage was visited from Wed, 12/11/2013 - 03:02

Update: The Javascript on this page is now built into Twine 1.4! It is no longer necessary to install it.

I've noticed that a good deal of variable usage in Twine is simply employed to track whether or not you've visited a certain passage previously, or done so a number of times. This script code provides you with a function that can give this value straight, without needing to use the <<set>> macro.

window.visited = function(e) {
	var ret,c;
	e || (e = state.history[0].passage.title);
  	for(ret=c=0; c<state.history.length; c++) {
		if(state.history[c].passage && state.history[c].passage.title == e) {
			ret++;
		}
	}
	return ret;
}

To use it, use "visited("Passage")" as a value in a <<set>>, <<if>> or <<print>> macro. It will equal the number of times you've visited the passage whose name is between the quotes and parentheses. For instance:

  1. <<if visited("Store")>>You've been to the store.<<endif>>
  2. <<if not visited("Firepit") and not visited("Maggotpit")>>You've not yet been to the fire pit or maggot pit.<<endif>>
  3. <<if visited("Trap Floor") gt 2>>Your repeated stomping is making the floor weaken.<<endif>>
  4. You've visited the chasm <<print visited("Dark Chasm")>> times.<<endif>>
  5. <<set $count = visited("Jewelers")>>You've visited the Jeweler's <<print $count>> times.<<endif>>

Also, instead of a passage name, you can put a variable.
  1. <<if visited($bossPassage)>>If only you'd had this when you'd fought the boss!<<endif>>
  2. <<set $beenToMyHome = visited($myHome)>>

New: If you just put visited(), then it will count visits to the current passage, without you needing to include the passage's name.
<<set $beenHereBefore = visited()>>

In addition, here is a function called "visitedbefore" which can be used to tell you if a passage has ever, in the course of the game, been visited before another passage.

window.visitedbefore = function(e,f) {
	var h,c,ret;
  	for(ret=c=0; c<state.history.length; c++) {
		h = state.history[c].passage;
		if(h && h.title == e) {
			return true;
		} else if (h && h.title == f) {
			return false;
		}
	}
	return false;
}

This only returns true or false. Use it like so:
  1. <<if visitedbefore("Firepit", "Maggotpit")>>First the fire pit, then the maggot pit, now this?!<<endif>>
  2. <<if visited("Armory") and visitedbefore("Firepit", "Maggotpit")>>First the fire pit, then the maggot pit, now this?!<<endif>>

Again, variables can be substituted for passage name strings:
  1. <<if visitedbefore("Dragon Hoard", $myHome)>>You must've left it at home after meeting the dragon.<<endif>>

The two passage names must be separated by a comma.

Some notes:

  1. This doesn't count use of the <<display>> macro as a visit.
  2. If neither passage has been visited, visitedbefore() will return false.

Feel free to report any bugs to @webbedspace.

pensive-mosquitoes