antimarty fortune cookie script

Kingdom of Loathing fortune cookie tracker

Você precisará instalar uma extensão como Tampermonkey, Greasemonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Userscripts para instalar este script.

Você precisará instalar uma extensão como o Tampermonkey para instalar este script.

Você precisará instalar um gerenciador de scripts de usuário para instalar este script.

(Eu já tenho um gerenciador de scripts de usuário, me deixe instalá-lo!)

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

(Eu já possuo um gerenciador de estilos de usuário, me deixar fazer a instalação!)

// antimarty's fortune cookie script, based in part on:
// csemaj's KoL Script 
//     Copyright (c) 2007, James Cammarata
//     Based on code written by Byung Kim (Tard) http://kol.dashida.com and OneTonTomato's scripts
// toggle preference code from lukifer's mrscript
//	   http://www.noblesse-oblige.org/lukifer/scripts/
// script update code based on DrEvi1's hatrack helper, which credits Picklish
// fixes for lag combatting inventory screens by Firvagor
// now using Charon's account options tab code
// Released under the GPL license
// http://www.gnu.org/copyleft/gpl.html
//
// ==UserScript==
// @name		   antimarty fortune cookie script
// @namespace	   antimarty
// @include		   *kingdomofloathing.com/*.php*
// @include		   *127.0.0.1:600*/*.php*
// @include		   *localhost:600*/*.php*
// @include		   localhost:18481/*.php*
// @version		   0.5.8
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_xmlhttpRequest
// 
// @description	   Kingdom of Loathing fortune cookie tracker
// ==/UserScript==

// released versions:
// Version 0.5.7 - clan speakeasy, new topmenu frame rearrangement, gm grant stuff, move to Greasy Fork
// Version 0.5.5 - kolhs semis; red fox; bram the stoker
// Version 0.5.4 - new undersea SRs
// Version 0.5.3 - new giant castle SRs, fix oxygenarian detection
// Version 0.5.2 - updated for new level 8 and level 9 semis, and typo for friars
// Version 0.5.1 - new hidden temple semi rare
// Version 0.5.0 - add last location info to char pane if no popups
// Version 0.4.9 - bug fix for deep fat friars' adventure name
// Version 0.4.8 - bug fix for auto-attack combat macros, change version check
// Version 0.4.7 - add disable popups option as FF4 workaround
// Version 0.4.6 - bug fix for noncombat semis
// Version 0.4.5 - Show initial bracket for new ascension, bug fix for puttied/faxed/arrow'd SR monsters
// Version 0.4.4 - ascii, kge fights from fax/putty/camera/arrowing aren't semis; support new options page
// Version 0.4.3 - add elf alley semi
// Version 0.4.2 - add the pixel stopwatch
// Version 0.4.1, use the turnsplayed native counter
// Version 0.4.0, display a predicted cookie window if no cookie eaten
// Version 0.3.9, support for billiards room semi
// Version 0.3.8, sanity check numbers when user loads charsheet
// Version 0.3.7, misc bug fixes
// Version 0.3.6, fixes (courtesy Firvagor) for crimbo anti-lag changes to inventory screens; clear counter after semi-rare
// Version 0.3.5, filter impossible cookie values; check for updates automatically
// Version 0.3.4, support for hobopolis adventures
// Version 0.3.3, bugfixes encore
// Version 0.3.2, bugfixes
// Version 0.3.1, bugfixes
// Version 0.3.0, remember most recent semi-rare. Re-fix bugs re-introduced in 0.2.6
//     for unascended chars and compact mode, thanks to bad version control.
// Version 0.2.6, reduced overhead, and bug fixes
// Version 0.2.5, compact mode support and support for unascended chars
// Version 0.2.3, improved sanity checker
// Version 0.2.0, includes sanity checker
// Version 0.1.1, bugfixes
// Version 0.1.0 initial beta

// Known bugs:
// doesn't work in the kolmafia relay browser if you have this option set:
//	 [] Force results to reload inline for [use] links
// ... because the results page never reloads, so greasemonkey scripts don't run
// may not save data correctly if Firefox doesn't exit cleanly (Greasemonkey issue)

// basic logic to do this without retrieving character pane data:
// - store an internal counter for adventures used
// - look at the adventures remaining
// - every time the pane is refreshed:
//	 - if the remaining adventures decreases, decrease the counter by that amount
//	 - if stays the same, do nothing
//	 - if increases, do nothing
// warn when hit zero
//
// read char sheet as a sanity check when the counter doesn't seem to be
// decrementing normally

// (temporarily?) unused, with move to Greasy Fork
/* var currentVersion = "0.5.7";
var scriptSite = "http://userscripts.org/scripts/show/13180"
// this is autogenerated by userscripts.org from Userscript @ comments above, use to reduce bandwidth on version check
var scriptURL = "http://userscripts.org/scripts/source/13180.meta.js";  
 */
////////////////////////////////////////////////////////////////////////////////
// Based on a function taken from OneTonTomato's UpUp skill script
function GM_get(target, callback) {
   GM_xmlhttpRequest({
	  method: 'GET',
	  url: target,
	  onload:function(details) {
		 if( typeof callback=='function' ){
			callback(details.responseText);
		 }
	  }
   });
}

// Check version number of script on the web
function CheckScriptVersion(data)
{
// alert("inside version check");
    // Preemptively set error, in case request fails...
    GM_setValue("webVersion", "Error")

	var m = data.match(/@version\s*([0-9.]+)/);
	if (m)	{
		GM_setValue("webVersion", m[1]);
	}
}

////////////////////////////////////////////////////////////////////////////////
// parse the char pane for the player name
// revised version! now taken directly from kolpreviousnadventures to handle compact mode
function getPlayerNameFromCharpane() {
	var username = document.getElementsByTagName("b");
	if (!username || username.length < 1) return false;
	username = username[0];
	if (!username) return false;
	username = username.firstChild;
	if (!username) return false;
	// in full mode the link is <a><b>Name</b></a>
	// in compact mode it's <b><a>Name</a></b>
	// so have to handle this, and also can use it to tell
	// whether it's in compact mode or not.
	var fullmode = true;
	while (username && username.nodeType == 1)
	{
		username = username.firstChild;
		fullmode = false;
	}
	if (!username) return false;
	username = username.nodeValue;
	if (!username) return false;
	username = username.toLowerCase();
//	alert("found username " + username + ", fullmode: " + fullmode);
	return {'username': username, 'fullmode': fullmode};
}

