function TntGame(id, pc) {
	this.id = id;
	this.pc = pc;
	this.friends = [];
	this.lastFriendNum = 0;
	this.lastSummoned = 0;
	this.befriended = false;
	this.foes = [];
	this.turns = 1;
	this.foesDefeated = 0;
	this.onContinue = TntGame.noop;
	this.updateDisplay = TntGame.noop;
	this.hideFoeDisplay = TntGame.noop;
	this.hideFriendDisplay = TntGame.noop;
	this.updateFoesDistanceDisplay = TntGame.noop;
	this.updateTargetFoe = TntGame.noop;
	this.updateTurnsDisplay = TntGame.noop;
	this.addTargetActions = TntGame.noop;
	this.targetFoe = 0;
	TntGame.allGames[id] = this;
	this.newCombat();
}

TntGame.allGames = [];

TntGame.getGame = function(id) {
	return TntGame.allGames[id];
};

TntGame.noop = function() {};

TntGame.calcAdd = function(stat) {
	if (stat < 9) return stat - 9;
	if (stat > 12) return stat - 12;
	return 0;
};

TntGame.rollSR = function(lvl, stt, charLvl) {
	if (!charLvl) charLvl = 0;
	var r = Adv.myrandom.dice(2,6);
	var roll = r[0];
	while (Adv.maxEntry(r, 1, 6) == 2) {
		r = Adv.myrandom.dice(2,6);
		roll += r[0];
	}
	var srap = roll * lvl;
	var target = lvl * 5 + 15;
	var total = roll + stt + charLvl;
	var success = ((total >= target) && (roll != 3)) ? true : false;
	var missed = 0;
	if (!success) {
		if (total < target) missed = target - total;
		else missed = 1;
	}
	var srr = {"success" : success, "roll" : roll, "total" : total, "missed" : missed, "target" : target, "ap" : srap};
	return srr;
};

TntGame.prototype.runaway = function() {
	var maxFoeSpd = 0;
	var i;
	for (i=0; i<this.foes.length; ++i) {
		var foeSpd = this.foes[i].getSpd();
		if (foeSpd > maxFoeSpd) maxFoeSpd = foeSpd;
	}
	var foeSpdSr = TntGame.rollSR(1, maxFoeSpd);
	var pcSpdSr = this.pc.rollSR(1, "SPD", true);

//	this.adv.addContent("<p style='font-style: italic;'>You try to run away.</p>");
	if (foeSpdSr.total < pcSpdSr.total) {
		this.adv.addContent("<p style='font-size: 1.1em; color: #060;'>You get away!</p>");
		return true;
	} else {
//		this.adv.addContent("<p style='font-style: oblique; color: #600;'>You failed to get away...</p>");
		return false;
	}
};

TntGame.prototype.dodge = function() {
//	this.adv.addContent("<p style='font-style: italic;'>You attempt to dodge your foe's attack.</p>");
	var difficulty = 1;
	difficulty += Math.floor(this.turns / 8);
	if (this.pc.type == "Ranger") difficulty = 1;
	difficulty += Math.floor(this.combatTurns / 8);
	var pcSpdSr = this.pc.rollSR(difficulty, "SPD", true);
//	this.adv.addContent("<p>SPD SR, Target: " + pcSpdSr.target + ", Roll: " + pcSpdSr.roll + ", Total: " + pcSpdSr.total + ", Success: " + pcSpdSr.success + "</p>");
	if (pcSpdSr.success) {
//		this.adv.addContent("<p style='font-style: italic; color: #060;'>The way you sidestepped that attack, you might oughta consider a career as a dancer!</p>");
		return true;
	} else {
		var stubDmg = Adv.myrandom.dice(1,6)[0];
		this.adv.addContent("<p style='font-style: oblique; color: #600;'>You stumbled!</p>");
		this.pc.addSpiteDamage(stubDmg);
		return false;
	}
};

TntGame.prototype.talk = function() {
//	this.adv.addContent("<p style='font-style: italic;'>You start talking, turning on the charm.</p>");
	if (this.foes[this.targetFoe].comprehension) {
		var difficulty = 1; // parseInt(this.foes[this.targetFoe].getLife() / 10);
//		if (difficulty < 1) difficulty = 1;
		difficulty += this.numUnsummonedFriends();
		if (this.pc.type == "Leader") difficulty = 1;
		var pcChrSr = this.pc.rollSR(difficulty, "CHR", true);
//		this.adv.addContent("<p>CHR SR, Target: " + pcChrSr.target + ", Roll: " + pcChrSr.roll + ", Total: " + pcChrSr.total + ", Success: " + pcChrSr.success + "</p>");

		if (pcChrSr.success) {
//			this.adv.addContent("<p style='font-size: 1.0em; color: #060;'>You have such a way with words!</p>");
			return true;
		} else {
//			this.adv.addContent("<p style='font-style: oblique; color: #600;'>But your personality is falling flat today...</p>");
			return false;
		}
	} else {
//		this.adv.addContent("<p style='font-style: oblique; color: #600;'>Unfortunately, you don't speak this UGH monster's language!</p>");
		return false;
	}
};

