/*

		Turpidge version 1.1

	The Turpidge Game Engine by Matt Trobaugh is dedicated to the public domain under a CC0 Public Domain Dedication. To view a copy of this dedication, visit http://creativecommons.org/publicdomain/zero/1.0/.
*/


/*****************************************************
		PUBLIC VARIABLES
*****************************************************/


prologueIndex = 0;
epilogueIndex = 0;

currentLocation = null;
currentCharacter = null;
selectedCharacter = null;
busy = false;
dialogOpen = false;
controlsOpen = false;
tto = null;
ttc = null;
sightsSpaces = new Array();

screenWidth = 0;
screenHeight = 0;

saveObj = null;

playerTeam = new Array();
enemyTeam = new Array();
bothTeams = new Array();

walkableSpaces = new Array();

turn = new Object();

inBattle = false;

/****	end public variables ****/

/*****************************************************
		CONSTRUCTORS
*****************************************************/

function Locations()
{
	this.loc = new Array();
	
	this.setDefaultSpace = function(color, image, walk)
	{
		this.defaultSpace = new Space("", color, image, walk);
	}
	
	this.addLocation = function(name, width, height)
	{
		newLoc = new Location(name, width, height, this.defaultSpace);
		this.loc.push(newLoc);
		return newLoc;
	}
	
	this.getLocation = function(name)
	{
		var i;
		for(i=0;i<this.loc.length;i++)
		{
			if(this.loc[i].name == name)
			{
				return this.loc[i];
			}
		}
	}
	
}

function Location(name, width, height, defaultSpace)
{
	this.name = name;
	this.width = width;
	this.height = height;
	this.battle = null;
	
	this.spaces = new Array();
	this.things = new Array();
	
	var i;
	var j;
	
	for(i=0;i<width;i++)
	{
		col = new Array();
		for(j=0;j<height;j++)
		{
			spaceId = i + "-" + j;
			space = new Space(spaceId, defaultSpace.color, defaultSpace.image, defaultSpace.walk);
			col.push(space);
		}
		this.spaces.push(col);
	}
	
	this.setSpace = function(x, y, color, image, walk)
	{
		this.spaces[x][y].setSpace(color, image, walk);
	}
	
	this.setArea = function(x1, y1, x2, y2, color, image, walk)
	{
		var i;
		var j;
	
		for(i=x1;i<=x2;i++)
		{
			for(j=y1;j<=y2;j++)
			{
				this.spaces[i][j].setSpace(color, image, walk);
			}
		}
	}
	
	this.setLink = function(x, y, link)
	{
		this.spaces[x][y].link = link;
	}
	
	this.addThing = function(name, x, y, image)
	{
		thing = new Thing(name, x, y, image);
		this.things.push(thing);
		return thing;
	}
	
	
	this.getThing = function(name)
	{
		var i;
		for(i=0;i<this.things.length;i++)
		{
			if(this.things[i].name == name)
			{
				return this.things[i];
			}
		}
		
		return null;
	}
	
}

function Space(id, color, image, walk)
{
	this.id = id;
	this.color = color;
	this.image = image;
	this.walk = walk;
	this.link = "";
	
	this.setSpace = function(color, image, walk)
	{
		this.color = color;
		this.image = image;
		this.walk = walk;
	}
}

function Thing(name, x, y, image)
{
	this.name = name;
	this.x = x;
	this.y = y;
	this.image = image;
	this.click = null;
	this.spaceWalk = null;
}

function clickThing(locName, thingName)
{
	loc = null;
	thing = null;
	var i;
	for(i=0;i<locations.loc.length;i++)
	{
		if(locations.loc[i].name == locName)
		{
			loc = locations.loc[i];
			break;
		}
	}
	if(loc != null)
	{
		for(i=0;i<loc.things.length;i++)
		{
			if(loc.things[i].name == thingName)
			{
				thing = loc.things[i];
				break;
			}
		}
	}
	
	if(thing != null)
	{
		thing.click();
	}
}



function Battles()
{
	this.bat = new Array();
	
	this.addBattle = function(name, playerPositions, spoils)
	{
		newBat = new Battle(name, playerPositions, spoils);
		this.bat.push(newBat);
		return newBat;
	}
	
	this.getBattle = function(name)
	{
		for(var i=0;i<this.bat.length;i++)
		{
			if(this.bat[i].name == name)
			{
				return this.bat[i];
			}
		}
	}
}

function Battle(name, playerPositions, spoils)
{
	this.name = name;
	this.playerPositions = playerPositions;
	this.enemyTeam = new Array();
	this.enemyPositions = new Array();
	this.spoils = spoils;
	this.recurring = false;
	
	this.onWin = function()
	{
		return;
	}
	
	this.addEnemy = function(name, x, y)
	{
		protoEnemy = enemyCharacters.getCharacter(name);
		newEnemy = new Character(protoEnemy.name, protoEnemy.attack, protoEnemy.defense, protoEnemy.maxHP, protoEnemy.maxMP, protoEnemy.speed, protoEnemy.moveRange, protoEnemy.attackRange, protoEnemy.image);
		
		var i;
		for(i=0;i<protoEnemy.items.length;i++)
		{
			items.giveCharacterItem(newEnemy, protoEnemy.items[i].name);
		}
		for(i=0;i<protoEnemy.equipment.length;i++)
		{
			items.giveCharacterItem(newEnemy, protoEnemy.equipment[i].name);
		}
		
		
		newEnemy.spells = protoEnemy.spells;
			
		newEnemy.mode = protoEnemy.mode;
		newEnemy.money = protoEnemy.money;
		newEnemy.exp = protoEnemy.exp;
		
		newEnemy.bossStrategy = protoEnemy.bossStrategy;
		newEnemy.onDefeat = protoEnemy.onDefeat;
		
		newEnemy.x = x;
		newEnemy.y = y;
		
		this.enemyTeam.push(newEnemy);
		this.enemyPositions.push(x + "-" + y);
		
		return newEnemy;
	}
	
	this.resetBattle = function()
	{
		var i;
		for(i=0;i<this.enemyTeam.length;i++)
		{
			this.enemyTeam[i].HP = this.enemyTeam[i].maxHP;
			this.enemyTeam[i].MP = this.enemyTeam[i].maxMP;
			
			var enemyCoords = this.enemyPositions[i].split("-");
			var enemyX = parseInt(enemyCoords[0]);
			var enemyY = parseInt(enemyCoords[1]);
			
			this.enemyTeam[i].x = enemyX;
			this.enemyTeam[i].y = enemyY;
			
			if(this.enemyTeam[i].statusCondition != null)
			{
				statusConditions.cureCondition(this.enemyTeam[i]);
			}
			
			this.enemyTeam[i].status = "ok";
		}
	}
}

function setupBattle(battle)
{
	inBattle = true;
	enemyTeam = battle.enemyTeam;
	
	shuffleArray(battle.playerPositions);
	
	var i;
	for(i=0;i<battle.playerPositions.length;i++)
	{
		if(i < playerTeam.length && playerTeam[i].status != "dead")
		{
			coords = battle.playerPositions[i].split("-");
			placeUnit(playerTeam[i], parseInt(coords[0]), parseInt(coords[1]));
			bothTeams.push(playerTeam[i]);
		}
	}
	
	for(i=0;i<enemyTeam.length;i++)
	{
		placeUnit(enemyTeam[i], enemyTeam[i].x, enemyTeam[i].y);
		bothTeams.push(enemyTeam[i]);
	}
	
	bothTeams = shuffleArray(bothTeams);
	
	for(i=0;i<bothTeams.length;i++)
	{
		bothTeams[i].timeToTurn = Math.ceil((1 / bothTeams[i].speed) * 100);
	}
	
	setInterface();
	startTurn();	
}



function PlayerCharacters()
{
	this.chars = new Array();
	
	this.addCharacter = function(name, attack, defense, maxHP, maxMP, speed, moveRange, attackRange, image, charClass)
	{
		pc = new Character(name, attack, defense, maxHP, maxMP, speed, moveRange, attackRange, image);
		
		pc.charClass = charClass;
		
		this.chars.push(pc);
		return pc;
	}
	
	this.getCharacter = function(name)
	{
		var i;
		for(i=0;i<this.chars.length;i++)
		{
			if(this.chars[i].name == name)
			{
				return this.chars[i];
			}
		}
	}
}

function EnemyCharacters()
{
	this.chars = new Array();
	
	this.addCharacter = function(name, attack, defense, maxHP, maxMP, speed, moveRange, attackRange, image, mode, money, exp)
	{
		ec = new Character(name, attack, defense, maxHP, maxMP, speed, moveRange, attackRange, image);
		
		ec.mode = mode;
		ec.money = money;
		ec.exp = exp;
		
		ec.bossStrategy = null;
		ec.onDefeat = null;
		
		this.chars.push(ec);
		return ec;
	}
	
	this.getCharacter = function(name)
	{
		var i;
		for(i=0;i<this.chars.length;i++)
		{
			if(this.chars[i].name == name)
			{
				return this.chars[i];
			}
		}
	}
}

function Character(name, attack, defense, maxHP, maxMP, speed, moveRange, attackRange, image)
{
	this.name = name;
	this.status = "ok";
	this.exp = 0;
	this.level = 1;
	this.attack = attack;
	this.defense = defense;
	this.HP = maxHP;
	this.maxHP = maxHP;
	this.MP = maxMP;
	this.maxMP = maxMP;
	this.speed = speed;
	this.moveRange = moveRange;
	this.attackRange = attackRange;
	this.timeToTurn = 0;
	this.items = new Array();
	this.equipment = new Array();
	this.spells = new Array();
	this.image = image;
	
	this.getItem = function(itemName)
	{
		var i = 0;
		for(i=0;i<this.items.length;i++)
		{
			if(this.items[i].name == itemName)
			{
				return this.items[i];
			}
		}
	}
	
	this.useItem = function(itemNum, target)
	{
		thisItem = this.items[itemNum];
		mssg = thisItem.use(this, target);
		return mssg;
	}
	
	this.giveItem = function(itemNum, target)
	{
		thisItem = this.items[itemNum];
		this.items.splice(itemNum, 1);
		target.items.push(thisItem);
		
		mssg = this.name + " gave " + thisItem.name + " to " + target.name;
		return mssg;
	}
	
	this.equipItem = function(itemNum)
	{
		var i = 0;
		var thisItem = this.items[itemNum];
		if(this.charClass == null || thisItem.equipClasses.indexOf(this.charClass) == -1)
		{
			mssg = this.name + " can't equip this item";
			return mssg;
		}
		else
		{			
			for(i=0;i<this.equipment.length;i++)
			{
				if(this.equipment[i].equipType == thisItem.equipType)
				{
					this.unequipItem(i);
				}
			}
			
			this.equipment.push(thisItem);
			this.items.splice(itemNum, 1);
			
			for(i=0;i<thisItem.equipEffects.length;i++)
			{
				this[thisItem.equipEffectStats[i]] += thisItem.equipEffects[i];
			}
			
			return "ok";
		}
	}
	
	this.unequipItem = function(itemNum)
	{
		var i = 0;
		var thisItem = this.equipment[itemNum];
		
		this.items.push(thisItem);
		this.equipment.splice(itemNum, 1);
		
		for(i=0;i<thisItem.equipEffects.length;i++)
		{
			this[thisItem.equipEffectStats[i]] -= thisItem.equipEffects[i];
		}
	}
	
	this.learnSpell = function(name)
	{
		spell = spells.getSpell(name);
		this.spells.push(spell);
	}
	
	this.castSpell = function(spell, target)
	{
		if(this.MP < spell.MP)
		{
			mssg = this.name + " does not have enough MP to cast " + spell.name;
		}
		else
		{
			this.MP -= spell.MP;
			mssg = spell.cast(target);
		}
		
		return mssg;
	}
	
	this.levelUpTo = function(n)
	{
		while(this.level < n)
		{
			this.exp += levelingConstant;
			
			if(this.exp >= Math.round(levelingConstant+(this.level*levelingConstant*(this.level-1)/2)))
			{
				this.level++;
				
				template = levelTemplates.getTemplate(this.charClass);
				if(template == null)
				{
					template = levelTemplates.defaultTemplate;
				}
				
				var i;
				for(i=0;i<template.stats.length;i++)
				{
					currentStat = template.stats[i][0];
					currentVal = this[currentStat];
					
					// factor out effects of equipment
					for(j=0;j<this.equipment.length;j++)
					{
						statIndex = this.equipment[j].equipEffectStats.indexOf(currentStat);
						
						if(statIndex > -1)
						{
							currentVal += this.equipment[j].equipEffects[statIndex] * -1;
						}
					}
					
					// factor out effects of status conditions
					if(this.statusCondition != null)
					{
						statIndex = this.statusCondition.effectStats.indexOf(currentStat);
						
						if(statIndex > -1)
						{
							currentVal += this.statusCondition.effects[statIndex] * -1;
						}
					}
				
					this[currentStat] += Math.ceil(currentVal * (template.stats[i][1]/100));
					
				}
				
				for(i=0;i<template.spells.length;i++)
				{
					if(template.spells[i][1] == this.level)
					{
						this.learnSpell(template.spells[i][0]);
						
					}
				}
			}
		}
		
		this.HP = this.maxHP;
		this.MP = this.maxMP;
	}
}



function LevelTemplates()
{
	this.defaultTemplate = null;
	this.tmplt = new Array();
	
	this.addTemplate = function(charClass)
	{
		newTmplt = new LevelTemplate(charClass);
		this.tmplt.push(newTmplt);
		if(this.defaultTemplate == null)
		{
			this.defaultTemplate = newTmplt;
		}
		return newTmplt;
	}
	
	this.getTemplate = function(charClass)
	{
		for(var i=0;i<this.tmplt.length;i++)
		{
			if(this.tmplt[i].charClass == charClass)
			{
				return this.tmplt[i];
			}
		}
	}
}

function LevelTemplate(charClass)
{
	this.charClass = charClass;
	this.stats = new Array();
	this.spells = new Array();
	
	this.addStat = function(stat, increase)
	{
		newStat = new Array(stat, increase);
		this.stats.push(newStat);
	}
	
	this.addSpell = function(spell, level)
	{
		newSpell = new Array(spell, level);
		this.spells.push(newSpell);
	}
}



function Items()
{
	this.items = new Array();
	
	this.addItem = function(name, image, useEffects, useEffectStats, cures, inflicts, equipClasses, equipType, equipEffects, equipEffectStats, spell)
	{
		newItem = new Item(name, image, useEffects, useEffectStats, cures, inflicts, equipClasses, equipType, equipEffects, equipEffectStats, spell);
		this.items.push(newItem);
		
		return newItem;
	}
	
	this.addUsableItem = function(name, image, useEffects, useEffectStats, cures, inflicts)
	{
		this.addItem(name, image, useEffects, useEffectStats, cures, inflicts, "", "", "", "", "");
	}
	
	this.addEquipment = function(name, image, equipClasses, equipType, equipEffects, equipEffectStats, spell)
	{
		this.addItem(name, image, "", "", "", "", equipClasses, equipType, equipEffects, equipEffectStats, spell);
	}
	
	this.getItem = function(name)
	{
		var i;
		for(i=0;i<this.items.length;i++)
		{
			if(this.items[i].name == name)
			{
				return this.items[i];
			}
		}
	}
	
	this.getShopItem = function(itemName, price)
	{
		inventoryItem = this.getItem(itemName);
		
		inventoryCode = '<div style="width:' + (tileSize + 20) + 'px;text-align:center;float:left;"><img style="cursor:pointer;" onClick="openDialog(this, items.buyItem(\'' + itemName + '\', ' + price + '))" src="images/' + inventoryItem.image + '" /><br/>' + price + ' ' + monies[0] + '.</div>';
		
		return inventoryCode;
	}

	this.buyItem = function(itemName, price)
	{
		if(price > playerMoney){return "Sorry, you can't afford that.";}
		else
		{
			playerMoney -= price;
			protoItem = this.getItem(itemName);
			
			newItem = new Item(protoItem.name, protoItem.image, protoItem.useEffects.toString(), protoItem.useEffectStats.toString(), protoItem.cures.toString(), protoItem.inflicts, protoItem.equipClasses.toString(), protoItem.equipType, protoItem.equipEffects.toString(), protoItem.equipEffectStats.toString(), protoItem.spell);
			
			currentCharacter.items.push(newItem);
			
			openControls(currentCharacter.name);
			itemHandler();
			
			var divHeight = document.getElementById("measuringDiv").offsetHeight - document.getElementById("dialogCloseButtonDiv").offsetHeight;
			
			return '<div style="height:' + divHeight + 'px;">Thanks. Have a nice day.</div>';
		}
	}

	this.giveCharacterItem = function(character, itemName)
	{
		protoItem = this.getItem(itemName);
			
		newItem = new Item(protoItem.name, protoItem.image, protoItem.useEffects.toString(), protoItem.useEffectStats.toString(), protoItem.cures.toString(), protoItem.inflicts, protoItem.equipClasses.toString(), protoItem.equipType, protoItem.equipEffects.toString(), protoItem.equipEffectStats.toString(), protoItem.spell);
		
		character.items.push(newItem);
	}
	
	this.giveCharacterEquipment = function(character, itemName)
	{
		protoItem = this.getItem(itemName);
			
		newItem = new Item(protoItem.name, protoItem.image, protoItem.useEffects.toString(), protoItem.useEffectStats.toString(), protoItem.cures.toString(), protoItem.inflicts, protoItem.equipClasses.toString(), protoItem.equipType, protoItem.equipEffects.toString(), protoItem.equipEffectStats.toString(), protoItem.spell);
		
		character.items.push(newItem);
		
		if(newItem.equipClasses.indexOf(character.charClass) > -1)
		{
			character.equipItem(character.items.indexOf(newItem));
		}
	}
}

function Item(name, image, useEffects, useEffectStats, cures, inflicts, equipClasses, equipType, equipEffects, equipEffectStats, spell)
{
	this.name = name;
	this.image = image;
	
	var i;
	
	this.useEffects = new Array();
	if(useEffects != "")
	{
		this.useEffects = useEffects.split(",");
		for(i=0;i<this.useEffects.length;i++)
		{
			this.useEffects[i] = parseInt(this.useEffects[i]);
		}
	}
	
	this.useEffectStats = new Array();
	if(useEffectStats != "")
	{
		this.useEffectStats = useEffectStats.split(",");
		for(i=0;i<this.useEffectStats.length;i++)
		{
			this.useEffectStats[i] = this.useEffectStats[i].trim();
		}
	}
	
	this.cures = new Array();
	if(cures != "")
	{
		this.cures = cures.split(",");
		for(i=0;i<this.cures.length;i++)
		{
			this.cures[i] = this.cures[i].trim();
		}
	}
	
	this.inflicts = inflicts;
	
	this.equipClasses = new Array();
	if(equipClasses != "")
	{
		this.equipClasses = equipClasses.split(",");
		for(i=0;i<this.equipClasses.length;i++)
		{
			this.equipClasses[i] = this.equipClasses[i].trim();
		}
	}
	
	
	this.equipType = equipType;
	
	this.equipEffects = new Array();
	if(equipEffects != "")
	{
		this.equipEffects = equipEffects.split(",");
		for(i=0;i<this.equipEffects.length;i++)
		{
			this.equipEffects[i] = parseInt(this.equipEffects[i]);
		}
	}
	
	this.equipEffectStats = new Array();
	if(equipEffectStats != "")
	{
		this.equipEffectStats = equipEffectStats.split(",");
		for(i=0;i<this.equipEffectStats.length;i++)
		{
			this.equipEffectStats[i] = this.equipEffectStats[i].trim();
		}
	}
	
	this.spell = spell;
	
	this.use = function(user, target)
	{
		mssgParts = new Array();
		var i;
		for(i=0;i<this.useEffects.length;i++)
		{
			oldStat = target[this.useEffectStats[i]];
			target[this.useEffectStats[i]] += this.useEffects[i];
			
			mssgChange = " increased by ";
			if(this.useEffects[i] < 0)
			{
				mssgChange = " decreased by ";
			}
			
			if(target["max" + this.useEffectStats[i]] != null && target[this.useEffectStats[i]] > target["max" + this.useEffectStats[i]])
			{
				target[this.useEffectStats[i]] = target["max" + this.useEffectStats[i]];
			}
			else if(target[this.useEffectStats[i]] < 0)
			{
				target[this.useEffectStats[i]] = 0;
			}
			
			mssgEffect = Math.abs(target[this.useEffectStats[i]] - oldStat);
			mssgPart = target.name + "'s " + this.useEffectStats[i] + mssgChange + mssgEffect;
			mssgParts.push(mssgPart);
		}
		
		if(this.cures.length > 0 && this.cures.indexOf(targets[i].status) > -1)
		{
			var curedStatus = targets[i].status;
			statusConditions.cureCondition(targets[i]);
		
			mssgParts.push(targets[i].name + " is no longer " + curedStatus);
		}
		
		if(this.inflicts != "")
		{
			if(inBattle == false || targets[i].status == "dead")
			{
				mssgParts.push("failed to make " + targets[i].name + " " + this.inflicts);
			}
			else if(targets[i].status != "ok")
			{
				mssgParts.push("failed to make " + targets[i].name + " " + this.inflicts + " because " + targets[i].name + " is " + targets[i].status);
			}
			else
			{
				statusConditions.inflictCondition(this.inflicts, targets[i]);
				
				var condition = targets[i].statusCondition;
				
				mssgParts.push(targets[i].name + " is now " + targets[i].status);
				
				for(j=0;j<condition.effects.length;j++)
				{
					if(condition.effects[j] > -1)
					{
						mssgParts.push("&nbsp;&nbsp;&nbsp;" + condition.effectStats[j] + " has increased by " + condition.effects[j]);
					}
					else
					{
						mssgParts.push("&nbsp;&nbsp;&nbsp;" + condition.effectStats[j] + " has decreased by " + Math.abs(condition.effects[j]));
					}
				}
			}
		}
		
		mssg = "";
		for(i=0;i<mssgParts.length;i++)
		{
			if(i != 0)
			{
				mssg += "<br/>";
			}
			mssg += mssgParts[i];
		}
		
		if(mssg == "")
		{
			mssg = "Nothing happened";
		}
		
		if(this.equipType == "")
		{
			itemNum = user.items.indexOf(this);
			user.items.splice(itemNum, 1);
		}
		
		return mssg;
	}
}