////////////////////////////////////////////////////////////////////////////////
// parse the char sheet (not the sidepane) for the player name
function getPlayerNameFromCharsheet(data) {
	// it's an href with syntax something like 
	// showplayer.php?who=PlayerID">PlayerName</a>
	var playerName = /showplayer\.php\?who\=\d+\">([^<]+)<\/a/i.exec(data);  // sometimes this fails, don't know why
	if(playerName)
		return playerName[1].toLowerCase();
	else
		return null;
}

////////////////////////////////////////////////////////////////////////////////
// parse the char sheet (not pane) for the total adventure count
// taken from the csemaj cookie script
// the "(this run)" only appears if you have ascended 
function getTurnsPlayed(data) {
	var turncount = "0";
	if(data.indexOf("Turns Played (this run)") >= 0) {
// alert("parsing datasheet for turns for an ascended char");
		turncount = /Turns Played \(this run\)[^>]*>(<[^>]+>)*([\d,]+)/i.exec(data)[2];
	}
	else {
// alert("parsing datasheet for turns for an UNascended char");
		turncount = /Turns Played[^>]*>(<[^>]+>)*([\d,]+)/i.exec(data)[2];
	}
// alert("found turncount=" + turncount);
	return parseInt(turncount.replace(',',''),10);
}

function getDaysPlayed(data) {
	var dayCount = 0;
	if(data.indexOf("Days Played (this run)") >= 0) {
// alert("parsing datasheet for days for an ascended char");
		dayCount = /Days Played \(this run\)[^>]*>(<[^>]+>)*([\d,]+)/i.exec(data)[2];
	}
	else {
// alert("parsing datasheet for days for an UNascended char");
		dayCount = /Days Played[^>]*>(<[^>]+>)*([\d,]+)/i.exec(data)[2];
	}
// alert("found dayCount=" + dayCount);
	return parseInt(dayCount.replace(',',''),10);
}

// parse the charpane info for the password hash (use as a session ID)
function getPwdHash(data){
    var pwdHash = /pwdhash \= \"(.*?)\"/i.exec(data)[1]; // the .*? is the non-greedy version of .*

// alert("got pwdHash: " + pwdHash);
	return pwdHash;
}

// parse the charpane info for the turnsplayed counter
// updates at the end of the adventure, not during the fight
function getTurnsplayedVar(data){
    var turnsplayed = /turnsthisrun \= (\d+)/i.exec(data)[1];

	return parseInt(turnsplayed);
}

////////////////////////////////////////////////////////////////////////////////
// parse the main page for the name of the (noncombat) adventure - assuming 
// it's the next bolded thing after "Adventure Results:"
function getAdventureName(data) {
    var adventureName = "";
    if ( data.indexOf( "Adventure Results:" ) != -1 ) {   // kol mafia can put up stuff that requires this check
        adventureName = /Results:<\/b>.*?<b>(.*?)<\/b>/i.exec(data)[1];
    }
    // the hobopolis rares are choice adventures, not normal noncombats
    else if(document.location.pathname.indexOf("choice.php") != -1) {
	// look for adventure name as something in bold on blue background
        adventureName = /bgcolor=\"blue\"><b>(.*?)<\/b>/i.exec(data)[1];
    }
	
	// check for known broken adventures
	if(adventureName == "") {
		if(data.indexOf( "There once was a bleary-eyed cyclops" ) != -1 ){
			adventureName = "The Bleary-Eyed Cyclops";
		}
	}

// alert("got adventure name: " + adventureName);
    return adventureName;
}

////////////////////////////////////////////////////////////////////////////////
// parse the main page for the name of the adventure
function getMonsterName(data) {
	var monsterName = /id=\"monname\"> *(.*?)<\/span>/i.exec(data);
	if(monsterName) 
		monsterName = monsterName[1].toLowerCase();
	else 
		return {'monsterName': "", 'fromPutty': false};
	
	// don't count monsters from putty/fax/camera/arrowing
	var fromPutty = data.indexOf("You put the copied monster on the ground") != -1 ? true : false;
	if(!fromPutty)
		fromPutty = data.indexOf("You gaze at the photocopy") != -1 ? true : false;
	if(!fromPutty)
		fromPutty = data.indexOf("You reach down to open up the camera") != -1 ? true : false;
	if(!fromPutty)
		fromPutty = data.indexOf("hear a wolf whistle from behind you") != -1 ? true : false;
	if(!fromPutty)
		fromPutty = data.indexOf("You play back the recording") != -1 ? true : false;
	if(!fromPutty)
		fromPutty = data.indexOf("%%") != -1 ? true : false;  // some sort of error we see a lot with copied monsters
		
//  alert("got monster name: *" + monsterName + "*; from putty = " + fromPutty);
	return {'monsterName': monsterName, 'fromPutty': fromPutty};
}