TntGame.prototype.doAction = function(act) {
	this.adv.clearActions();
	this.adv.showInitContent();
	this.pc.dodged = false;
	if (act == "Rogue" || act == "Warrior" || act == "Wizard"
			|| act == "Ranger" || act == "Leader") {
		if (this.turns != 1) {
			alert("Error: You can't change character types in the middle of your UGH adventure!");
			return;
		}
		this.pc.distance = 0;
		this.pc.type = act;
		if (this.pc.type == "Warrior") this.pc.armorValue *= 2;
		if (this.pc.type == "Rogue") {
			var lk = this.pc.getStat("LK");
			var iq = this.pc.getStat("INT");
			var ch = this.pc.getStat("CHR");
			var maxStat = lk;
			if (iq > maxStat) maxStat = iq;
			if (ch > maxStat) maxStat = ch;
			var bonus = Adv.myrandom.dice(1,6)[0];
			this.pc.roguery = maxStat + bonus;
		}
		this.pc.calcLevel();
		this.pc.display();
		if (this.setCharacterType) this.setCharacterType(act);
		if (this.setNewActions) this.setNewActions(1);
		return;
	}
	if (act == "Try Again") {
		location.reload();
		return;
	}
	if (act == "High Scores") {
		if (typeof this.highScoresURL != "undefined")
			location.href = this.highScoresURL + "?trollname=" + escape(this.pc.Name);
		return;
	}
	var i;
	var j;
	var plural = "";
	var durationlvl = 0;
	var numberlvl = 0;
	var levelDist = {"duration" : 1, "effect" : 1};
	var numFoes = this.foes.length;
	var doResolveAttacks = true;
	if (act == "Next") {
		this.targetFoe = 0;
		this.nextTurn();
		this.newCombat();
		this.updateDisplay();
//		this.adv.clearContent();
		for (i=0; i<this.foes.length; ++i) {
			this.foes[i].display();
			this.foes[i].clearTmpEffects();
		}
		this.pc.display();
		this.pc.clearTmpEffects();
		for (i=0; i<this.friends.length; ++i) {
			this.friends[i].display();
			this.friends[i].clearTmpEffects();
		}
		if (this.setNewActions)
			this.setNewActions(this.turns);
		return;
	}

	this.nextCombatTurn();

	if (act == "Run Away") {
		if (this.runaway() == true) {
			this.clearFoes();
			this.onContinue();
			return;
		}
	}

	if (act == "Chat") {
		if (this.talk()) {
			if (typeof this.foes[this.targetFoe].MR != "undefined") {
//				this.adv.addContent("<p>" + this.foes[this.targetFoe].Name + " is impressed with you, and joins forces with you!</p>");
				var companion = new TntMonster();
				companion.setPrefix("companion" + this.lastFriendNum);
				this.lastFriendNum++;
//				companion.setName("<span style='color: green;'>Friendly UGH " + this.lastFriendNum + "</span>");
				companion.setName("#" + this.lastFriendNum);
				if (this.initFriend) this.initFriend(companion);
				companion.initMR(this.foes[this.targetFoe].getMaxLife());
				companion.MR = this.foes[this.targetFoe].getLife();
				companion.summoned = false;
				companion.plural = false;
				companion.duration = 0;
				companion.isChatting = true;
				companion.attack = {};
				companion.clearAttack();
				companion.distance = 0;
				companion.display();
				this.addFriend(companion);
				this.befriended = true;
				this.hideFoeDisplay(this.foes[this.targetFoe].prefix);
				Adv.removeFromArray(this.foes, this.targetFoe);
				this.clearTargetFoe();
				if (this.foes.length == 0) {
					companion.isChatting = false;
					this.onContinue();
					return;
				} else {
					this.pc.isChatting = true;
				}
			}
		} else {
			this.pc.isChatting = true;
		}
	}

	var magiclvl = 0;
	if (act == "TTYF") {
		magiclvl = this.magic("TTYF", 1, 6, this.pc, this.foes[this.targetFoe]);
		if (magiclvl > 0) {
			var ttyfDmg = this.doubling(this.pc.INT, 1, magiclvl);
			this.pc.setHpt(ttyfDmg);
			this.foes[this.targetFoe].setMinimumDamage(ttyfDmg);
//			this.adv.addContent("<p>You cast TTYF for " + ttyfDmg + " damage.</p>");
		} else if (magiclvl == 0) {
			this.changedMindSpell("TTYF");
			return;
		}
	} else if (act == "Protective Pentagram") {
		magiclvl = this.magic("Protective Pentagram", 4, 24, this.pc, this.pc);
		if (magiclvl > 0) {
//			this.adv.addContent("<p>You cast Protective Pentagram upon yourself.</p>");
			var protEffect = new TntEffect("Protective Pentagram");
			protEffect.setDuration(this.doubling(2, 4, magiclvl));
			this.pc.addEffect(protEffect);
		} else if (magiclvl == 0) {
			this.changedMindSpell("Protective Pentagram");
			return;
		}
	} else if (act == "Slush Yuck") {
		magiclvl = this.magic("Slush Yuck", 3, 15, this.pc, null);
		if (magiclvl > 0) {
			if (this.foes.length > 1) plural = "s";
//			this.adv.addContent("<p>You cast Slush Yuck under your foe" + plural + ".</p>");
			var levelDist = this.getMagicLevelDist(magiclvl, 3);
			durationlvl = levelDist.duration;
			numberlvl = levelDist.effect;
			j = 0;
			var powerlvl = this.doubling(3, 3, numberlvl);
			var numberEffected = powerlvl;
			if (numberEffected > numFoes) numberEffected = numFoes;
			var greaterEffect = Math.ceil(powerlvl / numberEffected);
			var lesserEffect = greaterEffect - 1;
			var numEffectedLesser = 0;
			var numEffectedGreater = 1;
			if (numberEffected > 1) {
				numEffectedGreater = powerlvl % numberEffected;
				if (!numEffectedGreater) numEffectedGreater = numberEffected;
				numEffectedLesser = numberEffected - numEffectedLesser;
			}
			var slushTurns = this.doubling(2, 3, durationlvl);
			var slushEffect = greaterEffect;
			for (i=0; i<numberEffected; ++i) {
				if (i >= numEffectedGreater) {
					slushEffect = lesserEffect;
				}
				var slushSpellEffect = new TntEffect("Slush Yuck");
				slushSpellEffect.setDuration(slushTurns);
				var stt = this.foes[i].getStat("SPD");
				var sr = TntGame.rollSR(magiclvl, stt);
				if (!sr.success) {
					slushEffect += 2;
				}
				slushSpellEffect.rolledSR = true;
				slushSpellEffect.madeSR = sr.success;
				slushSpellEffect.srLevel = magiclvl;
				slushSpellEffect.stat = "SPD";
				slushSpellEffect.setEffectAmount(slushEffect);
				this.foes[i].addEffect(slushSpellEffect);
			}
//			this.foes[this.targetFoe].distance = 0;
//			this.setAllCanAttack(true);
		} else if (magiclvl == 0) {
			this.changedMindSpell("Slush Yuck");
			return;
		}
	} else if (act == "HTP") {
		magiclvl = this.magic("HTP", 1, 4, this.pc, this.foes[this.targetFoe]);
		if (magiclvl > 0) {
			var htpSpellEffect = new TntEffect("HTP");
			htpSpellEffect.setDuration(this.doubling(1, 1, magiclvl));
			this.foes[this.targetFoe].addEffect(htpSpellEffect);
			if ((this.friends.length > 0) && (this.foes[0].distance < 4)) {
//				this.setDistanceAllFoes(0);
				this.setAllCanAttack(true);
			}
		} else if (magiclvl == 0) {
			this.changedMindSpell("HTP");
			return;
		}
	} else if (act == "DBGR") {
		magiclvl = this.magic("DBGR", 1, 10, this.pc, null);
		if (magiclvl > 0) {
			var skeletonMR = this.pc.STR + this.pc.CON;
			levelDist = this.getMagicLevelDist(magiclvl, 1);
			durationlvl = levelDist.duration;
			numberlvl = levelDist.effect;

			var numSkulls = this.doubling(1, 1, numberlvl);
			var skeletons = new TntMonster();
			skeletons.setPrefix("skeletons" + this.lastSummoned);
			this.lastSummoned++;
			var skeletonName = "Skeleton";
			if (numSkulls > 1) skeletonName = numSkulls + " Skeletons";
			skeletons.setName(skeletonName);
			skeletons.initMR(skeletonMR * numSkulls);
			skeletons.summoned = true;
			skeletons.plural = (numSkulls > 1);
			skeletons.duration = this.doubling(2, 1, durationlvl) - 1; // the initial decrement of the first turn must be done now...
			skeletons.calculateAttack();
			skeletons.display();
			this.addFriend(skeletons);
		} else if (magiclvl == 0) {
			this.changedMindSpell("DBGR");
			return;
		}
	} else if (act == "Wait") {
		this.pc.isWaiting = true;
	} else if (act == "Close") {
		this.pc.isClosing = true;
	} else if (act == "Fight") {
		this.setDistanceAllFoes(0);
		this.setAllCanAttack(true);
		doResolveAttacks = true;
	} else if (act == "Evade") {
		this.pc.isDodging = true;
		this.setDistanceAllFoes(0);
		this.setAllCanAttack(true);
		doResolveAttacks = true;
		this.pc.dodged = this.dodge();
	} else if (act == "Forward") {
//		this.adv.addContent("<p>You move towards your foe" + plural + "!</p>");
		var distSpd = this.pc.getStat("SPD") + 10;
		var distTraveled = Adv.myrandom.dice(2, distSpd)[0];
		this.moveFoes(distTraveled);
		this.pc.isMoving = true;
	} else if (act == "Charge") {
		this.moveFoes(this.foes[this.targetFoe].distance);
		this.setAllCanAttack(true);
		doResolveAttacks = true;
		this.pc.isCharging = true;
	} else if (act == "Missile") {
//		this.adv.addContent("<p>You take a shot at the oncoming enemy, at a distance of " + this.foes[this.targetFoe].distance + " yards.</p>");
		var srroll = this.pc.rollSR(this.getMissileSRLevel(), "DEX", true);
//		this.adv.addContent("<p>DEX SR, Target: " + srroll.target + ", Roll: " + srroll.roll + ", Total: " + srroll.total + ", Success: " + srroll.success + "</p>");
		if (srroll.success == true) {
			this.pc.calculateMissileAttack();
			this.foes[this.targetFoe].setMinimumDamage(this.pc.getHpt());
			this.foes[this.targetFoe].addSpiteDamage(this.pc.getSpite());
		} else {
			this.adv.addContent("<p>You missed!</p>");
			this.pc.clearAttack();
		}
		this.pc.isShooting = true;
		doResolveAttacks = true;
	} else if (typeof this.specialActions == "function") {
		doResolveAttacks = this.specialActions(act);
	}
	doResolveAttacks |= this.closing();
	this.setEncounterActions();
	if (doResolveAttacks) this.resolveAttacks();
};