function Spells()
{
	this.spells = new Array();
	
	this.addSpell = function(name, image, canTarget, mp, range, splashRange, effects, effectStats, cures, inflicts)
	{
		spell = new Spell(name, image, canTarget, mp, range, splashRange, effects.toString(), effectStats.toString(), cures.toString(), inflicts);
		this.spells.push(spell);
		
		return spell;
	}
	
	this.getSpell = function(name)
	{
		var i;
		for(i=0;i<this.spells.length;i++)
		{
			if(this.spells[i].name == name)
			{
				return this.spells[i];
			}
		}
	}
}

function Spell(name, image, canTarget, mp, range, splashRange, effects, effectStats, cures, inflicts)
{
	this.name = name;
	this.image = image;
	this.canTarget = canTarget;
	this.MP = mp;
	this.range = range;
	this.splashRange = splashRange;
	
	var i;
	var j;
	
	this.effects = new Array();
	if(effects != "")
	{
		this.effects = effects.split(",");
		for(i=0;i<this.effects.length;i++)
		{
			this.effects[i] = parseInt(this.effects[i]);
		}
	}
	
	this.effectStats = new Array();
	if(effectStats != "")
	{
		this.effectStats = effectStats.split(",");
		for(i=0;i<this.effectStats.length;i++)
		{
			this.effectStats[i] = this.effectStats[i].trim();
		}
	}
	
	this.cures = new Array();
	if(cures != "")
	{
		this.cures = cures.split(",");
		for(i=0;i<this.cures.length;i++)
		{
			this.cures[i] = this.cures[i].trim();
		}
	}
	
	this.inflicts = inflicts;
	
	this.cast = function(target)
	{
		targets = new Array();
		targets.push(target);
		
		if(inBattle == true && this.splashRange > 0)
		{
			targets = turn.targets;
		}
				
		mssgParts = new Array();
		
		var i;
		var j;
		
		for(i=0;i<targets.length;i++)
		{
			if(this.effects.length > 0)
			{
				for(j=0;j<this.effects.length;j++)
				{
					oldStat = targets[i][this.effectStats[j]];
					targets[i][this.effectStats[j]] += this.effects[j];
					
					if(targets[i]["max" + this.effectStats[j]] != null && targets[i][this.effectStats[j]] > targets[i]["max" + this.effectStats[j]])
					{
						targets[i][this.effectStats[j]] = targets[i]["max" + this.effectStats[j]];
					}
					else if(targets[i][this.effectStats[j]] < 0)
					{
						targets[i][this.effectStats[j]] = 0;
					}
					
					mssgChange = " increased by ";
					if(oldStat > targets[i][this.effectStats[j]])
					{
						mssgChange = " decreased by ";
					}
					
					mssgEffect = Math.abs(targets[i][this.effectStats[j]] - oldStat);
					mssgPart = targets[i].name + "'s " + this.effectStats[j] + mssgChange + mssgEffect;
					mssgParts.push(mssgPart);
				}
			}
			
			if(this.cures.length > 0 && this.cures.indexOf(targets[i].status) > -1)
			{
				var curedStatus = targets[i].status;
				statusConditions.cureCondition(targets[i]);
			
				mssgParts.push(targets[i].name + " is no longer " + curedStatus);
			}
			
			if(this.inflicts != "")
			{
				if(inBattle == false || targets[i].status == "dead")
				{
					mssgParts.push("failed to make " + targets[i].name + " " + this.inflicts);
				}
				else if(targets[i].status != "ok")
				{
					mssgParts.push("failed to make " + targets[i].name + " " + this.inflicts + " because " + targets[i].name + " is " + targets[i].status);
				}
				else
				{
					statusConditions.inflictCondition(this.inflicts, targets[i]);
					var condition = targets[i].statusCondition;
					
					mssgParts.push(targets[i].name + " is now " + targets[i].status);
					
					for(j=0;j<condition.effects.length;j++)
					{
						if(condition.effects[j] > -1)
						{
							mssgParts.push("&nbsp;&nbsp;&nbsp;" + condition.effectStats[j] + " has increased by " + condition.effects[j]);
						}
						else
						{
							mssgParts.push("&nbsp;&nbsp;&nbsp;" + condition.effectStats[j] + " has decreased by " + Math.abs(condition.effects[j]));
						}
					}
				}
			}
		}
		
		mssg = "";
		for(i=0;i<mssgParts.length;i++)
		{
			if(i != 0)
			{
				mssg += "<br/>";
			}
			mssg += mssgParts[i];
		}
		
		if(mssg == "")
		{
			mssg = "Nothing happened";
		}
		
		return mssg;
	}
}



function StatusConditions()
{
	this.conditions = new Array();
	
	this.addCondition = function(name, effects, effectStats, counters)
	{
		var newCond = new StatusCondition(name, effects, effectStats, counters);
		this.conditions.push(newCond);
		return newCond;
	}
	
	this.getCondition = function(name)
	{
		var i;
		for(i=0;i<this.conditions.length;i++)
		{
			if(this.conditions[i].name == name)
			{
				return this.conditions[i];
			}
		}
	}
	
	this.inflictCondition = function(name, target)
	{
		var protoCondition = this.getCondition(name);
		
		var condition = new StatusCondition(name, protoCondition.effects.toString(), protoCondition.effectStats.toString(), protoCondition.counters);
		
		var i;
		for(i=0;i<condition.effects.length;i++)
		{
			// if effect is negative, don't go past 1
			if(condition.effects[i] < 0)
			{
				if(target[condition.effectStats[i]] + condition.effects[i] < 1)
				{
					condition.effects[i] = (target[condition.effectStats[i]] - 1) * -1;
				}
			}
			
			// if effect is positive, don't go past max
			if(condition.effects[i] > 0)
			{
				if(target["max" + condition.effectStats[i]] != null && target[condition.effectStats[i]] + condition.effects[i] > target["max" + condition.effectStats[i]])
				{
					condition.effects[i] = target["max" + condition.effectStats[i]];
				}
			}
			
			target[condition.effectStats[i]] += condition.effects[i];
			
			
			// if effectStat is maxSomething, make sure the something isnt more than max
			if(condition.effectStats[i].indexOf("max") == 0)
			{
				var something = condition.effectStats[i].substring(3, condition.effectStats[i].length);
				
				if(target[something] != null && target[something] > target[condition.effectStats[i]])
				{
					target[something] = target[condition.effectStats[i]];
				}
			}
		}
		
		target.statusCondition = condition;
		target.status = name;
	}
	
	this.cureCondition = function(target)
	{
		if(target.statusCondition != null)
		{
			var condition = target.statusCondition;
			var i;
			for(i=0;i<condition.effects.length;i++)
			{
				target[condition.effectStats[i]] -= condition.effects[i];
			
				// not less than 1
				if(target[condition.effectStats[i]] < 1)
				{
					target[condition.effectStats[i]] = 1;
				}
				
				// not more that max
				if(target["max" + condition.effectStats[i]] != null && target[condition.effectStats[i]] > target["max" + condition.effectStats[i]])
				{
					target[condition.effectStats[i]] = target["max" + condition.effectStats[i]];
				}
				
				// if the effectStat was maxSomething, make sure something isn't more than max
				if(condition.effectStats[i].indexOf("max") == 0)
				{
					var something = condition.effectStats[i].substring(3, condition.effectStats[i].length);
					
					if(target[something] != null && target[something] > target[condition.effectStats[i]])
					{
						target[something] = target[condition.effectStats[i]];
					}
				}
				
			}
			
			target.statusCondition = null;
			target.status = "ok";
		}
	}
}

function StatusCondition(name, effects, effectStats, counters)
{
	var i;
	this.name = name;
	
	this.effects = effects.split(",");
	for(i=0;i<this.effects.length;i++)
	{
		this.effects[i] = parseInt(this.effects[i]);
	}
	
	this.effectStats = effectStats.split(",");
	for(i=0;i<this.effectStats.length;i++)
	{
		this.effectStats[i] = this.effectStats[i].trim();
	}
	
	this.counters = counters;
	this.firstTurn = true;
}

/****	end constructors	****/

/*****************************************************
		NON-SPECIFIC FUNCTIONS
*****************************************************/

function setSplashScreen(screen)
{
	var ssc = document.getElementById("splashScreenContainer");
	ssc.style.cssFloat = "left";
	ssc.style.opacity = "0";
	ssc.style.position = "fixed";
	
	getScreenDimensions();
	
	ssc.innerHTML = screen;
	ssWidth = ssc.offsetWidth;
	ssHeight = ssc.offsetHeight;
	
	if(ssWidth < screenWidth)
	{
		ssc.style.left = Math.floor((screenWidth - ssWidth) / 2) + "px";
	}
	if(ssHeight < screenHeight)
	{
		ssc.style.top = Math.floor((screenHeight - ssHeight) / 2) + "px";
	}
	
	ssc.style.opacity = "1";
}

function newGame()
{
	if(prologue.length > 0)
	{
		prologueIndex = 0;
		setSplashScreen(prologue[0]);
	}
	else
	{
		document.body.removeChild(document.getElementById("splashScreenContainer"));
		beginning();
	}
}

function prologueNext()
{
	if(prologueIndex + 1 < prologue.length)
	{
		prologueIndex++;
		setSplashScreen(prologue[prologueIndex]);
	}
	else
	{
		document.body.removeChild(document.getElementById("splashScreenContainer"));
		beginning();
	}
}

function beginning()
{
	currentCharacter = playerCharacters.chars[0];
	playerTeam.push(currentCharacter);
	
	setLocation(startLocation);
	placeUnit(currentCharacter, startLocationX, startLocationY);
	
	center(startLocationX, startLocationY);
	
	// setup controls
	document.getElementById("interface").innerHTML = nonbattleControls;
	standardControlButtons = document.getElementById("controlButtons").innerHTML;
	
	positionNonbattleControls();
}

function endGame()
{
	busy = true;
	closeDialog();

	var currentCharIndex = playerCharacters.chars.indexOf(currentCharacter);
	var charDiv = document.getElementById("player" + currentCharIndex);
	
	charDiv.setAttribute("onClick", "");
	
	var gameBoardDiv = document.getElementById("gameBoard");
	var interfaceDiv = document.getElementById("interface");
	var toolTipDiv = document.getElementById("toolTip");
	
	if(charDiv.style.opacity == "")
	{
		charDiv.style.opacity = 1;
	}
	if(gameBoardDiv.style.opacity == "")
	{
		gameBoardDiv.style.opacity = 1;
	}
	if(interfaceDiv.style.opacity == "")
	{
		interfaceDiv.style.opacity = 1;
	}
	if(toolTipDiv.style.opacity == "")
	{
		toolTipDiv.style.opacity = 1;
	}
	
	if(charDiv.style.opacity > 0.1)
	{
		var newOpacity = (Math.floor((charDiv.style.opacity - 0.1) * 10)) / 10;
		
		charDiv.style.opacity = newOpacity;
		gameBoardDiv.style.opacity = newOpacity;
		interfaceDiv.style.opacity = newOpacity;
		toolTipDiv.style.opacity = newOpacity;
		
		egto = setTimeout("endGame()", 100);
	}
	else
	{
		var ssc = document.createElement("div");
		var idAttr = document.createAttribute("id");
		idAttr.nodeValue = "splashScreenContainer";
		ssc.setAttributeNode(idAttr);
		document.body.appendChild(ssc);
		
		if(epilogue.length > 0)
		{
			epilogueIndex = 0;
			setSplashScreen(epilogue[0]);
		}
		else
		{
			setSplashScreen('<div style="background-color:#ffffff;padding:20px;">The End</div>');
		}
	}
}

function epilogueNext()
{
	if(epilogueIndex + 1 < epilogue.length)
	{
		epilogueIndex++;
		setSplashScreen(epilogue[epilogueIndex]);
	}
	else
	{
		var loc = document.location.toString();
		document.location = loc;
	}
}

function setLocation(locName)
{
	var loc = locations.getLocation(locName);
	walkableSpaces = new Array();
	
	board = "";
	var i = 0;
	var j = 0;
	for(i=0;i<loc.spaces.length;i++)
	{
		board += '<div style="display:inline-block;">';
		for(j=0;j<loc.spaces[i].length;j++)
		{
			board += '<div class="space" id="';
			board += loc.spaces[i][j].id;
			board += '" link="' + loc.spaces[i][j].link;
			board += '" style="background-color:';
			board += loc.spaces[i][j].color;
			board += ';height:' + tileSize + 'px';
			board += ';width:' + tileSize + 'px';
			if(loc.spaces[i][j].image.length > 0)
			{
				board += ';background-image:url(\'images/';
				board += loc.spaces[i][j].image;
				board += '\')';
			}
			board += '"><span style="visibility:hidden;">&nbsp;</span></div>';
			
			if(loc.spaces[i][j].walk != 0)
			{
				walkableSpaces.push(loc.spaces[i][j].id);
			}
		}
		board += '</div>';
	}
	
	document.getElementById("gameBoard").innerHTML = board;
	currentLocation = loc;
	
	colWidth = document.getElementById("0-0").parentNode.offsetWidth;
	document.getElementById("gameBoard").style.width = colWidth * loc.width + "px";
	
	// so keyHandler works in ie w/o having to click on the gameboard
	document.body.focus();
	
	if(loc.things.length > 0)
	{
		for(i=0;i<loc.things.length;i++)
		{
			placeThing(loc, loc.things[i]);
		}
	}
}

function placeThing(loc, thing)
{
	if(thing.spaceWalk == null)
	{
		thing.spaceWalk = loc.spaces[thing.x][thing.y].walk;
	}
	
	loc.spaces[thing.x][thing.y].walk = 0;

	spaceId = thing.x + "-" + thing.y;
	thingCode = '<img id="thing_' + thing.name + '" src="images/' + thing.image + '" ';
	if(thing.click != null)
	{
		click = 'clickThing(\'' + loc.name + '\', \'' + thing.name + '\')';
		thingCode += 'style="cursor:pointer;" onClick="' + click + '" ';
	}
	thingCode += '/>';
	document.getElementById(spaceId).innerHTML = thingCode;
}

function removeThing(thing)
{
	// if player has continued this might be a copy, so let's make sure we have the real thing
	thing = currentLocation.getThing(thing.name);
	
	spaceId = thing.x + "-" + thing.y;
	
	document.getElementById(spaceId).innerHTML = '<span style="visibility:hidden;">&nbsp</span>';
	
	thingNum = currentLocation.things.indexOf(thing);

	currentLocation.things.splice(thingNum, 1);
	
	currentLocation.spaces[thing.x][thing.y].walk = thing.spaceWalk;
}

function placeUnit(unit, x, y)
{
	if(playerTeam.indexOf(unit) > -1)
	{
		team = "player";
		index = playerTeam.indexOf(unit);
	}
	else
	{
		team = "enemy";
		index = enemyTeam.indexOf(unit);
	}
	
	spaceTop = document.getElementById(x + "-" + y).offsetTop;
	spaceLeft = document.getElementById(x + "-" + y).offsetLeft;
	
	
	charDiv = document.createElement("div");
	idAttr = document.createAttribute("id");
	idAttr.nodeValue = team + index;
	styleAttr = document.createAttribute("style");
	styleAttr.nodeValue = "width:" + tileSize + "px;height:" + tileSize + "px;overflow:hidden;position:absolute;top:" + spaceTop + "px;left:" + spaceLeft + "px;";
	charDiv.setAttributeNode(idAttr);
	charDiv.setAttributeNode(styleAttr);
	document.body.appendChild(charDiv);
	
	unit.x = x;
	unit.y = y;
	unit.elementId = team + index;

	charDiv.innerHTML = '<img id="' + team + index + 'Img" src="images/' + unit.image + '" style="position:relative;top:0px;left:0px;" />';
	
	charDiv.setAttribute("onMouseover", "setTooltip('" + team + "'," + index + ")");
	charDiv.setAttribute("onMouseout" , "clearTooltip()");
	
	if(inBattle == false)
	{
		charDiv.style.cursor = "pointer";
		charDiv.setAttribute("onClick", "openControls(\"" + unit.name + "\")");
	}
}

function keyHandler(evnt)
{
	if(window.event) // ie
	{
		keyCode = evnt.keyCode;
	}
	else
	{
		keyCode = evnt.which;
	}
	
	if(keyCode == 71)//spacebar
	{
		window.open("guide.html", "guide", "");
	}
	else if(busy == false)
	{
		if(inBattle == true)
		{
			if(keyCode == 87)//w
			{
				window.scrollBy(0, (-1 * scrollSpeed * 5));
			}
			else if(keyCode == 65)//a
			{
				window.scrollBy((-1 * scrollSpeed * 5), 0);
			}
			else if(keyCode == 83)//s
			{
				window.scrollBy(0, scrollSpeed * 5);
			}
			else if(keyCode == 68)//d
			{
				window.scrollBy(scrollSpeed * 5, 0);
			}
		}
		else
		{
			if(dialogOpen)
			{
				closeDialog();
			}
			if(controlsOpen)
			{
				closeControls();
			}
			
			if(keyCode == 87)//w
			{
				//move up
				newX = currentCharacter.x;
				newY = currentCharacter.y - 1;
				
				move(newX, newY);
			}
			else if(keyCode == 65)//a
			{
				//move left
				newX = currentCharacter.x - 1;
				newY = currentCharacter.y;
				
				move(newX, newY);
			}
			else if(keyCode == 83)//s
			{
				//move down
				newX = currentCharacter.x;
				newY = currentCharacter.y + 1;
				
				move(newX, newY);
			}
			else if(keyCode == 68)//d
			{
				//move right
				newX = currentCharacter.x + 1;
				newY = currentCharacter.y;
				
				move(newX, newY);
			}
		}
	}
}

function magicHandler()
{
	if(inBattle == true)
	{
		battleMagicHandler();
	}
	else
	{
		nonbattleMagicHandler();
	}
}

function itemHandler()
{
	if(inBattle == true)
	{
		battleItemHandler();
	}
	else
	{
		nonbattleItemHandler();
	}
}

function move(destX, destY)
{
	if(inBattle == true)
	{
		document.getElementById("endTurnButton").disabled = true;

		route = getRoute(turn.going.x, turn.going.y, destX, destY);
		
		if(turn.team == playerTeam)
		{
			done = playerFinishedMoving;
		}
		else
		{
			done = enemyFinishedMoving;
		}
		
		walk(turn.going, route, done);
	}
	else // inBattle == false
	{
		if(destX < 0 || destY < 0){return;}
		else if(destX > currentLocation.width + 1 || destY > currentLocation.height + 1){return;}
		else if(currentLocation.spaces[destX][destY].walk == 1)
		{
			busy = true;
			
			route = new Array(destX + "-" + destY);
			
			walk(currentCharacter, route, null);
		}
	}
}