// process a noncombat result for semi-rareness
var semis =
{
  noncombats: {
	"Play Misty For Me"		:	"the Haunted Kitchen",
	"Like the Sunglasses, But Less Comfortable"	:	"the Haunted Library",
	"The Pilsbury Doughjerk"	:	"the Haunted Pantry",
	"The Bleary-Eyed Cyclops"	:	"the Limerick Dungeon",  // I don't see the title appear when I get this adv.
	"In the Still of the Alley"	:	"the Sleazy Back Alley",
	"Natural Selection"		:	"the Goatlet",
	"Not Quite as Cold as Ice"	:	"the Lair of the Ninja Snowmen",
	"Prior to Always"		:	"a Battlefield",
	"How Does He Smell?"		:	"the Batrat and Ratbat Burrow",
	"All The Rave"			:	"the Castle Top Floor",
	"Le Chauve-Souris du Parfum"	:	"Guano Junction",
	"Hands On"			:	"the Harem",
	"You Can Top Our Desserts, But You Can't Beat Our Meats" :	"the Laboratory",
	"Rokay, Raggy!"			:	"the Menagerie Level 2",
	"A Menacing Phantom"		:	"the Misspelled Cemetery",
	"Lunchboxing"			:	"the Outskirts of Cobb's Knob",
	"Filth, Filth, and More Filth"	:	"South of the Border",
	"It's The Only Way To Be Sure"	:	"the Deep Fat Friars",
	"It's the Only Way to be Sure"	:	"Pandamonium slums",
	"Two Sizes Too Small"		:	"the Hidden City",
	"Some Bricks Do, In Fact, Hang in the Air"  :	"the Inexplicable Door",
	"Blaaargh! Blaaargh!"		:	"the Spooky Forest",
	"Monty of County Crisco"	:	"Whitey's Grove",
	"The Latest Sorcerous Developments"	:	"the Hippy Camp (pre-war)",
	"Sand in the Vaseline"		:	"the Orcish Frat House (pre-war)",
	"Yo Ho Ho and a Bottle of Whatever This Is"	:	"the Obligatory Pirate's Cove",
	"A Tight Squeeze"		:	"BurnBarrel Blvd.",
	"Cold Comfort"			:	"Exposure Esplanade",
	"Juicy!"			:	"the Heap",
	"Flowers for You"		:	"the Ancient Hobo Burial Ground",
	"Maybe It's a Sexy Snake!"	:	"the Purple Light District",
	"What a Tosser"				:	"Elf Alley",
	"A Shark's Chum"			:	"The Haunted Billiards Room",
	"The Time This Fire"		:	"Vanya's Castle Chapel",
	"Oh, <i>There</i> Have it Gone" : "A-Boo Peek",
	"Synecdoche, Twin Peak"	: "Twin Peak",
	"It's a Gas Gas Gas"	: "Oil Peak",
	"Fit and Finish"		: "the Castle Basement",
	"Ahead of the Game"		: "the Castle Ground Floor",
	"Razor, Scooter"		: "the Dive Bar",
	"Deeps Impact"			: "the Briny Deeps",
	"The Haggling"			: "the Brinier Deepers",
	"Camera On, James"		: "the Wreck of the Edgar Fitzsimmons",
	"Dragon the Line"		: "Madness Reef",
	"A Drawer of Chests"	: "the Mer-Kin Outpost",
	"Through the Locking Glass"	: "the Hallowed Halls",
	"Clay Is Great, But Leather Is Bether" : "Ye Olde Medievale Villagee",
	"Where There's Smoke...":	"The Copperhead Club",
	"Methinks the Protesters Doth Protest Too Little": "A Mob of Zeppelin Protesters",
	// fake ones for testing
//	"A Dash of Boulder"		:	"the Dungeons of Doom - Boulder",
//	"Meat Score!"			:	"the Treasury - Meat Score",
	
  },
  combats: {  // use lowercase
	"some bad ascii art"		:	"the Valley Beyond The Orc Chasm",
	"a knob goblin elite guard captain" : 	"the Cobb's Knob Kitchens",
	"a knob goblin embezzler" 	:	"the Treasury",
	"a c. h. u. m. chieftain"	: 	"a Maze of Sewer Tunnels",
	"baa'baa'bu'ran"			:	"the Hidden Temple",
	"a 7-foot dwarf foreman" 	: "Itznotyerzitz Mine",
	"a moister oyster"			: "An Octopus's Garden",
	"françois verte, art teacher" : "Art Class",  // some encoding issue with this one
	"x-fingered shop teacher" : 	"Shop Class", // need to resolve the X (1-11)
	"mrs. k, the chemistry teacher"	: "Chemistry class",
	"the red fox"	: "The Red Zeppelin",
	"bram the stoker" : "The Haunted Boiler Room",
	"a full-length mirror" : "The Haunted Storage Room",
	// fake ones for testing
//	"a knob goblin elite guardsman"	:	"the Treasury",
//      "a swarm of killer bees"	:	"the Dungeons of Doom",
  },
};	  

function clearCounters(playerName) {
		GM_setValue(playerName+"_lastSemiTurn",-1);
		GM_setValue(playerName+"_lastSemiLocation","");
		
		GM_setValue(playerName+"_luckyTurn1", -1);
		GM_setValue(playerName+"_luckyTurn2", -1);
		GM_setValue(playerName+"_luckyTurn3", -1);
}

function checkForNoncombatSemi(data) {
	theAdv = getAdventureName(document.body.innerHTML);
// alert("in checkForNoncombatSemi(), adv name = " + theAdv);
// alert("semis.noncombats[theAdv] = " + semis.noncombats[theAdv]);
	
	if(semis.noncombats[theAdv] != undefined) {
		var playerName = GM_getValue("currentPlayer"); 
		var turncount = GM_getValue(playerName+"_turncount", 0);
//		var turncount = getTurnsplayedVar(top.frames[0].document);

// alert("Found semirare adv \'" + theAdv + "\' in area " + semis.noncombats[theAdv] + " on tuncount " + turncount + " for player " + playerName);
		// found a semi, clear counters
		// this might backfire if using the counter as a generic countdown for other purposes, e.g. wossname tracking
		clearCounters(playerName);

		GM_setValue(playerName+"_lastSemiTurn",turncount+1);  // the turncount var isn't updated yet
		GM_setValue(playerName+"_allowBracket",true);
		GM_setValue(playerName+"_lastSemiLocation",semis.noncombats[theAdv]);

		// trigger char pane refresh with the new info
		top.frames[0].location.reload();
	}
}

function checkForCombatSemi(data) {
	var monster = getMonsterName(document.body.innerHTML);
	theAdv = monster.monsterName; 

	if(monster.fromPutty == false && semis.combats[theAdv] != undefined) {
		var playerName = GM_getValue("currentPlayer"); 
		var turncount = GM_getValue(playerName+"_turncount", 0);
//		var turncount = getTurnsplayedVar(top.frames[0].document);

// alert("Found semi rare adv \'" + theAdv + "\' in area " + semis.combats[theAdv] + " - for player " + playerName + " on turn " + turncount );
		// found a semi, clear counters
		// this might backfire if using the counter as a generic countdown for other purposes, e.g. wossname tracking
		clearCounters(playerName);

		GM_setValue(playerName+"_lastSemiTurn",turncount+1);  // the turncount var isn't updated yet
		GM_setValue(playerName+"_allowBracket",true);
		GM_setValue(playerName+"_lastSemiLocation",semis.combats[theAdv]);

		// trigger char pane refresh with the new info
		top.frames[0].location.reload();
	}
}