TntGame.prototype.getMissileSRLevel = function() {
	if (this.pc.type == "Ranger") return 1;
	if (this.foes[this.targetFoe].distance < 4) return 1;
	if (this.foes[this.targetFoe].distance < 11) return 2;
	if (this.foes[this.targetFoe].distance < 34) return 3;
	if (this.foes[this.targetFoe].distance < 101) return 4;
	return 5;
};

TntGame.prototype.magic = function(spellname, baselevel, basecost, caster, target) {
	caster.clearAttack();
	caster.castSpell = true;
	var charlvl = caster.getWizardLevel();
	var magicPrompt = "At what level do you wish to cast your spell (minimum level = " + baselevel + ")? ";
	var resisted = false;
	if (target && target.WIZ > caster.WIZ) {
		magicPrompt += "(You get a Bad Feeling about casting your spell.) ";
		resisted = true;
	}
	magicPrompt += "Enter 0 or click Cancel to change your action.";
	var lvl = baselevel;
	if (caster == this.pc) {
		if (!this.lastSpellLevel) this.lastSpellLevel = 1;
		var defLevel = this.lastSpellLevel;
		if ((caster.type == "Rogue") || (defLevel < baselevel)) {
			defLevel = baselevel;
		}
		if (caster.type == "Wizard" || resisted) {
			lvl = parseInt(window.prompt(magicPrompt, defLevel));
		} else {
			lvl = defLevel;
		}
	}
	if (!lvl) return 0;
	this.lastSpellLevel = lvl;

	var fizzles = false;

	if (lvl < baselevel) {
		if (caster == this.pc) {
//			this.adv.addContent("<p>You try to cast " + spellname + " at level " + lvl + ", but it must be cast at level " + baselevel + " or higher. Your spell fizzles.</p>");
			fizzles = true;
//			return -1;
		}
	}

	if (caster.type == "Rogue") {
		if (lvl > baselevel) {
//			this.adv.addContent("<p>You try to cast " + spellname + " at level " + lvl + ", but being a Rogue, you can not cast the spell at higher than its base level of " + baselevel + ". Your spell fizzles.</p>");
			fizzles = true;
//			return -1;
		}
	}

	var statmin = 10;
	var i;
	for (i=2; i<=lvl; ++i) {
		statmin += i;
	}
	var dexlow = false;
	var intlow = false;
	if (caster.DEX < statmin) {
		dexlow = true;
//		if (caster == this.pc) {
//			this.adv.addContent("<p>Your DEX is too low to cast " + spellname + " at level " + lvl + ". (You need " + statmin + ".)</p>");
//		}
	}
	if (caster.INT < statmin) {
		intlow = true;
//		if (caster == this.pc) {
//			this.adv.addContent("<p>Your INT is too low to cast " + spellname + " at level " + lvl + ". (You need " + statmin + ".)</p>");
//		}
	}
	if (intlow || dexlow || fizzles) {
		if (caster == this.pc) {
			this.adv.addContent("<p>Your spell fizzles.</p>");
		}
		return -1;
	}

	var totwizcost = basecost * (lvl - baselevel + 1);
	if ((charlvl > lvl) && caster.type && (caster.type == "Wizard")) {
		totwizcost -= (charlvl - lvl);
	}
	if ((typeof caster.hasFocus == "function") && caster.hasFocus() && caster.type && (caster.type == "Wizard")) {
		totwizcost -= charlvl;
	}
	if (totwizcost < 1) totwizcost = 1;
//	if (caster == this.pc) {
//		this.adv.addContent("<p>You attempt to cast " + spellname + " at level " + lvl + " for a total cost of " + totwizcost + " WIZ.</p>");
//	}
	if (totwizcost > caster.WIZ) {
		if (caster == this.pc) {
//			this.adv.addContent("<p>You don't have enough WIZ! The spell fizzles...</p>");
			this.adv.addContent("<p>Your spell fizzles.</p>");
		}
		return -1;
	}
	caster.WIZ -= totwizcost;
	if (resisted) {
		if (caster == this.pc) {
//			this.adv.addContent("<p>Your target's WIZ is higher than yours! The spell fizzles...</p>");
			this.adv.addContent("<p>Your spell fizzles.</p>");
		}
		target.WIZ -= totwizcost;
		return -1;
	}
	var srroll = [];
	if (caster == this.pc) {
		srroll = this.pc.rollSR(lvl, "INT", true);
//		this.adv.addContent("<p>INT SR, Target: " + srroll.target + ", Roll: " + srroll.roll + ", Total: " + srroll.total + ", Success: " + srroll.success + "</p>");
	} else {
		srroll = TntGame.rollSR(lvl, caster.INT);
	}
	if (srroll.success == false) {
		this.adv.addContent("<p>Your spell fizzles.</p>");
		return -1;
	}
	if (typeof caster.addAP == "function") caster.addAP(totwizcost);
	return lvl;
};