function walk(walkingChar, route, done)
{
	idParts = route[0].split("-");
	x = parseInt(idParts[0]);
	y = parseInt(idParts[1]);
	
	spaceTop = document.getElementById(route[0]).offsetTop;
	spaceLeft = document.getElementById(route[0]).offsetLeft;
	
	charDiv = document.getElementById(walkingChar.elementId);
	charImg = document.getElementById(walkingChar.elementId + "Img");
	
	// this will be 1, -1, or 0. determines the direction the character needs to move.
	moveX = x - walkingChar.x;
	moveY = y - walkingChar.y;
	
	// set the direction for the image
	if(moveX > 0)
	{
		// face right
		charImg.style.top = (-1 * tileSize) + "px";
	}
	else if(moveX < 0)
	{
		// face left
		charImg.style.top = (-2 * tileSize) + "px";
	}
	else if(moveY > 0)
	{
		// face down
		charImg.style.top = "0px";
	}
	else if(moveY < 0)
	{
		// face up
		charImg.style.top = (-3 * tileSize) + "px";
	}
	
	charDiv.style.left = charDiv.offsetLeft + (10 * moveX) + "px";
	charDiv.style.top = charDiv.offsetTop + (10 * moveY) + "px";
	
	// scroll the screen so the character is still in the center
	targetCenterX = charDiv.offsetLeft + Math.round(charDiv.offsetWidth / 2);
	targetCenterY = charDiv.offsetTop + Math.round(charDiv.offsetHeight / 2);
	scrollX = targetCenterX - Math.round(screenWidth / 2) + centerOffsetX;
	scrollY = targetCenterY - Math.round(screenHeight / 2) + centerOffsetY;
	scrollTo(scrollX, scrollY);
	
	// this is what does the walking animation
	if(charImg.offsetLeft == 0)
	{
		charImg.style.left = (-1 * tileSize) + "px";
	}
	else
	{
		charImg.style.left = "0px";
	}
	
	if(charDiv.offsetLeft == spaceLeft && charDiv.offsetTop == spaceTop)
	{
		walkingChar.x = x;
		walkingChar.y = y;
		route.shift();
	}
	
	if(route.length > 0)
	{
		walking = walkingChar;
		doneFunction = done;
		w = setTimeout("walk(walking, route, doneFunction)", Math.round(100/walkSpeed));
	}
	else if(inBattle == true)
	{
		done();
	}
	else // inBattle == false
	{
		charImg.style.left = "0px";
		
		link = document.getElementById(currentCharacter.x + "-" + currentCharacter.y).getAttribute("link");
		if(link != "")
		{
			tempA = link.split("|");
			tempB = tempA[1].split("-");
			
			locName = tempA[0];
			playerX = parseInt(tempB[0]);
			playerY = parseInt(tempB[1]);
			
			document.body.removeChild(document.getElementById(currentCharacter.elementId));
			
			setLocation(locName);
	
			if(currentLocation.battle == null)
			{
				placeUnit(currentCharacter, playerX, playerY);
				
				center(playerX, playerY);
			}
			else
			{
				setupBattle(currentLocation.battle);
			}
		}
		
		busy = false;
	}
	
}

function setTooltip(team, index)
{
	if(team == "player")
	{
		ttc = playerTeam[index];
	}
	else
	{
		ttc = enemyTeam[index];
	}
	
	tto = setTimeout("displayTooltip()", 500);
}

function displayTooltip()
{
	toolTip = document.getElementById("toolTip");
	charDiv = document.getElementById(ttc.elementId);

	tooltipText = ttc.name;
	if(ttc.status != "ok")
	{
		tooltipText += "<br/>(" + ttc.status + ")";
	}
	tooltipText += "<br/>HP: " + ttc.HP + "/" + ttc.maxHP + "<br/>MP: " + ttc.MP + "/" + ttc.maxMP + "<br/>Att/Def: " + ttc.attack + "/" + ttc.defense;
	
	toolTip.innerHTML = tooltipText;
	if((currentLocation.width - ttc.x) * tileSize > toolTip.offsetWidth + 10)
	{
		toolTip.style.left = (charDiv.offsetLeft + charDiv.offsetWidth + 5) + "px";
	}
	else
	{
		toolTip.style.left = (charDiv.offsetLeft - toolTip.offsetWidth - 5) + "px";
	}
	
	if((currentLocation.height - ttc.y) * tileSize > toolTip.offsetHeight + 5)
	{
		toolTip.style.top = charDiv.offsetTop + "px";
	}
	else
	{
		toolTip.style.top = (charDiv.offsetTop + tileSize - toolTip.offsetHeight) + "px";
	}
	
	toolTip.style.visibility = "visible";
}

function clearTooltip()
{
	clearTimeout(tto);
	document.getElementById("toolTip").style.visibility = "hidden";
}

function shuffleArray(array) 
{
	var i = 0;
	var j = 0;

	// The Fisher-Yates Shuffle:
	for (i=array.length-1; i>0; i--) 
	{
		j = Math.floor(Math.random() * (i + 1));
		temp = array[i];
		array[i] = array[j];
		array[j] = temp;
	}
	return array;
}

function addCssClass(id, cssClass)
{
	classes = document.getElementById(id).getAttribute("class");
	if(classes == null){classes = "";}
	
	classArray = classes.split(" ");
	classArray.push(cssClass);
	document.getElementById(id).setAttribute("class", classArray.join(" "));
}

function removeCssClass(id, cssClass)
{
	var i = 0;

	classes = document.getElementById(id).getAttribute("class");
	
	if(classes != null)
	{
		classArray = classes.split(" ");
		for(i=0;i<classArray.length;i++)
		{
			if(classArray[i] == cssClass)
			{
				classArray.splice(i, 1);
			}
		}
		document.getElementById(id).setAttribute("class", classArray.join(" "));
	}
}

function getScreenDimensions()
{
	if (window.innerWidth)
	{
		screenWidth = window.innerWidth;
		screenHeight = window.innerHeight;
	}
	else if(document.documentElement.clientWidth && document.documentElement.clientWidth!=0)
	{
		screenWidth = document.documentElement.clientWidth;
		screenHeight = document.documentElement.clientHeight;
	}
	else if(document.body.clientWidth)
	{
		screenWidth = document.body.clientWidth;
		screenHeight = document.body.clientWidth;
	}
	else
	{
		screenWidth = 1000;
		screenHeight = 1000;
	}
}

function saveGame()
{
	var save = new Object;
	
	save.locations = locations;
	save.playerCharacters = playerCharacters;
	save.playerTeam = new Array();
	for(var i=0;i<playerTeam.length;i++)
	{
		save.playerTeam.push(playerTeam[i].name)
	}
	save.currentLocation = currentLocation.name;
	save.currentCharacter = currentCharacter.name;
	save.playerMoney = playerMoney;
	
	var saveStr = JSON.stringify(save, function(key, value)
	{
		if(typeof value == "function")
		{
			var funcText = value.toString();
			return funcText;
		}
		else
		{
			return value;
		}
	});
	
	try
	{
		localStorage.trpgSaveStr = saveStr;
		return true;
	}
	catch(e)
	{
		return false;
	}
}

function continueGame()
{
	inBattle = false;

	if(localStorage.trpgSaveStr == null)
	{
		location.reload();
	}
	else
	{
		saveObj = JSON.parse(localStorage.trpgSaveStr);
		saveObj = objectify(saveObj);
		
		locations = saveObj.locations;
		playerCharacters = saveObj.playerCharacters;
		playerTeam = new Array();
		
		for(var i=0;i<saveObj.playerTeam.length;i++)
		{
			playerTeam.push(playerCharacters.getCharacter(saveObj.playerTeam[i]));
		}
		
		currentLocation = locations.getLocation(saveObj.currentLocation);
		currentCharacter = playerCharacters.getCharacter(saveObj.currentCharacter);
		playerMoney = saveObj.playerMoney;
		
		try
		{
			document.body.removeChild(document.getElementById("splashScreenContainer"));
		}
		catch(e){}
		
		setLocation(currentLocation.name);
		placeUnit(currentCharacter, currentCharacter.x, currentCharacter.y);
		
		center(currentCharacter.x, currentCharacter.y);
		
		// setup controls
		document.getElementById("interface").innerHTML = nonbattleControls;
		standardControlButtons = document.getElementById("controlButtons").innerHTML;
		
		positionNonbattleControls();
	}
}

function objectify(obj)
{
	for(var key in obj)
	{
		if(typeof(obj[key]) == "object")
		{
			obj[key] = objectify(obj[key]);
		}
		else if(typeof(obj[key]) == "string" && obj[key].indexOf("function") == 0)
		{
			eval("obj[key] = " + obj[key]);
		}
	}
	return obj;
}

function openGuide()
{
	var locStr = document.location.toString();
	var locParts = locStr.split("/");
	var guideLoc = "";
	var i;
	
	for(i=0;i<locParts.length;i++)
	{
		if(i == locParts.length-1)
		{
			guideLoc += "guide.html";
		}
		else
		{
			guideLoc += locParts[i] + "/";
		}
	}
	
	window.open(guideLoc);
}

/****	end non-specific functions	****/

/*****************************************************
		BATTLE-SPECIFIC FUNCTIONS
*****************************************************/

function addEnemy(name)
{
	protoEnemy = enemyCharacters.getCharacter(name);
	newEnemy = new Character(protoEnemy.name, protoEnemy.attack, protoEnemy.defense, protoEnemy.maxHP, protoEnemy.maxMP, protoEnemy.speed, protoEnemy.moveRange, protoEnemy.attackRange, protoEnemy.image);
		
	newEnemy.mode = protoEnemy.mode;
	newEnemy.money = protoEnemy.money;
	newEnemy.exp = protoEnemy.exp;
	
	enemyTeam.push(newEnemy);
	
	return newEnemy;
}

function setInterface()
{
	document.getElementById("interface").innerHTML = battleControls + scoreBoard;
	
	setScoreBoard();
	
	document.getElementById("attackButton").disabled = true;
	document.getElementById("magicButton").disabled = true;
	document.getElementById("itemButton").disabled = true;
	
	positionBattleControls();
	positionScoreBoard();
	
	document.getElementById("controls").style.visibility = "visible";
	document.getElementById("scoreBoard").style.visibility = "visible";
}

function setScoreBoard()
{
	var playerBoard = "";
	var enemyBoard = "";
	var i;
	
	for(i=0;i<playerTeam.length;i++)
	{
		playerBoard += getCharBoard("player", i);
	}
		
	for(i=0;i<enemyTeam.length;i++)
	{
		enemyBoard += getCharBoard("enemy", i);
	}
		
	document.getElementById("scoreBoardPlayerChars").innerHTML = playerBoard;
	document.getElementById("scoreBoardEnemyChars").innerHTML = enemyBoard;
	
	for(i=0;i<playerTeam.length;i++)
	{
		if(playerTeam[i].status == "dead")
		{
			addCssClass("scoreBoardPlayerChar" + i, "scoreBoardDeadChar");
		}
	}
}

function getCharBoard(team, charNum)
{
	if(team == "player")
	{
		board = scoreBoardPlayerChar;
		thisChar = playerTeam[charNum];
	}
	else
	{
		board = scoreBoardEnemyChar;
		thisChar = enemyTeam[charNum];
	}

	while(board.indexOf("%ID%") > -1)
	{
		board = board.replace("%ID%", charNum);
	}
	while(board.indexOf("%NAME%") > -1)
	{
		board = board.replace("%NAME%", thisChar.name);
	}
	while(board.indexOf("%HP%") > -1)
	{
		board = board.replace("%HP%", thisChar.HP);
	}
	while(board.indexOf("%MAXHP%") > -1)
	{
		board = board.replace("%MAXHP%", thisChar.maxHP);
	}
	
	return board;
}

function setPanel()
{
	var i = 0;

	panelStuff = '<div><div style="float:left;padding:3px;text-align:center;"><div style="width:'
	panelStuff += tileSize + 'px;height:' + tileSize + 'px;overflow:hidden;"><img src="images/';
	panelStuff += turn.going.image;
	panelStuff += '" /></div>' + turn.going.name + '</div>';
	
	panelStuff += '<div><div style="float:left;padding:3px;padding-left:8px;">';	
	if(turn.team == playerTeam)
	{
		panelStuff += 'Class: ' + turn.going.charClass + '<br/>';
	}	
	panelStuff += 'HP: ' + turn.going.HP + '/' + turn.going.maxHP + '<br/>';
	panelStuff += 'MP: ' + turn.going.MP + '/' + turn.going.maxMP + '</div>';
	
	panelStuff += '<div style="float:left;padding:3px;padding-left:8px;">';	
	if(turn.team == playerTeam)
	{
		panelStuff += 'Level: ' + turn.going.level + '<br/>';
	}	
	panelStuff += 'Attack: ' + turn.going.attack + '<br/>';
	panelStuff += 'Defense: ' + turn.going.defense + '</div></div>';
	
	panelStuff += '<div style="float:left;padding:3px;padding-left:8px;">';
	panelStuff += 'Status: ' + turn.going.status + '<br/>';	
	if(turn.team == playerTeam)
	{
		panelStuff += 'Speed: ' + turn.going.speed + '<br/>';
		panelStuff += 'Move: ' + turn.going.moveRange;
	}	
	panelStuff += '</div></div>';
	
	panelStuff += '<div style="clear:left;"><div style="float:left;text-align:center;">Equipment:&nbsp;</div>';
	if(turn.going.equipment.length == 0)
	{
		panelStuff += 'None';
	}
	else
	{
		for(i=0;i<turn.going.equipment.length;i++)
		{
			panelStuff += '<img id="equipment' + i + '" style="margin:5px;float:left;" src="images/' + turn.going.equipment[i].image + '" />';
		}
	}
	panelStuff += '<div>';	
	document.getElementById("panel").innerHTML = panelStuff;
}

function clearPanel()
{
	document.getElementById("panel").innerHTML = "";
}

function panelOut(panelStuff)
{
	document.getElementById("panel").innerHTML += panelStuff;
	document.getElementById("panel").scrollTop = document.getElementById("panel").scrollHeight;
}

function normalize()
{
	if(turn.moveOptions != null)
	{
		while(turn.moveOptions.length > 0)
		{
			removeCssClass(turn.moveOptions[0].spaceID, "moveOption");
			document.getElementById(turn.moveOptions[0].spaceID).setAttribute("onClick", "");
			turn.moveOptions.shift();
		}
	}
	
	if(turn.rangeSpaces != null)
	{
		while(turn.rangeSpaces.length > 0)
		{
			removeCssClass(turn.rangeSpaces[0].spaceID, "attackRange");
			removeCssClass(turn.rangeSpaces[0].spaceID, "spellRange");
			removeCssClass(turn.rangeSpaces[0].spaceID, "itemRange");
			turn.rangeSpaces.shift();
		}
	}
	
	if(turn.targetOptions != null)
	{
		while(turn.targetOptions.length > 0)
		{
			document.getElementById(turn.targetOptions[0].elementId).style.cursor = "default";
			document.getElementById(turn.targetOptions[0].elementId).setAttribute("onClick", "");
			
			if(playerTeam.indexOf(turn.targetOptions[0]) > -1)
			{
				var index = playerTeam.indexOf(turn.targetOptions[0]);
				document.getElementById(turn.targetOptions[0].elementId).setAttribute("onMouseover", "setTooltip('player', " + index + ")");
			}
			else
			{
				var index = enemyTeam.indexOf(turn.targetOptions[0]);
				document.getElementById(turn.targetOptions[0].elementId).setAttribute("onMouseover", "setTooltip('enemy', " + index + ")");
			}
			
			document.getElementById(turn.targetOptions[0].elementId).setAttribute("onMouseout", "clearTooltip()");
			
			turn.targetOptions.shift();
		}
	}
	
	document.getElementById(turn.going.elementId).style.cursor = "default";
	document.getElementById(turn.going.elementId).setAttribute("onClick", "");
}

function startTurn()
{
	setNext();
	
	if(playerTeam.indexOf(turn.going) > -1)
	{
		turn.team = playerTeam;
		turn.otherTeam = enemyTeam;
		startCharacterTurn = function(){playerTurn();};
	}
	else
	{
		turn.team = enemyTeam;
		turn.otherTeam = playerTeam;
		
		if(turn.going.bossStrategy != null)
		{
			startCharacterTurn = function(){turn.going.bossStrategy();};
		}
		else
		{
			startCharacterTurn = function(){enemyTurn();};
		}
	}
	
	scrollToCenter(turn.going.x, turn.going.y);	
}

function setNext()
{
	stop = false;
	var i;
	while(stop == false)
	{
		for(i=0;i<bothTeams.length;i++)
		{
			bothTeams[i].timeToTurn--;
			
			if(bothTeams[i].timeToTurn < 1)
			{
				bothTeams[i].timeToTurn = Math.ceil((1 / bothTeams[i].speed) * 100);
				turn.going = bothTeams[i];
				
				// now to shift the array so the next character is first next turn
				onDeckNum = i+1;
				
				if(onDeckNum >= bothTeams.length){onDeckNum = 0;}
				
				onDeck = bothTeams[onDeckNum];
				
				while(bothTeams.indexOf(onDeck) != 0)
				{
					tempChar = bothTeams.shift();
					bothTeams.push(tempChar);
				}
				
				return;
			}
		}
	}
}

function playerTurn()
{
	var i = 0;
	turn.exp = 0;
	turn.money = 0;
	var statusMssg = "";
	
	if(turn.going.statusCondition != null)
	{
		if(turn.going.statusCondition.firstTurn == true)
		{
			turn.going.statusCondition.firstTurn = false;
		}
		else
		{
			var n = Math.random() * turn.going.statusCondition.counters;
			if(n < 1)
			{
				statusMssg = turn.going.name + " is no longer " + turn.going.status + " - ";
				statusConditions.cureCondition(turn.going);
			}
			else
			{
				turn.going.statusCondition.counters--;
			}
		}
	}

	document.getElementById("controlsHead").innerHTML = statusMssg +  'Move Character or <a href="javascript:void(0)" onClick="playerFinishedMoving()">Stay</a>';
	
	//this will need to be undisabled, though
	document.getElementById("endTurnButton").disabled = false;
	
	setPanel();
	
	setMoveOptions();
	
	for(i=0;i<turn.moveOptions.length;i++)
	{
		addCssClass(turn.moveOptions[i].spaceID, "moveOption");
		
		thisSpace = document.getElementById(turn.moveOptions[i].spaceID);
		thisSpace.setAttribute("onClick", "move(" + turn.moveOptions[i].x + ", " + turn.moveOptions[i].y + ")");
	}
	
	document.getElementById(turn.going.elementId).style.cursor = "pointer";
	document.getElementById(turn.going.elementId).setAttribute("onClick", "playerFinishedMoving()");
}

function playerFinishedMoving()
{
	document.getElementById(turn.going.elementId).style.cursor = "default";
	document.getElementById(turn.going.elementId).setAttribute("onClick", "");
	
	document.getElementById(turn.going.elementId + "Img").style.top = "0px";
	document.getElementById(turn.going.elementId + "Img").style.left = "0px";
	
	// unhighlight moveOption spaces
	normalize();	
	
	document.getElementById("controlsHead").innerHTML = "&nbsp;";
	
	// turn on buttons
	document.getElementById("attackButton").disabled = false;
	document.getElementById("magicButton").disabled = false;
	document.getElementById("itemButton").disabled = false;
	document.getElementById("endTurnButton").disabled = false;
}

function attackHandler()
{
	normalize();	
	setPanel();
	
	var i = 0;
	turn.rangeSpaces = getRangeSpaces(turn.going.x, turn.going.y, turn.going.attackRange);
	
	for(i=0;i<turn.rangeSpaces.length;i++)
	{
		addCssClass(turn.rangeSpaces[i].spaceID, "attackRange");
	}
	
	turn.targetOptions = getTargetOptions(turn.going.attackRange, "enemy");
	
	if(turn.targetOptions.length == 0)
	{
		document.getElementById("controlsHead").innerHTML = "No Targets in Range";
	}
	else
	{
		document.getElementById("controlsHead").innerHTML = "Select a Target";
	
		for(i=0;i<turn.targetOptions.length;i++)
		{
			targetIndex = bothTeams.indexOf(turn.targetOptions[i]);
			
			targetDiv = document.getElementById(turn.targetOptions[i].elementId);
			targetDiv.style.cursor = "pointer";
			
			
			targetDiv.setAttribute("onClick", "startAttack(" + targetIndex + ")");
			
			targetDiv.setAttribute("onMouseover", "setSights('attack'," + i + ")");
		}
	}
}