////////////////////////////////////////////////////////////////////////////////
// callback function to process the main charsheet as a sanity check after 
// something questionable was spotted, or just on a new session
// **** mostly deprecated ****
function sanityCheckCharsheet(data) {
// alert("entering sanity check");
	var playerName = getPlayerNameFromCharsheet(data);
	GM_setValue("currentPlayer", playerName);
	
	var turncount = getTurnsPlayed(data); // total turns played
	
	if(isNaN(turncount) ) {
// alert("sanityCheckCharsheet - unable to parse either turncount (" + turncount + ") or remaining adv count (" + remainingAdventureCount + "), aborting");
		return;	 // hopefully will try again with more success, can't continue
	}

	GM_setValue(playerName+"_turncount", turncount);  // I'll try to keep this up to date

	// if the previous turncount makes no sense, zero it. After ascending would be an example
	var lastSemiTurn = GM_getValue(playerName+"_lastSemiTurn",-1);
	if( lastSemiTurn > turncount+1) {
		GM_setValue(playerName+"_lastSemiTurn",-1);
		GM_setValue(playerName+"_lastSemiLocation","");
	}
	var prevDayCount = GM_getValue(playerName+"_dayCount",-1);

	var dayCount = getDaysPlayed(data);
	if(!isNaN(dayCount)) {
		if(dayCount < prevDayCount) { // must have ascended
			GM_setValue(playerName+"_lastSemiTurn",-1);
			GM_setValue(playerName+"_lastSemiLocation","");
		}
		GM_setValue(playerName+"_dayCount",dayCount);
	}

	// set a flag is we are oxy, since it affects the cookie spacing
	if( data.match("Oxygenarian"))
		GM_setValue(playerName+"_isOxy", true);
	else	
		GM_setValue(playerName+"_isOxy", false);
	
}

////////////////////////////////////////////////////////////////////////////////
// watch for the lucky numbers result on the main page
function processMain(doc) {
	var countdown1 = -1;
	var countdown2 = -1;
	var countdown3 = -1;
	var pos = -1;

// alert("in processMain()");	  
	///////NEW STUFF (Firvagor) - changed the if line to use the div instead of the body, since the results, and a hidden field is made inside the div so infinite looping doesn't occur////////// 
	//if the hidden field is found, don't do anything
	if (doc.getElementById("cookiedone")!=null){return;}

	var playerName = GM_getValue( "currentPlayer");
	var divElement = doc.getElementById("effdiv");
	
	var bqElement = doc.getElementsByTagName("blockquote");
//	if(bqElement[0])
//		alert("processMain: speakeasy quote = " + bqElement[0]);

	if ( divElement ) {
 // alert("found divElement");

	doc.getElementById("effdiv").innerHTML += "<input type='hidden' id='cookiedone' name='completed' value='yes'>"; 
		if((pos = doc.getElementById("effdiv").innerHTML.indexOf( "Lucky numbers:" )) != -1 ) {

 // alert("found lucky numbers");
			// need to parse the text, format is "Lucky numbers: ###, ###, ###"
			var cookieText = doc.getElementById("effdiv").innerHTML.substring(pos, pos+30);

			// first one starts after the colon, next two after commas
			pos = cookieText.indexOf(":");
			cookieText = cookieText.substring(pos+1);
			countdown1 = parseInt(cookieText);

			pos = cookieText.indexOf(",");
			cookieText = cookieText.substring(pos+1);
			countdown2 = parseInt(cookieText);

			pos = cookieText.indexOf(",");
			cookieText = cookieText.substring(pos+1);
			countdown3 = parseInt(cookieText);

			// elegantly sort them
			{
				var temp;
				if(countdown1 > countdown2) {
					temp = countdown1; countdown1 = countdown2; countdown2 = temp;
				}
				if(countdown2 > countdown3) {
					temp = countdown2; countdown2 = countdown3; countdown3 = temp;
				}
				if(countdown1 > countdown2) {
					temp = countdown1; countdown1 = countdown2; countdown2 = temp;
				}
			}
//		alert("processMain: cookie cookieText=" + cookieText + ", lucky numbers are " + countdown1 + ", " + countdown2 + ", " + countdown3);
		}
	}
		
	// speakeasy drink; format is "burp-speak the number <b>30</b>"
	// doesn't work, is there really an effdiv for this? didn't see it in the text
	// try a blockquote instead... doesn't sound too reliable
//		else if((pos = doc.getElementById("effdiv").innerHTML.indexOf( "burp-speak the number" )) != -1 ) {
	if(bqElement[0] && (pos = bqElement[0].innerHTML.indexOf( "burp-speak the number" )) != -1 ) {
 // alert("processing speakeasy");
		bqElement[0].innerHTML += "<input type='hidden' id='cookiedone' name='completed' value='yes'>"; 
		
		var cookieText = bqElement[0].innerHTML.substring(pos, pos+30);

		// just one number, bolded
		pos = cookieText.indexOf("<b>");
		cookieText = cookieText.substring(pos+3);
		countdown1 = parseInt(cookieText);
		countdown2 = -1;
		countdown3 = -1;
// alert("processMain: speakeasy cookieText=" + cookieText + ", lucky numbers are " + countdown1 + ", " + countdown2 + ", " + countdown3);
	}

	if(countdown1>=0 || countdown2>=0 || countdown3>=0) {
	   // filter out nonsense values: 
	   // - too high ( > 200 since last semi, 120 for oxy)
	   // - too low ( < 160 since last semi, or < 100 if oxy)
	   // the filters only apply if you found a semi recently; otherwise the counter starts
	   // after a would-be semi, or ascension, with your first adventure.php location
	   // adventure, but it's too much trouble to keep track
	   GM_setValue(playerName+"_allowSanityCheck", false);	 // lock out the other pane from panicking
															 // must call processCharsheet now, to clear this
	   var allowBracket = GM_getValue(playerName+"_allowBracket",false);
	   GM_setValue(playerName+"_allowBracket",false);  // no reason to put up reminder after this

	   var turncount = GM_getValue(playerName+"_turncount", 0);
	   var lastSemiTurn = GM_getValue(playerName+"_lastSemiTurn",-1);
	   var wasOxy = GM_getValue(playerName+"_isOxy", false);
	   GM_setValue(playerName+"_isOxy", false);  // ate a cookie, must not be oxy
	   var minCount = 160; var maxCount = 200;
	   if( wasOxy ) { 
			minCount = 100; maxCount = 120; 
	   }
	   if(turncount < 70) {  // newly ascended
			minCount = 70; maxCount = 80; lastSemiTurn = 0;
		}	   
	   var turnsSinceSemi = turncount - lastSemiTurn;

 // alert("filtering lucky numbers for " + playerName + " based on turncount=" + turncount + ", lastSemiTurn=" + lastSemiTurn + ", wasOxy=" + wasOxy + ", turnsSinceSemi = " + turnsSinceSemi );
	   // eliminate counters that are too high on an absolute basis, then try to
	   // eliminate ones too high and low based on last semi 
	   if(countdown1 > maxCount) countdown1 = -1;
	   if(countdown2 > maxCount) countdown2 = -1;
	   if(countdown3 > maxCount) countdown3 = -1;
	   
	   if(lastSemiTurn != -1 && turnsSinceSemi <= maxCount && allowBracket) {
		   if( countdown1 + turnsSinceSemi > maxCount ) countdown1 = -1;
		   if( countdown2 + turnsSinceSemi > maxCount ) countdown2 = -1;
		   if( countdown3 + turnsSinceSemi > maxCount ) countdown3 = -1;
	   }
		   
	   if(lastSemiTurn != -1) {
		   if( countdown1 + turnsSinceSemi < minCount ) countdown1 = -1;
		   if( countdown2 + turnsSinceSemi < minCount ) countdown2 = -1;
		   if( countdown3 + turnsSinceSemi < minCount ) countdown3 = -1;
	   }
	   
		// now to compare them vs existing numbers
		// if there is no match, stick them in as the current numbers
		// if there is a match, use that and zero the other two
	   var oldLuckyTurn1 = GM_getValue(playerName+"_luckyTurn1",-1);
	   var oldLuckyTurn2 = GM_getValue(playerName+"_luckyTurn2",-1);
	   var oldLuckyTurn3 = GM_getValue(playerName+"_luckyTurn3",-1);
	   var oldCountdown1 = oldLuckyTurn1 != -1 ? oldLuckyTurn1 - turncount : -1; 
	   var oldCountdown2 = oldLuckyTurn2 != -1 ? oldLuckyTurn2 - turncount : -1; 
	   var oldCountdown3 = oldLuckyTurn3 != -1 ? oldLuckyTurn3 - turncount : -1;

		var noPopups = GM_getValue("noPopups", false);
	   
	   // need to watch out for -1 matching -1 since we reset values above
	   // check for self-match in new cookie values first
	   if(countdown1 != -1 && (countdown1==countdown2 || countdown1 == countdown3)) {
		  if(!noPopups) alert(countdown1 + " turns until a semi-rare!");
		  countdown2 = -1;
		  countdown3 = -1;
	   }
	   else if(countdown2 != -1 && countdown2 == countdown3) {
		  if(!noPopups) alert(countdown2 + " turns until a semi-rare!");
		  countdown1 = -1;
		  countdown3 = -1;
	   }
	   else if (countdown1 != -1 && (countdown1 == oldCountdown1 || countdown1 == oldCountdown2 || countdown1 == oldCountdown3 || countdown2 == -1 && countdown3 == -1)) {
		  if(!noPopups) alert(countdown1 + " turns until a semi-rare!");
		  countdown2 = -1;
		  countdown3 = -1;
	   }
	   else if (countdown2 != -1 && (countdown2 == oldCountdown1 || countdown2 == oldCountdown2 || countdown2 == oldCountdown3 || countdown1 == -1 && countdown3 == -1)) {
		  if(!noPopups) alert(countdown2 + " turns until a semi-rare!");
		  countdown1 = -1;
		  countdown3 = -1;
	   }
	   else if (countdown3 != -1 && (countdown3 == oldCountdown1 || countdown3 == oldCountdown2 || countdown3 == oldCountdown3 || countdown1 == -1 && countdown2 == -1)) {
		  if(!noPopups) alert(countdown3 + " turns until a semi-rare!");
		  countdown1 = -1;
		  countdown2 = -1;
	   }
	   
	   GM_setValue(playerName+"_luckyTurn1",countdown1 != -1 ? countdown1 + turncount : -1);
	   GM_setValue(playerName+"_luckyTurn2",countdown2 != -1 ? countdown2 + turncount : -1);
	   GM_setValue(playerName+"_luckyTurn3",countdown3 != -1 ? countdown3 + turncount : -1);

	   // load and parse the main charsheet to set the behind the scene variables that 
	   // convert the cookie countdown into actual adventure number for each cookie
//	   GM_get(baseURL + charSheet, processCharsheet);

		// trigger char pane refresh with the new info
		top.frames[0].location.reload();
	}
}