TntGame.prototype.getMagicLevelDist = function(magiclvl, baselevel) {
	var extraDurationLevels = 0;
	var extraLevels = magiclvl - baselevel;
	if (extraLevels > 0) {
		if (!this.lastExtraDuration) this.lastExtraDuration = 0;
		var gotit = false;
		while (!gotit) {
			extraDurationLevels = parseInt(window.prompt("How many extra levels (0-" + extraLevels + ") do you want to allocate towards extending the duration of your spell?", this.lastExtraDuration));
			if (!extraDurationLevels) extraDurationLevels = 0;
			if ((extraDurationLevels >= 0) && (extraDurationLevels <= extraLevels)) {
				this.lastExtraDuration = extraDurationLevels;
				gotit = true;
			}
		}
	}
	return {"duration" : (extraDurationLevels + baselevel),
			"effect" : (baselevel + extraLevels - extraDurationLevels)};
};

TntGame.prototype.changedMindSpell = function(spellName) {
	this.adv.addContent("<p>You change your mind about casting " + spellName + ". Choose an action.</p>");
	this.combatTurns--;
};

TntGame.prototype.doubling = function(baseEffect, baseLevel, castingLevel) {
	if (castingLevel < baseLevel) return 0;
	if (baseEffect <= 0) return 0;
	if (baseLevel < 1) return 0;
	var effect = baseEffect;
	var i;
	for (i=baseLevel; i<castingLevel; ++i) {
		effect *= 2;
	}
	return effect;
};