function battleMagicHandler()
{
	normalize();
	
	var i = 0;
	
	// display spells in panel
	panelStuff = '<div><div style="float:left;padding:3px;text-align:center;"><div style="width:';
	panelStuff += tileSize + 'px;height:' + tileSize + 'px;overflow:hidden;"><img src="images/';
	panelStuff += turn.going.image;
	panelStuff += '" /></div>' + turn.going.name + '<br/>MP: ' + turn.going.MP + '/' + turn.going.maxMP + '</div>';
	
	panelStuff += '<div style="float:left;">';
	if(turn.going.spells.length == 0)
	{
		panelStuff += "No Magic";
	}
	else
	{
		for(i=0;i<turn.going.spells.length;i++)
		{
			panelStuff += '<div id="spellDiv' + i + '" style="float:left;padding:5px;text-align:center;cursor:pointer;" onClick="targetSpell(' + i + ')"><img src="images/' + turn.going.spells[i].image + '" /><br/>' + turn.going.spells[i].name + ' (' + turn.going.spells[i].MP + ')' + '</div>';
		}
	}
	panelStuff += '</div>';
	
	//document.getElementById("panel").innerHTML = panelStuff;
	clearPanel();
	panelOut(panelStuff);
}

function targetSpell(spellIndex)
{
	normalize();
	
	var i = 0;
	
	for(i=0;i<turn.going.spells.length;i++)
	{
		spellId = "spellDiv" + i;
		if(i == spellIndex)
		{
			addCssClass(spellId, "spellRange");
		}
		else
		{
			removeCssClass(spellId, "spellRange");
		}
	}

	if(turn.going.MP < turn.going.spells[spellIndex].MP)
	{
		document.getElementById("controlsHead").innerHTML = "Not Enough MP";
	}
	else
	{
		turn.spell = turn.going.spells[spellIndex];
		
		turn.rangeSpaces = getRangeSpaces(turn.going.x, turn.going.y, turn.spell.range);
		
		for(i=0;i<turn.rangeSpaces.length;i++)
		{
			addCssClass(turn.rangeSpaces[i].spaceID, "spellRange");
		}
		
		turn.targetOptions = getTargetOptions(turn.spell.range, turn.spell.canTarget);
		
		if(turn.targetOptions.length == 0)
		{
			document.getElementById("controlsHead").innerHTML = "No Targets in Range";
		}
		else
		{
			document.getElementById("controlsHead").innerHTML = "Select a Target";
		
			for(i=0;i<turn.targetOptions.length;i++)
			{
				targetIndex = bothTeams.indexOf(turn.targetOptions[i]);
				
				targetDiv = document.getElementById(turn.targetOptions[i].elementId);
				targetDiv.style.cursor = "pointer";
				
				targetDiv.setAttribute("onClick", "startMagic(" + targetIndex + ")");
				targetDiv.setAttribute("onMouseover", "setSights('spell'," + i + ")");
			}
		}
	}
}

function battleItemHandler()
{
	var i = 0;
	
	normalize();
	
	// display items in panel
	panelStuff = '<div><div style="float:left;padding:3px;text-align:center;"><div style="width:';
	panelStuff += tileSize + 'px;height:' + tileSize + 'px;overflow:hidden;"><img src="images/';
	panelStuff += turn.going.image;
	panelStuff += '" /></div>' + turn.going.name + '</div>';
	
	turn.usableItems = new Array();
	
	// add usable equipped items first
	for(i=0;i<turn.going.equipment.length;i++)
	{
		if(turn.going.equipment[i].spell != "")
		{
			turn.usableItems.push(turn.going.equipment[i]);
		}
	}
	for(i=0;i<turn.going.items.length;i++)
	{
		if(turn.going.items[i].equipType == "")
		{
			turn.usableItems.push(turn.going.items[i]);
		}
	}
	
	
	panelStuff += '<div style="float:left;">';
	if(turn.usableItems.length < 1)
	{
		panelStuff += "No Items";
	}
	else
	{
		for(i=0;i<turn.usableItems.length;i++)
		{
			panelStuff += '<div id="itemDiv' + i + '" style="float:left;padding:5px;text-align:center;cursor:pointer;" onClick="targetItem(' + i + ')"><img src="images/' + turn.usableItems[i].image + '" /><br/>' + turn.usableItems[i].name + '</div>';
		}
	}
	
	panelStuff += '</div>'
	
	clearPanel();
	panelOut(panelStuff);
}

function targetItem(itemIndex)
{
	normalize();
	
	var i = 0;
	turn.item = turn.usableItems[itemIndex];
	
	for(i=0;i<turn.usableItems.length;i++)
	{
		itemId = "itemDiv" + i;
		if(i == itemIndex)
		{
			addCssClass(itemId, "itemRange");
		}
		else
		{
			removeCssClass(itemId, "itemRange");
		}
	}
	
	if(turn.usableItems[itemIndex].spell != "")
	{
		itemSpell = spells.getSpell(turn.item.spell);
		turn.rangeSpaces = getRangeSpaces(turn.going.x, turn.going.y, itemSpell.range);
		for(i=0;i<turn.rangeSpaces.length;i++)
		{
			addCssClass(turn.rangeSpaces[i].spaceID, "spellRange");
		}
		
		turn.targetOptions = getTargetOptions(itemSpell.range, itemSpell.canTarget);
	}
	else // just a regular usable item
	{
		turn.rangeSpaces = getRangeSpaces(turn.going.x, turn.going.y, 1);
		for(i=0;i<turn.rangeSpaces.length;i++)
		{
			addCssClass(turn.rangeSpaces[i].spaceID, "itemRange");
		}
		
		turn.targetOptions = getTargetOptions(1, "ally");
	}
	
	if(turn.targetOptions.length == 0)
	{
		document.getElementById("controlsHead").innerHTML = "No Targets in Range";
	}
	else
	{
		document.getElementById("controlsHead").innerHTML = "Select a Target";
		
		for(i=0;i<turn.targetOptions.length;i++)
		{
			targetIndex = bothTeams.indexOf(turn.targetOptions[i]);
			
			targetDiv = document.getElementById(turn.targetOptions[i].elementId);
			targetDiv.style.cursor = "pointer";
			
			targetDiv.setAttribute("onClick", "startItem(" + targetIndex + ")");
			
			if(turn.item.spell == "")
			{
				targetDiv.setAttribute("onMouseover", "setSights('item'," + i + ")");
			}
			else
			{
				targetId = turn.targetOptions[i].elementId;
				turn.spell = spells.getSpell(turn.item.spell);
				targetDiv.setAttribute("onMouseover", "setSights('spell'," + i + ")");
			}
		}
	}
}

function finishPlayerTurn()
{
	var i = 0;
	var j = 0;

	if(turn.exp > 0 && turn.money > 0)
	{
		turn.going.exp += turn.exp;
		playerMoney += turn.money;
		
		panelOut("<br/>" + turn.going.name + " gains " + turn.exp + " Exp. and " + turn.money + " " + money);
	}
	else if(turn.exp > 0)
	{
		turn.going.exp += turn.exp;
		
		panelOut("<br/>" + turn.going.name + " gains " + turn.exp + " Exp.");
	}
	else if(turn.money > 0) // I don't think this can actually happen
	{
		playerMoney += turn.money;
		
		panelOut("<br/>" + turn.going.name + " gains " + turn.money + " " + money);
	}
	
	// see if turn.going leveled up
	
	if(turn.going.exp >= Math.round(levelingConstant+(turn.going.level*levelingConstant*(turn.going.level-1)/2)))
	{
		turn.going.level++;
		
		panelOut("<br/><br/>" + turn.going.name + " is now level " + turn.going.level);
		
		template = levelTemplates.getTemplate(turn.going.charClass);
		if(template == null)
		{
			template = levelTemplates.defaultTemplate;
		}
		
		for(i=0;i<template.stats.length;i++)
		{
			currentStat = template.stats[i][0];
			currentVal = turn.going[currentStat];
			
			// factor out effects of equipment
			for(j=0;j<turn.going.equipment.length;j++)
			{
				statIndex = turn.going.equipment[j].equipEffectStats.indexOf(currentStat);
				
				if(statIndex > -1)
				{
					currentVal += turn.going.equipment[j].equipEffects[statIndex] * -1;
				}
			}
			
			// factor out effects of status conditions
			if(turn.going.statusCondition != null)
			{
				statIndex = turn.going.statusCondition.effectStats.indexOf(currentStat);
				
				if(statIndex > -1)
				{
					currentVal += turn.going.statusCondition.effects[statIndex] * -1;
				}
			}
		
			turn.going[currentStat] += Math.ceil(currentVal * (template.stats[i][1]/100));
			
			panelOut("<br/>" + turn.going.name + "'s " + currentStat + " increased by " + Math.ceil(currentVal * (template.stats[i][1]/100)));
			
			if(currentStat == "maxHP")
			{
				document.getElementById("scoreBoardPlayerChar" + playerTeam.indexOf(turn.going) + "MaxHp").innerHTML = turn.going.maxHP;
			}
		}
		
		for(i=0;i<template.spells.length;i++)
		{
			if(template.spells[i][1] == turn.going.level)
			{
				turn.going.learnSpell(template.spells[i][0]);
				
				panelOut("<br/>" + turn.going.name + " learned " + template.spells[i][0]);
			}
		}
	}
	
	
	// see if player won
	othersLeft = 0;
	for(i=0;i<turn.otherTeam.length;i++)
	{
		if(turn.otherTeam[i].status != "dead")
		{
			othersLeft++;
		}
	}
	
	if(othersLeft < 1)
	{
		// player won
		// give spoils to turn.going (in case main character is dead)
		
		panelOut("<br/><br/>You Win<br/>");
		
		if(currentLocation.battle.spoils.length > 0)
		{
			for(i=0;i<currentLocation.battle.spoils.length;i++)
			{
				if(isNaN(currentLocation.battle.spoils[i]))
				{
					items.giveCharacterItem(turn.going, currentLocation.battle.spoils[i]);
					
					firstLetter = currentLocation.battle.spoils[i][0].toLowerCase();
					if(firstLetter == "a" || firstLetter == "e" || firstLetter == "i" || firstLetter == "o" || firstLetter == "u")
					{
						panelOut("<br/>You found an " + currentLocation.battle.spoils[i]);
					}
					else
					{
						panelOut("<br/>You found a " + currentLocation.battle.spoils[i]);
					}
				}
				else
				{
					playerMoney += currentLocation.battle.spoils[i];
					
					if(currentLocation.battle.spoils[i] > 1)
					{
						panelOut("<br/>You found " + currentLocation.battle.spoils[i] + " " + monies);
					}
					else // only 1
					{
						panelOut("<br/>You found " + currentLocation.battle.spoils[i] + " " + money);
					}
				}
			}
		}
		
		// when "end turn" button is clicked (so this is in endTurn()):
		// set currentCharacter to first playerTeam member that isn't dead
		// remove the other characters from the location
		// remove/hide user interface elements
		// set inBattle to false
	}
	
	document.getElementById("endTurnButton").disabled = false;
}

function enemyTurn()
{
	var i = 0;
	var j = 0;
	
	if(turn.going.statusCondition != null)
	{
		if(turn.going.statusCondition.firstTurn == true)
		{
			turn.going.statusCondition.firstTurn = false;
		}
		else
		{
			var n = Math.random() * turn.going.statusCondition.counters;
			if(n < 1)
			{
				document.getElementById("controlsHead").innerHTML = turn.going.name + " is no longer " + turn.going.status;
				statusConditions.cureCondition(turn.going);
			}
			else
			{
				turn.going.statusCondition.counters--;
			}
		}
	}
	
	setPanel();
	
	setMoveOptions();
	turn.moveOptions = getSpaceDanger(turn.moveOptions);
	
	attackOptions = getAttackOptions();
	supportOptions = getSupportOptions();
	defenseOptions = getDefenseOptions();
	
	finalOptions = new Array();
	
	//evaluate attackOptions
	if(attackOptions.length > 1)
	{
		attackOptions.sort(function(a,b) {return a.winability - b.winability;});
		points = 0;
		for(i=0;i<attackOptions.length;i++)
		{
			if(i > 0 && attackOptions[i].winability > attackOptions[i-1].winability)
			{
				points++;
			}		
			attackOptions[i].score = points;
		}
		
		attackOptions.sort(function(a,b) {return a.efficacy - b.efficacy;});
		points = 0;
		for(i=0;i<attackOptions.length;i++)
		{
			if(i > 0 && attackOptions[i].efficacy > attackOptions[i-1].efficacy)
			{
				points++;
			}
			attackOptions[i].score += points;
		}
		
		attackOptions.sort(function(a,b) {return b.dist - a.dist;});
		points = 0;
		for(i=0;i<attackOptions.length;i++)
		{
			if(i > 0 && attackOptions[i].dist < attackOptions[i-1].dist)
			{
				points++;
			}
			attackOptions[i].score += points;
		}
		
		// add bonus points for splash targets
		for(i=0;i<attackOptions.length;i++)
		{
			attackOptions[i].score += attackOptions[i].splashTargets;
		}
		
		attackOptions = shuffleArray(attackOptions);
		attackOptions.sort(function(a,b) {return b.score - a.score;});
		attackOptions.sort(function(a,b) {return b.inRange - a.inRange;});
		attackOptions.sort(function(a,b) {return b.finishOff - a.finishOff;});
		
		// if there are some finishOff=1's, lowest winability should get priority
		// that way they finish off the toughest guy first
		fo = new Array();
		nfo = new Array();
		for(i=0;i<attackOptions.length;i++)
		{
			if(attackOptions[i].finishOff == 1)
			{
				fo.push(attackOptions[i]);
			}
			else
			{
				nfo.push(attackOptions[i]);
			}
		}
		if(fo.length > 1)
		{
			fo.sort(function(a,b) {return a.winability - b.winability;});
		}
		attackOptions = fo.concat(nfo);
	}
	
	finalOptions.push(attackOptions[0]);	
	
	// evaluate support options
	if(supportOptions.length > 1)
	{
		supportOptions.sort(function(a,b) {return a.efficacy - b.efficacy;});
		points = 0;
		for(i=0;i<supportOptions.length;i++)
		{
			if(i > 0 && supportOptions[i].efficacy > supportOptions[i-1].efficacy)
			{
				points++;
			}
			supportOptions[i].score = points;
		}
		
		supportOptions.sort(function(a,b) {return b.dist - a.dist;});
		points = 0;
		for(i=0;i<supportOptions.length;i++)
		{
			if(i > 0 && supportOptions[i].dist < supportOptions[i-1].dist)
			{
				points++;
			}
			supportOptions[i].score += points;
		}
		
		supportOptions = shuffleArray(supportOptions);
		
		supportable = new Array();
		longshots = new Array();
		for(i=0;i<supportOptions.length;i++)
		{
			supportOptions[i].score += supportOptions.splashTargets;
			if(supportOptions[i].turnsUntilDeath - supportOptions[i].dist >= 0)
			{
				supportable.push(supportOptions[i]);
			}
			else
			{
				longshots.push(supportOptions[i]);
			}
		}
		
		if(supportable.length > 1)
		{
			supportable.sort(function(a,b) {return (b.turnsUntilDeath - b.dist) - (a.turnsUntilDeath - a.dist);});
			points = 0;
			for(i=0;i<supportable.length;i++)
			{
				if(i > 0 && (supportable[i].turnsUntilDeath - supportable[i].dist) < (supportable[i-1].turnsUntilDeath - supportable[i-1].dist))
				{
					points++;
				}
				supportable[i].score += points;
			}
			
			supportable.sort(function(a,b) {return b.score - a.score;});
			supportable.sort(function(a,b) {return b.critical - a.critical;});
		}
		
		if(longshots.length > 1)
		{
			longshots.sort(function(a,b) {return (a.turnsUntilDeath - a.dist) - (b.turnsUntilDeath - b.dist);});
			points = 0;
			for(i=0;i<longshots.length;i++)
			{
				if(i > 0 && (longshots[i].turnsUntilDeath - longshots[i].dist) > (longshots[i-1].turnsUntilDeath - longshots[i-1].dist))
				{
					points++;
				}
				longshots[i].score += points;
			}
			
			longshots.sort(function(a,b) {return b.score - a.score;});
		}
		
		supportOptions = supportable.concat(longshots);
	}
	
	// I may need to make a "standing by" support option if the array is empty
	if(supportOptions.length > 0)
	{
		finalOptions.push(supportOptions[0]);
	}
	
	// evaluate defense options
	for(i=0;i<defenseOptions.length;i++)
	{
		defenseOptions[i].hasSecondaryOpts = 0;
		
		if(defenseOptions[i].inRange == 1)
		{
			for(j=0;j<attackOptions.length;j++)
			{
				overlap = getOverlap(attackOptions[j].rangeSpaces, defenseOptions[i].spacesBetween);
				overlap = getOverlap(turn.moveOptions, overlap);
				
				if(overlap.length > 0)
				{
					defenseOptions[i].hasSecondaryOpts = 1;
				}
			}
			for(j=0;j<supportOptions.length;j++)
			{
				overlap = getOverlap(supportOptions[j].rangeSpaces, defenseOptions[i].spacesBetween);
				overlap = getOverlap(turn.moveOptions, overlap);
				
				if(overlap.length > 0)
				{
					defenseOptions[i].hasSecondaryOpts = 1;
				}
			}
			
		}
	}
	
	if(defenseOptions.length > 1)
	{
		defenseOptions.sort(function(a,b) {return b.hasSecondaryOpts - a.hasSecondaryOpts;});
		defenseOptions.sort(function(a,b) {return a.spaceDist - b.spaceDist;});
		defenseOptions.sort(function(a,b) {return a.turnsUntilDeath - b.turnsUntilDeath;});
		
		defensible = new Array();
		longshots = new Array();
		for(i=0;i<defenseOptions.length;i++)
		{
			if(defenseOptions[i].spaceDist <= defenseOptions[i].turnsUntilDeath)
			{
				defensible.push(defenseOptions[i]);
			}
			else
			{
				longshots.push(defenseOptions[i]);
			}
		}
		defenseOptions = defensible.concat(longshots);
	}
	
	if(defenseOptions.length > 0)
	{
		finalOptions.push(defenseOptions[0]);
	}
	
	
	
	// evaluate options
	for(i=0;i<finalOptions.length;i++)
	{
		if(finalOptions[i] == attackOptions[0])
		{
			finalOptions[i].type = "attack";
			finalOptions[i].pts = 0;
			if(finalOptions[i].inRange == 1)
			{
				finalOptions[i].pts += 1;
			}
			if(finalOptions[i].finishOff == 1)
			{
				finalOptions[i].pts += 1;
			}
			
			finalOptions[i].modeIndex = turn.going.mode.indexOf("a");
			if(finalOptions[i].modeIndex == 0)
			{
				finalOptions[i].pts += 1;
			}
		}
		else if(finalOptions[i] == supportOptions[0])
		{
			finalOptions[i].type = "support";
			finalOptions[i].pts = 0;
			if(finalOptions[i].inRange == 1)
			{
				finalOptions[i].pts += 1;
			}
			if(finalOptions[i].critical == 1)
			{
				finalOptions[i].pts += 1;
			}
			
			finalOptions[i].modeIndex = turn.going.mode.indexOf("s");
			if(finalOptions[i].modeIndex == 0)
			{
				finalOptions[i].pts += 1;
			}
		}
		else if(finalOptions[i] == defenseOptions[0])
		{
			finalOptions[i].type = "defense";
			finalOptions[i].pts = 0;
			if(finalOptions[i].inRange == 1)
			{
				finalOptions[i].pts += 1;
			}
			if(finalOptions[i].hasSecondaryOpts == 1)
			{
				finalOptions[i].pts += 1;
			}
			
			finalOptions[i].modeIndex = turn.going.mode.indexOf("d");
			if(finalOptions[i].modeIndex == 0)
			{
				finalOptions[i].pts += 1;
			}
		}
	}
	
	if(finalOptions.length > 1)
	{
		finalOptions.sort(function(a,b) {return a.modeIndex - b.modeIndex;});
		finalOptions.sort(function(a,b) {return b.pts - a.pts;});
	}
	
	// figure out where to move
	
	moveOpts = turn.moveOptions;
	
	if(finalOptions[0].type == "attack")
	{
		if(finalOptions[0].inRange == 1)
		{
			moveOpts = getOverlap(moveOpts, finalOptions[0].rangeSpaces);
		}
		else
		{
			for(i=0;i<moveOpts.length;i++)
			{
				coords = moveOpts[i].spaceID.split("-");
				distX = Math.abs(coords[0] - finalOptions[0].target.x);
				distY = Math.abs(coords[1] - finalOptions[0].target.y);
				dist = Math.ceil((distX + distY - finalOptions[0].method.range) / turn.going.moveRange);
				if(dist < 0){dist = 0;}
				moveOpts[i].dist = dist;
			}
		}
		
		for(i=0;i<moveOpts.length;i++)
		{
			thisOption = new Array();
			thisOption[0] = new Object;
			thisOption[0].spaceID = moveOpts[i].spaceID;
		
			moveOpts[i].defensibility = 0;
			for(j=0;j<defenseOptions.length;j++)
			{
				if(getOverlap(thisOption, defenseOptions[j].spacesBetween).length > 0)
				{
					moveOpts[i].defensibility += defenseOptions.length - j;
				}
			}
			
			moveOpts[i].supportibility = 0;
			for(j=0;j<supportOptions.length;j++)
			{
				if(getOverlap(thisOption, supportOptions[j].rangeSpaces).length > 0)
				{
					moveOpts[i].supportOption = supportOptions[j];
					moveOpts[i].supportibility = supportOptions.length - j;
					break;
				}
			}
		}
		
		moveOpts = shuffleArray(moveOpts);
		if(finalOptions[0].inRange == 1)
		{
			moveOpts.sort(function(a,b) {return a.spaceDanger - b.spaceDanger;});
			if(turn.going.mode.indexOf("d") < turn.going.mode.indexOf("s"))
			{
				moveOpts.sort(function(a,b) {return b.defensibility - a.defensibility;});
			}
		}
		else
		{
			moveOpts.sort(function(a,b) {return a.spaceDanger - b.spaceDanger;});
			moveOpts.sort(function(a,b) {return b.supportibility - a.supportibility;});
			moveOpts.sort(function(a,b) {return a.dist - b.dist;});
		}
	}
	else if(finalOptions[0].type == "support")
	{
		if(finalOptions[0].inRange == 1 && finalOptions[0].target != turn.going)
		{
			moveOpts = getOverlap(moveOpts, finalOptions[0].rangeSpaces);
		}
		else
		{
			for(i=0;i<moveOpts.length;i++)
			{
				coords = moveOpts[i].spaceID.split("-");
				distX = Math.abs(coords[0] - finalOptions[0].target.x);
				distY = Math.abs(coords[1] - finalOptions[0].target.y);
				dist = Math.ceil((distX + distY - finalOptions[0].method.range) / turn.going.moveRange);
				if(dist < 0){dist = 0;}
				moveOpts[i].dist = dist;
			}
		}
		
		moveOpts = shuffleArray(moveOpts);
		moveOpts.sort(function(a,b) {return a.spaceDanger - b.spaceDanger;});
		if(finalOptions[0].dist > 1)
		{
			moveOpts.sort(function(a,b) {return a.dist - b.dist;});
		}
	}
	else if(finalOptions[0].type == "defense")
	{
		if(finalOptions[0].inRange == 1)
		{
			moveOpts = getOverlap(moveOpts, finalOptions[0].spacesBetween);
			
			for(i=0;i<moveOpts.length;i++)
			{
				coords = moveOpts[i].spaceID.split("-");
				distX = Math.abs(coords[0] - finalOptions[0].character.x);
				distY = Math.abs(coords[1] - finalOptions[0].character.y);
				moveOpts[i].charDist = distX + distY;
				distX = Math.abs(coords[0] - finalOptions[0].threat.character.x);
				distY = Math.abs(coords[1] - finalOptions[0].threat.character.y);
				moveOpts[i].threatDist = distX + distY;
			}
			
		}
		else
		{
			for(i=0;i<moveOpts.length;i++)
			{
				coords = moveOpts[i].spaceID.split("-");
				
				targetCoords = finalOptions[0].closestSpaceBetween.spaceID.split("-");
				
				distX = Math.abs(coords[0] - targetCoords[0]);				
				distY = Math.abs(coords[1] - targetCoords[1]);
				
				dist = Math.ceil((distX + distY) / turn.going.moveRange);
				if(dist < 0){dist = 0;}
				moveOpts[i].dist = dist;
			}
		}
		
		for(i=0;i<moveOpts.length;i++)
		{
			thisOption = new Array();
			thisOption[0] = new Object;
			thisOption[0].spaceID = moveOpts[i].spaceID;
		
			moveOpts[i].attackibility = 0;
			
			for(j=0;j<attackOptions.length;j++)
			{
				if(getOverlap(thisOption, attackOptions[j].rangeSpaces).length > 0)
				{
					moveOpts[i].attackOption = attackOptions[j];
					moveOpts[i].attackibility = attackOptions.length - j;
					break;
				}
			}
			
			moveOpts[i].supportibility = 0;
			for(j=0;j<supportOptions.length;j++)
			{
				if(getOverlap(thisOption, supportOptions[j].rangeSpaces).length > 0)
				{
					moveOpts[i].supportOption = supportOptions[j];
					moveOpts[i].supportibility = supportOptions.length - j;
					break;
				}
			}
			
			if(moveOpts[i].attackibility > 0 && moveOpts[i].supportibility > 0)
			{
				if(turn.going.mode.indexOf("a") < turn.going.mode.indexOf("s"))
				{
					moveOpts[i].supportibility = 0;
				}
				else
				{
					moveOpts[i].attackibility = 0;
				}
			}
		}
		
		moveOpts = shuffleArray(moveOpts);
		if(finalOptions[0].inRange == 1)
		{
			// if indexOf("a") < indexOf("s"): as close to threat as possible
			moveOpts.sort(function(a,b) {return a.threatDist - b.threatDist;});
			
			// else if indexOf("s") < indexOf("a"): as close to character as possible, but at least as far as threat.range
			if(turn.going.mode.indexOf("s") < turn.going.mode.indexOf("a"))
			{
				safe = new Array();
				tooClose = new Array();
				for(i=0;i<moveOpts.length;i++)
				{
					if(moveOpts[i].charDist < finalOptions[0].threat.range)
					{
						tooClose.push(moveOpts[i]);
					}
					else
					{
						safe.push(moveOpts[i]);
					}
				}
					
				safe.sort(function(a,b) {return a.charDist - b.charDist;});
				// tooClose is already sorted by closest to enemy
				moveOpts = safe.concat(tooClose);
			}
		}
		
		moveOpts.sort(function(a,b) {return b.attackibility - a.attackibility;});
		moveOpts.sort(function(a,b) {return b.supportibility - a.supportibility;});
		
		if(finalOptions[0].inRange == 0)
		{
			moveOpts.sort(function(a,b) {return a.dist - b.dist;});
		}
		
		finalOptions[0].attackOption = null;
		finalOptions[0].supportOption = null;
		if(moveOpts[0].attackibility > 0)
		{
			finalOptions[0].attackOption = moveOpts[0].attackOption;
		}
		if(moveOpts[0].supportibility > 0)
		{
			finalOptions[0].supportOption = moveOpts[0].supportOption;
		}
	}
	
	turn.strategy = finalOptions[0];
	
	if(moveOpts[0].spaceID == turn.going.x + "-" + turn.going.y)
	{
		enemyFinishedMoving();
	}
	else
	{
		coords = moveOpts[0].spaceID.split("-");
		move(coords[0], coords[1]);
	}
}