////////////////////////////////////////////////////////////////////////////////
function manualCookieEntry() {
	var playerName = getPlayerNameFromCharpane().username;
// alert("player name: " + playerName);
	GM_setValue("currentPlayer", playerName);  // store for other functions that need to know who's playing
	var noPopups = GM_getValue("noPopups", false);
	if(noPopups) return;  // need to figure out some way to enter values without using a popup
	
	var turncount = GM_getValue(playerName+"_turncount", -1);
	var luckyTurn1 = GM_getValue(playerName+"_luckyTurn1", -1);
	var luckyTurn2 = GM_getValue(playerName+"_luckyTurn2", -1);
	var luckyTurn3 = GM_getValue(playerName+"_luckyTurn3", -1);
	
	var oldCountdown1 = luckyTurn1 > 0 ? luckyTurn1 - turncount : -1;
	var oldCountdown2 = luckyTurn2 > 0 ? luckyTurn2 - turncount : -1;
	var oldCountdown3 = luckyTurn3 > 0 ? luckyTurn3 - turncount : -1;

	var countdown1 = -1;
	var countdown2 = -1;
	var countdown3 = -1;
	var displayText = "";
	
	if(oldCountdown1 > -1) 
		displayText += oldCountdown1;
	if(oldCountdown2 > -1) {
		if(displayText != "") displayText += ", ";
		displayText += oldCountdown2;
	}
	if(oldCountdown3 > -1) {
		if(displayText != "") displayText += ", ";
		displayText += oldCountdown3;
	}

	var lastSemiTurn = GM_getValue(playerName+"_lastSemiTurn",-1);
	var lastSemiLocation = GM_getValue(playerName+"_lastSemiLocation","");
	var promptText = "";
	if(lastSemiTurn > -1 && turncount >= lastSemiTurn ) {
		promptText = "Last semirare found " + (turncount - lastSemiTurn) + " turns ago, at " + lastSemiLocation + ".\n\n";
	}
	else {
		promptText = "Last semirare unknown.\n\n"
	}
	cookieText = prompt(promptText + "Enter 1-3 new cookie vals (-1 to clear)\n", displayText);

	if(cookieText) { // will be null if user cancels
		countdown1 = parseInt(cookieText);
		var pos = cookieText.indexOf(",");
		if(pos > 0) {
			cookieText = cookieText.substring(pos+1);
			countdown2 = parseInt(cookieText);
			pos = cookieText.indexOf(",");
			
			if(pos > 0) {
				cookieText = cookieText.substring(pos+1);
				countdown3 = parseInt(cookieText);
			}
		}
// alert("manual text entry, got values " + countdown1 + ", " + countdown2 + ", " + countdown3);
		GM_setValue(playerName+"_luckyTurn1",countdown1+turncount);
		GM_setValue(playerName+"_luckyTurn2",countdown2+turncount);
		GM_setValue(playerName+"_luckyTurn3",countdown3+turncount);
		GM_setValue(playerName+"_needSanityCheck", false);	// just in case we were in the middle of something
		GM_setValue(playerName+"_allowBracket",false);  // no reason to put up reminder after this

		// load and parse the main charsheet to set the behind the scene variables that 
		// convert the cookie countdown into actual adventure number for each cookie
//		GM_get(baseURL + charSheet, processCharsheet);
		// trigger char pane refresh with the new info
		top.frames[0].location.reload();

	}
}