TntGame.prototype.clearFriends = function() {
	this.friends = [];
};

TntGame.prototype.addFriend = function(friend) {
	this.friends[this.friends.length] = friend;
};

TntGame.prototype.clearSummonedFriends = function() {
	var i;
	for (i=this.friends.length - 1; i>=0; --i) {
		if (this.friends[i].summoned) {
			Adv.removeFromArray(this.friends, i);
		}
	}
};

TntGame.prototype.numSummonedFriends = function() {
	var num = 0;
	var i;
	for (i=this.friends.length - 1; i>=0; --i) {
		if (this.friends[i].summoned) {
			++num;
		}
	}
	return num;
};

TntGame.prototype.numUnsummonedFriends = function() {
	return this.friends.length - this.numSummonedFriends();
};

TntGame.prototype.clearFoes = function() {
	this.foes = [];
};

TntGame.prototype.addFoe = function(foe) {
	this.foes[this.foes.length] = foe;
};

TntGame.prototype.nextTurn = function() {
	this.turns++;
};

TntGame.prototype.nextCombatTurn = function() {
	this.combatTurns++;
//	this.adv.setContent("<p style='font-weight: bold; margin-top: 0; padding-top:3px;'>Encounter #" + this.turns + ", Combat Turn: <span id='combatTurns'>" + this.combatTurns + "</span></p>");
	this.updateTurnsDisplay(this.turns, this.combatTurns+1);
	this.pc.decrementEffects();
	this.pc.calculateAttack();
	this.pc.castSpell = false;
	this.pc.isWaiting = false;
	this.pc.isShooting = false;
	this.pc.isMoving = false;
	this.pc.isCharging = false;
	this.pc.isDodging = false;
	this.pc.dodged = false;
	for (i=0; i<this.foes.length; ++i) {
		this.foes[i].decrementEffects();
		this.foes[i].calculateAttack();
		this.foes[i].castSpell = false;
	}
	for (i=0; i<this.friends.length; ++i) {
		this.friends[i].decrementEffects();
		this.friends[i].calculateAttack();
		this.friends[i].castSpell = false;
	}
	this.updateTargetFoe();
};

TntGame.prototype.pruneExpired = function() {
	var i;
	for (i=this.friends.length - 1; i>=0; --i) {
		if (this.friends[i].getLife() <= 0
			|| (this.friends[i].summoned && this.friends[i].duration <= 0)) {
				if (this.friends[i].getLife() <= 0
					&& (!this.friends[i].summoned || this.friends[i].duration > 0)) {
						this.adv.addContent("<p style='color: red;'>" + this.friends[i].getName() + " has died.</p>");
						this.hideFriendDisplay(this.friends[i].prefix);
			}
			Adv.removeFromArray(this.friends, i);
		}
	}
	for (i=this.foes.length - 1; i>=0; --i) {
		if (this.foes[i].getLife() <= 0
			|| (this.foes[i].summoned && this.foes[i].duration <= 0)) {
			Adv.removeFromArray(this.foes, i);
			if (i == this.targetFoe) this.clearTargetFoe();
		}
	}
};