function getAttackOptions()
{
	var i = 0;
	var j = 0;
	var k = 0;
	
	attackMethods = new Array();
	
	method = new Object;
	method.type = "attack";
	method.power = turn.going.attack;
	method.range = turn.going.attackRange;
	method.mpCost = 0;
	attackMethods.push(method);
	
	allItems = turn.going.items.concat(turn.going.equipment)
	if(allItems.length > 0)
	{
		for(i=0;i<allItems.length;i++)
		{
			if(allItems[i].spell != "")
			{
				itemSpell = spells.getSpell(allItems[i].spell);
				hpIndex = itemSpell.effectStats.indexOf("HP");
				if(itemSpell.canTarget == "enemy")
				{
					method = new Object();
					method.type = "item";
					method.item = allItems[i];
					method.itemNum = turn.going.items.indexOf(allItems[i]);
					method.equipmentNum = turn.going.equipment.indexOf(allItems[i]);
					method.spell = itemSpell;
					method.damage = 0;
					if(hpIndex > -1)
					{
						method.damage = itemSpell.effects[hpIndex];
					}
					method.range = itemSpell.range;
					method.mpCost = 0;
					attackMethods.push(method);
				}
			}
		}
	}
	
	if(turn.going.spells.length > 0)
	{
		for(i=0;i<turn.going.spells.length;i++)
		{
			thisSpell = turn.going.spells[i];
			hpIndex = thisSpell.effectStats.indexOf("HP");
			if(thisSpell.canTarget == "enemy")
			{
				method = new Object;
				method.type = "spell";
				method.spell = thisSpell;
				method.damage = 0;
				if(hpIndex > -1)
				{
					method.damage = thisSpell.effects[hpIndex];
				}
				method.range = thisSpell.range;
				method.mpCost = thisSpell.MP;
				if(turn.going.MP >= thisSpell.MP)
				{
					attackMethods.push(method);
				}
			}
		}
	}
	
	attackOptions = new Array();
	
	for(i=0;i<attackMethods.length;i++)
	{
		for(j=0;j<turn.otherTeam.length;j++)
		{
			if(turn.otherTeam[j].status != "dead")
			{
				option = new Object;
				option.method = attackMethods[i];
				option.target = turn.otherTeam[j];
				
				distX = Math.abs(turn.going.x - option.target.x);
				distY = Math.abs(turn.going.y - option.target.y);
				option.dist = Math.ceil((distX + distY - option.method.range) / turn.going.moveRange);
				if(option.dist < 0){option.dist = 0;}
				
				option.rangeSpaces = getRangeSpaces(option.target.x, option.target.y, option.method.range);
				
				option.winability = getWinability(turn.going, option.target);
				
				if(option.method.type == "attack")
				{
					option.damage = Math.ceil(turn.going.attack / option.target.defense);
					option.splashTargets = 0;
					
					if(option.damage < option.target.HP)
					{
						option.efficacy = option.damage;
					}
					else
					{
						option.efficacy = option.target.HP;
					}
				}
				else
				{
					option.splashTargets = getSplashTargets(option.target, option.method.spell.splashRange, "enemy").length;
					
					//getSplashTargets returns all targets, including the original target, so...
					option.splashTargets--;
					
					option.efficacy = 0;
					if(option.method.spell.inflicts.length > 0 && (option.target.status == "ok" || option.method.spell.cures.indexOf(option.target.status) > -1))
					{
						option.efficacy += Math.round(option.target.HP / 3);
					}
					
					for(k=0;k<option.method.spell.effects.length;k++)
					{
						var effectVal = Math.abs(option.method.spell.effects[k]);
						
						if(option.target[option.method.spell.effectStats[k]] < effectVal)
						{
							effectVal = option.target[option.method.spell.effectStats[k]];
						}
						
						option.efficacy += effectVal;
					}
				}
				
				option.inRange = 0;
				option.finishOff = 0;
				
				if(getOverlap(turn.moveOptions, option.rangeSpaces).length > 0)
				{
					option.inRange = 1;
					if(option.damage >= option.target.HP)
					{
						option.finishOff = 1;
					}
				}
				if(option.efficacy > 0)
				{
					attackOptions.push(option);
				}
			}
		}
	}
	
	return attackOptions;
}

function getSupportOptions()
{
	var i = 0;
	var j = 0;
	var k = 0;
	
	supportMethods = new Array();
	
	allItems = turn.going.items.concat(turn.going.equipment);
	
	for(i=0;i<allItems.length;i++)
	{
		if(allItems[i].spell != "")
		{
			itemSpell = spells.getSpell(allItems[i].spell);
			hpIndex = itemSpell.effectStats.indexOf("HP");
			if(itemSpell.canTarget == "ally")
			{
				method = new Object;
				method.type = "item";
				method.itemNum = turn.going.items.indexOf(allItems[i]);//dont think i need this
				method.item = allItems[i];
				method.equipmentNum = turn.going.equipment.indexOf(allItems[i]);
				method.spell = itemSpell;
				method.range = itemSpell.range;
				method.cures = itemSpell.cures;
				method.inflicts = itemSpell.inflicts;
				method.effects = itemSpell.effects;
				method.effectStats = itemSpell.effectStats;
				supportMethods.push(method);
			}
		}
		else
		{
			method = new Object;
			method.type = "item";
			method.itemNum = turn.going.items.indexOf(allItems[i]);//dont think i need this
			method.item = allItems[i];
			method.spell = "";
			method.range = 1;
			method.cures = allItems[i].cures;
			method.inflicts = allItems[i].inflicts;
			method.effects = allItems[i].useEffects;
			method.effectStats = allItems[i].useEffectStats;
			supportMethods.push(method);
		}
	}
	
	for(i=0;i<turn.going.spells.length;i++)
	{
		thisSpell = turn.going.spells[i];
		if(thisSpell.canTarget == "ally")
		{
			method = new Object;
			method.type = "spell";
			method.spell = thisSpell;
			method.range = thisSpell.range;
			method.cures = thisSpell.cures;
			method.inflicts = thisSpell.inflicts;
			method.effects = thisSpell.effects;
			method.effectStats = thisSpell.effectStats;
			method.mpCost = thisSpell.MP;
			if(turn.going.MP >= thisSpell.MP)
			{
				supportMethods.push(method);
			}
		}
	}
	
	supportOptions = new Array();
	
	for(i=0;i<supportMethods.length;i++)
	{
		for(j=0;j<turn.team.length;j++)
		{
			if(turn.team[j].status != "dead")
			{
				option = new Object;
				option.method = supportMethods[i];
				option.target = turn.team[j];
				option.rangeSpaces = getRangeSpaces(option.target.x, option.target.y, option.method.range);
				
				option.threat = getPrimaryThreat(option.target);
				option.turnsUntilDeath = option.threat.dist + option.threat.turnsToKillTarget;
				if(option.threat.dist > 0){option.turnsUntilDeath -= 1;}
				
				if(option.turnsUntilDeath == 1)
				{
					option.critical = 1;
				}
				else
				{
					option.critical = 0;
				}
				
				distX = Math.abs(turn.going.x - option.target.x);
				distY = Math.abs(turn.going.y - option.target.y);
				option.dist = Math.ceil((distX + distY - option.method.range) / turn.going.moveRange);
				
				if(option.dist < 0){option.dist = 0;}
				
				option.inRange = 0;
				if(getOverlap(turn.moveOptions, option.rangeSpaces).length > 0)
				{
					option.inRange = 1;
				}
				
				// calculate effectiveness
				//this needs to be done as soon as method and target are set
				//everything else can be skipped if efficacy == 0
				option.efficacy = 0;
				if(option.method.cures.indexOf(option.target.status) > -1)
				{
					option.efficacy += Math.round(option.target.maxHP / 3);
				}
				
				if(option.method.inflicts.length > 0 && (option.target.status == "ok" || option.method.cures.indexOf(option.target.status) > -1))
				{
					option.efficacy += Math.ceil(option.target.HP / 3);
				}
				
				for(k=0;k<option.method.effects.length;k++)
				{
					var effectVal = option.method.effects[k];
					
					if(option.target["max" + option.method.effectStats[k]] != null && option.target["max" + option.method.effectStats[k]] - option.target[option.method.effectStats[k]] < effectVal)
					{
						effectVal = option.target["max" + option.method.effectStats[k]] - option.target[option.method.effectStats[k]];
					}
					
					option.efficacy += effectVal;
				}
				
				
				if(option.method.spell != "" && option.method.spell.splashRange > 0)
				{
					option.splashTargets = getSplashTargets(option.target, option.method.spell.splashRange, "ally").length;
					
					//getSplashTargets returns all targets, including the original target, so...
					option.splashTargets--;
				}
				else
				{
					option.splashTargets = 0;
				}
				
				if(option.efficacy > 0)
				{
					supportOptions.push(option);
				}
			}
		}
	}
	
	return supportOptions;
}

function getDefenseOptions()
{
	var i = 0;
	var j = 0;
	
	defenseOptions = new Array();
	
	for(i=0;i<turn.team.length;i++)
	{
		if(turn.team[i].status != "dead" && turn.team[i] != turn.going)
		{
		
			option = new Object;
			option.character = turn.team[i];
			
			option.threat = getPrimaryThreat(option.character);
			option.turnsUntilDeath = option.threat.dist + option.threat.turnsToKillTarget;
			if(option.threat.dist > 0){option.turnsUntilDeath -= 1;}
			
			option.spacesBetween = getSpacesBetween(option.character.x, option.character.y, option.threat.character.x, option.threat.character.y);
			
			if(option.spacesBetween.length > 0)
			{
				spaceDist = 0;
				option.spacesBetween = shuffleArray(option.spacesBetween);
				option.closestSpaceBetween = option.spacesBetween[0];
				for(j=0;j<option.spacesBetween.length;j++)
				{
					coords = option.spacesBetween[j].spaceID.split("-");
					
					distX = Math.abs(coords[0] - turn.going.x);
					distY = Math.abs(coords[1] - turn.going.y);
					
					if(j == 0){spaceDist = distX + distY;}
					else if(distX + distY < spaceDist)
					{
						spaceDist = distX + distY;
						option.closestSpaceBetween = option.spacesBetween[j];
					}
				}
				option.spaceDist = Math.ceil(spaceDist / turn.going.moveRange);
				
				option.inRange = 0;
				if(getOverlap(turn.moveOptions, option.spacesBetween).length > 0)
				{
					option.inRange = 1;
				}
				
				defenseOptions.push(option);
			}			
		}
	}
	
	return defenseOptions;
}

function enemyFinishedMoving()
{
	document.getElementById(turn.going.elementId + "Img").style.top = "0px";
	document.getElementById(turn.going.elementId + "Img").style.left = "0px";
	
	if(turn.strategy.type == "defense")
	{
		turn.strategy.inRange = 0;
	
		if(turn.going.mode.indexOf("a") < turn.going.mode.indexOf("s"))
		{
			if(turn.strategy.attackOption != null)
			{
				turn.strategy = turn.strategy.attackOption;
			}
			else if(turn.strategy.supportOption != null)
			{
				turn.strategy = turn.strategy.supportOption;
			}
		}
		else
		{
			if(turn.strategy.supportOption != null)
			{
				turn.strategy = turn.strategy.supportOption;
			}
			else if(turn.strategy.attackOption != null)
			{
				turn.strategy = turn.strategy.attackOption;
			}
		}
	}
	
	if(turn.strategy.inRange == 1)
	{
		if(turn.strategy.method.type == "attack")
		{
			targetIndex = bothTeams.indexOf(turn.strategy.target);
			setSights("attack", targetIndex);
			startAttack(targetIndex);
		}
		else if(turn.strategy.method.type == "item")
		{
			turn.item = turn.strategy.method.item;
			
			targetIndex = bothTeams.indexOf(turn.strategy.target);
			
			if(turn.item.spell != "")
			{
				turn.spell = spells.getSpell(turn.item.spell);
				setSights("spell", targetIndex);
			}
			else
			{
				setSights("item", targetIndex);
			}
			
			startItem(targetIndex);
		}
		else if(turn.strategy.method.type == "spell")
		{
			turn.spell = turn.strategy.method.spell;
			targetIndex = bothTeams.indexOf(turn.strategy.target);
			setSights("spell", targetIndex);
			startMagic(targetIndex);
		}
	}
	else
	{
		endTurn();
	}
	
	
}

function getPrimaryThreat(target)
{
	var i = 0;
	threats = new Array();
			
	for(i=0;i<turn.otherTeam.length;i++)
	{
		if(turn.otherTeam[i].status != "dead")
		{
			threat = new Object;
			threat.character = turn.otherTeam[i];
			
			// compute turns to kill target
			threat.damage = Math.round(threat.character.attack/target.defense);
			threat.range = threat.character.attackRange;
			
			magicPotential = getMagicPotential(threat.character);
			
			if(magicPotential[0] > threat.damage || (magicPotential[0] == threat.damage && magicPotential[1] > threat.range))
			{
				threat.damage = magicPotential[0];
				threat.range = magicPotential[1];
			}
			
			threat.turnsToKillTarget = Math.ceil(target.HP / threat.damage);
			
			//compute turns to kill going (i don't think i'm actually using this)
			damage = Math.round(threat.character.attack/target.defense);
			
			if(magicPotential[0] > damage)
			{
				damage = magicPotential[0];
			}
			
			threat.turnsToKillGoing = Math.ceil(turn.going.HP / damage);
			
			//distance as turns until target is in range
			distX = Math.abs(threat.character.x - target.x);
			distY = Math.abs(threat.character.y - target.y);
			
			threat.dist = Math.ceil((distX + distY - threat.range) / threat.character.moveRange);
			
			if(threat.dist < 0){threat.dist = 0;}
			
			threats.push(threat);
		}
	}
	
	if(threats.length < 1) 
	{
		// this should never happen because it would mean all opponents are dead
		alert("No threats. Is everybody dead?");
	}
	
	if(threats.length > 1)
	{
		threats = shuffleArray(threats);
		threats.sort(function(a,b) {return a.turnsToKillTarget - b.turnsToKillTarget;});
		threats.sort(function(a,b) {return a.dist - b.dist;});
	}
	
	return threats[0];
}