////////////////////////////////////////////////////////////////////////////////
// this function must be called when we are in the char sidepane
function getPlayerLevel(data) {
	var playerLevel = /Level (\d+)/i.exec(data);  // full mode
	if( !playerLevel)
		playerLevel = /Lvl\. (\d+)/i.exec(data);  // compact mode
	if( playerLevel)
		return parseInt(playerLevel[1],10);

	// normal level checks fail if astral spirit
	if(data.indexOf("Astral Spirit") != -1)
		return 0; // astral spirit
	else 
		return -1; // error
}

////////////////////////////////////////////////////////////////////////////////
// this function must be called when we are in the char sidepane
function updateCharacterPane() {
	var a = getPlayerNameFromCharpane();
	var playerName = a.username;
	var fullmode = a.fullmode;
	if( playerName == null )  // not sure why we sometimes see this, but doesn't seem to be at critical times
		return;

	GM_setValue("currentPlayer", playerName);  // store for other functions that need to know who's playing
	
	// if astral plane, need to reset counters
	// getPlayerLevel() returns 0 for astral plane
	var playerLevel = getPlayerLevel(document.documentElement.innerHTML);
	if(playerLevel == 0) {
		// clear the counters, no point in doing anything else
		clearCounters(playerName);
		return;
	}

	// check the session ID to see if we are still in the same session
	// if a new session, check if an update is available
	var pwdHash = getPwdHash(document.documentElement.innerHTML);
	var oldPwdHash = GM_getValue(playerName + "_pwdHash", 0);
	if(pwdHash != oldPwdHash) {
		// new session
		GM_setValue(playerName + "_pwdHash", pwdHash);
		
		// run sanity check on new session, make sure we haven't missed anything
// alert("calling sanity check");
		GM_get(baseURL + charSheet, sanityCheckCharsheet);
		
		// check for a new version of script if none seen already (asynch call, will run in parallel)
		// (temporarily?) removed for use with greasy fork
/* 		var webVer = GM_getValue("webVersion", "Error");
		if(webVer == "Error" || webVer <= currentVersion) {
//			alert("calling version check");
			GM_get(scriptURL, CheckScriptVersion);
		}
 */	
	}

	// new native counter!
	var turncount = getTurnsplayedVar(document.documentElement.innerHTML);
	var oldTurncount = GM_getValue(playerName+"_turncount", 0);
	GM_setValue(playerName+"_turncount", turncount);

	var lastSemiTurn = GM_getValue(playerName+"_lastSemiTurn",-1);
	var lastSemiLocation = GM_getValue(playerName+"_lastSemiLocation","");
	if(lastSemiTurn > turncount + 1) { // turncount var lags behind when fighting, so can have an off-by-1 issue
		// could happen if ascended
		lastSemiTurn = -1;
		GM_setValue(playerName+"_lastSemiTurn",-1);
		GM_setValue(playerName+"_lastSemiLocation","");
	}

	var luckyTurn1 = GM_getValue(playerName+"_luckyTurn1", -1);
	var luckyTurn2 = GM_getValue(playerName+"_luckyTurn2", -1);
	var luckyTurn3 = GM_getValue(playerName+"_luckyTurn3", -1);

	// if anything hit zero, warn the user
	var noPopups = GM_getValue("noPopups", false);
	var atSemi = false;
	if( turncount == luckyTurn1	|| turncount == luckyTurn2	|| turncount == luckyTurn3) {
		atSemi = true;
		if(!noPopups && turncount != oldTurncount) {
			var alertText = "Fortune cookie countdown hit zero!";
			if(lastSemiTurn > -1 && turncount >= lastSemiTurn) {
				alertText += "\n\nLast semirare found " + (turncount - lastSemiTurn) + " turns ago, at " + lastSemiLocation + ".";
			}
			else {
				alertText += "\n\nLast semirare unknown.";
			}
			confirm(alertText);
		}
	}
	
	var displayText = "";
	if(luckyTurn1 >= turncount) 
		displayText += luckyTurn1 - turncount;
	if(luckyTurn2 >= turncount) {
		if(displayText != "") displayText += ", ";
		displayText += luckyTurn2 - turncount;
	}
	if(luckyTurn3 >= turncount) {
		if(displayText != "") displayText += ", ";
		displayText += luckyTurn3 - turncount;
	}
	if(atSemi && noPopups)
		displayText += " (last SR: " + (lastSemiLocation == "" ? "unknown" : lastSemiLocation) + ")";
	if(atSemi && fullmode) {  // shows the html literally in compact mode
		displayText  = "<font color=\"red\"><b>" + displayText + "</b></font>";
	}

	// display turn var to figure out exactly how it works
//	displayText += " (tp=" + turnsplayedVar+")";
   
	var hideIfZeros = GM_getValue("hideIfZeros", false);

    if(displayText != ""
    || hideIfZeros == false ) {
		// display an FC bracket if no cookie eaten, and have found a semi recently
		var isOxy = GM_getValue(playerName+"_isOxy", false);
	    var turnsSinceSemi = turncount - lastSemiTurn;
	    var minCount = 160; var maxCount = 200;
	    if( isOxy ) { 
	    	minCount = 100; maxCount = 120; 
	    }
		if(displayText == "" && lastSemiTurn != -1 && turnsSinceSemi <= maxCount ) {
			displayText = "[" + Math.max(0, minCount - turnsSinceSemi) + "...";
			displayText += Math.max(0, maxCount - turnsSinceSemi) + "]";
		} else if (displayText == "" && turncount < 70) {  // default just-ascended bracket
			displayText = "[" + Math.max(0, 70 - turncount)  + "...";
			displayText += Math.max(0, 80 - turncount) + "]";
		}
		
		if(fullmode) {
			var newElement = document.createElement("FONT");
			newElement.innerHTML = "<b>"
			  + "<font size=2>Cookie Count: " 
			  + displayText
			  + "</font></b><br><br>"; ;
			newElement.setAttribute("onmouseover", 'this.style.opacity="0.5"');
			newElement.setAttribute("onmouseout", 'this.style.opacity="1"');
			newElement.setAttribute("id", 'fortuneCookieCounter');
			newElement.addEventListener("click", manualCookieEntry, true);
			newElement.align = "center";
	
			var elements = document.getElementsByTagName( "FONT" );
			for ( var i = 0; i < elements.length; ++i ){
				if ( elements[i].innerHTML.indexOf( "Last Adventure" ) != -1 ){
					// insert our before this one
					elements[i].parentNode.insertBefore(newElement,elements[i]);
					break;
				}
			}
		}
		else { // compact mode - different layout, make a table row and two data element
			var newTR = document.createElement('tr');

			var newElement = document.createElement("td");
			newElement.appendChild(document.createTextNode("Cookie:"));
			newElement.align = "right";
			newTR.appendChild(newElement);
			
			newElement = document.createElement("td");
			newElement.setAttribute("onmouseover", 'this.style.opacity="0.5"');
			newElement.setAttribute("onmouseout", 'this.style.opacity="1"');
			newElement.setAttribute("id", 'fortuneCookieCounter');
			newElement.addEventListener("click", manualCookieEntry, true);
			newElement.align = "left";
			newElement.style.fontWeight = "bold";
			newElement.appendChild(document.createTextNode(displayText));
			newTR.appendChild(newElement);
			
			var elements = document.getElementsByTagName( "TR" );
			var done = false;
			// if the last adventures script is running, insert before, else append to table
			for ( var i = 1; i < elements.length; ++i ){
				// normally "Adv", might be "Last Adventures" if that script is running
				if ( elements[i].innerHTML.indexOf( "Last Adventures" ) != -1 ){
					// insert ours before this one - experiment, back up one more
					elements[i].parentNode.insertBefore(newTR,elements[i-1]);
					done = true;
					break;
				}
			}
			if(!done) { // normal, no last adv script
				for ( var i = 0; i < elements.length; ++i ){
					 if ( elements[i].innerHTML.indexOf( "Adv" ) != -1 ){
						// insert ours at end of the table in compact mode
						elements[i].parentNode.appendChild(newTR);
						break;
					 }
				}
			}
		}
    }
}   