TntGame.prototype.newCombat = function() {
	this.combatTurns = 0;
	this.waitTurns = 0;
	this.engaged = false;
	this.targetFoe = 0;
	this.updateTargetFoe();
};

TntGame.prototype.resolveAttacks = function() {
	var i;
	var j;
	var k;
	var len;
	var which;
	var foeTotalHpt = 0;
	var foeTotalSpite = 0;
	var foeTotalMinDmg = 0;
	var friendTotalHpt = 0;
	var friendTotalSpite = 0;
	var friendTotalMinDmg = 0;
	for (i=0; i<this.foes.length; ++i) {
		if (this.foes[i].isAttacking(this)) {
			foeTotalHpt += Math.ceil(this.foes[i].getHpt() * this.foes[i].attackMultiplier());
			foeTotalSpite += this.foes[i].getSpite();
		}
		foeTotalMinDmg += this.foes[i].getMinimumDamage();
	}
	for (i=0; i<this.friends.length; ++i) {
		if (this.friends[i].isAttacking(this)) {
			friendTotalHpt += Math.ceil(this.friends[i].getHpt() * this.friends[i].attackMultiplier());
//			friendTotalHpt += this.friends[i].getHpt();
			friendTotalSpite += this.friends[i].getSpite();
		}
		friendTotalMinDmg += this.friends[i].getMinimumDamage();
	}
	if (this.pc.isAttacking(this)) {
		friendTotalHpt += Math.ceil(this.pc.getHpt() * this.pc.attackMultiplier());
//		friendTotalHpt += this.pc.getHpt();
		if (!this.pc.isShooting) {
			friendTotalSpite += this.pc.getSpite();
		}
	}
	friendTotalMinDmg += this.pc.getMinimumDamage();

	var foeDamage = friendTotalHpt - foeTotalHpt;
	var friendDamage = 0;
	if (foeDamage < 0) {
		friendDamage = -foeDamage;
		foeDamage = 0;
	}

	var foeResidualDmg = Math.max(0, foeDamage - foeTotalMinDmg);
	var friendResidualDmg = Math.max(0, friendDamage - friendTotalMinDmg);
	var numFoesHit = this.getTotalUnprotected(this.foes);
	var foeAvgDmg = 0;
	if (numFoesHit > 0) foeAvgDmg = Math.floor(foeResidualDmg / numFoesHit);
	var numFriendsHit = this.getTotalUnprotected(this.friends);
	var pcTmpProtected = this.pc.isProtected();
	var hasUnprotectedFriends
		= (this.getTotalUnprotected(this.friends) != 0);
//	if (numFriendsHit > 0) {
//		pcTmpProtected = true;
//	}
//	if ((numFriendsHit == 0) && !this.pc.isProtected()) {
//		numFriendsHit = 1;
//		pcTmpProtected = false;
//	}
	var pcTmpNormProtected = true;
	if (!hasUnprotectedFriends && !pcTmpProtected) {
		numFriendsHit = 1;
		pcTmpNormProtected = false;
	}

	var friendAvgDmg = 0;
	if (numFriendsHit > 0) friendAvgDmg = Math.floor(friendResidualDmg / numFriendsHit);
	var foeDistDmg = foeAvgDmg * numFoesHit;
	var friendDistDmg = friendAvgDmg * numFriendsHit;
	var foeRemDmg = foeResidualDmg - foeDistDmg;
	var friendRemDmg = friendResidualDmg - friendDistDmg;
	for (i=0; i<this.foes.length; ++i) {
		if (!this.foes[i].isProtected() && (this.foes[i].distance<4)) {
			this.foes[i].setNormalDamage(foeAvgDmg);
		}
	}
	for (i=0; i<this.friends.length; ++i) {
		if (!this.friends[i].isProtected()) {
			this.friends[i].setNormalDamage(friendAvgDmg);
		}
	}
	if (!pcTmpNormProtected) {
		this.pc.setNormalDamage(friendAvgDmg);
	}
	var which;
	if (numFoesHit > 0) {
		for (i=0; i<foeRemDmg; ++i) {
			which = this.getRandomUnprotected(this.foes, 0);
			if (which == -1) break;
			this.foes[which].addNormalDamage(1);
		}
	}
	var extras = 0;
	if (numFriendsHit > 0) {
		for (i=0; i<friendRemDmg; ++i) {
			which = this.getRandomUnprotected(this.friends, extras);
			if (which == -1) break;
			if (which < this.friends.length) {
				this.friends[which].addNormalDamage(1);
			} else {
				this.pc.addNormalDamage(1);
			}
		}
	}
	var spiteDmgDealt;
	var spiteToDeal = friendTotalSpite;
	var minSpite = Math.floor(spiteToDeal / 10);
	while (spiteToDeal > 0) {
		which = this.getRandomUnprotected(this.foes, 0);
		if (which == -1) break;
		if (which < this.foes.length) {
//			spiteDmgDealt = Adv.myrandom.randomBaseOne(spiteToDeal);
			spiteDmgDealt = Math.ceil(spiteToDeal / this.foes.length);
			if (spiteDmgDealt < minSpite) {
				spiteDmgDealt = minSpite + Adv.myrandom.randomBaseOne(spiteDmgDealt);
				if (spiteDmgDealt > spiteToDeal) {
					spiteDmgDealt = spiteToDeal;
				}
			}
			if (spiteToDeal < 5) spiteDmgDealt = spiteToDeal;
			this.foes[which].addSpiteDamage(spiteDmgDealt);
			spiteToDeal -= spiteDmgDealt;
		}
	}
	if (!pcTmpProtected) extras = 1;
	spiteToDeal = foeTotalSpite;
	minSpite = Math.floor(spiteToDeal / 10);
	while (spiteToDeal > 0) {
		which = this.getRandomUnprotected(this.friends, extras);
		if (which == -1) break;
//		spiteDmgDealt = Adv.myrandom.randomBaseOne(spiteToDeal);
//		spiteDmgDealt = Math.ceil(spiteToDeal / (1 + this.friends.length));
		spiteDmgDealt = spiteToDeal;
//		if (spiteDmgDealt < minSpite) {
//			spiteDmgDealt = minSpite + Adv.myrandom.randomBaseOne(spiteDmgDealt);
//			if (spiteDmgDealt > spiteToDeal) {
//				spiteDmgDealt = spiteToDeal;
//			}
//		}
//		if (spiteToDeal < 5) spiteDmgDealt = spiteToDeal;
		if (which < this.friends.length) {
			this.friends[which].addSpiteDamage(spiteDmgDealt);
		} else {
			this.pc.addSpiteDamage(spiteDmgDealt);
		}
		spiteToDeal -= spiteDmgDealt;
	}

	for (i=0; i<this.foes.length; ++i) {
		this.showAttack(this.foes[i]);
	}
	this.showAttack(this.pc);
	for (i=0; i<this.friends.length; ++i) {
		this.showAttack(this.friends[i]);
	}

	var foesRemaining = 0;
	for (i=0; i<this.foes.length; ++i) {
		this.showDamage(this.foes[i]);
		this.pc.addAP(this.foes[i].resolveCombatResult());
		this.foes[i].display();
		if (this.foes[i].getLife() > 0) foesRemaining++;
	}
	this.showDamage(this.pc);
	this.pc.resolveCombatResult();
	this.pc.display();
	for (i=0; i<this.friends.length; ++i) {
		this.showDamage(this.friends[i]);
		this.friends[i].resolveCombatResult();
		this.friends[i].display();
	}

	var done = false;
	if (foesRemaining == 0) {
		this.foesDefeated++;
		this.adv.addContent("<p style='font-size: 1.0em; color: #060;'>YOUR FOES ARE DEFEATED!</p>");
//		if (this.pc.getLife() > 0) {
//			this.adv.addContent("<p>Total Number of Encounters Survived so far: " + this.turns + "</p>");
//		}
		done = true;
		this.clearTargetFoe();
	}
	if (this.pc.getLife() <= 0) {
		this.adv.addContent("<p style='font-size: 1.1em; color: #600;'>YOU ARE DEFEATED! <span style='font-size: 1.2em; color: orange;'>UGH!</span></p>");
		done = true;
	}
	if (done) {
		if (this.pc.getLife() > 0) {
			this.onContinue();
		} else {
//			this.adv.addContent("<p>Better luck next time.</p>");
			this.adv.addContent("<p style='font-size: 1.0em;'>Total Number of Encounters Survived: " + (this.turns - 1) + "</p>");
			this.adv.clearActions();
			this.adv.addAction("Try Again");
			this.adv.addAction("High Scores");
			if (this.reportDeath) this.reportDeath();
		}
	} else {
		this.pruneExpired();
		this.addTargetActions();
	}
};