function getMagicPotential(guy)
{
	var i = 0;
	damage = 0;
	range = 0;

	if(guy.spells.length > 0)
	{
		for(i=0;i<guy.spells.length;i++)
		{
			if(guy.spells[i].effectStats.indexOf("HP") != -1 && guy.MP >= guy.spells[i].mp)
			{
				hpIndex = guy.spells[i].effectStats.indexOf("HP");
				if(guy.spells[i].effects[hpIndex] * -1 > damage)
				{
					damage = guy.spells[i].effects[hpIndex] * -1;
					range = guy.spells[i].range;
				}
			}
		}
	}
	
	totalItems = guy.items.concat(guy.equipment);
	
	if(totalItems.length > 0)
	{
		for(i=0;i<totalItems.length;i++)
		{
			if(totalItems[i].spell != "")
			{
				itemSpell = spells.getSpell(totalItems[i].spell);
				
				if(itemSpell.effectStats.indexOf("HP") != -1)
				{
					hpIndex = itemSpell.effectStats.indexOf("HP");
					
					if(itemSpell.effects[hpIndex] * -1 > damage)
					{
						damage = itemSpell.effects[hpIndex] * -1;
						range = itemSpell.range;
					}
				}
			}
		}
	}
	
	potential = new Array;
	potential[0] = damage;
	potential[1] = range;
	
	return potential;

}

function getWinability(attacker, target)
{
	attackerDamage = Math.round(attacker.attack / target.defense);
	
	magicPotential = getMagicPotential(attacker);
	if(magicPotential[0] > attackerDamage)
	{
		attackerDamage = magicPotential[0];
	}
	
	targetDamage = Math.round(target.attack / attacker.defense);
	
	magicPotential = getMagicPotential(target);
	if(magicPotential[0] > targetDamage)
	{
		targetDamage = magicPotential[0];
	}
	
	turnsToWin = target.HP / attackerDamage;
	turnsToLose = attacker.HP / targetDamage;
	winability = turnsToLose / turnsToWin;
	
	return winability;
}

function getSpacesBetween(x1, y1, x2, y2)
{
	var i = 0;
	var j = 0;
	spacesBetween = new Array();
	
	if(x1 == x2) // in the same column
	{
		Ydist = Math.abs(y1 - y2);
		if(Ydist == 1) //they are right next to each other
		{
			// maybe include these every time spaces are in same column?
			spacesBetween.push((x1-1) + "-" + y1);
			spacesBetween.push((x1+1) + "-" + y1);
			spacesBetween.push((x2-1) + "-" + y2);
			spacesBetween.push((x2+1) + "-" + y2);
			
		}
		else
		{
			if(y1 < y2)
			{
				from = y1 + 1;
				to = y2;
			}
			else
			{
				from = y2 + 1;
				to = y1;
			}
			
			for(i=from;i<to;i++)
			{
				spacesBetween.push(x1 + "-" + i);
			}
		}
	}
	else if(y1 == y2) // in the same row
	{		
		Xdist = Math.abs(x1 - x2);
		if(Xdist == 1) //they are right next to each other
		{
			// maybe include these every time the spaces are in the same row?
			spacesBetween.push(x1 + "-" + (y1-1));
			spacesBetween.push(x1 + "-" + (y1+1));
			spacesBetween.push(x2 + "-" + (y2-1));
			spacesBetween.push(x2 + "-" + (y2+1));
		}
		else
		{
			if(x1 < x2)
			{
				from = x1 + 1;
				to = x2;
			}
			else
			{
				from = x2 + 1;
				to = x1;
			}
			
			for(i=from;i<to;i++)
			{
				spacesBetween.push(i + "-" + y1);
			}
		}
	}
	else // diagonal
	{
		slope = (y2 - y1) / (x1 - x2);
		xDist = Math.abs(x1 - x2);
		yDist = Math.abs(y1 - y2);
		totalDist = xDist + yDist;
		
		if(x1 < x2)
		{
			startX = x1;
			startY = y1;
			endX = x2;
			endY = y2;
		}
		else
		{
			startX = x2;
			startY = y2;
			endX = x1;
			endY = y1;
		}
		
		if(slope > 0)
		{
			spacesBetween.push(startX + "-" + (startY - 1));
			spacesBetween.push((startX + 1) + "-" + startY);
			spacesBetween.push((startX + 1) + "-" + (startY - 1));
			
			spacesBetween.push(endX + "-" + (endY + 1));
			spacesBetween.push((endX - 1) + "-" + endY);
			spacesBetween.push((endX - 1) + "-" + (endY + 1));
			
			// i don't know what else to call this
			c = 1;
		}
		else //slope < 1
		{
			spacesBetween.push(startX + "-" + (startY + 1));
			spacesBetween.push((startX + 1) + "-" + startY);
			spacesBetween.push((startX + 1) + "-" + (startY + 1));
			
			spacesBetween.push(endX + "-" + (endY - 1));
			spacesBetween.push((endX - 1) + "-" + endY);
			spacesBetween.push((endX - 1) + "-" + (endY - 1));
			
			c = -1;
		}
		
		if(slope < 1 && slope > -1 && totalDist > 2)// shallow slope 
		{
			// start to end
			for(i=0;i<2;i++)
			{
				currentX = startX + 1;
				currentY = startY - c - (i * c);
				
				if((currentY < endY && c == 1) || (currentY > endY && c == -1)){break;}
				
				spacesBetween.push(currentX + "-" + currentY);
				
				key = 1 / slope * c;
				checkNum = 0;				
				
				while(currentX < endX - 1)
				{
					if((currentY <= endY + 1 && c == 1) || (currentY >= endY - 1 && c == -1))
					{
						while(currentX != endX - 1)
						{
							currentX++;
							spacesBetween.push(currentX + "-" + currentY);
						}
						break;
					}
					else
					{
						currentX++;
						spacesBetween.push(currentX + "-" + currentY);
						
						checkNum++;
						if(checkNum >= key)
						{
							currentY  = currentY - c;
							spacesBetween.push(currentX + "-" + currentY);
							
							checkNum -= key;
						}
					}
				}
			}
			
			// end to start
			for(i=0;i<2;i++)
			{
				currentX = endX - 1;
				currentY = endY + c + (i*c);
				
				if((currentY > startY && c == 1) || (currentY < startY && c == -1)){break;}
				
				spacesBetween.push(currentX + "-" + currentY);
				
				key = 1 / slope * c;
				checkNum = 0;

				while(currentX > startX + 1)
				{
					if((currentY >= startY - 1 && c == 1) || (currentY <= startY + 1 && c == -1))
					{
						while(currentX != startX + 1)
						{
							currentX--;
							spacesBetween.push(currentX + "-" + currentY);
						}
						break;
					}
					else
					{
						currentX--;
						spacesBetween.push(currentX + "-" + currentY);
						
						checkNum++;
						if(checkNum >= key)
						{
							currentY  = currentY + c;
							spacesBetween.push(currentX + "-" + currentY);
							
							checkNum -= key;
						}
					}
				}
			}
		}
		//else // slope is steeper than or equal to 1
		if(slope > 1 && slope < -1 && totalDist > 2)
		{
			// start to end
			for(i=0;i<2;i++)
			{
				currentX = startX + 1 + i;
				if(currentX > endX){break;}
				
				currentY = startY - c;
				
				spacesBetween.push(currentX + "-" + currentY);
				
				key = slope * c;
				checkNum = 0;
				
				while(currentY != endY + c)
				{
					if(currentX >= endX - 1)
					{
						while(currentY != endY + c)
						{
							currentY -= c;
							spacesBetween.push(currentX + "-" + currentY);
						}
						break;
					}
					else
					{
						currentY = currentY - c;
						spacesBetween.push(currentX + "-" + currentY);
						
						checkNum++;
						if(checkNum >= key)
						{
							currentX++;
							spacesBetween.push(currentX + "-" + currentY);
							
							checkNum -= key;
						}
					}
				}
			}
			
			// end to start
			for(i=0;i<2;i++)
			{
				currentX = endX - 1 - i;
				if(currentX < startX){break;}
				
				currentY = endY + c;
				
				spacesBetween.push(currentX + "-" + currentY);
				
				key = slope * c;
				checkNum = 0;	
				
				while(currentY != startY - c)
				{
					if(currentX <= startX + 1)
					{
						while(currentY != startY - c)
						{
							currentY += c;
							spacesBetween.push(currentX + "-" + currentY);
						}
						break;
					}
					else
					{
						currentY = currentY + c;
						spacesBetween.push(currentX + "-" + currentY);
						
						checkNum++;
						if(checkNum >= key)
						{
							currentX--;
							spacesBetween.push(currentX + "-" + currentY);
							
							checkNum -= key;
						}
					}
				}
			}
		}		
	}// end diagonal
	
	// exclude occupied and unwalkable spaces, weed out duplicates	
	occSpaces = new Array();
	for(i=0;i<bothTeams.length;i++)
	{
		// turn.going will need to know if he is already in defensive position
		if(bothTeams[i] != turn.going)
		{
			occSpaces[i] = bothTeams[i].x + "-" + bothTeams[i].y;
		}
	}
	finalArray = new Array();
	idArray = new Array();
	for(i=0;i<spacesBetween.length;i++)
	{
		if(occSpaces.indexOf(spacesBetween[i]) == -1 && walkableSpaces.indexOf(spacesBetween[i]) != -1 && idArray.indexOf(spacesBetween[i]) == -1)
		{
			newSpace = new Object;
			newSpace.spaceID = spacesBetween[i];
			finalArray.push(newSpace);
			idArray.push(spacesBetween[i]);
		}
	}
	
	return finalArray;
}

function getOverlap(spaceArray1, spaceArray2)
{
	var i = 0;
	var j = 0;
	overlap = new Array();
	
	for(i=0;i<spaceArray1.length;i++)
	{
		for(j=0;j<spaceArray2.length;j++)
		{
			if(spaceArray1[i].spaceID == spaceArray2[j].spaceID)
			{
				overlap.push(spaceArray1[i]);
				break;
			}
		}
	}
	
	return overlap;
}

function getSpaceDanger(spaces)
{
	var i = 0;
	var j = 0;
	var k = 0;
	
	// get potential damage and range
	opponentDamage = new Array();
	opponentRange = new Array();
	for(j=0;j<turn.otherTeam.length;j++)
	{
		if(turn.otherTeam[j].status == "dead")
		{
			damage = 0;
			range = 0;
		}
		else
		{
			damage = Math.round(turn.otherTeam[j].attack / turn.going.defense);
			range = turn.otherTeam[j].attackRange;
			
			magicPotential = getMagicPotential(turn.otherTeam[j]);
			if(magicPotential[0] > damage || (magicPotential[0] == damage && magicPotential[1] > range))
			{
				damage = magicPotential[0];
				range = magicPotential[1];
			}
		}
		opponentDamage[j] = damage;
		opponentRange[j] = range;
	}

	for(i=0;i<spaces.length;i++)
	{
		danger = 0;
	
		// Opponent Effect:		
		// damage without moving
		for(j=0;j<turn.otherTeam.length;j++)
		{
			if(turn.otherTeam[j].status != "dead")
			{
				distX = Math.abs(turn.otherTeam[j].x - spaces[i].x);
				distY = Math.abs(turn.otherTeam[j].y - spaces[i].y);
				if(distX + distY <= opponentRange[j])
				{
					danger += opponentDamage[j];
				}
			}
		}
		
		//damage with moving
		for(j=0;j<turn.otherTeam.length;j++)
		{
			opponentMoveOptions = getMoveOptions(turn.otherTeam[j].x, turn.otherTeam[j].y, turn.otherTeam[j].moveRange);
			
			for(k=0;k<opponentMoveOptions.length;k++)
			{
				distX = Math.abs(opponentMoveOptions[k].x - spaces[i].x);
				distY = Math.abs(opponentMoveOptions[k].y - spaces[i].y);
				if(distX + distY <= opponentRange[j])
				{
					danger += opponentDamage[j];
					break;
				}
			}
		}
				
				
		spaces[i].danger = danger;
		if(spaces[i].danger == 0){spaces[i].danger = 0.1;}
		
		
		// Cornered Effect
		nextMoveOptions = getMoveOptions(spaces[i].x, spaces[i].y, turn.going.moveRange);
		maxOptions = 2 * (Math.pow(turn.going.moveRange, 2) + turn.going.moveRange);
		
		corneredEffect = 2 - ((nextMoveOptions.length - 1) / maxOptions);		
		spaces[i].danger = spaces[i].danger * corneredEffect;
		
		
		// Ally Effect
		for(j=0;j<turn.team.length;j++)
		{
			if(turn.team[j] != turn.going && turn.team[j].status != "dead")
			{
				distX = Math.abs(turn.team[j].x - spaces[i].x);
				distY = Math.abs(turn.team[j].y - spaces[i].y);
			
				allyEffect = 1 + (((turn.team[j].moveRange * 2) - (distX + distY - 1)) / (turn.team[j].moveRange * 2));
				
				spaces[i].danger = spaces[i].danger / allyEffect;
			}
		}
	}
	
	return spaces;
}

function endTurn()
{
	var i = 0;
	var j = 0;

	normalize();
	
	if(turn.action != null)
	{
		turn.action = "";
	}
	
	if(turn.targets != null && turn.targets.length > 0)
	{
		turn.targets.splice(0, turn.targets.length);
	}
	
	if(turn.spellIndex != null)
	{
		turn.spellIndex = -1;
	}
	if(turn.itemIndex != null)
	{
		turn.itemIndex = -1;
	}
	if(turn.usableItems != null && turn.usableItems.length > 0)
	{
		turn.usableItems.splice(0, turn.usableItems.length);
	}
	
	document.getElementById("controlsHead").innerHTML = "&nbsp;";
	document.getElementById("panel").innerHTML = "&nbsp;";
	
	document.getElementById("attackButton").disabled = true;
	document.getElementById("magicButton").disabled = true;
	document.getElementById("itemButton").disabled = true;
	document.getElementById("endTurnButton").disabled = true;
	
	for(i=0;i<bothTeams.length;i++)
	{
		if(bothTeams[i].status == "dead")
		{
			bothTeams.splice(i, 1);
		}
	}
	
	othersLeft = 0;
	for(i=0;i<turn.otherTeam.length;i++)
	{
		if(turn.otherTeam[i].status != "dead")
		{
			othersLeft++;
		}
	}
	
	if(othersLeft < 1) // the battle is over
	{
		var i;
		
		for(i=0;i<playerTeam.length;i++)
		{
			if(playerTeam[i].statusCondition != null)
			{
				statusConditions.cureCondition(playerTeam[i]);
			}
		}
	
		if(turn.team == playerTeam)// player won
		{
			for(i=0;i<playerTeam.length;i++)
			{
				if(playerTeam[i].status != "dead")
				{
					currentCharacter = playerTeam[i];
					
					for(j=i+1;j<playerTeam.length;j++)
					{
						if(playerTeam[j].status != "dead")
						{
							document.body.removeChild(document.getElementById(playerTeam[j].elementId));
						}
					}
					
					break;
				}
			}
			
			currentLocation.battle.onWin();
			
			if(currentLocation.battle.recurring == true)
			{
				currentLocation.battle.resetBattle();
			}
			else
			{
				currentLocation.battle = null;
			}
			
			chardiv = document.getElementById(currentCharacter.elementId);
			chardiv.style.cursor = "pointer";
			teamIndex = playerTeam.indexOf(currentCharacter);
			chardiv.setAttribute("onmouseover", "setTooltip('player'," + teamIndex + ")");
			chardiv.setAttribute("onmouseout", "clearTooltip()");
			chardiv.setAttribute("onClick", "openControls(\"" + currentCharacter.name + "\")");
			
			center(currentCharacter.x, currentCharacter.y);
			
			// setup controls
			document.getElementById("interface").innerHTML = nonbattleControls;
			standardControlButtons = document.getElementById("controlButtons").innerHTML;
			
			positionNonbattleControls();
			
			inBattle = false;
		}
		else // enemy won
		{
			for(i=0;i<enemyTeam.length;i++)
			{
				if(enemyTeam[i].status != "dead")
				{
					document.body.removeChild(document.getElementById(enemyTeam[i].elementId));
				}
			}
			
			currentLocation.battle.resetBattle();
			
			continueGame();
		}
	}
	else
	{
		startTurn();
	}
}

function killCharacter(targetIndex)
{
	var i = 0;
	target = bothTeams[targetIndex];
	targetDiv = document.getElementById(target.elementId);
	
	if(targetDiv.style.opacity == "")
	{
		targetDiv.style.opacity = 1;
	}
	if(targetDiv.style.opacity > 0)
	{
		//targetDiv.style.opacity -= 0.1;
		// this was changed to fix a bug in chrome and safari
		newOpacity = (Math.floor((targetDiv.style.opacity - 0.1) * 10)) / 10;
		targetDiv.style.opacity = newOpacity;
		
		kto = setTimeout("killCharacter(" + targetIndex + ")", 100);
	}
	else
	{
		panelOut("<br/>" + target.name + " is dead");
		
		if(target.statusCondition != null)
		{
			statusConditions.cureCondition(target);
			target.HP = 0; // just in case
		}
		
		target.status = "dead";
		document.body.removeChild(targetDiv);
		
		turn.exp += target.exp;
		turn.money += target.money;
		
		if(target.onDefeat != null)
		{
			target.onDefeat();
		}
		
		othersLeft = 0;
		for(i=0;i<turn.otherTeam.length;i++)
		{
			if(turn.otherTeam[i].status != "dead")
			{
				othersLeft++;
			}
		}
		
		if(othersLeft < 1 && turn.team == enemyTeam)
		{
			panelOut("<br/><br/>You Lose");
		}
	}
	
}

function setMoveOptions()
{
	options = getMoveOptions(turn.going.x, turn.going.y, turn.going.moveRange);
	turn.moveOptions = options;
}

function getMoveOptions(x, y, range)
{
	var i = 0;
	var j = 0;
	
	occSpaces = new Array();
	for(i=0;i<bothTeams.length;i++)
	{
		occSpaces[i] = bothTeams[i].x + "-" + bothTeams[i].y;
	}

	options = new Array();
	optNum = 0;
	
	for(i=0;i<walkableSpaces.length;i++) // loop through walkable spaces
	{
		if(occSpaces.indexOf(walkableSpaces[i]) == -1)
		{
			spaceCoords = walkableSpaces[i].split("-");
			spaceX = parseInt(spaceCoords[0]);
			spaceY = parseInt(spaceCoords[1]);
		
			distX = Math.abs(x - spaceX);
			distY = Math.abs(y - spaceY);

			if(distX + distY <= range)
			{
				thisOne = new Object();
				thisOne.spaceID = walkableSpaces[i];

				thisOne.x = spaceX;
				thisOne.y = spaceY;

				options[optNum] = thisOne;
				optNum++;
			}
		}
	}

	here = new Object();
	here.spaceID = x + "-" + y;
	here.x = x;
	here.y = y;
	
	options.unshift(here);

	// to exclude spaces that aren't connected
	connected = new Array();
	connectedSids = new Array();
	
	connected.push(options[0]);
	connectedSids.push(options[0].spaceID);
	
	for(i=0;i<connected.length;i++)
	{
		for(j=1;j<options.length;j++)
		{
			distX = Math.abs(connected[i].x - options[j].x);
			distY = Math.abs(connected[i].y - options[j].y);
			
			if(distX + distY == 1 && connectedSids.indexOf(options[j].spaceID) == -1)
			{
				connected.push(options[j]);
				connectedSids.push(options[j].spaceID);
			}
		}
	}
	
	return connected;
}

function getRoute(origX, origY, destX, destY)
{
	// this acts weird if you are only moving one space, so...
	if(Math.abs(origX - destX) + Math.abs(origY - destY) == 1)
	{
		route = new Array();
		route[0] = destX + "-" + destY;
		return route;
	}
	
	var i = 0;
	
	routeOptions = new Array();
	optionsToCheck = new Array();
		
	// start with the origin
	routeOption = new Object();
	routeOption.x = origX;
	routeOption.y = origY;
	routeOption.parent = -1;
	
	routeOptions.push(routeOption);
	optionsToCheck.push(routeOption);
	
	routeKey = null;	
	
	while(optionsToCheck.length > 0)
	{
		for(i=0;i<turn.moveOptions.length;i++)
		{
			xDist = Math.abs(optionsToCheck[0].x - turn.moveOptions[i].x);
			yDist = Math.abs(optionsToCheck[0].y - turn.moveOptions[i].y);
			dist = xDist + yDist;
			
			if(dist == 1)
			{
				if(turn.moveOptions[i].x == destX && turn.moveOptions[i].y == destY)
				{
					routeKey = optionsToCheck[0];
					optionsToCheck.splice(0, optionsToCheck.length);
					break;
				}
			
				routeOption = new Object();
				routeOption.x = turn.moveOptions[i].x;
				routeOption.y = turn.moveOptions[i].y;
				routeOption.parent = routeOptions.indexOf(optionsToCheck[0]);
				
				routeOptions.push(routeOption);
				optionsToCheck.push(routeOption);
			}
		}

		optionsToCheck.shift();
	}
		
	if(routeKey == null)
	{
		alert("no route found");
	}
		
	route = new Array();
	route[0] = routeKey.x + "-" + routeKey.y;
	route[1] = destX + "-" + destY;
		
	while(routeKey.parent > 0)
	{
		routeKey = routeOptions[routeKey.parent];
		route.unshift(routeKey.x + "-" + routeKey.y);
	}
	
	return route;
}