////////////////////////////////////////////////////////////////////////////////
// set preferences
// code stolen from mr script
// not set on a per-player basis, would need to add code to parse account pane for char name
function toggleHideCountdown() {
//	  alert("in toggleHideCountdown()");

	var hideIfZeros = GM_getValue("hideIfZeros", false);
	hideIfZeros = !hideIfZeros;
	
	GM_setValue("hideIfZeros", hideIfZeros);
		
	// trigger char pane refresh with the new info
	top.frames[0].location.reload();
    var msg = document.getElementById('cookiecountertoggle');
    msg.innerHTML = (hideIfZeros ? "Hiding" : "Showing") + " Inactive Counter - Click to Change";
}

function togglePopups() {
//	  alert("in toggleHideCountdown()");

	var noPopups = GM_getValue("noPopups", false);
	noPopups = !noPopups;
	
	GM_setValue("noPopups", noPopups);
		
	// trigger char pane refresh with the new info
    var msg = document.getElementById('cookiepopups');
    msg.innerHTML = (noPopups ? "Popups Disabled " : "Using Popups") + " (disable for FF4) - Click to Change";
	top.frames[0].location.reload();
}

// --------------------------------------------
// ---------- account menu option -------------
// --------------------------------------------

// Charon's code
function buildPrefs() {
    if (!document.querySelector('#privacy'))
        return;
    if (!document.querySelector('#scripts')) {
        //scripts tab is not built, do it here
        var scripts = document.querySelector('ul').appendChild(document.createElement('li'));
        scripts.id = 'scripts';
        var a = scripts.appendChild(document.createElement('a'));
        a.href = '#';
        var img = a.appendChild(document.createElement('img'));
        img.src = 'http://images.kingdomofloathing.com/itemimages/cmonkey1.gif';
        img.align = 'absmiddle';
        img.border = '0';
        img.style.paddingRight = '10px';
        a.appendChild(document.createTextNode('Scripts'));
        a.addEventListener('click', function (e) {
                //make our new tab active when clicked, clear out the #guts div and add our settings to it
                e.stopPropagation();
                document.querySelector('.active').className = '';
                document.querySelector('#scripts').className = 'active';
                document.querySelector('#guts').innerHTML = '<div class="scaffold"></div>';
                document.querySelector('#guts').appendChild(getSettings());
            }, false);
    } else {
        //script tab already exists
         document.querySelector('#scripts').firstChild.addEventListener('click', function (e) {
                //some other script is doing the activation work, just add our settings
                e.stopPropagation();
                document.querySelector('#guts').appendChild(getSettings());
            }, false);
    }
}

function getSettings() {
    //build our settings and return them for appending
    var guts = document.body.appendChild(document.createElement('div'));
    guts.id = 'cookieprefs';
    var subhead = guts.appendChild(document.createElement('div'));
    subhead.className = 'subhead';
    subhead.textContent = 'Fortune Cookie Counter';
    var section = guts.appendChild(document.createElement('div'));
    section.className = 'indent';
    //call function in main script to actually make the settings
    section.appendChild(buildSettings());
    return guts;
}