TntGame.prototype.getTotalUnprotected = function(creatures) {
	var numUnprot = 0;
	for (i=0; i<creatures.length; ++i) {
		if (!creatures[i].isProtected() && (creatures[i].distance<4)) {
			++numUnprot;
		}
	}
	return numUnprot;
};

TntGame.prototype.getRandomUnprotected = function(creatures, extras) {
	if (creatures.length + extras == 0) return -1;
	var numUnprot = this.getTotalUnprotected(creatures);
	var which = Adv.myrandom.random(numUnprot + extras);
	if (which >= creatures.length) return which;
	var k = -1;
	var j;
	for (j=0; j<creatures.length; ++j) {
		if (!creatures[j].isProtected() && (creatures[j].distance<4)) {
			++k;
			if (k == which) break;
		}
	}
	return j;
};

TntGame.prototype.showAttack = function(combatant) {
//	var has = "has";
//	var turns = "turns";
//	var verbPlurality = "s";
//	if (combatant.plural == true) {
//		has = "have";
//		verbPlurality = "";
//	}
//	if (combatant.duration == 1) {
//		turns = "turn";
//	}
////	if (!combatant.isAttacking(this) && !combatant.castSpell) {
////		this.adv.addContent("<p>" + combatant.getName() + " is not attacking.</p>");
////	} else if (!combatant.castSpell) {
	if (combatant.isAttacking(this)) {
//		var adds = combatant.getAdds();
//		var dice = combatant.getDice();
		if (combatant.isShooting) {
//			adds = combatant.getMissileAdds();
//			dice = combatant.getMissileDice();
			combatant.reduceAmmo();
		}
//		var sign = adds >= 0 ? "+" : "";
//		var multiplier = combatant.attackMultiplier();
////		this.adv.addContent("<p>" + combatant.getName() + " attack" + verbPlurality + " (" + dice
////			+ "D" + sign + adds + ") for " + combatant.getHpt() + " damage"
////			+ (multiplier == 1.0 ? "" : (" (* " + (Math.floor(1000 * multiplier)/1000) + " = " + Math.ceil(combatant.getHpt() * multiplier)) + ")")
////			+ " + " + combatant.getSpite() + " spite damage.</p>");
////	} else {
//		// Anything to do here? I think not...
	}
////	if (combatant.summoned) {
////		this.adv.addContent("<p>" + combatant.getName() + " " + has + " " + combatant.duration + " combat " + turns + " remaining.</p>");
////	}
	combatant.showEffects(this.adv);
};