function getRangeSpaces(x, y, range)
{
	var j = 0;
	var k = 0;
	rangeSpaces = new Array();
	
	for(j=0;j<currentLocation.height;j++) // loop through rows
	{
		for(k=0;k<currentLocation.width;k++) // loop through spaces in row
		{
			distX = Math.abs(x - k);
			distY = Math.abs(y - j);
			
			if(distX + distY <= range)
			{
				rangeSpace = new Object;
				rangeSpace.spaceID = k + "-" + j;
				
				rangeSpaces.push(rangeSpace);
			}
		}
	}
	
	return rangeSpaces;
}

function getTargetOptions(attackRange, team)
{
	var i = 0;

	if(team == "ally"){checkArray = turn.team;}
	else if(team == "enemy"){checkArray = turn.otherTeam;}
	else{checkArray = bothTeams;}
	
	targetOptions = new Array();
	for(i=0;i<checkArray.length;i++)
	{
		if(checkArray[i].status != "dead")
		{
			distX = Math.abs(checkArray[i].x - turn.going.x);
			distY = Math.abs(checkArray[i].y - turn.going.y);
			
			if(distX + distY <= attackRange)
			{
				targetOptions.push(checkArray[i]);
			}
		}
	}
	
	return targetOptions;
}

function getSplashTargets(target, range, team)
{
	var i = 0;

	if(team == "ally"){checkArray = turn.team;}
	else if(team == "enemy"){checkArray = turn.otherTeam;}
	else{checkArray = bothTeams;}

	splashTargets = new Array();
	splashTargets[0] = target;

	for(i=0;i<checkArray.length;i++)
	{
		if(checkArray[i].status != "dead")
		{
			distX = Math.abs(checkArray[i].x - target.x);
			distY = Math.abs(checkArray[i].y - target.y);
			
			if(distX + distY <= range && checkArray[i] != target)
			{
				splashTargets.push(checkArray[i]);
			}
		}
	}
	
	return splashTargets;
}

function setSights(sightsType, indexNum)
{
	if(turn.team == playerTeam)
	{
		var targetChar = turn.targetOptions[indexNum];
	}
	else
	{
		var targetChar = bothTeams[indexNum];
	}
	
	var targetId = targetChar.x + "-" + targetChar.y;
	
	if(sightsType == "attack")
	{
		addCssClass(targetId, "attackSights");
		sightsSpaces.push(targetId);
	}
	else if(sightsType == "item")
	{
		addCssClass(targetId, "itemSights");
		sightsSpaces.push(targetId);
	}
	else // sightsType == "spell"
	{
		if(turn.spell.splashRange == 0)
		{
			addCssClass(targetId, "spellSights");
			sightsSpaces.push(targetId);
		}
		else // getting splash range sights
		{
			var startX = targetChar.x - turn.spell.splashRange;
			var startY = targetChar.y - turn.spell.splashRange;
			var endX = targetChar.x + turn.spell.splashRange;
			var endY = targetChar.y + turn.spell.splashRange;
			
			var x;
			var y;
			
			for(y=startY;y<=endY;y++)
			{
				for(x=startX;x<=endX;x++)
				{
					xDist = Math.abs(x - targetChar.x);
					yDist = Math.abs(y - targetChar.y);
					if(xDist + yDist <= turn.spell.splashRange)
					{
						addCssClass(x + "-" + y, "spellSights");
						sightsSpaces.push(x + "-" + y);
					}
				}
			}
		}
	}
	
	document.getElementById(targetChar.elementId).setAttribute("onMouseout", "clearSights()");
	
	if(turn.team == playerTeam)
	{
		if(playerTeam.indexOf(targetChar) > -1)
		{
			setTooltip("player", playerTeam.indexOf(targetChar));
		}
		else
		{
			setTooltip("enemy", enemyTeam.indexOf(targetChar));
		}
	}
	
}

function clearSights()
{
	clearTooltip();
	
	while(sightsSpaces.length > 0)
	{
		removeCssClass(sightsSpaces[0], "attackSights");
		removeCssClass(sightsSpaces[0], "itemSights");
		removeCssClass(sightsSpaces[0], "spellSights");
		sightsSpaces.shift();
	}
}

function startAttack(targetIndex)
{
	document.getElementById("attackButton").disabled = true;
	document.getElementById("magicButton").disabled = true;
	document.getElementById("itemButton").disabled = true;
	document.getElementById("endTurnButton").disabled = true;
	
	normalize();
	
	turn.action = "attack";
	
	turn.targets = new Array();
	turn.targets[0] = bothTeams[targetIndex];
	
	clearPanel();
	panelOut(turn.going.name + " attacks " + turn.targets[0].name);
	
	battleAnimation(0);
}

function finishAttack()
{
	document.getElementById("controlsHead").innerHML = "&nbsp;";
	
	clearSights();
	
	var targetHP = turn.targets[0].HP;

	// figure damage: attack +/- 20% / defense
	chance = Math.round((((Math.random() * 2) -1)) * (turn.going.attack * .2));
	damage = Math.ceil((turn.going.attack + chance) / turn.targets[0].defense);
	
	turn.targets[0].HP -= damage;
	
	panelOut("<br/>" + turn.targets[0].name + " takes " + damage + " damage");
	
	if(playerTeam.indexOf(turn.going) > -1)
	{
		if(targetHP < damage)
		{
			turn.exp += targetHP;
		}
		else
		{
			turn.exp += damage;
		}
	}
	
	if(playerTeam.indexOf(turn.targets[0]) > -1)
	{
		scoreBoardId = "scoreBoardPlayerChar" + playerTeam.indexOf(turn.targets[0]);
	}
	else
	{
		scoreBoardId = "scoreBoardEnemyChar" + enemyTeam.indexOf(turn.targets[0]);
	}
	
	targetKilled = false;
	
	if(turn.targets[0].HP <= 0)
	{
		turn.targets[0].HP = 0;
		
		document.getElementById(scoreBoardId + "Hp").innerHTML = "0";
		addCssClass(scoreBoardId, "scoreBoardDeadChar");
		
		targetIndex = bothTeams.indexOf(turn.targets[0]);
		killCharacter(targetIndex);
		targetKilled = true;
	}
	else
	{
		document.getElementById(scoreBoardId + "Hp").innerHTML = turn.targets[0].HP;
	}
	
	if(playerTeam.indexOf(turn.going) > -1)
	{
		if(targetKilled == true)
		{
			ept = setTimeout("finishPlayerTurn()", 1500);
		}
		else
		{
			finishPlayerTurn();
		}
	}
	else
	{
		if(targetKilled == true)
		{
			eet = setTimeout('document.getElementById("endTurnButton").disabled = false', 1500);
		}
		else
		{
			document.getElementById("endTurnButton").disabled = false;
		}
	}
}

function startMagic(targetIndex)
{
	document.getElementById("attackButton").disabled = true;
	document.getElementById("magicButton").disabled = true;
	document.getElementById("itemButton").disabled = true;
	document.getElementById("endTurnButton").disabled = true;
	
	normalize();

	turn.action = "magic";
	turn.target = bothTeams[targetIndex];
	
	clearPanel();
	panelOut(turn.going.name + " casts " + turn.spell.name + " on " + turn.target.name);
	
	turn.targets = getSplashTargets(bothTeams[targetIndex], turn.spell.splashRange, turn.spell.canTarget);
	
	battleAnimation(0);
}

function finishMagic()
{
	var i = 0;
	var j = 0;
	
	clearSights();
	
	document.getElementById("controlsHead").innerHTML = "&nbsp;";
	
	if(playerTeam.indexOf(turn.going) > -1)
	{
		var targetStats = new Array();
		var targetStatusConditions = new Array();
		for(i=0;i<turn.targets.length;i++)
		{
			targetStatusConditions[i] = turn.targets[i].statusCondition;
		
			targetStats[i] = new Array();
			for(j=0;j<turn.spell.effectStats.length;j++)
			{
				targetStats[i][j] = turn.targets[i][turn.spell.effectStats[j]];
			}
		}
	}
	
	mssg = turn.going.castSpell(turn.spell, turn.targets[0]);
	panelOut("<br/>" + mssg);
	
	if(playerTeam.indexOf(turn.going) > -1)
	{
		for(i=0;i<turn.targets.length;i++)
		{
			for(j=0;j<targetStats[i].length;j++)
			{
				turn.exp += Math.abs(targetStats[i][j] - turn.targets[i][turn.spell.effectStats[j]]);
			}
		}
		
		if(turn.spell.inflicts != "")
		{
			for(i=0;i<turn.targets.length;i++)
			{
				// if target is in the same condition the spell did not inflict a condition
				if(turn.targets[i].statusCondition != targetStatusConditions[i])
				{
					var thisExp = 0;
					for(j=0;j<turn.targets[i].statusCondition.effects.length;j++)
					{
						thisExp += Math.abs(turn.targets[i].statusCondition.effects[j]);
					}
					
					var multiplier = Math.floor(turn.targets[i].statusCondition.counters / 2);
					if(multiplier < 1){multiplier = 1;}
					
					turn.exp += thisExp * multiplier;
				}
			}
		}
		else if(turn.spell.cures.length > 0)
		{
			// i need to loop through targets to make sure they were cured
			for(i=0;i<turn.targets.length;i++)
			{
				if(turn.targets[i].status == "ok" && targetStatusConditions[i] != null)
				{
					var thisExp = 0;
					for(j=0;j<targetStatusConditions[i].effects.length;j++)
					{
						thisExp += Math.abs(targetStatusConditions[i].effects[j]);
					}
					
					turn.exp += thisExp;
				}
			}
		}
	}
	
	for(i=0;i<turn.targets.length;i++)
	{
		if(playerTeam.indexOf(turn.targets[i]) > -1)
		{
			scoreBoardId = "scoreBoardPlayerChar" + playerTeam.indexOf(turn.targets[i]);
		}
		else
		{
			scoreBoardId = "scoreBoardEnemyChar" + enemyTeam.indexOf(turn.targets[i]);
		}
		
		if(turn.targets[i].HP <= 0)
		{
			turn.targets[i].HP = 0;
			addCssClass(scoreBoardId, "scoreBoardDeadChar");
		}
		
		document.getElementById(scoreBoardId + "Hp").innerHTML = turn.targets[i].HP;
		document.getElementById(scoreBoardId + "MaxHp").innerHTML = turn.targets[i].maxHP;
	}
	
	targetKilled = false;
	
	for(i=0;i<turn.targets.length;i++)
	{
		if(turn.targets[i].HP <= 0)
		{
			targetIndex = bothTeams.indexOf(turn.targets[i]);
			killCharacter(targetIndex);
			targetKilled = true;
		}
	}
	
	if(playerTeam.indexOf(turn.going) > -1)
	{
		if(targetKilled == true)
		{
			ept = setTimeout("finishPlayerTurn()", 1500);
		}
		else
		{
			finishPlayerTurn();
		}
	}
	else
	{
		if(targetKilled == true)
		{
			eet = setTimeout('document.getElementById("endTurnButton").disabled = false', 1500);
		}
		else
		{
			document.getElementById("endTurnButton").disabled = false;
		}
	}
}

function startItem(targetIndex)
{
	document.getElementById("attackButton").disabled = true;
	document.getElementById("magicButton").disabled = true;
	document.getElementById("itemButton").disabled = true;
	document.getElementById("endTurnButton").disabled = true;
	
	normalize();
	
	turn.action = "item";
	
	if(turn.item.spell != "")
	{
		itemSpell = spells.getSpell(turn.item.spell);
		turn.targets = getSplashTargets(bothTeams[targetIndex], itemSpell.splashRange, itemSpell.canTarget);
	}
	else
	{
		turn.targets = new Array();
		turn.targets[0] = bothTeams[targetIndex];
	}
	
	clearPanel();
	panelOut(turn.going.name + " uses " + turn.item.name);
	if(turn.going != turn.targets[0])
	{
		panelOut(" on " + turn.targets[0].name);
	}
	
	battleAnimation(0);
}

function finishItem()
{
	var i = 0;
	var j = 0;
	
	clearSights();

	document.getElementById("controlsHead").innerHTML = "&nbsp;";
	
	if(turn.item.spell != "")
	{
		turn.spell = spells.getSpell(turn.item.spell);
	}
	
	if(playerTeam.indexOf(turn.going) > -1)
	{
		var targetStats = new Array();
		var targetStatusConditions = new Array();
		for(i=0;i<turn.targets.length;i++)
		{
			targetStatusConditions[i] = turn.targets[i].statusCondition;		
			targetStats[i] = new Array();
			
			if(turn.item.spell != "")
			{
				for(j=0;j<turn.spell.effectStats.length;j++)
				{
					targetStats[i][j] = turn.targets[i][turn.spell.effectStats[j]];
				}
			}
			else
			{
				for(j=0;j<turn.item.useEffectStats.length;j++)
				{
					targetStats[i][j] = turn.targets[i][turn.item.useEffectStats[j]];
				}
			}
		}
	}
	
	if(turn.item.spell != "")
	{
		mssg = turn.spell.cast(turn.targets[0]);
	}
	else // regular usable item
	{
		mssg = turn.item.use(turn.going, turn.targets[0]);
	}
	
	panelOut("<br/>" + mssg);
	
	if(playerTeam.indexOf(turn.going) > -1)
	{
		for(i=0;i<turn.targets.length;i++)
		{
			for(j=0;j<targetStats[i].length;j++)
			{
				if(turn.item.spell != "")
				{
					turn.exp += Math.abs(targetStats[i][j] - turn.targets[i][turn.spell.effectStats[j]]);
				}
				else
				{
					turn.exp += Math.abs(targetStats[i][j] - turn.targets[i][turn.item.useEffectStats[j]]);
				}
			}
		}
		
		if(turn.item.inflicts != "" || (turn.item.spell != "" && turn.spell.inflicts != ""))
		{
			for(i=0;i<turn.targets.length;i++)
			{
				// if target is in the same condition the spell did not inflict a condition
				if(turn.targets[i].statusCondition != targetStatusConditions[i])
				{
					var thisExp = 0;
					for(j=0;j<turn.targets[i].statusCondition.effects.length;j++)
					{
						thisExp += Math.abs(turn.targets[i].statusCondition.effects[j]);
					}
					
					var multiplier = Math.floor(turn.targets[i].statusCondition.counters / 2);
					if(multiplier < 1){multiplier = 1;}
					
					turn.exp += thisExp * multiplier;
				}
			}
		}
		else if(turn.item.cures.length > 0 || (turn.item.spell != "" &&  turn.spell.cures.length > 0))
		{
			// i need to loop through targets to make sure they were cured
			for(i=0;i<turn.targets.length;i++)
			{
				if(turn.targets[i].status == "ok" && targetStatusConditions[i] != null)
				{
					var thisExp = 0;
					for(j=0;j<targetStatusConditions[i].effects.length;j++)
					{
						thisExp += Math.abs(targetStatusConditions[i].effects[j]);
					}
					
					turn.exp += thisExp;
				}
			}
		}
	}
	
	for(i=0;i<turn.targets.length;i++)
	{
		if(playerTeam.indexOf(turn.targets[i]) > -1)
		{
			scoreBoardId = "scoreBoardPlayerChar" + playerTeam.indexOf(turn.targets[i]);
		}
		else
		{
			scoreBoardId = "scoreBoardEnemyChar" + enemyTeam.indexOf(turn.targets[i]);
		}
		
		if(turn.targets[i].HP <= 0)
		{
			turn.targets[i].HP = 0;
			addCssClass(scoreBoardId, "scoreBoardDeadChar");
		}
		
		document.getElementById(scoreBoardId + "Hp").innerHTML = turn.targets[i].HP;
	}
	
	targetKilled = false;
	
	for(i=0;i<turn.targets.length;i++)
	{
		if(turn.targets[i].HP <= 0)
		{
			targetIndex = bothTeams.indexOf(turn.targets[i]);
			killCharacter(targetIndex);
			targetKilled = true;
		}
	}
	
	if(playerTeam.indexOf(turn.going) > -1)
	{
		if(targetKilled == true)
		{
			ept = setTimeout("finishPlayerTurn()", 1500);
		}
		else
		{
			finishPlayerTurn();
		}
	}
	else
	{
		if(targetKilled == true)
		{
			eet = setTimeout('document.getElementById("endTurnButton").disabled = false', 1500);
		}
		else
		{
			document.getElementById("endTurnButton").disabled = false;
		}
	}
}

function battleAnimation(animationIndex)
{
	animationIndex++;
	
	var i = 0;
	
	distX = turn.going.x - turn.targets[0].x;
	distY = turn.going.y - turn.targets[0].y;
	
	if(animationIndex == 1 && turn.targets.indexOf(turn.going) == -1)
	{
		if(Math.abs(distY) > Math.abs(distX))
		{
			if(distY > 0)
			{
				// target is up
				document.getElementById(turn.going.elementId + "Img").style.top = (-3 * tileSize) + "px";
				for(i=0;i<turn.targets.length;i++)
				{
					if(turn.going.elementId.charAt(0) != turn.targets[i].elementId.charAt(0))
					{
						document.getElementById(turn.targets[i].elementId + "Img").style.top = "0px";
					}
				}
			}
			else
			{
				// target is down
				document.getElementById(turn.going.elementId + "Img").style.top = "0px";
				for(i=0;i<turn.targets.length;i++)
				{
					if(turn.going.elementId.charAt(0) != turn.targets[i].elementId.charAt(0))
					{
						document.getElementById(turn.targets[i].elementId + "Img").style.top = (-3 * tileSize) + "px";
					}
				}
			}
		}
		else
		{
			if(distX > 0)
			{
				// target is left
				document.getElementById(turn.going.elementId + "Img").style.top = (-2 * tileSize) + "px";
				for(i=0;i<turn.targets.length;i++)
				{
					if(turn.going.elementId.charAt(0) != turn.targets[i].elementId.charAt(0))
					{
						document.getElementById(turn.targets[i].elementId + "Img").style.top = (-1 * tileSize) + "px";
					}
				}
			}
			else
			{
				// target is right
				document.getElementById(turn.going.elementId + "Img").style.top = (-1 * tileSize) + "px";
				for(i=0;i<turn.targets.length;i++)
				{
					if(turn.going.elementId.charAt(0) != turn.targets[i].elementId.charAt(0))
					{
						document.getElementById(turn.targets[i].elementId + "Img").style.top = (-2 * tileSize) + "px";
					}
				}
			}
		}
	}
	
	if(animationIndex == 2 || animationIndex == 4)
	{
		document.getElementById(turn.going.elementId + "Img").style.left = (-2 * tileSize) + "px";
	}
	if(animationIndex == 3 || animationIndex == 5)
	{
		document.getElementById(turn.going.elementId + "Img").style.left = "0px";
	}
	
	// this is where target recoils. needs to handle multiple targets for splash damage
	if(Math.abs(distY) > Math.abs(distX))
	{
		if((distY > 0 && animationIndex == 7) || (distY < 0 && animationIndex == 6))
		{
			for(i=0;i<turn.targets.length;i++)
			{
				if(turn.going.elementId.charAt(0) != turn.targets[i].elementId.charAt(0))
				{
					currentTop = document.getElementById(turn.targets[i].elementId).offsetTop;
					document.getElementById(turn.targets[i].elementId).style.top = (currentTop + 10) + "px";
				}
			}
		}
		else if((distY > 0 && animationIndex == 6) || (distY < 0 && animationIndex == 7))
		{
			for(i=0;i<turn.targets.length;i++)
			{
				if(turn.going.elementId.charAt(0) != turn.targets[i].elementId.charAt(0))
				{
					currentTop = document.getElementById(turn.targets[i].elementId).offsetTop;
					document.getElementById(turn.targets[i].elementId).style.top = (currentTop - 10) + "px";
				}
			}
		}
	}
	if(Math.abs(distX) > Math.abs(distY))
	{
		if((distX > 0 && animationIndex == 6) || (distX < 0 && animationIndex == 7))
		{
			for(i=0;i<turn.targets.length;i++)
			{
				if(turn.going.elementId.charAt(0) != turn.targets[i].elementId.charAt(0))
				{
					currentLeft = document.getElementById(turn.targets[i].elementId).offsetLeft;
					document.getElementById(turn.targets[i].elementId).style.left = (currentLeft - 10) + "px";
				}
			}
		}
		else if((distX > 0 && animationIndex == 7) || (distX < 0 && animationIndex == 6))
		{
			for(i=0;i<turn.targets.length;i++)
			{
				if(turn.going.elementId.charAt(0) != turn.targets[i].elementId.charAt(0))
				{
					currentLeft = document.getElementById(turn.targets[i].elementId).offsetLeft;
					document.getElementById(turn.targets[i].elementId).style.left = (currentLeft + 10) + "px";
				}
			}
		}
	}
	
	if(animationIndex >= 8)
	{
		document.getElementById(turn.going.elementId + "Img").style.top = "0px";
		
		for(i=0;i<turn.targets.length;i++)
		{
			document.getElementById(turn.targets[i].elementId + "Img").style.top = "0px";
		}
	
		if(turn.action == "attack"){finishAttack();}
		else if(turn.action == "magic"){finishMagic();}
		else if(turn.action == "item"){finishItem();}
	}
	else
	{
		aato = setTimeout("battleAnimation(" + animationIndex + ")", Math.round(100/walkSpeed));
	}

}