function buildSettings() {
	var prefLink = document.createElement('a');
	var hideIfZeros = GM_getValue("hideIfZeros", false);

	prefLink.setAttribute('href','javascript:void(0)');
	prefLink.setAttribute('id','cookiecountertoggle');
    prefLink.innerHTML = (hideIfZeros ? "Hiding" : "Showing") + " Inactive Counter - Click to Change";
	prefLink.addEventListener("click", toggleHideCountdown, true);

	var prefAnchor = document.createElement('a');
	prefAnchor.setAttribute('name','opt'); prefAnchor.innerHTML = " ";
	var pDiddy = document.createElement('p');
	with(pDiddy)
	{	appendChild(prefAnchor);
		appendChild(prefLink);
	}

	prefLink = document.createElement('a');
	var noPopups = GM_getValue("noPopups", false);

	prefLink.setAttribute('href','javascript:void(0)');
	prefLink.setAttribute('id','cookiepopups');
    prefLink.innerHTML = (noPopups ? "Popups Disabled " : "Using Popups") + " (disable for FF4) - Click to Change";
	prefLink.addEventListener("click", togglePopups, true);

	prefAnchor = document.createElement('p');
	prefAnchor.setAttribute('name','opt'); prefAnchor.innerHTML = " ";
	
	with(pDiddy)
	{	appendChild(prefAnchor);
		appendChild(prefLink);
	}
	
	// add a link to update, if an update is available
	// (temporarily?) removed for use with Greasy Fork
/* 	var webVer = GM_getValue("webVersion");
	if (webVer != "Error" && webVer > currentVersion) {  // this is actually a text string comparison, not numerical
		var newElement = document.createElement('p');
		newElement.style.fontSize = "x-small";
		newElement.appendChild(document.createTextNode("New cookie script version " + webVer + " available: "));

		var hrefElement = document.createElement('a');
		hrefElement.setAttribute('href', scriptSite);
		hrefElement.setAttribute('target', "_blank");
		hrefElement.appendChild(document.createTextNode("here"));
		newElement.appendChild(hrefElement);
		
		pDiddy.appendChild(newElement); 
	}
 */
	return pDiddy;
}

////////////////////////////////////////////////////////////////////////////////
// main prog, just call the proper routine if we are on a pane we care about
var nodeBody   = document.getElementsByTagName("body").item(0);
var textBody   = "";
var baseURL	   = "";
var charSheet = "charsheet.php";
var playerName = GM_getValue( "currentPlayer");

if (nodeBody) {
   if (nodeBody.textContent) {
	  textBody = nodeBody.textContent;
   }
   else if (nodeBody.text) {
	  textBody = nodeBody.text;
   }
   baseURL = nodeBody.baseURI.substring(0,nodeBody.baseURI.lastIndexOf('/')+1);
}

// do normal page processing independently of whether started sanity check
if ( document.location.pathname.indexOf("charpane.php") != -1 ) {
	//////NEW STUFF (Firvagor) - since the charpane refreshes every time something is used, if the results section is found, run main function using manually located mainpane (can only use indexing for some reason)/////
	if (top.frames[2].document.getElementById("effdiv")!=null)  // was frames[1] until aug 2014 topmenu update
		processMain(top.frames[2].document);
	updateCharacterPane();
}
else if ( document.location.pathname.indexOf("inventory.php") != -1
  || document.location.pathname.indexOf("clan_viplounge.php")!= -1){ 
	 //alert("calling processMain() for " + document.location.pathname);
	 //////NEW STUFF (Firvagor) - passes in current document instead of nothing, just to define the frame used/////
	GM_setValue(playerName+"_fighting",0);
	processMain(document);
}
else if ( document.location.pathname.indexOf("charsheet.php") != -1){ 
//	alert("calling sanityCheckCharsheet() for " + document.location.pathname);
	GM_setValue(playerName+"_fighting",0);
	sanityCheckCharsheet(document.body.innerHTML);
}
else if ( document.location.pathname.indexOf("account.php") != -1 ) {
//	  alert("calling set prefs for " + document.location.pathname);
	GM_setValue(playerName+"_fighting",0);
    buildPrefs();
//	setPrefs();
}
else if ( document.location.pathname.indexOf("adventure.php") != -1
	|| document.location.pathname.indexOf("choice.php") != -1) {
	// adventure.php should trap all "normal" noncombats
	// choice noncombats are in choice.php - now needed for hobopolis
	// for the fortune cookie combat rares, need to process fight.php
	GM_setValue(playerName+"_fighting",0);
	checkForNoncombatSemi(document.body.innerHTML);
}
else if ( document.location.pathname.indexOf("fight.php") != -1 ) {
	// see if we are actively fighting (no asynch calls allowed while fighting!)
	var fighting = GM_getValue(playerName+"_fighting",0)
	// alert("prefight check - page = " + document.location.pathname + ", fighting = " + fighting);
	{
		if( fighting == 0) {
			//  just started a fight, see if it's a combat semi (orc chasm, kitchens, treasury)
			checkForCombatSemi(document.body.innerHTML);
		}
//	alert("incrementing fighting from " + fighting);
		fighting = fighting + 1;  // also count rounds, prevents doing things twice in same fight
		// fighting, but maybe we're done, look for adventure again tag
		// I forget why we look at paragraphs here!
//		var paragraphs = document.getElementsByTagName( "p" );
//		for ( var i = 0; i < paragraphs.length; ++i ) {
//			if ( paragraphs[i].innerHTML.indexOf( "Adventure Again (" ) != -1
//			|| 	paragraphs[i].innerHTML.indexOf("Go back to Your Inventory") != -1) {
			if ( document.body.innerHTML.indexOf( "Adventure Again (" ) != -1
			|| 	document.body.innerHTML.indexOf("Go back to Your Inventory") != -1) {
				fighting = 0;
//				break;
			}
//		}
	}
	GM_setValue(playerName+"_fighting",fighting);
//	alert("post fight - fighting = " + fighting);

}
else {
//	  alert("ignoring " + document.location.pathname);
}

// do sanity check (load charsheet asynchronously) if requested - not while fighting
if(GM_getValue(playerName+"_needSanityCheck",false) == true
&& GM_getValue(playerName+"_allowSanityCheck",false) == true ) {
	// alert("need sanity check flag detected!");
	// no sanity check allowed if fighting
	if( GM_getValue(playerName+"_fighting",0) == 0) {
	// alert("calling sanity check");	 
	   GM_setValue(playerName+"_needSanityCheck", false);
//	   alert("calling sanity check");
	   GM_get(baseURL + charSheet, sanityCheckCharsheet);
	} 
}