TntGame.prototype.showDamage = function(combatant) {
//	var verbPlurality = "s";
//	if (combatant.plural == true) {
//		verbPlurality = "";
//	}
//	var magicDamage = combatant.getMinimumDamage() > 0
//		? combatant.getMinimumDamage() + " missile/magical damage + "
//		: "";
//	this.adv.addContent("<p>" + combatant.getName() + " take" + verbPlurality + " "
//		+ magicDamage
//		+ combatant.getNormalDamage() + " damage + "
//		+ combatant.getSpiteDamage() + " spite damage on CON and armor.</p>");
};

TntGame.prototype.setAllCanAttack = function(canAttack) {
	this.pc.canAttack = canAttack;
	var i;
	for (i=0; i<this.foes.length; ++i)
		this.foes[i].canAttack = canAttack;
	for (i=0; i<this.friends.length; ++i)
		this.friends[i].canAttack = canAttack;
};

TntGame.prototype.setDistanceAllFoes = function(dist) {
	var gnf;
	for (gnf = 0; gnf < this.foes.length; ++gnf) {
		if (!this.foes[gnf].isParalyzed(this)) {
			this.foes[gnf].distance = dist;
		}
	}
};

TntGame.prototype.updateFoesDistance = function() {
	var fdist = this.foes[0].distance;
	this.setDistanceAllFoes(fdist);
};

TntGame.prototype.allFoesParalyzed = function() {
	var gnf;
	for (gnf = 0; gnf < this.foes.length; ++gnf) {
		if (!this.foes[gnf].isParalyzed(this)) {
			return false;
		}
	}
	return true;
};

TntGame.prototype.moveFoes = function(dist) {
	var gnf;
	for (gnf = 0; gnf < this.foes.length; ++gnf) {
		if (!this.foes[gnf].isParalyzed(this)) {
			this.foes[gnf].distance -= dist;
			if (this.foes[gnf].distance < 0) {
				this.foes[gnf].distance = 0;
			}
		}
	}
};

TntGame.prototype.nearestFoeDistance = function() {
	var gnf;
	if (this.foes.length < 1) return 0;
	var ndist = this.foes[0].distance;
	for (gnf = 0; gnf < this.foes.length; ++gnf) {
		if (this.foes[gnf].distance < ndist) {
			ndist = this.foes[gnf].distance;
		}
	}
	return ndist;
};

TntGame.prototype.closing = function() {
	var doResolveAttacks = false;
	var dist = this.nearestFoeDistance();

	var distSpd = this.foes[this.targetFoe].getStat("SPD");
	var distClosed = distSpd + Adv.myrandom.dice(3, 6)[0];

	var closing = this.pc.isClosing;
	if (this.pc.isClosing) {
		this.pc.isClosing = false;
		this.pc.isWaiting = true;
		this.moveFoes(dist>1 ? dist-1 : 0);
	}

	var newDist = dist;
	if (!closing) {
		this.moveFoes(distClosed);
		newDist = this.nearestFoeDistance();
		if ((newDist < 4) && (this.friends.length > 0)) {
//			this.adv.addContent("<p>" + this.pc.getName() + "'s companions move to the attack; the enemy is engaged!</p>");
			this.moveFoes(4);
		}
	}
	if (newDist == 0) {
		doResolveAttacks = true;
//		if (this.pc.isCharging) {
//			this.adv.addContent("<p>" + this.pc.getName() + " charges to the attack!</p>");
//		} else {
//			this.adv.addContent("<p>" + this.pc.getName() + " and " + this.foes[0].getName() + " are at close combat distance.</p>");
//		}
	}
	this.updateFoesDistanceDisplay();
	if (this.engaged) return true;
	this.engaged = doResolveAttacks;
	return doResolveAttacks;
};