function scrollToCenter(x, y)
{
	busy = true;
	
	target = document.getElementById(x + "-" + y);
	
	centerX = target.offsetLeft + Math.round(target.offsetWidth / 2) + centerOffsetX;
	centerY = target.offsetTop + Math.round(target.offsetHeight / 2) + centerOffsetY;

	currentX = window.pageXOffset + Math.round(screenWidth / 2);
	currentY = window.pageYOffset + Math.round(screenHeight / 2);
	
	dirX = centerX - currentX;
	dirY = centerY - currentY;
	
	moveX = 0;
	if(Math.abs(dirX) < 10){moveX = dirX;}
	else if(dirX > 0){moveX = 10;}
	else{moveX = -10;}
	
	moveY = 0;
	if(Math.abs(dirY) < 10){moveY = dirY;}
	else if(dirY > 0){moveY = 10;}
	else{moveY = -10;}
	
	scrollBy(moveX, moveY);
	
	newX = window.pageXOffset + Math.round(screenWidth / 2);
	newY = window.pageYOffset + Math.round(screenHeight / 2);
	
	if(newX != currentX || newY != currentY)
	{
		cto = setTimeout("scrollToCenter(" + x + ", " + y + ")", 100/scrollSpeed);
	}
	else
	{
		busy = false;
		startCharacterTurn();
	}
}

/****	end battle-specific functions	****/

/*****************************************************
		NONBATTLE-SPECIFIC FUNCTIONS
*****************************************************/

function openControls(name)
{
	controlsOpen = true;
	document.getElementById("controlsHead").innerHTML = monies + ": " + playerMoney;
	
	if(name == "team")
	{
		teamHandler();
	}
	else
	{
		characterHandler(name);
	}
	
	document.getElementById("controls").style.visibility = "visible";
}

function closeControls()
{
	document.getElementById("controls").style.visibility = "hidden";
	document.getElementById("panel").innerHTML = "";
	controlsOpen = false;
}

function teamHandler()
{
	panelStuff = "Select a Caracter:<br/>";
	var i;

	for(i=0;i<playerTeam.length;i++)
	{
		panelStuff += '<div onClick="characterHandler(\'' + playerTeam[i].name + '\')" style="float:left;padding:5px;text-align:center;cursor:pointer;">';
		panelStuff += '<div style="width:' + tileSize + 'px;height:' + tileSize + 'px;overflow:hidden;">';
		panelStuff += '<img src="images/' + playerTeam[i].image + '" /></div>';
		panelStuff += playerTeam[i].name + '</div>';
	}
	
	document.getElementById("teamButton").disabled = true;
	document.getElementById("magicButton").disabled = true;
	document.getElementById("itemButton").disabled = true;
	
	document.getElementById("cancelButton").setAttribute("onClick", "closeControls()");
	
	document.getElementById("panel").innerHTML = panelStuff;
}

function characterHandler(name)
{
	selectedCharacter = playerCharacters.getCharacter(name);

	panelStuff = '<div><div style="float:left;padding:3px;text-align:center;"><div style="width:'
	panelStuff += tileSize + 'px;height:' + tileSize + 'px;overflow:hidden;"><img src="images/';
	panelStuff += selectedCharacter.image;
	panelStuff += '" /></div>' + name + '</div>';
	
	panelStuff += '<div><div style="float:left;padding:3px;padding-left:8px;">';
	panelStuff += 'Class: ' + selectedCharacter.charClass + '<br/>';
	panelStuff += 'HP: ' + selectedCharacter.HP + '/' + selectedCharacter.maxHP + '<br/>';
	panelStuff += 'MP: ' + selectedCharacter.MP + '/' + selectedCharacter.maxMP + '</div>';
	
	panelStuff += '<div style="float:left;padding:3px;padding-left:8px;">';
	panelStuff += 'Level: ' + selectedCharacter.level + '<br/>';
	panelStuff += 'Attack: ' + selectedCharacter.attack + '<br/>';
	panelStuff += 'Defense: ' + selectedCharacter.defense + '</div></div>';
	
	panelStuff += '<div style="float:left;padding:3px;padding-left:8px;">';
	panelStuff += 'Status: ' + selectedCharacter.status + '<br/>';
	panelStuff += 'Speed: ' + selectedCharacter.speed + '<br/>';
	panelStuff += 'Move: ' + selectedCharacter.moveRange + '</div></div>';
	
	panelStuff += '<div style="clear:left;"><div style="float:left;text-align:center;">Equipment:&nbsp;</div>';
	if(selectedCharacter.equipment.length == 0)
	{
		panelStuff += 'None';
	}
	else
	{
		var i;
		for(i=0;i<selectedCharacter.equipment.length;i++)
		{
			panelStuff += '<img id="equipment' + i + '" style="cursor:pointer;margin:5px;float:left;" onClick="equipmentHandler(\'' + name + '\')" src="images/' + selectedCharacter.equipment[i].image + '" />';
		}
	}
	panelStuff += '<div>';
	
	document.getElementById("teamButton").disabled = false;
	document.getElementById("magicButton").disabled = false;
	document.getElementById("itemButton").disabled = false;
	
	document.getElementById("cancelButton").setAttribute("onClick", "teamHandler()");
	
	document.getElementById("panel").innerHTML = panelStuff;
}

function nonbattleMagicHandler()
{
	if(selectedCharacter.spells.length == 0)
	{
		panelStuff = selectedCharacter.name + ": No Magic.";
	}
	else
	{
		if(selectedCharacter.spells.length == 1)
		{
			panelStuff = selectedCharacter.name + ": 1 Spell<br/>";
		}
		else
		{
			panelStuff = selectedCharacter.name + ": " + selectedCharacter.spells.length + " Spells<br/>";
		}
		
		var i;
		for(i=0;i<selectedCharacter.spells.length;i++)
		{
			panelStuff += '<img id="spell' + i + '" style="margin:5px;float:left;';
			
			if(selectedCharacter.spells[i].canTarget == "ally" || selectedCharacter.spells[i].canTarget == "both")
			{
				panelStuff += 'cursor:pointer;" onClick="handleSpell(\'' + selectedCharacter.name + '\',  ' + i + ')';
			}
			
			panelStuff += '" src="images/' + selectedCharacter.spells[i].image + '" />';
		}
	}
	
	document.getElementById("magicButton").disabled = true;
	
	document.getElementById("cancelButton").setAttribute("onClick", "characterHandler('" + selectedCharacter.name + "')");
	
	document.getElementById("panel").innerHTML = panelStuff;
}

function handleSpell(charName, spellNum)
{
	panelStuff = "Who will " + charName + " cast " + selectedCharacter.spells[spellNum].name + " on?<br/>";
	
	var i;
	for(i=0;i<playerTeam.length;i++)
	{
		panelStuff += '<div onClick="castSpell(\'' + charName + '\', ' + spellNum + ', \'' + playerTeam[i].name + '\')" style="float:left;padding:5px;text-align:center;cursor:pointer;">';
		panelStuff += '<div style="width:' + tileSize + 'px;height:' + tileSize + 'px;overflow:hidden;">';
		panelStuff += '<img src="images/' + playerTeam[i].image + '" /></div>';
		panelStuff += playerTeam[i].name + '</div>';
	}
	
	document.getElementById("cancelButton").setAttribute("onClick", "magicHandler('" + charName + "')");
	document.getElementById("panel").innerHTML = panelStuff;
}

function castSpell(userName, spellNum, targetName)
{
	user = playerCharacters.getCharacter(userName);
	spell = user.spells[spellNum];
	target = playerCharacters.getCharacter(targetName);
	
	nonbattleAnimation(4);
	
	mssg = user.castSpell(spell, target);
	
	document.getElementById("magicButton").disabled = false;
	document.getElementById("cancelButton").setAttribute("onClick", "characterHandler('" + selectedCharacter.name + "')");
	
	document.getElementById("panel").innerHTML = mssg;
}

function nonbattleItemHandler()
{
	if(selectedCharacter.items.length == 0)
	{
		panelStuff = selectedCharacter.name + ": No Items.";
	}
	else
	{
		if(selectedCharacter.items.length == 1)
		{
			panelStuff = selectedCharacter.name + ": 1 Item<br/>";
		}
		else
		{
			panelStuff = selectedCharacter.name + ": " + selectedCharacter.items.length + " Items<br/>";
		}
	
		var i;
		for(i=0;i<selectedCharacter.items.length;i++)
		{
			panelStuff += '<img id="item' + i + '" style="cursor:pointer;margin:5px;float:left;" onClick="handleItem(\'' + selectedCharacter.name + '\',  ' + i + ')" src="images/' + selectedCharacter.items[i].image + '" />';
		}
	}
	
	document.getElementById("controlButtons").innerHTML = standardControlButtons;
	document.getElementById("itemButton").disabled = true;
	document.getElementById("cancelButton").setAttribute("onClick", "characterHandler('" + selectedCharacter.name + "')");
	
	document.getElementById("panel").innerHTML = panelStuff;
}

function handleItem(charName, itemNum)
{
	user = playerCharacters.getCharacter(charName);
	// un-highlight any item that may have previously been selected
	var i;
	for(i=0;i<user.items.length;i++)
	{
		/** I need to use a CSS class for this **/
		document.getElementById("item" + i).style.margin = "5px";
		document.getElementById("item" + i).style.border = "";
	}
		/** I need to use a CSS class for this **/
		//  use addCssClass/removeCssClass with class=itemRange
	document.getElementById("item" + itemNum).style.margin = "4px";
	document.getElementById("item" + itemNum).style.border = "solid 1px blue";
	
	
	document.getElementById("controlButtons").innerHTML = itemControlButtons;
	document.getElementById("useButton").setAttribute("onClick", "itemTargetHandler('use', '" + charName + "', '" + itemNum + "')");
	document.getElementById("giveButton").setAttribute("onClick", "itemTargetHandler('give', '" + charName + "', '" + itemNum + "')");
	document.getElementById("equipButton").setAttribute("onClick", "equipItem('" + charName + "', '" + itemNum + "')");
	document.getElementById("dropButton").setAttribute("onClick", "dropItem('" + charName + "', '" + itemNum + "')");
	document.getElementById("cancelButton").setAttribute("onClick", "itemHandler()");
}

function itemTargetHandler(action, userName, itemNum)
{
	panelStuff = "Select a Caracter:<br/>";
	if(action == "use")
	{
		panelStuff = "Who will you use it on?<br/>";
	}
	else if(action = "give")
	{
		panelStuff = "Who will you give it to?<br/>";
	}

	
	for(i=0;i<playerTeam.length;i++)
	{
		panelStuff += '<div onClick="' + action + 'Item(\'' + userName + '\', ' + itemNum + ', \'' + playerTeam[i].name + '\')" style="float:left;padding:5px;text-align:center;cursor:pointer;">';
		panelStuff += '<div style="width:' + tileSize + 'px;height:' + tileSize + 'px;overflow:hidden;">';
		panelStuff += '<img src="images/' + playerTeam[i].image + '" /></div>';
		panelStuff += playerTeam[i].name + '</div>';
	}
	
	document.getElementById("cancelButton").setAttribute("onClick", "itemHandler('" + userName + "')");
	document.getElementById("cancelButton").disabled = "";
	
	document.getElementById("panel").innerHTML = panelStuff;
}

function useItem(userName, itemNum, targetName)
{
	user = playerCharacters.getCharacter(userName);
	target = playerCharacters.getCharacter(targetName);
	
	nonbattleAnimation(4);
	
	mssg = user.useItem(itemNum, target);
	
	document.getElementById("controlButtons").innerHTML = standardControlButtons;
	document.getElementById("cancelButton").setAttribute("onClick", "characterHandler('" + selectedCharacter.name + "')");
	
	document.getElementById("panel").innerHTML = mssg;
}

function giveItem(userName, itemNum, targetName)
{
	user = playerCharacters.getCharacter(userName);
	target = playerCharacters.getCharacter(targetName);
	
	mssg = user.giveItem(itemNum, target);
	
	document.getElementById("controlButtons").innerHTML = standardControlButtons;
	document.getElementById("cancelButton").setAttribute("onClick", "characterHandler('" + selectedCharacter.name + "')");
	
	document.getElementById("panel").innerHTML = mssg;
}

function equipItem(charName, itemNum)
{
	mssg = playerCharacters.getCharacter(charName).equipItem(itemNum);
	if(mssg == "ok")
	{
		document.getElementById("controlButtons").innerHTML = standardControlButtons;
	
		characterHandler(charName);
	}
	else
	{
		document.getElementById("panel").innerHTML = mssg;
	}
}

function dropItem(charName, itemNum)
{
	selectedChar = playerCharacters.getCharacter(charName);
	selectedItem = selectedChar.items[itemNum];
	
	confirmation = confirm("Are you sure you want to drop the " + selectedItem.name + "?");
	
	if(confirmation)
	{
		selectedChar.items.splice(itemNum, 1);
		itemHandler(charName);
	}
}

function equipmentHandler(charName)
{
	var i = 0;
	var j = 0;
	selectedChar = playerCharacters.getCharacter(charName);
	panelStuff = charName + "'s Equipment:<br/>";
	
	for(i=0;i<selectedChar.equipment.length;i++)
	{
		panelStuff += '<div style="overflow:hidden;"><div style="cursor:pointer;margin:5px;float:left;">' + selectedChar.equipment[i].equipType + ':</div><div id="equip' + i + '" style="cursor:pointer;margin:5px;float:left;" onClick="handleEquipment(\'' + charName + '\', ' + i + ')"><img src="images/' + selectedChar.equipment[i].image + '" /></div><div style="margin:5px;float:left;">' + selectedChar.equipment[i].name;
		for(j=0;j<selectedChar.equipment[i].equipEffects.length;j++)
		{
			effect = selectedChar.equipment[i].equipEffects[j];
			if(effect > 0){effect = "+" + effect;}
			stat = selectedChar.equipment[i].equipEffectStats[j];
			
			panelStuff += '<br/>' + stat + ': ' + effect;
		}
		
		if(selectedChar.equipment[i].spell != "")
		{
			panelStuff += '<br/>Casts: ' + selectedChar.equipment[i].spell;
		}
		
		panelStuff += '</div></div>';
	}
	
	document.getElementById("controlButtons").innerHTML = standardControlButtons;
	document.getElementById("cancelButton").setAttribute("onClick", "characterHandler('" + selectedCharacter.name + "')");
	
	document.getElementById("panel").innerHTML = panelStuff;
}

function handleEquipment(charName, equipNum)
{
	selectedChar = playerCharacters.getCharacter(charName);
	
	// unhighlight any previously selected items
	var i;
	for(i=0;i<selectedChar.equipment.length;i++)
	{
		document.getElementById("equip" + i).style.border = "";
		document.getElementById("equip" + i).style.margin = "5px";
	}
	
	document.getElementById("equip" + equipNum).style.margin = "4px";
	document.getElementById("equip" + equipNum).style.border = "solid 1px blue";
	
	
	document.getElementById("controlButtons").innerHTML = itemControlButtons;
	
	document.getElementById("useButton").disabled = true;
	document.getElementById("giveButton").disabled = true;
	document.getElementById("equipButton").disabled = true;
	document.getElementById("dropButton").disabled = true;
	
	document.getElementById("unequipButton").setAttribute("onClick", "unequipItem('" + charName + "', " + equipNum + ")");
	document.getElementById("unequipButton").disabled = "";
	
	document.getElementById("cancelButton").setAttribute("onClick", "equipmentHandler('" + charName + "')");
}

function unequipItem(charName, equipNum)
{
	selectedChar = playerCharacters.getCharacter(charName);
	selectedChar.unequipItem(equipNum);
	equipmentHandler(charName);
}

function openDialog(speaker, text)
{
	dialogOpen = true;
	
	dialogContents = '<div id="measuringDiv" style="overflow:hidden;"><div id="dialogCloseButtonDiv" style="text-align:right;border-bottom:solid 1px grey;"><input type="image" src="images/closeButton.png" onClick="closeDialog()" style="cursor:pointer;" /></div>';
	dialogContents += text;
	dialogContents += '</div>';
	
	target = document.getElementById(speaker.x + "-" + speaker.y);
	dialog = document.getElementById("dialog");

	dialog.innerHTML = dialogContents;
	dialog.style.left = (target.offsetLeft + target.offsetWidth) + "px";
	
	if(target.offsetTop - dialog.offsetHeight >= 0)
	{
		dialog.style.top = (target.offsetTop - dialog.offsetHeight) + "px";
	}
	else if(target.offsetTop - dialog.offsetHeight > tileSize / -2)
	{
		dialog.style.top = "0px";
	}
	else // as close as possible
	{
		dialog.style.top = (0 - tileSize/2) + "px";
	}	
	
	dialog.style.opacity = 1;
}

function closeDialog()
{
	dialog = document.getElementById("dialog");
	
	dialog.style.opacity = 0;
	dialog.innerHTML = "";
	dialog.style.top = "0px";
	dialog.style.left = "0px";
	
	dialogOpen = false;
	
	document.body.focus();
}

function resetMainCharacter()
{
	if(playerTeam[0].status != "dead")
	{
		playerTeam[0].x = currentCharacter.x;
		playerTeam[0].y = currentCharacter.y;
		
		document.body.removeChild(document.getElementById(currentCharacter.elementId));
				
		currentCharacter = playerTeam[0];
		
		placeUnit(currentCharacter, currentCharacter.x, currentCharacter.y);
	}
}

function center(x, y)
{
	target = document.getElementById(x + "-" + y);
	
	targetCenterX = target.offsetLeft + Math.round(target.offsetWidth / 2);
    targetCenterY = target.offsetTop + Math.round(target.offsetHeight / 2);
	scrollX = targetCenterX - Math.round(screenWidth / 2) + centerOffsetX;
    scrollY = targetCenterY - Math.round(screenHeight / 2) + centerOffsetY;
	scrollTo(scrollX, scrollY);
}

function nonbattleAnimation(n)
{
	busy = true;
	charImg = document.getElementById(currentCharacter.elementId + "Img");

	// this is what does the attacking animation
	if(charImg.offsetLeft == 0)
	{
		charImg.style.left = (tileSize * -2) + "px";
	}
	else
	{
		charImg.style.left = "0px";
	}
	
	n--;
	if(n > 0)
	{
		ato = setTimeout("nonbattleAnimation(" + n + ")", 100);
	}
	else
	{
		charImg.style.left = "0px";
		busy = false;
	}
}

/****	end nonbattle-specific functions	****/

/*****************************************************
		DEBUGGING FUNCTIONS
*****************************************************/

function showSpaces(spaces)
{
	var i = 0;
	
	for(i=0;i<spaces.length;i++)
	{
		addCssClass(spaces[i].spaceID, "spellRange");
	}
	alert("showing " + spaces.length + " spaces");
	for(i=0;i<spaces.length;i++)
	{
		removeCssClass(spaces[i].spaceID, "spellRange");
	}
}

function showSpaceDanger(spaces)
{
	var i;
	for(i=0;i<spaces.length;i++)
	{
		document.getElementById(spaces[i].spaceID).innerHTML = spaces[i].danger;
	}
	
	alert(" ");
	for(i=0;i<spaces.length;i++)
	{
		document.getElementById(spaces[i].spaceID).innerHTML = '<span style="visibility:hidden;"> </span>';
	}
}

/****	end debugging functions	****/






